From 260c924010361137dd67be145e9d5c0850804768 Mon Sep 17 00:00:00 2001 From: xxrl <837951112@qq.com> Date: Mon, 7 Nov 2022 01:25:36 +0800 Subject: [PATCH 001/116] opt: mac scroll to fast --- libs/enigo/src/macos/macos_impl.rs | 57 ++++++++++++++++++++++++++++++ src/client.rs | 23 ++++++++++++ src/server/input_service.rs | 41 +++++++++++++++------ 3 files changed, 111 insertions(+), 10 deletions(-) diff --git a/libs/enigo/src/macos/macos_impl.rs b/libs/enigo/src/macos/macos_impl.rs index 520c9dca1..fb9c2d680 100644 --- a/libs/enigo/src/macos/macos_impl.rs +++ b/libs/enigo/src/macos/macos_impl.rs @@ -580,6 +580,63 @@ impl Enigo { _ => u16::MAX, } } + + #[inline] + fn mouse_scroll_impl(&mut self, length: i32, is_track_pad: bool, is_horizontal: bool) { + let mut scroll_direction = -1; // 1 left -1 right; + let mut length = length; + + if length < 0 { + length *= -1; + scroll_direction *= -1; + } + + // fix scroll distance for track pad + if is_track_pad { + length *= 3; + } + + if let Some(src) = self.event_source.as_ref() { + for _ in 0..length { + unsafe { + let units = if is_track_pad { + ScrollUnit::Pixel + } else { + ScrollUnit::Line + }; + let mouse_ev = if is_horizontal { + CGEventCreateScrollWheelEvent( + &src, + units, + 2, // CGWheelCount 1 = y 2 = xy 3 = xyz + 0, + scroll_direction, + ) + } else { + CGEventCreateScrollWheelEvent( + &src, + units, + 1, // CGWheelCount 1 = y 2 = xy 3 = xyz + scroll_direction, + ) + }; + + CGEventPost(CGEventTapLocation::HID, mouse_ev); + CFRelease(mouse_ev as *const std::ffi::c_void); + } + } + } + } + + /// handle scroll vertically + pub fn mouse_scroll_y(&mut self, length: i32, is_track_pad: bool) { + self.mouse_scroll_impl(length, is_track_pad, false) + } + + /// handle scroll horizontally + pub fn mouse_scroll_x(&mut self, length: i32, is_track_pad: bool) { + self.mouse_scroll_impl(length, is_track_pad, true) + } } #[inline] diff --git a/src/client.rs b/src/client.rs index d00df1c48..2be71828d 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1529,6 +1529,25 @@ pub async fn handle_test_delay(t: TestDelay, peer: &mut Stream) { } } +#[inline] +#[cfg(target_os = "macos")] +fn check_scroll_on_mac(mask: i32, x: i32, y: i32) -> bool { + if mask & 3 != 3 { + return false; + } + let btn = mask >> 3; + if y == -1 { + btn != 0xff88 && btn != -0x780000 + } else if y == 1 { + btn != 0x78 && btn != 0x780000 + } else if x != 0 { + // No mouse support horizontal scrolling. + true + } else { + false + } +} + /// Send mouse data. /// /// # Arguments @@ -1574,6 +1593,10 @@ pub fn send_mouse( if command { mouse_event.modifiers.push(ControlKey::Meta.into()); } + #[cfg(target_os = "macos")] + if check_scroll_on_mac(mask, x, y) { + mouse_event.modifiers.push(ControlKey::Scroll.into()); + } msg_out.set_mouse_event(mouse_event); interface.send(Data::Message(msg_out)); } diff --git a/src/server/input_service.rs b/src/server/input_service.rs index d91e9a799..ac46726ac 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -429,18 +429,39 @@ fn handle_mouse_(evt: &MouseEvent, conn: i32) { x = -x; y = -y; } - - // fix shift + scroll(down/up) #[cfg(target_os = "macos")] - if evt.modifiers.contains(&EnumOrUnknown::new(ControlKey::Shift)){ - x = y; - y = 0; + { + // TODO: support track pad on win. + let is_track_pad = evt + .modifiers + .contains(&EnumOrUnknown::new(ControlKey::Scroll)); + + // fix shift + scroll(down/up) + if !is_track_pad + && evt + .modifiers + .contains(&EnumOrUnknown::new(ControlKey::Shift)) + { + x = y; + y = 0; + } + + if x != 0 { + en.mouse_scroll_x(x, is_track_pad); + } + if y != 0 { + en.mouse_scroll_y(y, is_track_pad); + } } - if x != 0 { - en.mouse_scroll_x(x); - } - if y != 0 { - en.mouse_scroll_y(y); + + #[cfg(not(target_os = "macos"))] + { + if x != 0 { + en.mouse_scroll_x(x); + } + if y != 0 { + en.mouse_scroll_y(y); + } } } _ => {} From e2ac8d7a5b550d7fa89f83ead1245dcc28e38909 Mon Sep 17 00:00:00 2001 From: djex Date: Wed, 9 Nov 2022 12:16:55 -0500 Subject: [PATCH 002/116] fix: sending file from local to remote --- src/server/connection.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/server/connection.rs b/src/server/connection.rs index 96d202199..0c386210f 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -1607,8 +1607,7 @@ async fn start_ipc( file_num, data, compressed}) = data { - stream.send(&Data::FS(ipc::FS::WriteBlock{id, file_num, data: Bytes::new(), compressed})).await?; - stream.send_raw(data).await?; + stream.send(&Data::FS(ipc::FS::WriteBlock{id, file_num, data, compressed})).await?; } else { stream.send(&data).await?; } From ac3c7a1fa818870adc6efcc5cc1009bc478051c4 Mon Sep 17 00:00:00 2001 From: fufesou Date: Wed, 9 Nov 2022 16:35:08 +0800 Subject: [PATCH 003/116] better mouse control Signed-off-by: fufesou --- src/server/input_service.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/server/input_service.rs b/src/server/input_service.rs index 170d672c9..44ccece8e 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -373,7 +373,7 @@ fn fix_modifiers(modifiers: &[EnumOrUnknown], en: &mut Enigo, ck: i3 } } -fn is_mouse_active_by_conn(conn: i32) -> bool { +fn active_mouse_(conn: i32) -> bool { // out of time protection if LATEST_CURSOR_POS.lock().unwrap().0.elapsed() > MOUSE_MOVE_PROTECTION_TIMEOUT { return true; @@ -388,13 +388,13 @@ fn is_mouse_active_by_conn(conn: i32) -> bool { // check if input is in valid range match crate::get_cursor_pos() { Some((x, y)) => { - let is_same_input = (last_input.x - x).abs() < MOUSE_ACTIVE_DISTANCE + let can_active = (last_input.x - x).abs() < MOUSE_ACTIVE_DISTANCE && (last_input.y - y).abs() < MOUSE_ACTIVE_DISTANCE; - if !is_same_input { + if !can_active { last_input.x = -MOUSE_ACTIVE_DISTANCE * 2; last_input.y = -MOUSE_ACTIVE_DISTANCE * 2; } - is_same_input + can_active } None => true, } @@ -405,7 +405,7 @@ fn handle_mouse_(evt: &MouseEvent, conn: i32) { return; } - if !is_mouse_active_by_conn(conn) { + if !active_mouse_(conn) { return; } From 0cf2bfb5ef46469cc62040e5f763cfe324d522ec Mon Sep 17 00:00:00 2001 From: fufesou Date: Thu, 10 Nov 2022 14:32:22 +0800 Subject: [PATCH 004/116] save pin option on remote menubar Signed-off-by: fufesou --- flutter/lib/desktop/pages/remote_page.dart | 7 +- .../lib/desktop/pages/remote_tab_page.dart | 25 ++++-- .../lib/desktop/widgets/remote_menubar.dart | 85 ++++++++++++++++--- flutter/lib/models/state_model.dart | 1 + 4 files changed, 97 insertions(+), 21 deletions(-) diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index 76395be9d..21cbe45b9 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -28,14 +28,14 @@ class RemotePage extends StatefulWidget { RemotePage({ Key? key, required this.id, + required this.menubarState, }) : super(key: key); final String id; + final MenubarState menubarState; final SimpleWrapper?> _lastState = SimpleWrapper(null); FFI get ffi => (_lastState.value! as _RemotePageState)._ffi; - RxBool get showMenubar => - (_lastState.value! as _RemotePageState)._showMenubar; @override State createState() { @@ -50,7 +50,6 @@ class _RemotePageState extends State Timer? _timer; String keyboardMode = "legacy"; final _cursorOverImage = false.obs; - final _showMenubar = false.obs; late RxBool _showRemoteCursor; late RxBool _remoteCursorMoved; late RxBool _keyboardEnabled; @@ -239,7 +238,7 @@ class _RemotePageState extends State paints.add(RemoteMenubar( id: widget.id, ffi: _ffi, - show: _showMenubar, + state: widget.menubarState, onEnterOrLeaveImageSetter: (func) => _onEnterOrLeaveImage4Menubar = func, onEnterOrLeaveImageCleaner: () => _onEnterOrLeaveImage4Menubar = null, )); diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index 3068f2db7..4f7e9c5aa 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -9,6 +9,7 @@ import 'package:flutter_hbb/common/shared_state.dart'; import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/models/state_model.dart'; import 'package:flutter_hbb/desktop/pages/remote_page.dart'; +import 'package:flutter_hbb/desktop/widgets/remote_menubar.dart'; import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart'; import 'package:flutter_hbb/desktop/widgets/material_mod_popup_menu.dart' as mod_menu; @@ -43,9 +44,12 @@ class _ConnectionTabPageState extends State { static const IconData selectedIcon = Icons.desktop_windows_sharp; static const IconData unselectedIcon = Icons.desktop_windows_outlined; + late MenubarState _menubarState; + var connectionMap = RxList.empty(growable: true); _ConnectionTabPageState(Map params) { + _menubarState = MenubarState(); RemoteCountState.init(); final peerId = params['id']; if (peerId != null) { @@ -59,6 +63,7 @@ class _ConnectionTabPageState extends State { page: RemotePage( key: ValueKey(peerId), id: peerId, + menubarState: _menubarState, ), )); _update_remote_count(); @@ -88,7 +93,11 @@ class _ConnectionTabPageState extends State { selectedIcon: selectedIcon, unselectedIcon: unselectedIcon, onTabCloseButton: () => tabController.closeBy(id), - page: RemotePage(key: ValueKey(id), id: id), + page: RemotePage( + key: ValueKey(id), + id: id, + menubarState: _menubarState, + ), )); } else if (call.method == "onDestroy") { tabController.clear(); @@ -99,6 +108,12 @@ class _ConnectionTabPageState extends State { }); } + @override + void dispose() { + super.dispose(); + _menubarState.save(); + } + @override Widget build(BuildContext context) { final tabWidget = Container( @@ -177,7 +192,7 @@ class _ConnectionTabPageState extends State { ); } - // to-do: some dup code to ../widgets/remote_menubar + // Note: Some dup code to ../widgets/remote_menubar Widget _tabMenuBuilder(String key, CancelFunc cancelFunc) { final List> menu = []; const EdgeInsets padding = EdgeInsets.only(left: 8.0, right: 5.0); @@ -187,7 +202,6 @@ class _ConnectionTabPageState extends State { final ffi = remotePage.ffi; final pi = ffi.ffiModel.pi; final perms = ffi.ffiModel.permissions; - final showMenuBar = remotePage.showMenubar; menu.addAll([ MenuEntryButton( childBuilder: (TextStyle? style) => Text( @@ -202,11 +216,12 @@ class _ConnectionTabPageState extends State { ), MenuEntryButton( childBuilder: (TextStyle? style) => Obx(() => Text( - translate(showMenuBar.isTrue ? 'Hide Menubar' : 'Show Menubar'), + translate( + _menubarState.show.isTrue ? 'Hide Menubar' : 'Show Menubar'), style: style, )), proc: () { - showMenuBar.value = !showMenuBar.value; + _menubarState.switchShow(); cancelFunc(); }, padding: padding, diff --git a/flutter/lib/desktop/widgets/remote_menubar.dart b/flutter/lib/desktop/widgets/remote_menubar.dart index 26cc26ddd..be04cb2ba 100644 --- a/flutter/lib/desktop/widgets/remote_menubar.dart +++ b/flutter/lib/desktop/widgets/remote_menubar.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hbb/models/chat_model.dart'; import 'package:flutter_hbb/models/state_model.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:get/get.dart'; import 'package:provider/provider.dart'; import 'package:rxdart/rxdart.dart' as rxdart; @@ -21,6 +22,69 @@ import '../../common/shared_state.dart'; import './popup_menu.dart'; import './material_mod_popup_menu.dart' as mod_menu; +class MenubarState { + final kStoreKey = "remoteMenubarState"; + late RxBool show; + late RxBool _pin; + + MenubarState() { + final s = Get.find().getString(kStoreKey); + if (s == null) { + _initSet(false, false); + } + try { + final m = jsonDecode(s!); + if (m == null) { + _initSet(false, false); + } else { + _initSet(m['pin'] ?? false, m['pin'] ?? false); + } + } catch (e) { + debugPrint('Failed to decode menubar state ${e.toString()}'); + _initSet(false, false); + } + } + + _initSet(bool s, bool p) { + show = RxBool(s); + _pin = RxBool(p); + } + + bool get pin => _pin.value; + + switchShow() async { + show.value = !show.value; + } + + setShow(bool v) async { + if (show.value != v) { + show.value = v; + } + } + + switchPin() async { + _pin.value = !_pin.value; + // Save everytime changed, as this func will not be called frequently + await save(); + } + + setPin(bool v) async { + if (_pin.value != v) { + _pin.value = v; + // Save everytime changed, as this func will not be called frequently + await save(); + } + } + + save() async { + final success = await Get.find() + .setString(kStoreKey, jsonEncode({'pin': _pin.value}.toString())); + if (!success) { + debugPrint('Failed to save remote menu bar state'); + } + } +} + class _MenubarTheme { static const Color commonColor = MyTheme.accent; // kMinInteractiveDimension @@ -31,7 +95,7 @@ class _MenubarTheme { class RemoteMenubar extends StatefulWidget { final String id; final FFI ffi; - final RxBool show; + final MenubarState state; final Function(Function(bool)) onEnterOrLeaveImageSetter; final Function() onEnterOrLeaveImageCleaner; @@ -39,7 +103,7 @@ class RemoteMenubar extends StatefulWidget { Key? key, required this.id, required this.ffi, - required this.show, + required this.state, required this.onEnterOrLeaveImageSetter, required this.onEnterOrLeaveImageCleaner, }) : super(key: key); @@ -51,7 +115,6 @@ class RemoteMenubar extends StatefulWidget { class _RemoteMenubarState extends State { final Rx _hideColor = Colors.white12.obs; final _rxHideReplay = rxdart.ReplaySubject(); - final _pinMenubar = false.obs; bool _isCursorOverImage = false; window_size.Screen? _screen; @@ -63,7 +126,8 @@ class _RemoteMenubarState extends State { setState(() {}); } - RxBool get show => widget.show; + RxBool get show => widget.state.show; + bool get pin => widget.state.pin; @override initState() { @@ -82,7 +146,7 @@ class _RemoteMenubarState extends State { .throttleTime(const Duration(milliseconds: 5000), trailing: true, leading: false) .listen((int v) { - if (_pinMenubar.isFalse && show.isTrue && _isCursorOverImage) { + if (!pin && show.isTrue && _isCursorOverImage) { show.value = false; } }); @@ -196,18 +260,15 @@ class _RemoteMenubarState extends State { Widget _buildPinMenubar(BuildContext context) { return Obx(() => IconButton( - tooltip: - translate(_pinMenubar.isTrue ? 'Unpin menubar' : 'Pin menubar'), + tooltip: translate(pin ? 'Unpin menubar' : 'Pin menubar'), onPressed: () { - _pinMenubar.value = !_pinMenubar.value; + widget.state.switchPin(); }, icon: Obx(() => Transform.rotate( - angle: _pinMenubar.isTrue ? math.pi / 4 : 0, + angle: pin ? math.pi / 4 : 0, child: Icon( Icons.push_pin, - color: _pinMenubar.isTrue - ? _MenubarTheme.commonColor - : Colors.grey, + color: pin ? _MenubarTheme.commonColor : Colors.grey, ))), )); } diff --git a/flutter/lib/models/state_model.dart b/flutter/lib/models/state_model.dart index f6e3820b9..dab21fcb6 100644 --- a/flutter/lib/models/state_model.dart +++ b/flutter/lib/models/state_model.dart @@ -8,6 +8,7 @@ class StateGlobal { bool _fullscreen = false; final RxBool _showTabBar = true.obs; final RxDouble _resizeEdgeSize = 8.0.obs; + final RxBool showRemoteMenuBar = false.obs; int get windowId => _windowId; bool get fullscreen => _fullscreen; From 50d885d3e7f234434a9fae127f88b82c2afe3da6 Mon Sep 17 00:00:00 2001 From: fufesou Date: Thu, 10 Nov 2022 21:25:12 +0800 Subject: [PATCH 005/116] Remove SharedPreferences, debug win Signed-off-by: fufesou --- flutter/lib/common.dart | 37 +++--- flutter/lib/common/widgets/peer_tab_page.dart | 34 +++--- flutter/lib/consts.dart | 6 +- .../desktop/pages/desktop_setting_page.dart | 109 +++++++++--------- .../lib/desktop/widgets/remote_menubar.dart | 16 ++- flutter/lib/main.dart | 2 - flutter/lib/models/model.dart | 30 ++--- flutter/lib/models/user_model.dart | 4 +- flutter/pubspec.yaml | 1 - libs/hbb_common/src/config.rs | 29 ++++- src/client.rs | 28 +++++ src/core_main.rs | 2 +- src/flutter.rs | 1 + src/flutter_ffi.rs | 32 ++++- src/hbbs_http/account.rs | 2 +- src/server/video_qos.rs | 6 +- src/tray.rs | 18 +-- src/ui.rs | 12 +- src/ui_cm_interface.rs | 3 +- src/ui_interface.rs | 97 +++++++++++----- src/ui_session_interface.rs | 10 +- 21 files changed, 297 insertions(+), 182 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index ec83e1123..93fe0fee5 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -15,7 +15,6 @@ import 'package:flutter_hbb/main.dart'; import 'package:flutter_hbb/models/peer_model.dart'; import 'package:flutter_hbb/utils/multi_window_manager.dart'; import 'package:get/get.dart'; -import 'package:shared_preferences/shared_preferences.dart'; import 'package:uni_links/uni_links.dart'; import 'package:uni_links_desktop/uni_links_desktop.dart'; import 'package:window_manager/window_manager.dart'; @@ -205,18 +204,17 @@ class MyTheme { ); static ThemeMode getThemeModePreference() { - return themeModeFromString( - Get.find().getString("themeMode") ?? ""); + return themeModeFromString(bind.mainGetLocalOption(key: kCommConfKeyTheme)); } static void changeDarkMode(ThemeMode mode) { final preference = getThemeModePreference(); if (preference != mode) { if (mode == ThemeMode.system) { - Get.find().setString("themeMode", ""); + bind.mainSetLocalOption(key: kCommConfKeyTheme, value: ''); } else { - Get.find() - .setString("themeMode", mode.toShortString()); + bind.mainSetLocalOption( + key: kCommConfKeyTheme, value: mode.toShortString()); } Get.changeThemeMode(mode); if (desktopType == DesktopType.main) { @@ -1026,8 +1024,8 @@ Future saveWindowPosition(WindowType type, {int? windowId}) async { final isMaximized = await windowManager.isMaximized(); final pos = LastWindowPosition( sz.width, sz.height, position.dx, position.dy, isMaximized); - await Get.find() - .setString(kWindowPrefix + type.name, pos.toString()); + await bind.setLocalFlutterConfig( + k: kWindowPrefix + type.name, v: pos.toString()); break; default: final wc = WindowController.fromWindowId(windowId!); @@ -1037,9 +1035,10 @@ Future saveWindowPosition(WindowType type, {int? windowId}) async { final isMaximized = await wc.isMaximized(); final pos = LastWindowPosition( sz.width, sz.height, position.dx, position.dy, isMaximized); - debugPrint("saving frame: ${windowId}: ${pos.width}/${pos.height}, offset:${pos.offsetWidth}/${pos.offsetHeight}"); - await Get.find() - .setString(kWindowPrefix + type.name, pos.toString()); + debugPrint( + "saving frame: $windowId: ${pos.width}/${pos.height}, offset:${pos.offsetWidth}/${pos.offsetHeight}"); + await bind.setLocalFlutterConfig( + k: kWindowPrefix + type.name, v: pos.toString()); break; } } @@ -1109,7 +1108,7 @@ Future _adjustRestoreMainWindowOffset( .toDouble(); if (isDesktop || isWebDesktop) { - for(final screen in await window_size.getScreenList()) { + for (final screen in await window_size.getScreenList()) { frameLeft = min(screen.visibleFrame.left, frameLeft); frameTop = min(screen.visibleFrame.top, frameTop); frameRight = max(screen.visibleFrame.right, frameRight); @@ -1136,13 +1135,7 @@ Future restoreWindowPosition(WindowType type, {int? windowId}) async { debugPrint( "Error: windowId cannot be null when saving positions for sub window"); } - final pos = - Get.find().getString(kWindowPrefix + type.name); - - if (pos == null) { - debugPrint("no window position saved, ignore restore"); - return false; - } + final pos = bind.getLocalFlutterConfig(k: kWindowPrefix + type.name); var lpos = LastWindowPosition.loadFromString(pos); if (lpos == null) { debugPrint("window position saved, but cannot be parsed"); @@ -1175,7 +1168,8 @@ Future restoreWindowPosition(WindowType type, {int? windowId}) async { await _adjustRestoreMainWindowSize(lpos.width, lpos.height); final offset = await _adjustRestoreMainWindowOffset( lpos.offsetWidth, lpos.offsetHeight); - debugPrint("restore lpos: ${size.width}/${size.height}, offset:${offset?.dx}/${offset?.dy}"); + debugPrint( + "restore lpos: ${size.width}/${size.height}, offset:${offset?.dx}/${offset?.dy}"); if (offset == null) { await wc.center(); } else { @@ -1327,8 +1321,7 @@ void connect(BuildContext context, String id, Future> getHttpHeaders() async { return { - 'Authorization': - 'Bearer ${await bind.mainGetLocalOption(key: 'access_token')}' + 'Authorization': 'Bearer ${bind.mainGetLocalOption(key: 'access_token')}' }; } diff --git a/flutter/lib/common/widgets/peer_tab_page.dart b/flutter/lib/common/widgets/peer_tab_page.dart index 81559a3d3..9129e4711 100644 --- a/flutter/lib/common/widgets/peer_tab_page.dart +++ b/flutter/lib/common/widgets/peer_tab_page.dart @@ -22,27 +22,26 @@ class _PeerTabPageState extends State @override void initState() { - () async { - await bind.mainGetLocalOption(key: 'peer-tab-index').then((value) { - if (value == '') return; - final tab = int.parse(value); - _tabIndex.value = tab; - }); - await bind.mainGetLocalOption(key: 'peer-card-ui-type').then((value) { - if (value == '') return; - final tab = int.parse(value); - peerCardUiType.value = - tab == PeerUiType.list.index ? PeerUiType.list : PeerUiType.grid; - }); - }(); + setPeer(); super.initState(); } + setPeer() { + final index = bind.getLocalFlutterConfig(k: 'peer-tab-index'); + if (index == '') return; + _tabIndex.value = int.parse(index); + + final uiType = bind.getLocalFlutterConfig(k: 'peer-card-ui-type'); + if (uiType == '') return; + peerCardUiType.value = int.parse(uiType) == PeerUiType.list.index + ? PeerUiType.list + : PeerUiType.grid; + } + // hard code for now Future _handleTabSelection(int index) async { _tabIndex.value = index; - await bind.mainSetLocalOption( - key: 'peer-tab-index', value: index.toString()); + await bind.setLocalFlutterConfig(k: 'peer-tab-index', v: index.toString()); switch (index) { case 0: bind.mainLoadRecentPeers(); @@ -148,9 +147,8 @@ class _PeerTabPageState extends State decoration: peerCardUiType.value == type ? activeDeco : null, child: InkWell( onTap: () async { - await bind.mainSetLocalOption( - key: 'peer-card-ui-type', - value: type.index.toString()); + await bind.setLocalFlutterConfig( + k: 'peer-card-ui-type', v: type.index.toString()); peerCardUiType.value = type; }, child: Icon( diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index 48e99943f..acba32780 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -56,7 +56,11 @@ var kWindowEdgeSize = Platform.isWindows ? 1.0 : 5.0; const kWindowBorderWidth = 1.0; const kDesktopMenuPadding = EdgeInsets.only(left: 12.0, right: 3.0); -const kInvalidValueStr = "InvalidValueStr"; +const kInvalidValueStr = 'InvalidValueStr'; + +// Config key shared by flutter and other ui. +const kCommConfKeyTheme = 'theme'; +const kCommConfKeyLang = 'lang'; const kMobilePageConstraints = BoxConstraints(maxWidth: 600); diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index 12bb935e9..ab8f76ca5 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -5,6 +5,7 @@ import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hbb/common.dart'; +import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/desktop/pages/desktop_home_page.dart'; import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart'; import 'package:flutter_hbb/desktop/widgets/login.dart'; @@ -30,8 +31,8 @@ const double _kListViewBottomMargin = 15; const double _kTitleFontSize = 20; const double _kContentFontSize = 15; const Color _accentColor = MyTheme.accent; -const String _kSettingPageControllerTag = "settingPageController"; -const String _kSettingPageIndexTag = "settingPageIndex"; +const String _kSettingPageControllerTag = 'settingPageController'; +const String _kSettingPageIndexTag = 'settingPageIndex'; class _TabInfo { late final String label; @@ -250,19 +251,19 @@ class _GeneralState extends State<_General> { return _Card(title: 'Theme', children: [ _Radio(context, - value: "light", + value: 'light', groupValue: current, - label: "Light", + label: 'Light', onChanged: onChanged), _Radio(context, - value: "dark", + value: 'dark', groupValue: current, - label: "Dark", + label: 'Dark', onChanged: onChanged), _Radio(context, - value: "system", + value: 'system', groupValue: current, - label: "Follow System", + label: 'Follow System', onChanged: onChanged), ]); } @@ -286,8 +287,8 @@ class _GeneralState extends State<_General> { Widget audio(BuildContext context) { String getDefault() { - if (Platform.isWindows) return "System Sound"; - return ""; + if (Platform.isWindows) return 'System Sound'; + return ''; } Future getValue() async { @@ -300,7 +301,7 @@ class _GeneralState extends State<_General> { } setDevice(String device) { - if (device == getDefault()) device = ""; + if (device == getDefault()) device = ''; bind.mainSetOption(key: 'audio-input', value: device); } @@ -353,7 +354,7 @@ class _GeneralState extends State<_General> { 'allow-auto-record-incoming'), Row( children: [ - Text('${translate('Directory')}:'), + Text('${translate("Directory")}:'), Expanded( child: GestureDetector( onTap: canlaunch ? () => launchUrl(Uri.file(dir)) : null, @@ -386,26 +387,26 @@ class _GeneralState extends State<_General> { Widget language() { return _futureBuilder(future: () async { String langs = await bind.mainGetLangs(); - String lang = await bind.mainGetLocalOption(key: "lang"); - return {"langs": langs, "lang": lang}; + String lang = bind.mainGetLocalOption(key: kCommConfKeyLang); + return {'langs': langs, 'lang': lang}; }(), hasData: (res) { Map data = res as Map; - List langsList = jsonDecode(data["langs"]!); + List langsList = jsonDecode(data['langs']!); Map langsMap = {for (var v in langsList) v[0]: v[1]}; List keys = langsMap.keys.toList(); List values = langsMap.values.toList(); - keys.insert(0, ""); - values.insert(0, "Default"); - String currentKey = data["lang"]!; + keys.insert(0, ''); + values.insert(0, 'Default'); + String currentKey = data['lang']!; if (!keys.contains(currentKey)) { - currentKey = ""; + currentKey = ''; } return _ComboBox( keys: keys, values: values, initialKey: currentKey, onChanged: (key) async { - await bind.mainSetLocalOption(key: "lang", value: key); + await bind.mainSetLocalOption(key: kCommConfKeyLang, value: key); reloadAllWindows(); bind.mainChangeLanguage(lang: key); }, @@ -585,9 +586,9 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { kUseBothPasswords, ]; List values = [ - translate("Use temporary password"), - translate("Use permanent password"), - translate("Use both passwords"), + translate('Use temporary password'), + translate('Use permanent password'), + translate('Use both passwords'), ]; bool tmpEnabled = model.verificationMethod != kUsePermanentPassword; bool permEnabled = model.verificationMethod != kUseTemporaryPassword; @@ -830,12 +831,12 @@ class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin { // Setting page is not modal, oldOptions should only be used when getting options, never when setting. Map oldOptions = jsonDecode(data! as String); old(String key) { - return (oldOptions[key] ?? "").trim(); + return (oldOptions[key] ?? '').trim(); } - RxString idErrMsg = "".obs; - RxString relayErrMsg = "".obs; - RxString apiErrMsg = "".obs; + RxString idErrMsg = ''.obs; + RxString relayErrMsg = ''.obs; + RxString apiErrMsg = ''.obs; var idController = TextEditingController(text: old('custom-rendezvous-server')); var relayController = TextEditingController(text: old('relay-server')); @@ -864,9 +865,9 @@ class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin { } if (apiServer.isNotEmpty) { if (!apiServer.startsWith('http://') || - !apiServer.startsWith("https://")) { + !apiServer.startsWith('https://')) { apiErrMsg.value = - "${translate("API Server")}: ${translate("invalid_http")}"; + '${translate("API Server")}: ${translate("invalid_http")}'; return false; } } @@ -893,7 +894,7 @@ class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin { import() { Clipboard.getData(Clipboard.kTextPlain).then((value) { TextEditingController mytext = TextEditingController(); - String? aNullableString = ""; + String? aNullableString = ''; aNullableString = value?.text; mytext.text = aNullableString.toString(); if (mytext.text.isNotEmpty) { @@ -918,13 +919,13 @@ class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin { } }); } else { - showToast(translate("Invalid server configuration")); + showToast(translate('Invalid server configuration')); } } catch (e) { - showToast(translate("Invalid server configuration")); + showToast(translate('Invalid server configuration')); } } else { - showToast(translate("Clipboard is empty")); + showToast(translate('Clipboard is empty')); } }); } @@ -936,7 +937,7 @@ class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin { config['ApiServer'] = apiController.text.trim(); config['Key'] = keyController.text.trim(); Clipboard.setData(ClipboardData(text: jsonEncode(config))); - showToast(translate("Export server configuration successfully")); + showToast(translate('Export server configuration successfully')); } bool secure = !enabled; @@ -962,7 +963,7 @@ class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin { Obx(() => _LabeledTextField(context, 'API Server', apiController, apiErrMsg.value, enabled, secure)), _LabeledTextField( - context, 'Key', keyController, "", enabled, secure), + context, 'Key', keyController, '', enabled, secure), Row( mainAxisAlignment: MainAxisAlignment.end, children: [_Button('Apply', submit, enabled: enabled)], @@ -1039,28 +1040,28 @@ class _AboutState extends State<_About> { child: SingleChildScrollView( controller: scrollController, physics: NeverScrollableScrollPhysics(), - child: _Card(title: "About RustDesk", children: [ + child: _Card(title: 'About RustDesk', children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox( height: 8.0, ), - Text("Version: $version").marginSymmetric(vertical: 4.0), + Text('Version: $version').marginSymmetric(vertical: 4.0), InkWell( onTap: () { - launchUrlString("https://rustdesk.com/privacy"); + launchUrlString('https://rustdesk.com/privacy'); }, child: const Text( - "Privacy Statement", + 'Privacy Statement', style: linkStyle, ).marginSymmetric(vertical: 4.0)), InkWell( onTap: () { - launchUrlString("https://rustdesk.com"); + launchUrlString('https://rustdesk.com'); }, child: const Text( - "Website", + 'Website', style: linkStyle, ).marginSymmetric(vertical: 4.0)), Container( @@ -1074,11 +1075,11 @@ class _AboutState extends State<_About> { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "Copyright © 2022 Purslane Ltd.\n$license", + 'Copyright © 2022 Purslane Ltd.\n$license', style: const TextStyle(color: Colors.white), ), const Text( - "Made with heart in this chaotic world!", + 'Made with heart in this chaotic world!', style: TextStyle( fontWeight: FontWeight.w800, color: Colors.white), @@ -1472,10 +1473,10 @@ class _ComboBox extends StatelessWidget { void changeSocks5Proxy() async { var socks = await bind.mainGetSocks(); - String proxy = ""; - String proxyMsg = ""; - String username = ""; - String password = ""; + String proxy = ''; + String proxyMsg = ''; + String username = ''; + String password = ''; if (socks.length == 3) { proxy = socks[0]; username = socks[1]; @@ -1489,7 +1490,7 @@ void changeSocks5Proxy() async { gFFI.dialogManager.show((setState, close) { submit() async { setState(() { - proxyMsg = ""; + proxyMsg = ''; isInProgress = true; }); cancel() { @@ -1517,7 +1518,7 @@ void changeSocks5Proxy() async { } return CustomAlertDialog( - title: Text(translate("Socks5 Proxy")), + title: Text(translate('Socks5 Proxy')), content: ConstrainedBox( constraints: const BoxConstraints(minWidth: 500), child: Column( @@ -1530,7 +1531,7 @@ void changeSocks5Proxy() async { children: [ ConstrainedBox( constraints: const BoxConstraints(minWidth: 100), - child: Text("${translate('Hostname')}:") + child: Text('${translate("Hostname")}:') .marginOnly(bottom: 16.0)), const SizedBox( width: 24.0, @@ -1553,7 +1554,7 @@ void changeSocks5Proxy() async { children: [ ConstrainedBox( constraints: const BoxConstraints(minWidth: 100), - child: Text("${translate('Username')}:") + child: Text('${translate("Username")}:') .marginOnly(bottom: 16.0)), const SizedBox( width: 24.0, @@ -1575,7 +1576,7 @@ void changeSocks5Proxy() async { children: [ ConstrainedBox( constraints: const BoxConstraints(minWidth: 100), - child: Text("${translate('Password')}:") + child: Text('${translate("Password")}:') .marginOnly(bottom: 16.0)), const SizedBox( width: 24.0, @@ -1599,8 +1600,8 @@ void changeSocks5Proxy() async { ), ), actions: [ - TextButton(onPressed: close, child: Text(translate("Cancel"))), - TextButton(onPressed: submit, child: Text(translate("OK"))), + TextButton(onPressed: close, child: Text(translate('Cancel'))), + TextButton(onPressed: submit, child: Text(translate('OK'))), ], onSubmit: submit, onCancel: close, diff --git a/flutter/lib/desktop/widgets/remote_menubar.dart b/flutter/lib/desktop/widgets/remote_menubar.dart index be04cb2ba..75311c4c5 100644 --- a/flutter/lib/desktop/widgets/remote_menubar.dart +++ b/flutter/lib/desktop/widgets/remote_menubar.dart @@ -7,7 +7,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hbb/models/chat_model.dart'; import 'package:flutter_hbb/models/state_model.dart'; -import 'package:shared_preferences/shared_preferences.dart'; import 'package:get/get.dart'; import 'package:provider/provider.dart'; import 'package:rxdart/rxdart.dart' as rxdart; @@ -28,12 +27,14 @@ class MenubarState { late RxBool _pin; MenubarState() { - final s = Get.find().getString(kStoreKey); - if (s == null) { + final s = bind.getLocalFlutterConfig(k: kStoreKey); + if (s.isEmpty) { _initSet(false, false); + return; } + try { - final m = jsonDecode(s!); + final m = jsonDecode(s); if (m == null) { _initSet(false, false); } else { @@ -77,11 +78,8 @@ class MenubarState { } save() async { - final success = await Get.find() - .setString(kStoreKey, jsonEncode({'pin': _pin.value}.toString())); - if (!success) { - debugPrint('Failed to save remote menu bar state'); - } + bind.setLocalFlutterConfig( + k: kStoreKey, v: jsonEncode({'pin': _pin.value})); } } diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index ae15b5cf6..989ba12f5 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -15,7 +15,6 @@ import 'package:flutter_hbb/utils/multi_window_manager.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:get/get.dart'; import 'package:provider/provider.dart'; -import 'package:shared_preferences/shared_preferences.dart'; import 'package:window_manager/window_manager.dart'; import 'package:bot_toast/bot_toast.dart'; @@ -97,7 +96,6 @@ Future main(List args) async { Future initEnv(String appType) async { // global shared preference - await Get.putAsync(() => SharedPreferences.getInstance()); await platformFFI.init(appType); // global FFI, use this **ONLY** for global configuration // for convenience, use global FFI on mobile platform diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index be97b41ff..616a1c985 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -16,7 +16,6 @@ import 'package:flutter_hbb/models/server_model.dart'; import 'package:flutter_hbb/models/user_model.dart'; import 'package:flutter_hbb/models/state_model.dart'; import 'package:flutter_hbb/utils/multi_window_manager.dart'; -import 'package:shared_preferences/shared_preferences.dart'; import 'package:tuple/tuple.dart'; import 'package:image/image.dart' as img2; import 'package:flutter_custom_cursor/flutter_custom_cursor.dart'; @@ -1219,7 +1218,7 @@ class FFI { Future close() async { chatModel.close(); if (imageModel.image != null && !isWebDesktop) { - await savePreference(id, cursorModel.x, cursorModel.y, canvasModel.x, + await setCanvasConfig(id, cursorModel.x, cursorModel.y, canvasModel.x, canvasModel.y, canvasModel.scale, ffiModel.pi.currentDisplay); } bind.sessionClose(id: id); @@ -1267,9 +1266,10 @@ class PeerInfo { List displays = []; } -Future savePreference(String id, double xCursor, double yCursor, +const canvasKey = 'canvas'; + +Future setCanvasConfig(String id, double xCursor, double yCursor, double xCanvas, double yCanvas, double scale, int currentDisplay) async { - SharedPreferences prefs = await SharedPreferences.getInstance(); final p = {}; p['xCursor'] = xCursor; p['yCursor'] = yCursor; @@ -1277,25 +1277,27 @@ Future savePreference(String id, double xCursor, double yCursor, p['yCanvas'] = yCanvas; p['scale'] = scale; p['currentDisplay'] = currentDisplay; - prefs.setString('peer$id', json.encode(p)); + await bind.sessionSetFlutterConfig(id: id, k: canvasKey, v: jsonEncode(p)); } -Future?> getPreference(String id) async { +Future?> getCanvasConfig(String id) async { if (!isWebDesktop) return null; - SharedPreferences prefs = await SharedPreferences.getInstance(); - var p = prefs.getString('peer$id'); - if (p == null) return null; - Map m = json.decode(p); - return m; + var p = await bind.sessionGetFlutterConfig(id: id, k: canvasKey); + if (p == null || p.isEmpty) return null; + try { + Map m = json.decode(p); + return m; + } catch (e) { + return null; + } } void removePreference(String id) async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - prefs.remove('peer$id'); + await bind.sessionSetFlutterConfig(id: id, k: canvasKey, v: ''); } Future initializeCursorAndCanvas(FFI ffi) async { - var p = await getPreference(ffi.id); + var p = await getCanvasConfig(ffi.id); int currentDisplay = 0; if (p != null) { currentDisplay = p['currentDisplay']; diff --git a/flutter/lib/models/user_model.dart b/flutter/lib/models/user_model.dart index d2e83990b..e6065743c 100644 --- a/flutter/lib/models/user_model.dart +++ b/flutter/lib/models/user_model.dart @@ -19,7 +19,7 @@ class UserModel { void refreshCurrentUser() async { await getUserName(); - final token = await bind.mainGetLocalOption(key: 'access_token'); + final token = bind.mainGetLocalOption(key: 'access_token'); if (token == '') return; final url = await bind.mainGetApiServer(); final body = { @@ -73,7 +73,7 @@ class UserModel { if (userName.isNotEmpty) { return userName.value; } - final userInfo = await bind.mainGetLocalOption(key: 'user_info'); + final userInfo = bind.mainGetLocalOption(key: 'user_info'); if (userInfo.trim().isEmpty) { return ''; } diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index 4cb4b40a7..b7ffeec0a 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -40,7 +40,6 @@ dependencies: #firebase_analytics: ^9.1.5 package_info_plus: ^1.4.2 url_launcher: ^6.0.9 - shared_preferences: ^2.0.6 toggle_switch: ^1.4.0 dash_chat_2: ^0.0.14 draggable_float_widget: ^0.0.2 diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 9eb9cd369..cc9da6420 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -167,9 +167,12 @@ pub struct PeerConfig { #[serde(default)] pub show_quality_monitor: bool, - // the other scalar value must before this + // The other scalar value must before this #[serde(default)] pub options: HashMap, + // Various data for flutter ui + #[serde(default)] + pub ui_flutter: HashMap, #[serde(default)] pub info: PeerInfoSerde, #[serde(default)] @@ -897,6 +900,9 @@ pub struct LocalConfig { pub fav: Vec, #[serde(default)] options: HashMap, + // Various data for flutter ui + #[serde(default)] + ui_flutter: HashMap, } impl LocalConfig { @@ -968,6 +974,27 @@ impl LocalConfig { config.store(); } } + + pub fn get_flutter_config(k: &str) -> String { + if let Some(v) = LOCAL_CONFIG.read().unwrap().ui_flutter.get(k) { + v.clone() + } else { + "".to_owned() + } + } + + pub fn set_flutter_config(k: String, v: String) { + let mut config = LOCAL_CONFIG.write().unwrap(); + let v2 = if v.is_empty() { None } else { Some(&v) }; + if v2 != config.ui_flutter.get(&k) { + if v2.is_none() { + config.ui_flutter.remove(&k); + } else { + config.ui_flutter.insert(k, v); + } + config.store(); + } + } } #[derive(Debug, Default, Serialize, Deserialize, Clone)] diff --git a/src/client.rs b/src/client.rs index d00df1c48..a938702b3 100644 --- a/src/client.rs +++ b/src/client.rs @@ -6,6 +6,7 @@ use cpal::{ }; use magnum_opus::{Channels::*, Decoder as AudioDecoder}; use sha2::{Digest, Sha256}; +#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] use std::sync::atomic::Ordering; use std::{ collections::HashMap, @@ -984,6 +985,32 @@ impl LoginConfigHandler { self.save_config(config); } + /// Set a ui config of flutter for handler's [`PeerConfig`]. + /// + /// # Arguments + /// + /// * `k` - key of option + /// * `v` - value of option + pub fn set_ui_flutter(&mut self, k: String, v: String) { + let mut config = self.load_config(); + config.ui_flutter.insert(k, v); + self.save_config(config); + } + + /// Get a ui config of flutter for handler's [`PeerConfig`]. + /// Return String if the option is found, otherwise return "". + /// + /// # Arguments + /// + /// * `k` - key of option + pub fn get_ui_flutter(&self, k: &str) -> String { + if let Some(v) = self.config.ui_flutter.get(k) { + v.clone() + } else { + "".to_owned() + } + } + /// Toggle an option in the handler. /// /// # Arguments @@ -1947,6 +1974,7 @@ fn decode_id_pk(signed: &[u8], key: &sign::PublicKey) -> ResultType<(String, [u8 } } +#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] pub fn disable_keyboard_listening() { crate::ui_session_interface::KEYBOARD_HOOKED.store(true, Ordering::SeqCst); } diff --git a/src/core_main.rs b/src/core_main.rs index 86f77946f..2298aaad6 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -122,7 +122,7 @@ pub fn core_main() -> Option> { hbb_common::allow_err!(crate::rc::extract_resources(&args[1])); return None; } else if args[0] == "--tray" { - crate::tray::start_tray(crate::ui_interface::OPTIONS.clone()); + crate::tray::start_tray(); return None; } } diff --git a/src/flutter.rs b/src/flutter.rs index 18425476d..a79a32533 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -227,6 +227,7 @@ impl InvokeUiSession for FlutterHandler { id: i32, entries: &Vec, path: String, + #[allow(unused_variables)] is_local: bool, only_count: bool, ) { diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 9552bd36e..aba8f7e1b 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -19,12 +19,12 @@ use crate::flutter::{self, SESSIONS}; #[cfg(target_os = "android")] use crate::start_server; use crate::ui_interface::{self, *}; +#[cfg(not(any(target_os = "android", target_os = "ios")))] +use crate::ui_session_interface::CUR_SESSION; use crate::{ client::file_trait::FileManager, flutter::{make_fd_to_json, session_add, session_start_}, }; -#[cfg(not(any(target_os = "android", target_os = "ios")))] -use crate::ui_session_interface::CUR_SESSION; fn initialize(app_dir: &str) { *config::APP_DIR.write().unwrap() = app_dir.to_owned(); #[cfg(target_os = "android")] @@ -162,6 +162,28 @@ pub fn session_toggle_option(id: String, value: String) { } } +pub fn session_get_flutter_config(id: String, k: String) -> Option { + if let Some(session) = SESSIONS.read().unwrap().get(&id) { + Some(session.get_flutter_config(k)) + } else { + None + } +} + +pub fn session_set_flutter_config(id: String, k: String, v: String) { + if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { + session.set_flutter_config(k, v); + } +} + +pub fn get_local_flutter_config(k: String) -> SyncReturn { + SyncReturn(ui_interface::get_local_flutter_config(k)) +} + +pub fn set_local_flutter_config(k: String, v: String) { + ui_interface::set_local_flutter_config(k, v); +} + pub fn session_get_image_quality(id: String) -> Option { if let Some(session) = SESSIONS.read().unwrap().get(&id) { Some(session.get_image_quality()) @@ -537,8 +559,8 @@ pub fn main_post_request(url: String, body: String, header: String) { post_request(url, body, header) } -pub fn main_get_local_option(key: String) -> String { - get_local_option(key) +pub fn main_get_local_option(key: String) -> SyncReturn { + SyncReturn(get_local_option(key)) } pub fn main_set_local_option(key: String, value: String) { @@ -1021,7 +1043,7 @@ pub fn main_is_installed() -> SyncReturn { SyncReturn(is_installed()) } -pub fn main_start_grab_keyboard(){ +pub fn main_start_grab_keyboard() { #[cfg(not(any(target_os = "android", target_os = "ios")))] crate::ui_session_interface::global_grab_keyboard(); } diff --git a/src/hbbs_http/account.rs b/src/hbbs_http/account.rs index cdf724971..de0c82bb9 100644 --- a/src/hbbs_http/account.rs +++ b/src/hbbs_http/account.rs @@ -1,7 +1,7 @@ use super::HbbHttpResponse; use hbb_common::{ config::{Config, LocalConfig}, - log, sleep, tokio, ResultType, + log, ResultType, }; use reqwest::blocking::Client; use serde_derive::{Deserialize, Serialize}; diff --git a/src/server/video_qos.rs b/src/server/video_qos.rs index 7aaf12d92..ba67d3fc4 100644 --- a/src/server/video_qos.rs +++ b/src/server/video_qos.rs @@ -225,11 +225,7 @@ impl VideoQoS { } pub fn check_abr_config(&mut self) -> bool { - self.enable_abr = if let Some(v) = Config2::get().options.get("enable-abr") { - v != "N" - } else { - true // default is true - }; + self.enable_abr = "N" != Config::get_option("enable-abr"); self.enable_abr } diff --git a/src/tray.rs b/src/tray.rs index 80647fa17..3fe43197a 100644 --- a/src/tray.rs +++ b/src/tray.rs @@ -1,14 +1,13 @@ -use hbb_common::log::debug; +use super::ui_interface::get_option_opt; #[cfg(target_os = "linux")] -use hbb_common::log::{error, info}; +use hbb_common::log::{debug, error, info}; #[cfg(target_os = "linux")] use libappindicator::AppIndicator; #[cfg(target_os = "linux")] +use std::collections::HashMap; +#[cfg(target_os = "linux")] use std::env::temp_dir; -use std::{ - collections::HashMap, - sync::{Arc, Mutex}, -}; +use std::sync::{Arc, Mutex}; #[cfg(target_os = "windows")] use trayicon::{MenuBuilder, TrayIconBuilder}; #[cfg(target_os = "windows")] @@ -25,7 +24,7 @@ enum Events { } #[cfg(target_os = "windows")] -pub fn start_tray(options: Arc>>) { +pub fn start_tray() { let event_loop = EventLoop::::with_user_event(); let proxy = event_loop.create_proxy(); let icon = include_bytes!("../res/tray-icon.ico"); @@ -39,13 +38,13 @@ pub fn start_tray(options: Arc>>) { let old_state = Arc::new(Mutex::new(0)); let _sender = crate::ui_interface::SENDER.lock().unwrap(); event_loop.run(move |event, _, control_flow| { - if options.lock().unwrap().get("ipc-closed").is_some() { + if get_option_opt("ipc-closed").is_some() { *control_flow = ControlFlow::Exit; return; } else { *control_flow = ControlFlow::Wait; } - let stopped = if let Some(v) = options.lock().unwrap().get("stop-service") { + let stopped = if let Some(v) = get_option_opt("stop-service") { !v.is_empty() } else { false @@ -173,6 +172,7 @@ fn get_default_app_indicator() -> Option { /// Get service status /// Return [`true`] if service is running, [`false`] otherwise. +#[cfg(target_os = "linux")] #[inline] fn get_service_status(options: Arc>>) -> bool { if let Some(v) = options.lock().unwrap().get("stop-service") { diff --git a/src/ui.rs b/src/ui.rs index b11e574ba..2d7f8d70a 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -33,7 +33,8 @@ pub mod win_privacy; type Message = RendezvousMessage; -pub type Childs = Arc)>>; +pub type Children = Arc)>>; +#[allow(dead_code)] type Status = (i32, bool, i64, String); lazy_static::lazy_static! { @@ -43,6 +44,7 @@ lazy_static::lazy_static! { struct UIHostHandler; +// to-do: dead code? fn check_connect_status( reconnect: bool, ) -> ( @@ -111,8 +113,8 @@ pub fn start(args: &mut [String]) { args[1] = id; } if args.is_empty() { - let child: Childs = Default::default(); - std::thread::spawn(move || check_zombie(child)); + let children: Children = Default::default(); + std::thread::spawn(move || check_zombie(children)); crate::common::check_software_update(); frame.event_handler(UI {}); frame.sciter_handler(UIHostHandler {}); @@ -662,10 +664,10 @@ impl sciter::host::HostHandler for UIHostHandler { } } -pub fn check_zombie(childs: Childs) { +pub fn check_zombie(children: Children) { let mut deads = Vec::new(); loop { - let mut lock = childs.lock().unwrap(); + let mut lock = children.lock().unwrap(); let mut n = 0; for (id, c) in lock.1.iter_mut() { if let Ok(Some(_)) = c.try_wait() { diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 61366594c..09e259fa2 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -2,13 +2,14 @@ use std::sync::Arc; use std::{ collections::HashMap, - iter::FromIterator, ops::{Deref, DerefMut}, sync::{ atomic::{AtomicI64, Ordering}, RwLock, }, }; +#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] +use std::iter::FromIterator; #[cfg(windows)] use clipboard::{cliprdr::CliprdrClientContext, empty_clipboard, set_conn_enabled, ContextSend}; diff --git a/src/ui_interface.rs b/src/ui_interface.rs index 29b09addc..d7d1b9979 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -9,32 +9,37 @@ use std::{ use hbb_common::password_security; use hbb_common::{ allow_err, - config::{self, Config, LocalConfig, PeerConfig, RENDEZVOUS_PORT, RENDEZVOUS_TIMEOUT}, - directories_next, - futures::future::join_all, - log, - protobuf::Message as _, - rendezvous_proto::*, + config::{self, Config, LocalConfig, PeerConfig}, + directories_next, log, sleep, - tcp::FramedStream, tokio::{self, sync::mpsc, time}, }; -use crate::{common::SOFTWARE_UPDATE_URL, ipc, platform}; +#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] +use hbb_common::{ + config::{RENDEZVOUS_PORT, RENDEZVOUS_TIMEOUT}, + futures::future::join_all, + protobuf::Message as _, + rendezvous_proto::*, + tcp::FramedStream, +}; + #[cfg(feature = "flutter")] use crate::hbbs_http::account; +use crate::{common::SOFTWARE_UPDATE_URL, ipc, platform}; +#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] type Message = RendezvousMessage; -pub type Childs = Arc)>>; +pub type Children = Arc)>>; type Status = (i32, bool, i64, String); // (status_num, key_confirmed, mouse_time, id) lazy_static::lazy_static! { - pub static ref CHILDS : Childs = Default::default(); - pub static ref UI_STATUS : Arc> = Arc::new(Mutex::new((0, false, 0, "".to_owned()))); - pub static ref OPTIONS : Arc>> = Arc::new(Mutex::new(Config::get_options())); - pub static ref ASYNC_JOB_STATUS : Arc> = Default::default(); - pub static ref TEMPORARY_PASSWD : Arc> = Arc::new(Mutex::new("".to_owned())); + static ref CHILDREN : Children = Default::default(); + static ref UI_STATUS : Arc> = Arc::new(Mutex::new((0, false, 0, "".to_owned()))); + static ref OPTIONS : Arc>> = Arc::new(Mutex::new(Config::get_options())); + static ref ASYNC_JOB_STATUS : Arc> = Default::default(); + static ref TEMPORARY_PASSWD : Arc> = Arc::new(Mutex::new("".to_owned())); } #[cfg(not(any(target_os = "android", target_os = "ios")))] @@ -44,15 +49,16 @@ lazy_static::lazy_static! { #[inline] pub fn recent_sessions_updated() -> bool { - let mut childs = CHILDS.lock().unwrap(); - if childs.0 { - childs.0 = false; + let mut children = CHILDREN.lock().unwrap(); + if children.0 { + children.0 = false; true } else { false } } +#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] #[inline] pub fn get_id() -> String { #[cfg(any(target_os = "android", target_os = "ios"))] @@ -143,10 +149,9 @@ pub fn get_license() -> String { #[cfg(windows)] if let Some(lic) = crate::platform::windows::get_license() { #[cfg(feature = "flutter")] - { - return format!("Key: {}\nHost: {}\nApi: {}", lic.key, lic.host, lic.api); - } + return format!("Key: {}\nHost: {}\nApi: {}", lic.key, lic.host, lic.api); // default license format is html formed (sciter) + #[cfg(not(feature = "flutter"))] return format!( "
Key: {}
Host: {} Api: {}", lic.key, lic.host, lic.api @@ -155,6 +160,11 @@ pub fn get_license() -> String { Default::default() } +#[inline] +pub fn get_option_opt(key: &str) -> Option { + OPTIONS.lock().unwrap().get(key).map(|x| x.clone()) +} + #[inline] pub fn get_option(key: String) -> String { get_option_(&key) @@ -180,6 +190,16 @@ pub fn set_local_option(key: String, value: String) { LocalConfig::set_option(key, value); } +#[inline] +pub fn get_local_flutter_config(key: String) -> String { + LocalConfig::get_flutter_config(&key) +} + +#[inline] +pub fn set_local_flutter_config(key: String, value: String) { + LocalConfig::set_flutter_config(key, value); +} + #[inline] pub fn peer_has_password(id: String) -> bool { !PeerConfig::load(&id).password.is_empty() @@ -230,7 +250,7 @@ pub fn test_if_valid_server(host: String) -> String { } #[inline] -#[cfg(not(any(target_os = "android", target_os = "ios")))] +#[cfg(feature = "flutter")] pub fn get_sound_inputs() -> Vec { let mut a = Vec::new(); #[cfg(not(target_os = "linux"))] @@ -345,12 +365,15 @@ pub fn set_socks(proxy: String, username: String, password: String) { .ok(); } +#[cfg(not(any(target_os = "android", target_os = "ios")))] #[inline] pub fn is_installed() -> bool { - #[cfg(not(any(target_os = "android", target_os = "ios")))] - { - return crate::platform::is_installed(); - } + crate::platform::is_installed() +} + +#[cfg(any(target_os = "android", target_os = "ios"))] +#[inline] +pub fn is_installed() -> bool { false } @@ -495,7 +518,7 @@ pub fn remove_peer(id: String) { #[inline] pub fn new_remote(id: String, remote_type: String) { - let mut lock = CHILDS.lock().unwrap(); + let mut lock = CHILDREN.lock().unwrap(); let args = vec![format!("--{}", remote_type), id.clone()]; let key = (id.clone(), remote_type.clone()); if let Some(c) = lock.1.get_mut(&key) { @@ -612,6 +635,7 @@ pub fn get_version() -> String { crate::VERSION.to_owned() } +#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] #[inline] pub fn get_app_name() -> String { crate::get_app_name() @@ -650,6 +674,7 @@ pub fn create_shortcut(_id: String) { crate::platform::windows::create_shortcut(&_id).ok(); } +#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] #[inline] pub fn discover() { std::thread::spawn(move || { @@ -694,6 +719,7 @@ pub fn open_url(url: String) { allow_err!(std::process::Command::new(p).arg(url).spawn()); } +#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] #[inline] pub fn change_id(id: String) { *ASYNC_JOB_STATUS.lock().unwrap() = " ".to_owned(); @@ -800,13 +826,19 @@ pub fn is_release() -> bool { return false; } +#[cfg(not(any(target_os = "android", target_os = "ios")))] +#[inline] +pub fn is_root() -> bool { + crate::platform::is_root() +} + +#[cfg(any(target_os = "android", target_os = "ios"))] #[inline] pub fn is_root() -> bool { - #[cfg(not(any(target_os = "android", target_os = "ios")))] - return crate::platform::is_root(); false } +#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] #[inline] pub fn check_super_user_permission() -> bool { #[cfg(feature = "flatpak")] @@ -818,10 +850,10 @@ pub fn check_super_user_permission() -> bool { } #[allow(dead_code)] -pub fn check_zombie(childs: Childs) { +pub fn check_zombie(children: Children) { let mut deads = Vec::new(); loop { - let mut lock = childs.lock().unwrap(); + let mut lock = children.lock().unwrap(); let mut n = 0; for (id, c) in lock.1.iter_mut() { if let Ok(Some(_)) = c.try_wait() { @@ -928,6 +960,7 @@ pub(crate) async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedRe } } +#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] #[tokio::main(flavor = "current_thread")] pub(crate) async fn send_to_cm(data: &ipc::Data) { if let Ok(mut c) = ipc::connect(1000, "_cm").await { @@ -935,9 +968,12 @@ pub(crate) async fn send_to_cm(data: &ipc::Data) { } } +#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] const INVALID_FORMAT: &'static str = "Invalid format"; +#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] const UNKNOWN_ERROR: &'static str = "Unknown error"; +#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] #[tokio::main(flavor = "current_thread")] async fn change_id_(id: String, old_id: String) -> &'static str { if !hbb_common::is_valid_custom_id(&id) { @@ -987,6 +1023,7 @@ async fn change_id_(id: String, old_id: String) -> &'static str { err } +#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] async fn check_id( rendezvous_server: String, old_id: String, diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index bf03ed2d3..ead60299a 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -98,6 +98,14 @@ impl Session { self.lc.write().unwrap().save_view_style(value); } + pub fn set_flutter_config(&mut self, k: String, v: String) { + self.lc.write().unwrap().set_ui_flutter(k, v); + } + + pub fn get_flutter_config(&self, k: String) -> String { + self.lc.write().unwrap().get_ui_flutter(&k) + } + pub fn toggle_option(&mut self, name: String) { let msg = self.lc.write().unwrap().toggle_option(name.clone()); if name == "enable-file-transfer" { @@ -1590,7 +1598,7 @@ pub fn global_grab_keyboard() { #[cfg(any(target_os = "windows", target_os = "macos"))] std::thread::spawn(move || { let func = move |event: Event| match event.event_type { - EventType::KeyPress(key) | EventType::KeyRelease(key) => { + EventType::KeyPress(..) | EventType::KeyRelease(..) => { // grab all keys if !IS_IN.load(Ordering::SeqCst) { return Some(event); From b000fd1ea8260d38be61610b28ec216f04090145 Mon Sep 17 00:00:00 2001 From: fufesou Date: Thu, 10 Nov 2022 07:26:09 -0800 Subject: [PATCH 006/116] build linux Signed-off-by: fufesou --- src/client/io_loop.rs | 3 +- src/core_main.rs | 7 +++-- src/flutter.rs | 1 + src/flutter_ffi.rs | 2 +- src/server/dbus.rs | 8 +++-- src/server/video_service.rs | 3 +- src/tray.rs | 63 ++++++++++++++++--------------------- src/ui_interface.rs | 2 ++ 8 files changed, 44 insertions(+), 45 deletions(-) diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 52042da06..04d1d4d29 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -23,9 +23,10 @@ use hbb_common::rendezvous_proto::ConnType; use hbb_common::tokio::{ self, sync::mpsc, - sync::Mutex as TokioMutex, time::{self, Duration, Instant, Interval}, }; +#[cfg(windows)] +use hbb_common::tokio::sync::Mutex as TokioMutex; use hbb_common::{ allow_err, message_proto::*, diff --git a/src/core_main.rs b/src/core_main.rs index 2298aaad6..d22d4e71b 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -149,12 +149,12 @@ pub fn core_main() -> Option> { std::thread::spawn(move || crate::start_server(true)); // to-do: for flutter, starting tray not ready yet, or we can reuse sciter's tray implementation. } - #[cfg(all(target_os = "linux"))] + #[cfg(target_os = "linux")] { let handler = std::thread::spawn(move || crate::start_server(true)); - crate::tray::start_tray(crate::ui_interface::OPTIONS.clone()); + crate::tray::start_tray(); // revent server exit when encountering errors from tray - handler.join(); + hbb_common::allow_err!(handler.join()); } } else if args[0] == "--import-config" { if args.len() == 2 { @@ -249,5 +249,6 @@ fn core_main_invoke_new_connection(mut args: std::env::Args) -> Option *mut *mut c_char { } // https://gist.github.com/iskakaushik/1c5b8aa75c77479c33c4320913eebef6 +#[cfg(windows)] fn rust_args_to_c_args(args: Vec, outlen: *mut c_int) -> *mut *mut c_char { let mut v = vec![]; diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index aba8f7e1b..21603227f 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -440,7 +440,7 @@ pub fn session_resume_job(id: String, act_id: i32, is_remote: bool) { pub fn main_get_sound_inputs() -> Vec { #[cfg(not(any(target_os = "android", target_os = "ios")))] return get_sound_inputs(); - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(any(target_os = "android", target_os = "ios"))] vec![String::from("")] } diff --git a/src/server/dbus.rs b/src/server/dbus.rs index a7b21f0dc..5a38fe7cb 100644 --- a/src/server/dbus.rs +++ b/src/server/dbus.rs @@ -6,7 +6,9 @@ use dbus::blocking::Connection; use dbus_crossroads::{Crossroads, IfaceBuilder}; use hbb_common::{log}; -use std::{error::Error, fmt, time::Duration, collections::HashMap}; +use std::{error::Error, fmt, time::Duration}; +#[cfg(feature = "flutter")] +use std::collections::HashMap; const DBUS_NAME: &str = "org.rustdesk.rustdesk"; const DBUS_PREFIX: &str = "/dbus"; @@ -65,7 +67,7 @@ fn handle_client_message(builder: &mut IfaceBuilder<()>) { DBUS_METHOD_NEW_CONNECTION, (DBUS_METHOD_NEW_CONNECTION_ID,), (DBUS_METHOD_RETURN,), - move |_, _, (peer_id,): (String,)| { + move |_, _, (_peer_id,): (String,)| { #[cfg(feature = "flutter")] { use crate::flutter::{self, APP_TYPE_MAIN}; @@ -77,7 +79,7 @@ fn handle_client_message(builder: &mut IfaceBuilder<()>) { { let data = HashMap::from([ ("name", "new_connection"), - ("peer_id", peer_id.as_str()) + ("peer_id", _peer_id.as_str()) ]); if !stream.add(serde_json::ser::to_string(&data).unwrap_or("".to_string())) { log::error!("failed to add dbus message to flutter global dbus stream."); diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 5927bddec..9696ef08d 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -33,10 +33,11 @@ use std::{ collections::HashSet, io::ErrorKind::WouldBlock, ops::{Deref, DerefMut}, - sync::Once, time::{self, Duration, Instant}, }; #[cfg(windows)] +use std::sync::Once; +#[cfg(windows)] use virtual_display; pub const SCRAP_UBUNTU_HIGHER_REQUIRED: &str = "Wayland requires Ubuntu 21.04 or higher version."; diff --git a/src/tray.rs b/src/tray.rs index 3fe43197a..30bdc5a59 100644 --- a/src/tray.rs +++ b/src/tray.rs @@ -4,9 +4,8 @@ use hbb_common::log::{debug, error, info}; #[cfg(target_os = "linux")] use libappindicator::AppIndicator; #[cfg(target_os = "linux")] -use std::collections::HashMap; -#[cfg(target_os = "linux")] use std::env::temp_dir; +#[cfg(target_os = "windows")] use std::sync::{Arc, Mutex}; #[cfg(target_os = "windows")] use trayicon::{MenuBuilder, TrayIconBuilder}; @@ -16,6 +15,7 @@ use winit::{ event_loop::{ControlFlow, EventLoop}, }; +#[cfg(target_os = "windows")] #[derive(Clone, Eq, PartialEq, Debug)] enum Events { DoubleClickTrayIcon, @@ -44,17 +44,13 @@ pub fn start_tray() { } else { *control_flow = ControlFlow::Wait; } - let stopped = if let Some(v) = get_option_opt("stop-service") { - !v.is_empty() - } else { - false - }; - let stopped = if stopped { 2 } else { 1 }; + let stopped = is_service_stoped(); + let state = if stopped { 2 } else { 1 }; let old = *old_state.lock().unwrap(); - if stopped != old { + if state != old { hbb_common::log::info!("State changed"); let mut m = MenuBuilder::new(); - if stopped == 2 { + if state == 2 { m = m.item( &crate::client::translate("Start Service".to_owned()), Events::StartService, @@ -66,7 +62,7 @@ pub fn start_tray() { ); } tray_icon.set_menu(&m).ok(); - *old_state.lock().unwrap() = stopped; + *old_state.lock().unwrap() = state; } match event { @@ -91,10 +87,9 @@ pub fn start_tray() { /// [Block] /// This function will block current execution, show the tray icon and handle events. #[cfg(target_os = "linux")] -pub fn start_tray(options: Arc>>) { - use std::time::Duration; - +pub fn start_tray() { use gtk::traits::{GtkMenuItemExt, MenuShellExt, WidgetExt}; + info!("configuring tray"); // init gtk context if let Err(err) = gtk::init() { @@ -103,17 +98,17 @@ pub fn start_tray(options: Arc>>) { } if let Some(mut appindicator) = get_default_app_indicator() { let mut menu = gtk::Menu::new(); - let running = get_service_status(options.clone()); + let stoped = is_service_stoped(); // start/stop service - let label = if !running { + let label = if stoped { crate::client::translate("Start Service".to_owned()) } else { crate::client::translate("Stop service".to_owned()) }; let menu_item_service = gtk::MenuItem::with_label(label.as_str()); menu_item_service.connect_activate(move |item| { - let lock = crate::ui_interface::SENDER.lock().unwrap(); - update_tray_service_item(options.clone(), item); + let _lock = crate::ui_interface::SENDER.lock().unwrap(); + update_tray_service_item(item); }); menu.append(&menu_item_service); // show tray item @@ -128,19 +123,17 @@ pub fn start_tray(options: Arc>>) { } #[cfg(target_os = "linux")] -fn update_tray_service_item(options: Arc>>, item: >k::MenuItem) { - use gtk::{ - traits::{GtkMenuItemExt, ListBoxRowExt}, - MenuItem, - }; - if get_service_status(options.clone()) { - debug!("Now try to stop service"); - item.set_label(&crate::client::translate("Start Service".to_owned())); - crate::ipc::set_option("stop-service", "Y"); - } else { +fn update_tray_service_item(item: >k::MenuItem) { + use gtk::traits::GtkMenuItemExt; + + if is_service_stoped() { debug!("Now try to start service"); item.set_label(&crate::client::translate("Stop service".to_owned())); crate::ipc::set_option("stop-service", ""); + } else { + debug!("Now try to stop service"); + item.set_label(&crate::client::translate("Start Service".to_owned())); + crate::ipc::set_option("stop-service", "Y"); } } @@ -170,15 +163,13 @@ fn get_default_app_indicator() -> Option { Some(appindicator) } -/// Get service status -/// Return [`true`] if service is running, [`false`] otherwise. -#[cfg(target_os = "linux")] +/// Check if service is stoped. +/// Return [`true`] if service is stoped, [`false`] otherwise. #[inline] -fn get_service_status(options: Arc>>) -> bool { - if let Some(v) = options.lock().unwrap().get("stop-service") { - debug!("service stopped: {}", v); - v.is_empty() +fn is_service_stoped() -> bool { + if let Some(v) = get_option_opt("stop-service") { + v == "Y" } else { - true + false } } diff --git a/src/ui_interface.rs b/src/ui_interface.rs index d7d1b9979..7d520662d 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -190,11 +190,13 @@ pub fn set_local_option(key: String, value: String) { LocalConfig::set_option(key, value); } +#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] #[inline] pub fn get_local_flutter_config(key: String) -> String { LocalConfig::get_flutter_config(&key) } +#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] #[inline] pub fn set_local_flutter_config(key: String, value: String) { LocalConfig::set_flutter_config(key, value); From 3d768098f8e0e1abc7388cd65e4172d222529348 Mon Sep 17 00:00:00 2001 From: fufesou Date: Fri, 11 Nov 2022 14:28:35 +0800 Subject: [PATCH 007/116] fix mouse cannot be controled, when show remote cursor is on Signed-off-by: fufesou --- src/server/input_service.rs | 57 ++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/src/server/input_service.rs b/src/server/input_service.rs index 44ccece8e..b47872c34 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -13,6 +13,8 @@ use std::{ time::Instant, }; +const INVALID_CURSOR_POS: i32 = i32::MIN; + #[derive(Default)] struct StateCursor { hcursor: u64, @@ -28,14 +30,27 @@ impl super::service::Reset for StateCursor { } } -#[derive(Default)] struct StatePos { cursor_pos: (i32, i32), } +impl Default for StatePos { + fn default() -> Self { + Self { + cursor_pos: (INVALID_CURSOR_POS, INVALID_CURSOR_POS), + } + } +} + impl super::service::Reset for StatePos { fn reset(&mut self) { - self.cursor_pos = (0, 0); + self.cursor_pos = (INVALID_CURSOR_POS, INVALID_CURSOR_POS); + } +} + +impl StatePos { + fn is_valid(&self) -> bool { + self.cursor_pos.0 != INVALID_CURSOR_POS && self.cursor_pos.1 != INVALID_CURSOR_POS } } @@ -114,25 +129,27 @@ fn update_last_cursor_pos(x: i32, y: i32) { fn run_pos(sp: GenericService, state: &mut StatePos) -> ResultType<()> { if let Some((x, y)) = crate::get_cursor_pos() { update_last_cursor_pos(x, y); - if state.cursor_pos.0 != x || state.cursor_pos.1 != y { - state.cursor_pos = (x, y); - let mut msg_out = Message::new(); - msg_out.set_cursor_position(CursorPosition { - x, - y, - ..Default::default() - }); - let exclude = { - let now = get_time(); - let lock = LATEST_INPUT_CURSOR.lock().unwrap(); - if now - lock.time < 300 { - lock.conn - } else { - 0 - } - }; - sp.send_without(msg_out, exclude); + if state.is_valid() { + if state.cursor_pos.0 != x || state.cursor_pos.1 != y { + let mut msg_out = Message::new(); + msg_out.set_cursor_position(CursorPosition { + x, + y, + ..Default::default() + }); + let exclude = { + let now = get_time(); + let lock = LATEST_INPUT_CURSOR.lock().unwrap(); + if now - lock.time < 300 { + lock.conn + } else { + 0 + } + }; + sp.send_without(msg_out, exclude); + } } + state.cursor_pos = (x, y); } sp.snapshot(|sps| { From ee4aa0d0ac2664aea2b934800b874b41592568d6 Mon Sep 17 00:00:00 2001 From: fufesou Date: Fri, 11 Nov 2022 14:53:37 +0800 Subject: [PATCH 008/116] trivial code refactor Signed-off-by: fufesou --- src/server/input_service.rs | 44 ++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/server/input_service.rs b/src/server/input_service.rs index b47872c34..780c1106a 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -49,8 +49,14 @@ impl super::service::Reset for StatePos { } impl StatePos { + #[inline] fn is_valid(&self) -> bool { - self.cursor_pos.0 != INVALID_CURSOR_POS && self.cursor_pos.1 != INVALID_CURSOR_POS + self.cursor_pos.0 != INVALID_CURSOR_POS + } + + #[inline] + fn is_moved(&self, x: i32, y: i32) -> bool { + self.is_valid() && (self.cursor_pos.0 != x || self.cursor_pos.1 != y) } } @@ -129,25 +135,23 @@ fn update_last_cursor_pos(x: i32, y: i32) { fn run_pos(sp: GenericService, state: &mut StatePos) -> ResultType<()> { if let Some((x, y)) = crate::get_cursor_pos() { update_last_cursor_pos(x, y); - if state.is_valid() { - if state.cursor_pos.0 != x || state.cursor_pos.1 != y { - let mut msg_out = Message::new(); - msg_out.set_cursor_position(CursorPosition { - x, - y, - ..Default::default() - }); - let exclude = { - let now = get_time(); - let lock = LATEST_INPUT_CURSOR.lock().unwrap(); - if now - lock.time < 300 { - lock.conn - } else { - 0 - } - }; - sp.send_without(msg_out, exclude); - } + if state.is_moved(x, y) { + let mut msg_out = Message::new(); + msg_out.set_cursor_position(CursorPosition { + x, + y, + ..Default::default() + }); + let exclude = { + let now = get_time(); + let lock = LATEST_INPUT_CURSOR.lock().unwrap(); + if now - lock.time < 300 { + lock.conn + } else { + 0 + } + }; + sp.send_without(msg_out, exclude); } state.cursor_pos = (x, y); } From cb28a48f6fcebb7a8b5fc9051b4a3f339b45161d Mon Sep 17 00:00:00 2001 From: Kingtous Date: Fri, 11 Nov 2022 22:04:50 +0800 Subject: [PATCH 009/116] fix: windows maximize issue --- flutter/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index b7ffeec0a..b75f2e361 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -63,7 +63,7 @@ dependencies: desktop_multi_window: git: url: https://github.com/Kingtous/rustdesk_desktop_multi_window - ref: 0831243da7231c82ea56ebaeb36e650620d4a23b + ref: fc14252a5e32236b68a91df0be12d9950c525069 freezed_annotation: ^2.0.3 tray_manager: git: From 614fcca1b80fb3dae4034f114421dd55c4c301dd Mon Sep 17 00:00:00 2001 From: Kingtous Date: Sat, 12 Nov 2022 12:24:50 +0800 Subject: [PATCH 010/116] opt: windows static and vc140_1 compile --- flutter/windows/CMakeLists.txt | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/flutter/windows/CMakeLists.txt b/flutter/windows/CMakeLists.txt index c6192b584..5cf603360 100644 --- a/flutter/windows/CMakeLists.txt +++ b/flutter/windows/CMakeLists.txt @@ -1,6 +1,6 @@ # Project-level configuration. cmake_minimum_required(VERSION 3.14) -project(flutter_hbb LANGUAGES CXX) +project(rustdesk LANGUAGES CXX) # The name of the executable created for the application. Change this to change # the on-disk name of your application. @@ -28,6 +28,18 @@ set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") +# Replace /MD flags to /MT to use static vcruntine +set(CompilerFlags + CMAKE_CXX_FLAGS + CMAKE_CXX_FLAGS_DEBUG + CMAKE_CXX_FLAGS_RELEASE + CMAKE_C_FLAGS + CMAKE_C_FLAGS_DEBUG + CMAKE_C_FLAGS_RELEASE + ) +foreach(CompilerFlag ${CompilerFlags}) + string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}") +endforeach() # Use Unicode for all projects. add_definitions(-DUNICODE -D_UNICODE) @@ -41,6 +53,8 @@ function(APPLY_STANDARD_SETTINGS TARGET) target_compile_features(${TARGET} PUBLIC cxx_std_17) target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") target_compile_options(${TARGET} PRIVATE /EHsc) + # Disable VC140_1 + target_compile_options(${TARGET} PRIVATE /d2FH4-) target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") endfunction() From d436f4946f4e8149f7f1358ab78284122f0d7924 Mon Sep 17 00:00:00 2001 From: "Miguel F. G" <116861809+flusheDData@users.noreply.github.com> Date: Sat, 12 Nov 2022 12:14:18 +0100 Subject: [PATCH 011/116] 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 7582926f3..2eef088c3 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -305,7 +305,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Translate mode", "Modo traducido"), ("Use temporary password", "Usar contraseña temporal"), ("Use permanent password", "Usar contraseña permamente"), - ("Use both passwords", "Usar ambas comtraseñas"), + ("Use both passwords", "Usar ambas contraseñas"), ("Set permanent password", "Establecer contraseña permamente"), ("Set temporary password length", "Establecer largo de contraseña temporal"), ("Enable Remote Restart", "Activar reinicio remoto"), From 30ed047335432497f3f848d1bec313798db063fc Mon Sep 17 00:00:00 2001 From: solokot Date: Sat, 12 Nov 2022 15:01:13 +0300 Subject: [PATCH 012/116] Updated ru.rs --- src/lang/ru.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 4eae0d153..7d7b0c6ad 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -387,7 +387,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please Select the screen to be shared(Operate on the peer side).", "Пожалуйста, выберите экран для совместного использования (работайте на одноранговой стороне)."), ("Show RustDesk", "Показать RustDesk"), ("This PC", "Этот компьютер"), - ("or", ""), - ("Continue with", ""), + ("or", "или"), + ("Continue with", "Продолжить с"), ].iter().cloned().collect(); } From 4ce4830274b044584b8e52c9865ea203d2daedd0 Mon Sep 17 00:00:00 2001 From: xxrl <837951112@qq.com> Date: Sat, 12 Nov 2022 20:39:16 +0800 Subject: [PATCH 013/116] fix: disable check scroll for flutter mac --- src/client.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client.rs b/src/client.rs index 2be71828d..768e7bc33 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1530,7 +1530,7 @@ pub async fn handle_test_delay(t: TestDelay, peer: &mut Stream) { } #[inline] -#[cfg(target_os = "macos")] +#[cfg(all(target_os = "macos", not(feature = "flutter")))] fn check_scroll_on_mac(mask: i32, x: i32, y: i32) -> bool { if mask & 3 != 3 { return false; @@ -1593,7 +1593,7 @@ pub fn send_mouse( if command { mouse_event.modifiers.push(ControlKey::Meta.into()); } - #[cfg(target_os = "macos")] + #[cfg(all(target_os = "macos", not(feature = "flutter")))] if check_scroll_on_mac(mask, x, y) { mouse_event.modifiers.push(ControlKey::Scroll.into()); } From 730cd4ab104b3e78c3e7c3f84a109a5b8e489eeb Mon Sep 17 00:00:00 2001 From: fufesou Date: Sat, 12 Nov 2022 22:33:10 +0800 Subject: [PATCH 014/116] Show alias if set, on remote tab Signed-off-by: fufesou --- flutter/lib/common/shared_state.dart | 22 +++++++++++++++++++ flutter/lib/common/widgets/peer_card.dart | 2 +- .../desktop/pages/file_manager_tab_page.dart | 1 + .../desktop/pages/port_forward_tab_page.dart | 1 + .../lib/desktop/pages/remote_tab_page.dart | 1 + .../lib/desktop/widgets/tabbar_widget.dart | 10 +++++++++ flutter/lib/models/model.dart | 15 ++++++++++++- src/flutter_ffi.rs | 5 +++++ 8 files changed, 55 insertions(+), 2 deletions(-) diff --git a/flutter/lib/common/shared_state.dart b/flutter/lib/common/shared_state.dart index 4cfe219e4..5ae618dfe 100644 --- a/flutter/lib/common/shared_state.dart +++ b/flutter/lib/common/shared_state.dart @@ -201,3 +201,25 @@ class RemoteCountState { static RxInt find() => Get.find(tag: tag()); } + +class PeerStringOption { + static String tag(String id, String opt) => 'peer_{$opt}_$id'; + + static void init(String id, String opt, String Function() init_getter) { + final key = tag(id, opt); + if (!Get.isRegistered(tag: key)) { + final RxString value = RxString(init_getter()); + Get.put(value, tag: key); + } + } + + static void delete(String id, String opt) { + final key = tag(id, opt); + if (Get.isRegistered(tag: key)) { + Get.delete(tag: key); + } + } + + static RxString find(String id, String opt) => + Get.find(tag: tag(id, opt)); +} diff --git a/flutter/lib/common/widgets/peer_card.dart b/flutter/lib/common/widgets/peer_card.dart index c99cf2e68..5796c7d20 100644 --- a/flutter/lib/common/widgets/peer_card.dart +++ b/flutter/lib/common/widgets/peer_card.dart @@ -584,7 +584,7 @@ abstract class BasePeerCard extends StatelessWidget { submit() async { isInProgress.value = true; name = controller.text; - await bind.mainSetPeerOption(id: id, key: 'alias', value: name); + await bind.mainSetPeerAlias(id: id, alias: name); if (isAddressBook) { gFFI.abModel.setPeerAlias(id, name); await gFFI.abModel.pushAb(); diff --git a/flutter/lib/desktop/pages/file_manager_tab_page.dart b/flutter/lib/desktop/pages/file_manager_tab_page.dart index d0f6c800e..7e07eaa9a 100644 --- a/flutter/lib/desktop/pages/file_manager_tab_page.dart +++ b/flutter/lib/desktop/pages/file_manager_tab_page.dart @@ -83,6 +83,7 @@ class _FileManagerTabPageState extends State { controller: tabController, onWindowCloseButton: handleWindowCloseButton, tail: const AddButton().paddingOnly(left: 10), + labelGetter: DesktopTab.labelGetterAlias, )), ); return Platform.isMacOS diff --git a/flutter/lib/desktop/pages/port_forward_tab_page.dart b/flutter/lib/desktop/pages/port_forward_tab_page.dart index 403afe343..d4c0a86f8 100644 --- a/flutter/lib/desktop/pages/port_forward_tab_page.dart +++ b/flutter/lib/desktop/pages/port_forward_tab_page.dart @@ -94,6 +94,7 @@ class _PortForwardTabPageState extends State { return true; }, tail: AddButton().paddingOnly(left: 10), + labelGetter: DesktopTab.labelGetterAlias, )), ); return Platform.isMacOS diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index 4f7e9c5aa..5e49895f4 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -128,6 +128,7 @@ class _ConnectionTabPageState extends State { onWindowCloseButton: handleWindowCloseButton, tail: const AddButton().paddingOnly(left: 10), pageViewBuilder: (pageView) => pageView, + labelGetter: DesktopTab.labelGetterAlias, tabBuilder: (key, icon, label, themeConf) => Obx(() { final connectionType = ConnectionTypeState.find(key); if (!connectionType.isValid()) { diff --git a/flutter/lib/desktop/widgets/tabbar_widget.dart b/flutter/lib/desktop/widgets/tabbar_widget.dart index b9e126c61..506399e6f 100644 --- a/flutter/lib/desktop/widgets/tabbar_widget.dart +++ b/flutter/lib/desktop/widgets/tabbar_widget.dart @@ -9,6 +9,7 @@ import 'package:flutter/material.dart' hide TabBarTheme; import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/main.dart'; +import 'package:flutter_hbb/common/shared_state.dart'; import 'package:flutter_hbb/models/platform_model.dart'; import 'package:flutter_hbb/models/state_model.dart'; import 'package:get/get.dart'; @@ -252,6 +253,15 @@ class DesktopTab extends StatelessWidget { tabType == DesktopTabType.main || tabType == DesktopTabType.cm; } + static RxString labelGetterAlias(String peerId) { + final opt = 'alias'; + PeerStringOption.init(peerId, opt, () { + final alias = bind.mainGetPeerOptionSync(id: peerId, key: opt); + return alias.isEmpty ? peerId : alias; + }); + return PeerStringOption.find(peerId, opt); + } + @override Widget build(BuildContext context) { return Column(children: [ diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 616a1c985..53a040eed 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -15,6 +15,7 @@ import 'package:flutter_hbb/models/file_model.dart'; import 'package:flutter_hbb/models/server_model.dart'; import 'package:flutter_hbb/models/user_model.dart'; import 'package:flutter_hbb/models/state_model.dart'; +import 'package:flutter_hbb/common/shared_state.dart'; import 'package:flutter_hbb/utils/multi_window_manager.dart'; import 'package:tuple/tuple.dart'; import 'package:image/image.dart' as img2; @@ -189,6 +190,8 @@ class FfiModel with ChangeNotifier { rustDeskWinManager.newRemoteDesktop(arg); }); } + } else if (name == 'alias') { + handleAliasChanged(evt); } }; } @@ -198,6 +201,13 @@ class FfiModel with ChangeNotifier { platformFFI.setEventCallback(startEventListener(peerId)); } + handleAliasChanged(Map evt) { + final rxAlias = PeerStringOption.find(evt['id'], 'alias'); + if (rxAlias.value != evt['alias']) { + rxAlias.value = evt['alias']; + } + } + handleSwitchDisplay(Map evt) { final oldOrientation = _display.width > _display.height; var old = _pi.currentDisplay; @@ -927,7 +937,7 @@ class CursorModel with ChangeNotifier { // my throw exception, because the listener maybe already dispose notifyListeners(); } catch (e) { - debugPrint('notify cursor: $e'); + debugPrint('WARNING: updateCursorId $id, without notifyListeners(). $e'); } } @@ -980,6 +990,9 @@ class CursorModel with ChangeNotifier { _hotx = tmp.item2; _hoty = tmp.item3; notifyListeners(); + } else { + debugPrint( + 'WARNING: updateCursorId $id, cache is ${_cache == null ? "null" : "not null"}. without notifyListeners()'); } } diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 21603227f..a0f94fdbd 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -592,6 +592,11 @@ pub fn main_set_peer_option_sync(id: String, key: String, value: String) -> Sync SyncReturn(true) } +pub fn main_set_peer_alias(id: String, alias: String) { + main_broadcast_message(&HashMap::from([("name", "alias"), ("id", &id), ("alias", &alias)])); + set_peer_option(id, "alias".to_owned(), alias) +} + pub fn main_forget_password(id: String) { forget_password(id) } From 1a917b1603bb5ce4e3ab6cca125cd8f74f7731fd Mon Sep 17 00:00:00 2001 From: Kingtous Date: Sun, 13 Nov 2022 14:57:46 +0800 Subject: [PATCH 015/116] opt: add windows custom cursor cache --- flutter/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index b75f2e361..56cb4b204 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -72,7 +72,7 @@ dependencies: flutter_custom_cursor: git: url: https://github.com/Kingtous/rustdesk_flutter_custom_cursor - ref: dec2166e881c47d922e1edc484d10d2cd5c2103b + ref: ac3c1bf816197863cdcfa42d008962ff644132b0 window_size: git: url: https://github.com/google/flutter-desktop-embedding.git From 6b3c2f3beb32c5f59c82d104e62afdbb93ebf24e Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 13 Nov 2022 18:11:13 +0800 Subject: [PATCH 016/116] fix android build errors and warnings Signed-off-by: fufesou --- libs/hbb_common/src/config.rs | 58 ++++++++++++++++++++--------------- libs/scrap/src/android/mod.rs | 3 -- src/common.rs | 4 ++- src/flutter_ffi.rs | 11 ++++--- src/platform/mod.rs | 1 + src/server.rs | 8 +++-- src/server/connection.rs | 4 ++- src/server/video_service.rs | 2 +- src/ui_cm_interface.rs | 4 +-- src/ui_interface.rs | 5 +-- src/ui_session_interface.rs | 10 +++--- 11 files changed, 65 insertions(+), 45 deletions(-) diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index cc9da6420..a7836cef7 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -8,7 +8,6 @@ use std::{ }; use anyhow::Result; -use directories_next::ProjectDirs; use rand::Rng; use serde_derive::{Deserialize, Serialize}; use sodiumoxide::crypto::sign; @@ -375,12 +374,15 @@ 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()); - if let Some(path) = dirs_next::home_dir() { - patch(path) - } else if let Ok(path) = std::env::current_dir() { - path - } else { - std::env::temp_dir() + #[cfg(not(any(target_os = "android", target_os = "ios")))] + { + if let Some(path) = dirs_next::home_dir() { + patch(path) + } else if let Ok(path) = std::env::current_dir() { + path + } else { + std::env::temp_dir() + } } } @@ -391,17 +393,20 @@ impl Config { path.push(p); return path; } - #[cfg(not(target_os = "macos"))] - let org = ""; - #[cfg(target_os = "macos")] - let org = ORG.read().unwrap().clone(); - // /var/root for root - if let Some(project) = ProjectDirs::from("", &org, &*APP_NAME.read().unwrap()) { - let mut path = patch(project.config_dir().to_path_buf()); - path.push(p); - return path; + #[cfg(not(any(target_os = "android", target_os = "ios")))] + { + #[cfg(not(target_os = "macos"))] + let org = ""; + #[cfg(target_os = "macos")] + let org = ORG.read().unwrap().clone(); + // /var/root for root + if let Some(project) = directories_next::ProjectDirs::from("", &org, &*APP_NAME.read().unwrap()) { + let mut path = patch(project.config_dir().to_path_buf()); + path.push(p); + return path; + } + return "".into(); } - return "".into(); } #[allow(unreachable_code)] @@ -580,16 +585,19 @@ impl Config { .to_string(), ); } - let mut id = 0u32; + #[cfg(not(any(target_os = "android", target_os = "ios")))] - if let Ok(Some(ma)) = mac_address::get_mac_address() { - for x in &ma.bytes()[2..] { - id = (id << 8) | (*x as u32); + { + let mut id = 0u32; + if let Ok(Some(ma)) = mac_address::get_mac_address() { + for x in &ma.bytes()[2..] { + id = (id << 8) | (*x as u32); + } + id = id & 0x1FFFFFFF; + Some(id.to_string()) + } else { + None } - id = id & 0x1FFFFFFF; - Some(id.to_string()) - } else { - None } } diff --git a/libs/scrap/src/android/mod.rs b/libs/scrap/src/android/mod.rs index 92d84676e..9040395fa 100644 --- a/libs/scrap/src/android/mod.rs +++ b/libs/scrap/src/android/mod.rs @@ -1,6 +1,3 @@ pub mod ffi; -use std::sync::RwLock; pub use ffi::*; - -use lazy_static::lazy_static; diff --git a/src/common.rs b/src/common.rs index 85fcae304..ea02cf810 100644 --- a/src/common.rs +++ b/src/common.rs @@ -6,10 +6,12 @@ use std::{ #[cfg(not(any(target_os = "android", target_os = "ios")))] pub use arboard::Clipboard as ClipboardContext; +#[cfg(not(any(target_os = "android", target_os = "ios")))] +use hbb_common::compress::decompress; use hbb_common::{ allow_err, anyhow::bail, - compress::{compress as compress_func, decompress}, + compress::{compress as compress_func}, config::{self, Config, COMPRESS_LEVEL, RENDEZVOUS_TIMEOUT}, get_version_number, log, message_proto::*, diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index a0f94fdbd..3c9ce96b9 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -16,8 +16,6 @@ use hbb_common::{ // use crate::hbbs_http::account::AuthResult; use crate::flutter::{self, SESSIONS}; -#[cfg(target_os = "android")] -use crate::start_server; use crate::ui_interface::{self, *}; #[cfg(not(any(target_os = "android", target_os = "ios")))] use crate::ui_session_interface::CUR_SESSION; @@ -838,7 +836,12 @@ pub fn main_is_root() -> bool { } pub fn get_double_click_time() -> SyncReturn { - SyncReturn(crate::platform::get_double_click_time() as _) + #[cfg(not(any(target_os = "android", target_os = "ios")))] + { + return SyncReturn(crate::platform::get_double_click_time() as _); + } + #[cfg(any(target_os = "android", target_os = "ios"))] + SyncReturn(500i32) } pub fn main_start_dbus_server() { @@ -1133,7 +1136,7 @@ pub mod server_side { JNIEnv, }; - use hbb_common::{config::Config, log}; + use hbb_common::log; use crate::start_server; diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 37164de31..f6b79da59 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -14,6 +14,7 @@ pub mod macos; #[cfg(target_os = "linux")] pub mod linux; +#[cfg(not(any(target_os = "android", target_os = "ios")))] use hbb_common::{message_proto::CursorData, ResultType}; #[cfg(not(target_os = "macos"))] const SERVICE_INTERVAL: u64 = 300; diff --git a/src/server.rs b/src/server.rs index 08b8c5b5b..6e549c9f4 100644 --- a/src/server.rs +++ b/src/server.rs @@ -5,7 +5,7 @@ use hbb_common::{ allow_err, anyhow::{anyhow, Context}, bail, - config::{Config, Config2, CONNECT_TIMEOUT, RELAY_PORT}, + config::{Config, CONNECT_TIMEOUT, RELAY_PORT}, log, message_proto::*, protobuf::{Enum, Message as _}, @@ -14,7 +14,11 @@ use hbb_common::{ sodiumoxide::crypto::{box_, secretbox, sign}, timeout, tokio, ResultType, Stream, }; -use service::{GenericService, Service, ServiceTmpl, Subscriber}; +#[cfg(not(any(target_os = "android", target_os = "ios")))] +use hbb_common::config::Config2; +#[cfg(not(any(target_os = "android", target_os = "ios")))] +use service::ServiceTmpl; +use service::{GenericService, Service, Subscriber}; use std::{ collections::HashMap, net::SocketAddr, diff --git a/src/server/connection.rs b/src/server/connection.rs index 96d202199..891c48888 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -27,10 +27,12 @@ use scrap::android::call_main_service_mouse_input; use serde_json::{json, value::Value}; use sha2::{Digest, Sha256}; use std::sync::{ - atomic::{AtomicI64, Ordering}, + atomic::AtomicI64, mpsc as std_mpsc, }; #[cfg(not(any(target_os = "android", target_os = "ios")))] +use std::sync::atomic::Ordering; +#[cfg(not(any(target_os = "android", target_os = "ios")))] use system_shutdown; pub type Sender = mpsc::UnboundedSender<(Instant, Arc)>; diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 9696ef08d..81ab494e5 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -530,7 +530,7 @@ fn run(sp: GenericService) -> ResultType<()> { frame_controller.set_send(now, send_conn_ids); } scrap::Frame::RAW(data) => { - if (data.len() != 0) { + if data.len() != 0 { let send_conn_ids = handle_one_frame(&sp, data, ms, &mut encoder, recorder.clone())?; frame_controller.set_send(now, send_conn_ids); diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 09e259fa2..72225b3fb 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -15,7 +15,7 @@ use std::iter::FromIterator; use clipboard::{cliprdr::CliprdrClientContext, empty_clipboard, set_conn_enabled, ContextSend}; use serde_derive::Serialize; -use crate::ipc::{self, new_listener, Connection, Data}; +use crate::ipc::{self, Connection, Data}; #[cfg(windows)] use hbb_common::tokio::sync::Mutex as TokioMutex; use hbb_common::{ @@ -434,7 +434,7 @@ pub async fn start_ipc(cm: ConnectionManager) { allow_err!(crate::ui::win_privacy::start()); }); - match new_listener("_cm").await { + match ipc::new_listener("_cm").await { Ok(mut incoming) => { while let Some(result) = incoming.next().await { match result { diff --git a/src/ui_interface.rs b/src/ui_interface.rs index 7d520662d..a334fb6fb 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -26,7 +26,7 @@ use hbb_common::{ #[cfg(feature = "flutter")] use crate::hbbs_http::account; -use crate::{common::SOFTWARE_UPDATE_URL, ipc, platform}; +use crate::{common::SOFTWARE_UPDATE_URL, ipc}; #[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] type Message = RendezvousMessage; @@ -253,6 +253,7 @@ pub fn test_if_valid_server(host: String) -> String { #[inline] #[cfg(feature = "flutter")] +#[cfg(not(any(target_os = "android", target_os = "ios")))] pub fn get_sound_inputs() -> Vec { let mut a = Vec::new(); #[cfg(not(target_os = "linux"))] @@ -782,7 +783,7 @@ pub fn default_video_save_directory() -> String { } #[cfg(not(any(target_os = "android", target_os = "ios")))] - if let Some(home) = platform::get_active_user_home() { + if let Some(home) = crate::platform::get_active_user_home() { let name = if cfg!(target_os = "macos") { "Movies" } else { diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index ead60299a..4467fee00 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -1,10 +1,10 @@ #[cfg(not(any(target_os = "android", target_os = "ios")))] -use crate::client::get_key_state; +use crate::client::{get_key_state, SERVER_KEYBOARD_ENABLED}; use crate::client::io_loop::Remote; use crate::client::{ check_if_retry, handle_hash, handle_login_from_ui, handle_test_delay, input_os_password, load_config, send_mouse, start_video_audio_threads, FileManager, Key, LoginConfigHandler, - QualityStatus, KEY_MAP, SERVER_KEYBOARD_ENABLED, + QualityStatus, KEY_MAP, }; #[cfg(target_os = "linux")] use crate::common::IS_X11; @@ -16,8 +16,8 @@ use hbb_common::tokio::{self, sync::mpsc}; use hbb_common::{allow_err, message_proto::*}; use hbb_common::{fs, get_version_number, log, Stream}; #[cfg(not(any(target_os = "android", target_os = "ios")))] -use rdev::Keyboard as RdevKeyboard; -use rdev::{Event, EventType, EventType::*, Key as RdevKey, KeyboardState}; +use rdev::{Keyboard as RdevKeyboard, KeyboardState}; +use rdev::{Event, EventType, EventType::*, Key as RdevKey}; use std::collections::{HashMap, HashSet}; use std::ops::{Deref, DerefMut}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; @@ -30,6 +30,7 @@ pub static HOTKEY_HOOKED: AtomicBool = AtomicBool::new(false); #[cfg(windows)] static mut IS_ALT_GR: bool = false; #[cfg(feature = "flutter")] +#[cfg(not(any(target_os = "android", target_os = "ios")))] use crate::flutter::FlutterHandler; lazy_static::lazy_static! { @@ -1570,6 +1571,7 @@ fn get_all_hotkey_state( } #[cfg(feature = "flutter")] +#[cfg(not(any(target_os = "android", target_os = "ios")))] pub fn send_key_event_to_session(event: rdev::Event) { if let Some(handler) = CUR_SESSION.lock().unwrap().as_ref() { handler.handle_hotkey_event(event); From a3afb0310940aa6afe7772f52a10a8049332a8c6 Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 13 Nov 2022 23:41:07 +0800 Subject: [PATCH 017/116] fix cursor (hotx,hoty) && add default remote cursor image Signed-off-by: fufesou --- flutter/lib/desktop/pages/remote_page.dart | 20 ++-- flutter/lib/mobile/pages/remote_page.dart | 14 ++- flutter/lib/models/model.dart | 107 ++++++++++++--------- 3 files changed, 83 insertions(+), 58 deletions(-) diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index 21cbe45b9..8d0de3b41 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -340,10 +340,8 @@ class ImagePaint extends StatelessWidget { return FlutterCustomMemoryImageCursor( pixbuf: cache.data, key: key, - // hotx: cache.hotx, - // hoty: cache.hoty, - hotx: 0, - hoty: 0, + hotx: cache.hotx, + hoty: cache.hoty, imageWidth: (cache.width * cache.scale).toInt(), imageHeight: (cache.height * cache.scale).toInt(), ); @@ -488,11 +486,19 @@ class CursorPaint extends StatelessWidget { final m = Provider.of(context); final c = Provider.of(context); // final adjust = m.adjustForKeyboard(); + double hotx = m.hotx; + double hoty = m.hoty; + if (m.image == null) { + if (m.defaultCache != null) { + hotx = m.defaultCache!.hotx; + hoty = m.defaultCache!.hoty; + } + } return CustomPaint( painter: ImagePainter( - image: m.image, - x: m.x - m.hotx + c.x / c.scale, - y: m.y - m.hoty + c.y / c.scale, + image: m.image ?? m.defaultImage, + x: m.x - hotx + c.x / c.scale, + y: m.y - hoty + c.y / c.scale, scale: c.scale), ); } diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index 0662fce2b..5dd01264b 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -862,11 +862,19 @@ class CursorPaint extends StatelessWidget { final c = Provider.of(context); final adjust = gFFI.cursorModel.adjustForKeyboard(); var s = c.scale; + double hotx = m.hotx; + double hoty = m.hoty; + if (m.image == null) { + if (m.defaultCache != null) { + hotx = m.defaultCache!.hotx; + hoty = m.defaultCache!.hoty; + } + } return CustomPaint( painter: ImagePainter( - image: m.image, - x: m.x * s - m.hotx + c.x, - y: m.y * s - m.hoty + c.y - adjust, + image: m.image ?? m.defaultImage, + x: m.x * s - hotx + c.x, + y: m.y * s - hoty + c.y - adjust, scale: 1), ); } diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 53a040eed..61185b016 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -721,8 +721,11 @@ class CursorData { height: (height * scale).toInt(), ) .getBytes(format: img2.Format.bgra); - hotx = (width * scale) / 2; - hoty = (height * scale) / 2; + if (hotx > 0 && hoty > 0) { + // default cursor data + hotx = (width * scale) / 2; + hoty = (height * scale) / 2; + } } } this.scale = scale; @@ -737,6 +740,7 @@ class CursorData { class CursorModel with ChangeNotifier { ui.Image? _image; + ui.Image? _defaultImage; final _images = >{}; CursorData? _cache; final _defaultCacheId = -1; @@ -756,6 +760,7 @@ class CursorModel with ChangeNotifier { WeakReference parent; ui.Image? get image => _image; + ui.Image? get defaultImage => _defaultImage; CursorData? get cache => _cache; CursorData? get defaultCache => _getDefaultCache(); @@ -771,30 +776,45 @@ class CursorModel with ChangeNotifier { DateTime.now().difference(_last_peer_mouse).inMilliseconds < kMouseControlTimeoutMSec; - CursorModel(this.parent); + CursorModel(this.parent) { + _getDefaultImage(); + _getDefaultCache(); + } Set get cachedKeys => _cacheKeys; addKey(String key) => _cacheKeys.add(key); + Future _getDefaultImage() async { + if (_defaultImage == null) { + final defaultImg = defaultCursorImage!; + // This function is called only one time, no need to care about the performance. + Uint8List data = defaultImg.getBytes(format: img2.Format.rgba); + _defaultImage = await img.decodeImageFromPixels( + data, defaultImg.width, defaultImg.height, ui.PixelFormat.rgba8888); + } + return _defaultImage; + } + CursorData? _getDefaultCache() { if (_defaultCache == null) { + Uint8List data; if (Platform.isWindows) { - Uint8List data = defaultCursorImage!.getBytes(format: img2.Format.bgra); - _hotx = defaultCursorImage!.width / 2; - _hoty = defaultCursorImage!.height / 2; - - _defaultCache = CursorData( - peerId: id, - id: _defaultCacheId, - image: defaultCursorImage?.clone(), - scale: 1.0, - data: data, - hotx: _hotx, - hoty: _hoty, - width: defaultCursorImage!.width, - height: defaultCursorImage!.height, - ); + data = defaultCursorImage!.getBytes(format: img2.Format.bgra); + } else { + data = Uint8List.fromList(img2.encodePng(defaultCursorImage!)); } + double scale = 1.0; + _defaultCache = CursorData( + peerId: id, + id: _defaultCacheId, + image: defaultCursorImage?.clone(), + scale: scale, + data: data, + hotx: (defaultCursorImage!.width * scale) / 2, + hoty: (defaultCursorImage!.height * scale) / 2, + width: defaultCursorImage!.width, + height: defaultCursorImage!.height, + ); } return _defaultCache; } @@ -926,13 +946,15 @@ class CursorModel with ChangeNotifier { var height = int.parse(evt['height']); List colors = json.decode(evt['colors']); final rgba = Uint8List.fromList(colors.map((s) => s as int).toList()); - var pid = parent.target?.id; final image = await img.decodeImageFromPixels( rgba, width, height, ui.PixelFormat.rgba8888); - if (parent.target?.id != pid) return; _image = image; - _images[id] = Tuple3(image, _hotx, _hoty); - await _updateCache(image, id, width, height); + if (await _updateCache(image, id, width, height)) { + _images[id] = Tuple3(image, _hotx, _hoty); + } else { + _hotx = 0; + _hoty = 0; + } try { // my throw exception, because the listener maybe already dispose notifyListeners(); @@ -941,44 +963,33 @@ class CursorModel with ChangeNotifier { } } - _updateCache(ui.Image image, int id, int w, int h) async { - Uint8List? data; - img2.Image? image2; + Future _updateCache(ui.Image image, int id, int w, int h) async { + ui.ImageByteFormat imgFormat = ui.ImageByteFormat.png; if (Platform.isWindows) { - ByteData? data2 = - await image.toByteData(format: ui.ImageByteFormat.rawRgba); - if (data2 != null) { - data = data2.buffer.asUint8List(); - image2 = img2.Image.fromBytes(w, h, data); - } else { - data = defaultCursorImage?.getBytes(format: img2.Format.bgra); - image2 = defaultCursorImage?.clone(); - _hotx = defaultCursorImage!.width / 2; - _hoty = defaultCursorImage!.height / 2; - } - } else { - ByteData? data2 = await image.toByteData(format: ui.ImageByteFormat.png); - if (data2 != null) { - data = data2.buffer.asUint8List(); - } else { - data = Uint8List.fromList(img2.encodePng(defaultCursorImage!)); - _hotx = defaultCursorImage!.width / 2; - _hoty = defaultCursorImage!.height / 2; - } + imgFormat = ui.ImageByteFormat.rawRgba; } + ByteData? imgBytes = await image.toByteData(format: imgFormat); + if (imgBytes == null) { + return false; + } + + Uint8List? data = imgBytes.buffer.asUint8List(); _cache = CursorData( peerId: this.id, id: id, - image: image2, + image: Platform.isWindows ? img2.Image.fromBytes(w, h, data) : null, scale: 1.0, data: data, - hotx: _hotx, - hoty: _hoty, + hotx: 0, + hoty: 0, + // hotx: _hotx, + // hoty: _hoty, width: w, height: h, ); _cacheMap[id] = _cache!; + return true; } updateCursorId(Map evt) async { From 60a30042c0b1359bb846f579787bc3a8b65a8bbb Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 13 Nov 2022 19:35:59 -0800 Subject: [PATCH 018/116] cursor pos linux Signed-off-by: fufesou --- flutter/lib/desktop/pages/remote_page.dart | 4 ++-- flutter/lib/mobile/pages/remote_page.dart | 8 ++++---- flutter/lib/models/model.dart | 19 +++++++++++-------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index 8d0de3b41..015eb3037 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -490,8 +490,8 @@ class CursorPaint extends StatelessWidget { double hoty = m.hoty; if (m.image == null) { if (m.defaultCache != null) { - hotx = m.defaultCache!.hotx; - hoty = m.defaultCache!.hoty; + hotx = m.defaultImage!.width / 2; + hoty = m.defaultImage!.height / 2; } } return CustomPaint( diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index 5dd01264b..07304d2d3 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -866,15 +866,15 @@ class CursorPaint extends StatelessWidget { double hoty = m.hoty; if (m.image == null) { if (m.defaultCache != null) { - hotx = m.defaultCache!.hotx; - hoty = m.defaultCache!.hoty; + hotx = m.defaultImage!.width / 2; + hoty = m.defaultImage!.height / 2; } } return CustomPaint( painter: ImagePainter( image: m.image ?? m.defaultImage, - x: m.x * s - hotx + c.x, - y: m.y * s - hoty + c.y - adjust, + x: m.x * s - hotx * s + c.x, + y: m.y * s - hoty * s + c.y - adjust, scale: 1), ); } diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 61185b016..cf4c63952 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -721,14 +721,14 @@ class CursorData { height: (height * scale).toInt(), ) .getBytes(format: img2.Format.bgra); - if (hotx > 0 && hoty > 0) { - // default cursor data - hotx = (width * scale) / 2; - hoty = (height * scale) / 2; - } } } this.scale = scale; + if (hotx > 0 && hoty > 0) { + // default cursor data + hotx = (width * scale) / 2; + hoty = (height * scale) / 2; + } return scale; } @@ -798,20 +798,23 @@ class CursorModel with ChangeNotifier { CursorData? _getDefaultCache() { if (_defaultCache == null) { Uint8List data; + double scale = 1.0; + double hotx = (defaultCursorImage!.width * scale) / 2; + double hoty = (defaultCursorImage!.height * scale) / 2; if (Platform.isWindows) { data = defaultCursorImage!.getBytes(format: img2.Format.bgra); } else { data = Uint8List.fromList(img2.encodePng(defaultCursorImage!)); } - double scale = 1.0; + _defaultCache = CursorData( peerId: id, id: _defaultCacheId, image: defaultCursorImage?.clone(), scale: scale, data: data, - hotx: (defaultCursorImage!.width * scale) / 2, - hoty: (defaultCursorImage!.height * scale) / 2, + hotx: hotx, + hoty: hoty, width: defaultCursorImage!.width, height: defaultCursorImage!.height, ); From 98bb47a81ddf751b16d87ccaa4f6da77ff4eda67 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 14 Nov 2022 15:05:44 +0800 Subject: [PATCH 019/116] fix cursor lost control sometime && refactor some Camel-Case flutter Signed-off-by: fufesou --- flutter/lib/models/input_model.dart | 22 +++++++++++----------- flutter/lib/models/model.dart | 14 +++++++------- src/server/input_service.rs | 20 ++++++++++++++++---- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/flutter/lib/models/input_model.dart b/flutter/lib/models/input_model.dart index 30a01cda7..83171514d 100644 --- a/flutter/lib/models/input_model.dart +++ b/flutter/lib/models/input_model.dart @@ -42,7 +42,7 @@ class InputModel { // mouse final isPhysicalMouse = false.obs; int _lastMouseDownButtons = 0; - Offset last_mouse_pos = Offset.zero; + Offset lastMousePos = Offset.zero; get id => parent.target?.id ?? ""; @@ -308,23 +308,23 @@ class InputModel { double y = max(0.0, evt['y']); final cursorModel = parent.target!.cursorModel; - if (cursorModel.is_peer_control_protected) { - last_mouse_pos = ui.Offset(x, y); + if (cursorModel.isPeerControlProtected) { + lastMousePos = ui.Offset(x, y); return; } - if (!cursorModel.got_mouse_control) { - bool self_get_control = - (x - last_mouse_pos.dx).abs() > kMouseControlDistance || - (y - last_mouse_pos.dy).abs() > kMouseControlDistance; - if (self_get_control) { - cursorModel.got_mouse_control = true; + if (!cursorModel.gotMouseControl) { + bool selfGetControl = + (x - lastMousePos.dx).abs() > kMouseControlDistance || + (y - lastMousePos.dy).abs() > kMouseControlDistance; + if (selfGetControl) { + cursorModel.gotMouseControl = true; } else { - last_mouse_pos = ui.Offset(x, y); + lastMousePos = ui.Offset(x, y); return; } } - last_mouse_pos = ui.Offset(x, y); + lastMousePos = ui.Offset(x, y); var type = ''; var isMove = false; diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index cf4c63952..d7fc414d5 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -753,8 +753,8 @@ class CursorModel with ChangeNotifier { double _hoty = 0; double _displayOriginX = 0; double _displayOriginY = 0; - bool got_mouse_control = true; - DateTime _last_peer_mouse = DateTime.now() + bool gotMouseControl = true; + DateTime _lastPeerMouse = DateTime.now() .subtract(Duration(milliseconds: 2 * kMouseControlTimeoutMSec)); String id = ''; WeakReference parent; @@ -772,8 +772,8 @@ class CursorModel with ChangeNotifier { double get hotx => _hotx; double get hoty => _hoty; - bool get is_peer_control_protected => - DateTime.now().difference(_last_peer_mouse).inMilliseconds < + bool get isPeerControlProtected => + DateTime.now().difference(_lastPeerMouse).inMilliseconds < kMouseControlTimeoutMSec; CursorModel(this.parent) { @@ -806,7 +806,7 @@ class CursorModel with ChangeNotifier { } else { data = Uint8List.fromList(img2.encodePng(defaultCursorImage!)); } - + _defaultCache = CursorData( peerId: id, id: _defaultCacheId, @@ -1012,8 +1012,8 @@ class CursorModel with ChangeNotifier { /// Update the cursor position. updateCursorPosition(Map evt, String id) async { - got_mouse_control = false; - _last_peer_mouse = DateTime.now(); + gotMouseControl = false; + _lastPeerMouse = DateTime.now(); _x = double.parse(evt['x']); _y = double.parse(evt['y']); try { diff --git a/src/server/input_service.rs b/src/server/input_service.rs index 780c1106a..653187bc3 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -209,6 +209,7 @@ lazy_static::lazy_static! { static EXITING: AtomicBool = AtomicBool::new(false); const MOUSE_MOVE_PROTECTION_TIMEOUT: Duration = Duration::from_millis(1_000); +// Actual diff of (x,y) is (1,1) here. But 5 may be tolerant. const MOUSE_ACTIVE_DISTANCE: i32 = 5; // mac key input must be run in main thread, otherwise crash on >= osx 10.15 @@ -406,14 +407,25 @@ fn active_mouse_(conn: i32) -> bool { return false; } + let in_actived_dist = |a: i32, b: i32| -> bool { (a - b).abs() < MOUSE_ACTIVE_DISTANCE }; + // check if input is in valid range match crate::get_cursor_pos() { Some((x, y)) => { - let can_active = (last_input.x - x).abs() < MOUSE_ACTIVE_DISTANCE - && (last_input.y - y).abs() < MOUSE_ACTIVE_DISTANCE; + let mut can_active = + in_actived_dist(last_input.x, x) && in_actived_dist(last_input.y, y); if !can_active { - last_input.x = -MOUSE_ACTIVE_DISTANCE * 2; - last_input.y = -MOUSE_ACTIVE_DISTANCE * 2; + // Try agin + // No need to care about sleep here. It's not a common case. + std::thread::sleep(std::time::Duration::from_micros(10)); + if let Some((x2, y2)) = crate::get_cursor_pos() { + can_active = + in_actived_dist(last_input.x, x2) && in_actived_dist(last_input.y, y2); + } + } + if !can_active { + last_input.x = INVALID_CURSOR_POS / 2; + last_input.y = INVALID_CURSOR_POS / 2; } can_active } From 7f640b77f0a902f7659e54944b3b86db9794b159 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 14 Nov 2022 16:16:38 +0800 Subject: [PATCH 020/116] fix cursor linux force update after remote cursor moved Signed-off-by: fufesou --- flutter/lib/desktop/pages/remote_page.dart | 34 ++++++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index 015eb3037..2b8c99940 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -251,14 +251,12 @@ class _RemotePageState extends State bool get wantKeepAlive => true; } -class ImagePaint extends StatelessWidget { +class ImagePaint extends StatefulWidget { final String id; final Rx cursorOverImage; final Rx keyboardEnabled; final Rx remoteCursorMoved; final Widget Function(Widget)? listenerBuilder; - final ScrollController _horizontal = ScrollController(); - final ScrollController _vertical = ScrollController(); ImagePaint( {Key? key, @@ -269,6 +267,21 @@ class ImagePaint extends StatelessWidget { this.listenerBuilder}) : super(key: key); + @override + State createState() => _ImagePaintState(); +} + +class _ImagePaintState extends State { + bool _lastRemoteCursorMoved = false; + final ScrollController _horizontal = ScrollController(); + final ScrollController _vertical = ScrollController(); + + String get id => widget.id; + Rx get cursorOverImage => widget.cursorOverImage; + Rx get keyboardEnabled => widget.keyboardEnabled; + Rx get remoteCursorMoved => widget.remoteCursorMoved; + Widget Function(Widget)? get listenerBuilder => widget.listenerBuilder; + @override Widget build(BuildContext context) { final m = Provider.of(context); @@ -278,9 +291,18 @@ class ImagePaint extends StatelessWidget { mouseRegion({child}) => Obx(() => MouseRegion( cursor: cursorOverImage.isTrue ? keyboardEnabled.isTrue - ? (remoteCursorMoved.isTrue - ? SystemMouseCursors.none - : _buildCustomCursor(context, s)) + ? (() { + if (remoteCursorMoved.isTrue) { + _lastRemoteCursorMoved = true; + return SystemMouseCursors.none; + } else { + if (_lastRemoteCursorMoved) { + _lastRemoteCursorMoved = false; + _firstEnterImage.value = true; + } + return _buildCustomCursor(context, s); + } + }()) : _buildDisabledCursor(context, s) : MouseCursor.defer, onHover: (evt) {}, From 3d5be47b1b42802d0b3cd0a74a14dae35e8e53c6 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 14 Nov 2022 17:17:15 +0800 Subject: [PATCH 021/116] fix cursor key mismatch Signed-off-by: fufesou --- flutter/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index 56cb4b204..ed7fad5dd 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -72,7 +72,7 @@ dependencies: flutter_custom_cursor: git: url: https://github.com/Kingtous/rustdesk_flutter_custom_cursor - ref: ac3c1bf816197863cdcfa42d008962ff644132b0 + ref: bfb19c84a8244771488bc05cc5f9c9b5e0324cfd window_size: git: url: https://github.com/google/flutter-desktop-embedding.git From 47d7e7ad938103193e898cee4a2e730264545cb7 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 14 Nov 2022 17:54:39 +0800 Subject: [PATCH 022/116] input service, trivial refactor for cursor Signed-off-by: fufesou --- src/server/input_service.rs | 43 ++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/server/input_service.rs b/src/server/input_service.rs index 653187bc3..4650865bd 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -126,7 +126,7 @@ pub fn new_pos() -> GenericService { } fn update_last_cursor_pos(x: i32, y: i32) { - let mut lock = LATEST_CURSOR_POS.lock().unwrap(); + let mut lock = LATEST_SYS_CURSOR_POS.lock().unwrap(); if lock.1 .0 != x || lock.1 .1 != y { (lock.0, lock.1) = (Instant::now(), (x, y)) } @@ -144,7 +144,7 @@ fn run_pos(sp: GenericService, state: &mut StatePos) -> ResultType<()> { }); let exclude = { let now = get_time(); - let lock = LATEST_INPUT_CURSOR.lock().unwrap(); + let lock = LATEST_PEER_INPUT_CURSOR.lock().unwrap(); if now - lock.time < 300 { lock.conn } else { @@ -203,8 +203,8 @@ lazy_static::lazy_static! { Arc::new(Mutex::new(Enigo::new())) }; static ref KEYS_DOWN: Arc>> = Default::default(); - static ref LATEST_INPUT_CURSOR: Arc> = Default::default(); - static ref LATEST_CURSOR_POS: Arc> = Arc::new(Mutex::new((Instant::now().sub(MOUSE_MOVE_PROTECTION_TIMEOUT), (0, 0)))); + static ref LATEST_PEER_INPUT_CURSOR: Arc> = Default::default(); + static ref LATEST_SYS_CURSOR_POS: Arc> = Arc::new(Mutex::new((Instant::now().sub(MOUSE_MOVE_PROTECTION_TIMEOUT), (0, 0)))); } static EXITING: AtomicBool = AtomicBool::new(false); @@ -397,13 +397,12 @@ fn fix_modifiers(modifiers: &[EnumOrUnknown], en: &mut Enigo, ck: i3 fn active_mouse_(conn: i32) -> bool { // out of time protection - if LATEST_CURSOR_POS.lock().unwrap().0.elapsed() > MOUSE_MOVE_PROTECTION_TIMEOUT { + if LATEST_SYS_CURSOR_POS.lock().unwrap().0.elapsed() > MOUSE_MOVE_PROTECTION_TIMEOUT { return true; } - let mut last_input = LATEST_INPUT_CURSOR.lock().unwrap(); // last conn input may be protected - if last_input.conn != conn { + if LATEST_PEER_INPUT_CURSOR.lock().unwrap().conn != conn { return false; } @@ -412,20 +411,25 @@ fn active_mouse_(conn: i32) -> bool { // check if input is in valid range match crate::get_cursor_pos() { Some((x, y)) => { + let (last_in_x, last_in_y) = { + let lock = LATEST_PEER_INPUT_CURSOR.lock().unwrap(); + (lock.x, lock.y) + }; let mut can_active = - in_actived_dist(last_input.x, x) && in_actived_dist(last_input.y, y); + in_actived_dist(last_in_x, x) && in_actived_dist(last_in_y, y); if !can_active { // Try agin // No need to care about sleep here. It's not a common case. std::thread::sleep(std::time::Duration::from_micros(10)); if let Some((x2, y2)) = crate::get_cursor_pos() { can_active = - in_actived_dist(last_input.x, x2) && in_actived_dist(last_input.y, y2); + in_actived_dist(last_in_x, x2) && in_actived_dist(last_in_y, y2); } } if !can_active { - last_input.x = INVALID_CURSOR_POS / 2; - last_input.y = INVALID_CURSOR_POS / 2; + let mut lock = LATEST_PEER_INPUT_CURSOR.lock().unwrap(); + lock.x = INVALID_CURSOR_POS / 2; + lock.y = INVALID_CURSOR_POS / 2; } can_active } @@ -446,15 +450,6 @@ fn handle_mouse_(evt: &MouseEvent, conn: i32) { crate::platform::windows::try_change_desktop(); let buttons = evt.mask >> 3; let evt_type = evt.mask & 0x7; - if evt_type == 0 { - let time = get_time(); - *LATEST_INPUT_CURSOR.lock().unwrap() = Input { - time, - conn, - x: evt.x, - y: evt.y, - }; - } let mut en = ENIGO.lock().unwrap(); #[cfg(not(target_os = "macos"))] let mut to_release = Vec::new(); @@ -479,6 +474,14 @@ fn handle_mouse_(evt: &MouseEvent, conn: i32) { } match evt_type { 0 => { + let time = get_time(); + *LATEST_PEER_INPUT_CURSOR.lock().unwrap() = Input { + time, + conn, + x: evt.x, + y: evt.y, + }; + en.mouse_move_to(evt.x, evt.y); } 1 => match buttons { From e6698f32d79cda41b84896f9e5485049fa75fe48 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 14 Nov 2022 18:39:49 +0800 Subject: [PATCH 023/116] Add some comments on mouse handler(input service) Signed-off-by: fufesou --- src/server/input_service.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/server/input_service.rs b/src/server/input_service.rs index 4650865bd..f2591df0b 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -408,7 +408,7 @@ fn active_mouse_(conn: i32) -> bool { let in_actived_dist = |a: i32, b: i32| -> bool { (a - b).abs() < MOUSE_ACTIVE_DISTANCE }; - // check if input is in valid range + // Check if input is in valid range match crate::get_cursor_pos() { Some((x, y)) => { let (last_in_x, last_in_y) = { @@ -417,10 +417,13 @@ fn active_mouse_(conn: i32) -> bool { }; let mut can_active = in_actived_dist(last_in_x, x) && in_actived_dist(last_in_y, y); + // The cursor may not have been moved to last input position if system is busy now. + // While this is not a common case, we check it again after some time later. if !can_active { - // Try agin - // No need to care about sleep here. It's not a common case. + // 10 micros may be enough for system to move cursor. + // We do not care about the situation which system is too slow(more than 10 micros is required). std::thread::sleep(std::time::Duration::from_micros(10)); + // Sleep here can also somehow suppress delay accumulation. if let Some((x2, y2)) = crate::get_cursor_pos() { can_active = in_actived_dist(last_in_x, x2) && in_actived_dist(last_in_y, y2); From 41b0c77faa2d57a22cce8695672519617c53070a Mon Sep 17 00:00:00 2001 From: Kingtous Date: Mon, 14 Nov 2022 15:41:43 +0800 Subject: [PATCH 024/116] feat: support create shortcut for peers --- flutter/lib/common/widgets/peer_card.dart | 30 +++++++++++++++++++++++ src/core_main.rs | 10 ++++++-- src/flutter_ffi.rs | 5 ++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/flutter/lib/common/widgets/peer_card.dart b/flutter/lib/common/widgets/peer_card.dart index 5796c7d20..8df84af6c 100644 --- a/flutter/lib/common/widgets/peer_card.dart +++ b/flutter/lib/common/widgets/peer_card.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hbb/common/widgets/address_book.dart'; @@ -446,6 +448,22 @@ abstract class BasePeerCard extends StatelessWidget { ); } + /// Only avaliable on Windows. + @protected + MenuEntryBase _createShortCutAction(String id) { + return MenuEntryButton( + childBuilder: (TextStyle? style) => Text( + translate('Create Desktop Shortcut'), + style: style, + ), + proc: () { + bind.mainCreateShortcut(id: id); + }, + padding: menuPadding, + dismissOnClicked: true, + ); + } + @protected Future> _forceAlwaysRelayAction(String id) async { const option = 'force-always-relay'; @@ -649,6 +667,9 @@ class RecentPeerCard extends BasePeerCard { menuItems.add(_rdpAction(context, peer.id)); } menuItems.add(_wolAction(peer.id)); + if (Platform.isWindows) { + menuItems.add(_createShortCutAction(peer.id)); + } menuItems.add(MenuEntryDivider()); menuItems.add(_renameAction(peer.id, false)); menuItems.add(_removeAction(peer.id, () async { @@ -681,6 +702,9 @@ class FavoritePeerCard extends BasePeerCard { menuItems.add(_rdpAction(context, peer.id)); } menuItems.add(_wolAction(peer.id)); + if (Platform.isWindows) { + menuItems.add(_createShortCutAction(peer.id)); + } menuItems.add(MenuEntryDivider()); menuItems.add(_renameAction(peer.id, false)); menuItems.add(_removeAction(peer.id, () async { @@ -715,6 +739,9 @@ class DiscoveredPeerCard extends BasePeerCard { menuItems.add(_rdpAction(context, peer.id)); } menuItems.add(_wolAction(peer.id)); + if (Platform.isWindows) { + menuItems.add(_createShortCutAction(peer.id)); + } menuItems.add(MenuEntryDivider()); menuItems.add(_removeAction(peer.id, () async {})); return menuItems; @@ -740,6 +767,9 @@ class AddressBookPeerCard extends BasePeerCard { menuItems.add(_rdpAction(context, peer.id)); } menuItems.add(_wolAction(peer.id)); + if (Platform.isWindows) { + menuItems.add(_createShortCutAction(peer.id)); + } menuItems.add(MenuEntryDivider()); menuItems.add(_renameAction(peer.id, false)); menuItems.add(_removeAction(peer.id, () async {})); diff --git a/src/core_main.rs b/src/core_main.rs index d22d4e71b..39b13999e 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -1,6 +1,10 @@ use hbb_common::log; -// shared by flutter and sciter main function +/// shared by flutter and sciter main function +/// +/// [Note] +/// If it returns [`None`], then the process will terminate, and flutter gui will not be started. +/// If it returns [`Some`], then the process will continue, and flutter gui will be started. pub fn core_main() -> Option> { // https://docs.rs/flexi_logger/latest/flexi_logger/error_info/index.html#write // though async logger more efficient, but it also causes more problems, disable it for now @@ -223,6 +227,8 @@ fn import_config(path: &str) { /// /// [Note] /// this is for invoke new connection from dbus. +/// If it returns [`None`], then the process will terminate, and flutter gui will not be started. +/// If it returns [`Some`], then the process will continue, and flutter gui will be started. #[cfg(feature = "flutter")] fn core_main_invoke_new_connection(mut args: std::env::Args) -> Option> { args.position(|element| { @@ -250,5 +256,5 @@ fn core_main_invoke_new_connection(mut args: std::env::Args) -> Option Date: Mon, 14 Nov 2022 19:48:42 +0800 Subject: [PATCH 025/116] feat: implement --connect unilinks convert on windows --- src/core_main.rs | 17 +++++++++++++++-- src/platform/windows.rs | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/core_main.rs b/src/core_main.rs index 39b13999e..443ef92ea 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -1,7 +1,7 @@ use hbb_common::log; /// shared by flutter and sciter main function -/// +/// /// [Note] /// If it returns [`None`], then the process will terminate, and flutter gui will not be started. /// If it returns [`Some`], then the process will continue, and flutter gui will be started. @@ -255,6 +255,19 @@ fn core_main_invoke_new_connection(mut args: std::env::Args) -> Option Vec { .chain(Some(0).into_iter()) .collect() } + +/// send message to currently shown window +pub fn send_message_to_hnwd( + class_name: &str, + window_name: &str, + dw_data: usize, + data: &str, + show_window: bool, +) -> bool { + unsafe { + let class_name_utf16 = wide_string(class_name); + let window_name_utf16 = wide_string(window_name); + let window = FindWindowW(class_name_utf16.as_ptr(), window_name_utf16.as_ptr()); + if window.is_null() { + log::warn!("no such window {}:{}", class_name, window_name); + return false; + } + let mut data_struct = COPYDATASTRUCT::default(); + data_struct.dwData = dw_data; + let mut data_zero: String = data.chars().chain(Some('\0').into_iter()).collect(); + println!("send {:?}", data_zero); + data_struct.cbData = data_zero.len() as _; + data_struct.lpData = data_zero.as_mut_ptr() as _; + SendMessageW( + window, + WM_COPYDATA, + 0, + &data_struct as *const COPYDATASTRUCT as _, + ); + if show_window { + ShowWindow(window, SW_NORMAL); + SetForegroundWindow(window); + } + } + return true; +} From b3ce8789a2f46b59e48c708722621cf5e99fc0c9 Mon Sep 17 00:00:00 2001 From: 21pages Date: Mon, 14 Nov 2022 18:24:47 +0800 Subject: [PATCH 026/116] fix hwcodec available decoders by compile res file to library Signed-off-by: 21pages --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 9243933e5..00916eabd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2463,7 +2463,7 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hwcodec" version = "0.1.0" -source = "git+https://github.com/21pages/hwcodec#bf73e8e650abca3e004e96a245086b3647b9d84a" +source = "git+https://github.com/21pages/hwcodec#f54d69b35251ade110373403ddefcb8b49c87305" dependencies = [ "bindgen", "cc", From 6eaddda28f3753448c1ed1378a53bad0ad1c615b Mon Sep 17 00:00:00 2001 From: CodeBurnCorp <118165981+CodeBurnCorp@users.noreply.github.com> Date: Mon, 14 Nov 2022 13:51:15 +0100 Subject: [PATCH 027/116] Correction of Hungarian translation There were many Hungarian typos in the document. --- src/lang/hu.rs | 560 ++++++++++++++++++++++++------------------------- 1 file changed, 280 insertions(+), 280 deletions(-) diff --git a/src/lang/hu.rs b/src/lang/hu.rs index c449c393d..6a75b6958 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -2,392 +2,392 @@ lazy_static::lazy_static! { pub static ref T: std::collections::HashMap<&'static str, &'static str> = [ ("Status", "Státusz"), - ("Your Desktop", "A te asztalod"), - ("desk_tip", "Az asztalod ezzel az ID-vel, és jelszóval érhető el."), + ("Your Desktop", "Saját azonosító"), + ("desk_tip", "A számítógép ezzel a jelszóval és azonosítóval érhető el távolról."), ("Password", "Jelszó"), ("Ready", "Kész"), ("Established", "Létrejött"), - ("connecting_status", "Kapcsolódás a RustDesk hálózatához..."), - ("Enable Service", "A szolgáltatás bekapcsolása"), - ("Start Service", "Szolgáltatás Elindítása"), - ("Service is running", "A szolgáltatás fut"), - ("Service is not running", "A szolgáltatás nem fut"), - ("not_ready_status", "A RustDesk nem áll készen. Kérlek nézd meg a hálózati beállításaidat."), - ("Control Remote Desktop", "Távoli Asztal Kontrollálása"), - ("Transfer File", "Fájl Transzfer"), - ("Connect", "Kapcsolódás"), - ("Recent Sessions", "Korábbi Sessionök"), - ("Address Book", "Címköny"), - ("Confirmation", "Megerősít"), + ("connecting_status", "Csatlakozás folyamatban..."), + ("Enable Service", "Szolgáltatás engedélyezése"), + ("Start Service", "Szolgáltatás indítása"), + ("Service is running", "Szolgáltatás aktív"), + ("Service is not running", "Szolgáltatás inaktív"), + ("not_ready_status", "Kapcsolódási hiba. Kérlek ellenőrizze a hálózati beállításokat."), + ("Control Remote Desktop", "Távoli számítógép vezérlése"), + ("Transfer File", "Fájlátvitel"), + ("Connect", "Csatlakozás"), + ("Recent Sessions", "Legutóbbi munkamanetek"), + ("Address Book", "Címjegyzék"), + ("Confirmation", "Megerősítés"), ("TCP Tunneling", "TCP Tunneling"), ("Remove", "Eltávolít"), - ("Refresh random password", "Véletlenszerű jelszó frissítése"), + ("Refresh random password", "Új véletlenszerű jelszó"), ("Set your own password", "Saját jelszó beállítása"), - ("Enable Keyboard/Mouse", "Billentyűzet/Egér bekapcsolása"), - ("Enable Clipboard", "Megosztott vágólap bekapcsolása"), - ("Enable File Transfer", "Fájl transzer bekapcsolása"), - ("Enable TCP Tunneling", "TCP Tunneling bekapcsolása"), - ("IP Whitelisting", "IP Fehérlista"), - ("ID/Relay Server", "ID/Relay Szerver"), - ("Import Server Config", "Szerver Konfiguráció Importálása"), - ("Export Server Config", ""), + ("Enable Keyboard/Mouse", "Billentyűzet/egér engedélyezése"), + ("Enable Clipboard", "Megosztott vágólap engedélyezése"), + ("Enable File Transfer", "Fájlátvitel engedélyezése"), + ("Enable TCP Tunneling", "TCP Tunneling engedélyezése"), + ("IP Whitelisting", "IP engedélyezési lista"), + ("ID/Relay Server", "Kiszolgáló szerver"), + ("Import Server Config", "Szerver konfiguráció importálása"), + ("Export Server Config", "Szerver konfiguráció exportálása"), ("Import server configuration successfully", "Szerver konfiguráció sikeresen importálva"), - ("Export server configuration successfully", ""), + ("Export server configuration successfully", "Szerver konfiguráció sikeresen exportálva"), ("Invalid server configuration", "Érvénytelen szerver konfiguráció"), ("Clipboard is empty", "A vágólap üres"), - ("Stop service", "Szolgáltatás Kikapcsolása"), - ("Change ID", "ID Megváltoztatása"), + ("Stop service", "Szolgáltatás leállítása"), + ("Change ID", "Azonosító megváltoztatása"), ("Website", "Weboldal"), - ("About", "Rólunk: "), + ("About", "Rólunk"), ("Mute", "Némítás"), - ("Audio Input", "Audo Bemenet"), - ("Enhancements", "Javítások"), - ("Hardware Codec", "Hardware Kodek"), - ("Adaptive Bitrate", "Adaptív Bitrate"), - ("ID Server", "ID Szerver"), - ("Relay Server", "Relay Szerver"), - ("API Server", "API Szerver"), + ("Audio Input", "Hangátvitel"), + ("Enhancements", "Fejlesztések"), + ("Hardware Codec", "Hardware kodek"), + ("Adaptive Bitrate", "Adaptív bitráta"), + ("ID Server", "Szerver azonosító/domain"), + ("Relay Server", "Kiszolgáló szerver"), + ("API Server", "API szerver"), ("invalid_http", "A címnek mindenképpen http(s)://-el kell kezdődnie."), - ("Invalid IP", "A megadott íp cím helytelen."), - ("id_change_tip", "Csak a-z, A-Z, 0-9 csoportokba tartozó karakterek, illetve a _ karakter van engedélyezve. Az első karakternek mindenképpen a-z, A-Z csoportokba kell esnie. Az ID hosszúsága 6-tól, 16 karakter."), + ("Invalid IP", "A megadott IP cím helytelen."), + ("id_change_tip", "Csak a-z, A-Z, 0-9 csoportokba tartozó karakterek, illetve a _ karakter van engedélyezve. Az első karakternek mindenképpen a-z, A-Z csoportokba kell esnie. Az azonosító hosszúsága 6-tól, 16 karakter."), ("Invalid format", "Érvénytelen formátum"), - ("server_not_support", "Még nem támogatott a szerver által"), - ("Not available", "Nem érhető el"), + ("server_not_support", "Nem támogatott a szerver által"), + ("Not available", "Nem elérhető"), ("Too frequent", "Túl gyakori"), ("Cancel", "Mégsem"), - ("Skip", "Kihagy"), - ("Close", "Bezár"), - ("Retry", "Újrapróbálkozás"), + ("Skip", "Kihagyás"), + ("Close", "Bezárás"), + ("Retry", "Újra"), ("OK", "OK"), - ("Password Required", "A jelszó megadása kötelező"), - ("Please enter your password", "Kérlek írd be a jelszavad"), - ("Remember password", "Kérlek emlékezz a jelszóra"), + ("Password Required", "Jelszó megadása kötelező"), + ("Please enter your password", "Kérem írja be a jelszavát"), + ("Remember password", "Jelszó megjegyzése"), ("Wrong Password", "Hibás jelszó"), - ("Do you want to enter again?", "Újra szeretnéd próbálni?"), - ("Connection Error", "Kapcsolódási Hiba"), + ("Do you want to enter again?", "Szeretne újra belépni?"), + ("Connection Error", "Csatlakozási hiba"), ("Error", "Hiba"), ("Reset by the peer", "A kapcsolatot alaphelyzetbe állt"), - ("Connecting...", "Kapcsolódás..."), - ("Connection in progress. Please wait.", "A kapcsolódás folyamatban van. Kérlek várj."), - ("Please try 1 minute later", "Kérlek próbáld újra 1 perc múlva."), - ("Login Error", "Belépési Hiba"), + ("Connecting...", "Csatlakozás..."), + ("Connection in progress. Please wait.", "Csatlakozás folyamatban. Kérem várjon."), + ("Please try 1 minute later", "Kérem próbálja meg 1 perc múlva"), + ("Login Error", "Bejelentkezési hiba"), ("Successful", "Sikeres"), - ("Connected, waiting for image...", "Kapcsolódva, várakozás a képre..."), + ("Connected, waiting for image...", "Csatlakozva, várakozás a kép adatokra..."), ("Name", "Név"), - ("Type", "Fajta"), + ("Type", "Típus"), ("Modified", "Módosított"), ("Size", "Méret"), - ("Show Hidden Files", "Rejtett Fájlok Mutatása"), - ("Receive", "Kapni"), - ("Send", "Küldeni"), - ("Refresh File", "Fájlok Frissítése"), - ("Local", "Lokális"), + ("Show Hidden Files", "Rejtett fájlok mutatása"), + ("Receive", "Fogad"), + ("Send", "Küld"), + ("Refresh File", "Fájl frissítése"), + ("Local", "Helyi"), ("Remote", "Távoli"), - ("Remote Computer", "Távoli Számítógép"), - ("Local Computer", "Lokális Számítógép"), - ("Confirm Delete", "Törlés Megerősítése"), + ("Remote Computer", "Távoli számítógép"), + ("Local Computer", "Helyi számítógép"), + ("Confirm Delete", "Törlés megerősítése"), ("Delete", "Törlés"), ("Properties", "Tulajdonságok"), - ("Multi Select", "Több fájl kiválasztása"), - ("Select All", ""), - ("Unselect All", ""), - ("Empty Directory", "Üres Könyvtár"), + ("Multi Select", "Többszörös kijelölés"), + ("Select All", "Összes kijelölése"), + ("Unselect All", "Kijelölések megszűntetése"), + ("Empty Directory", "Üres könyvtár"), ("Not an empty directory", "Nem egy üres könyvtár"), - ("Are you sure you want to delete this file?", "Biztosan törölni szeretnéd ezt a fájlt?"), - ("Are you sure you want to delete this empty directory?", "Biztosan törölni szeretnéd ezt az üres könyvtárat?"), - ("Are you sure you want to delete the file of this directory?", "Biztosan törölni szeretnéd a fájlokat ebben a könyvtárban?"), - ("Do this for all conflicts", "Ezt tedd az összes konfliktussal"), + ("Are you sure you want to delete this file?", "Biztosan törli ezt a fájlt?"), + ("Are you sure you want to delete this empty directory?", "Biztosan törli ezt az üres könyvtárat?"), + ("Are you sure you want to delete the file of this directory?", "Biztos benne, hogy törölni szeretné a könyvtár tartalmát?"), + ("Do this for all conflicts", "Tegye ezt minden ütközéskor"), ("This is irreversible!", "Ez a folyamat visszafordíthatatlan!"), - ("Deleting", "A törlés folyamatban"), + ("Deleting", "Törlés folyamatban"), ("files", "fájlok"), - ("Waiting", "Várunk"), - ("Finished", "Végzett"), - ("Speed", "Gyorsaság"), - ("Custom Image Quality", "Egyedi Képminőség"), + ("Waiting", "Várakozás"), + ("Finished", "Befejezve"), + ("Speed", "Sebesség"), + ("Custom Image Quality", "Egyedi képminőség"), ("Privacy mode", "Inkognító mód"), - ("Block user input", "Felhasználói input blokkokolása"), - ("Unblock user input", "Felhasználói input blokkolásának feloldása"), + ("Block user input", "Felhasználói bevitel letiltása"), + ("Unblock user input", "Felhasználói bevitel engedélyezése"), ("Adjust Window", "Ablakméret beállítása"), - ("Original", "Eredeti"), - ("Shrink", "Zsugorított"), - ("Stretch", "Nyújtott"), + ("Original", "Eredeti méret"), + ("Shrink", "Kicsinyítés"), + ("Stretch", "Nyújtás"), ("Scrollbar", "Görgetősáv"), - ("ScrollAuto", "Görgessen Auto"), - ("Good image quality", "Jó képminőség"), - ("Balanced", "Balanszolt"), - ("Optimize reaction time", "Válaszidő optimializálása"), - ("Custom", ""), - ("Show remote cursor", "Távoli kurzor mutatása"), - ("Show quality monitor", "Minőségi monitor mutatása"), - ("Disable clipboard", "Vágólap Kikapcsolása"), - ("Lock after session end", "Lezárás a session végén"), - ("Insert", "Beszúrás"), - ("Insert Lock", "Beszúrási Zároló"), + ("ScrollAuto", "Automatikus görgetés"), + ("Good image quality", "Eredetihez hű"), + ("Balanced", "Kiegyensúlyozott"), + ("Optimize reaction time", "Gyorsan reagáló"), + ("Custom", "Egyedi"), + ("Show remote cursor", "Távoli kurzor megjelenítése"), + ("Show quality monitor", ""), + ("Disable clipboard", "Közös vágólap kikapcsolása"), + ("Lock after session end", "Távoli fiók zárolása a munkamenet végén"), + ("Insert", ""), + ("Insert Lock", "Távoli fiók zárolása"), ("Refresh", "Frissítés"), - ("ID does not exist", "Ez az ID nem létezik"), - ("Failed to connect to rendezvous server", "A randevú szerverhez való kapcsolódás sikertelen"), - ("Please try later", "Kérlek próbád később"), - ("Remote desktop is offline", "A távoli asztal offline"), + ("ID does not exist", "Az azonosító nem létezik"), + ("Failed to connect to rendezvous server", "Nem sikerült csatlakozni a kiszolgáló szerverhez"), + ("Please try later", "Kérjük, próbálja később"), + ("Remote desktop is offline", "A távoli számítógép offline állapotban van"), ("Key mismatch", "Eltérés a kulcsokban"), ("Timeout", "Időtúllépés"), - ("Failed to connect to relay server", "A relay szerverhez való kapcsolódás sikertelen"), - ("Failed to connect via rendezvous server", "A randevú szerverrel való kapcsolódás sikertelen"), - ("Failed to connect via relay server", "A relay szerverrel való kapcsolódás sikertelen"), - ("Failed to make direct connection to remote desktop", "A távoli asztalhoz való direkt kapcsolódás sikertelen"), + ("Failed to connect to relay server", "Nem sikerült csatlakozni a közvetítő szerverhez"), + ("Failed to connect via rendezvous server", "Nem sikerült csatlakozni a kiszolgáló szerveren keresztül"), + ("Failed to connect via relay server", "Nem sikerült csatlakozni a közvetítő szerveren keresztül"), + ("Failed to make direct connection to remote desktop", "Nem sikerült közvetlen kapcsolatot létesíteni a távoli számítógéppel"), ("Set Password", "Jelszó Beállítása"), - ("OS Password", "Operációs Rendszer Jelszavának Beállítása"), - ("install_tip", "Az UAC (Felhasználói Fiók Felügyelet) miatt, a RustDesk nem fog rendesen funkcionálni mint távoli oldal néhány esetben. Hogy ezt kikerüld, vagy kikapcsold, kérlek nyomj rá a gombra ezalatt az üzenet alatt, hogy feltelepítsd a RustDesket a rendszerre."), - ("Click to upgrade", "Kattints a frissítés telepítéséhez"), - ("Click to download", "Kattints a letöltéshez"), - ("Click to update", "Kattints a frissítés letöltéséhez"), + ("OS Password", "Operációs rendszer jelszavának beállítása"), + ("install_tip", "Előfordul, hogy bizonyos esetekben hiba léphet fel a Portable verzió használata során. A megfelelő működés érdekében, kérem telepítse a RustDesk alkalmazást a számítógépre."), + ("Click to upgrade", "Kattintson ide a frissítés telepítéséhez"), + ("Click to download", "Kattintson ide a letöltéshez"), + ("Click to update", "Kattintson ide a frissítés letöltéséhez"), ("Configure", "Beállítás"), - ("config_acc", "Ahhoz hogy a RustDesket távolról irányítani tudd, \"Elérhetőségi\" jogokat kell adnod a RustDesk-nek."), - ("config_screen", "Ahhoz hogy a RustDesket távolról irányítani tudd, \"Képernyőfelvételi\" jogokat kell adnod a RustDesk-nek."), + ("config_acc", "A távoli vezérléshez a RustDesk-nek \"Kisegítő lehetőség\" engedélyre van szüksége"), + ("config_screen", "A távoli vezérléshez szükséges a \"Képernyőfelvétel\" engedély megadása"), ("Installing ...", "Telepítés..."), ("Install", "Telepítés"), ("Installation", "Telepítés"), ("Installation Path", "Telepítési útvonal"), - ("Create start menu shortcuts", "Start menu parancsikon létrehozása"), - ("Create desktop icon", "Asztali icon létrehozása"), - ("agreement_tip", "Azzal hogy elindítod a telepítést, elfogadod a licenszszerződést."), - ("Accept and Install", "Elfogadás és Telepítés"), - ("End-user license agreement", "Felhasználói licencszerződés"), - ("Generating ...", "Generálás..."), - ("Your installation is lower version.", "A jelenleg feltelepített verzió régebbi."), - ("not_close_tcp_tip", "Ne zárd be ezt az ablakot miközben a tunnelt használod"), - ("Listening ...", "Halgazózás..."), - ("Remote Host", "Távoli Host"), - ("Remote Port", "Távoli Port"), - ("Action", "Akció"), - ("Add", "Add"), - ("Local Port", "Lokális Port"), - ("Local Address", ""), - ("Change Local Port", ""), - ("setup_server_tip", "Egy gyorsabb kapcsolatért, kérlek hostolj egy saját szervert"), - ("Too short, at least 6 characters.", "Túl rövid, legalább 6 karakter"), + ("Create start menu shortcuts", "Start menü parancsikonok létrehozása"), + ("Create desktop icon", "Ikon létrehozása az asztalon"), + ("agreement_tip", "A telepítés folytatásával automatikusan elfogadásra kerül a licensz szerződés."), + ("Accept and Install", "Elfogadás és telepítés"), + ("End-user license agreement", "Felhasználói licensz szerződés"), + ("Generating ...", "Létrehozás..."), + ("Your installation is lower version.", "A telepített verzió alacsonyabb."), + ("not_close_tcp_tip", "Ne zárja be ezt az ablakot miközben a tunnelt használja"), + ("Listening ...", "Keresés..."), + ("Remote Host", "Távoli kiszolgáló"), + ("Remote Port", "Távoli port"), + ("Action", "Indítás"), + ("Add", "Hozzáadás"), + ("Local Port", "Helyi port"), + ("Local Address", "Helyi cím"), + ("Change Local Port", "Helyi port megváltoztatása"), + ("setup_server_tip", "Gyorsabb kapcsolat érdekében, hozzon létre saját szervert"), + ("Too short, at least 6 characters.", "Túl rövid, legalább 6 karakter."), ("The confirmation is not identical.", "A megerősítés nem volt azonos"), - ("Permissions", "Jogok"), - ("Accept", "Elfogad"), - ("Dismiss", "Elutasít"), - ("Disconnect", "Szétkapcsolás"), + ("Permissions", "Engedélyek"), + ("Accept", "Elfogadás"), + ("Dismiss", "Elutasítás"), + ("Disconnect", "Kapcsolat bontása"), ("Allow using keyboard and mouse", "Billentyűzet és egér használatának engedélyezése"), ("Allow using clipboard", "Vágólap használatának engedélyezése"), ("Allow hearing sound", "Hang átvitelének engedélyezése"), ("Allow file copy and paste", "Fájlok másolásának és beillesztésének engedélyezése"), - ("Connected", "Kapcsolódva"), - ("Direct and encrypted connection", "Direkt, és titkosított kapcsolat"), - ("Relayed and encrypted connection", "Relayelt, és titkosított kapcsolat"), - ("Direct and unencrypted connection", "Direkt, és nem titkosított kapcsolat"), - ("Relayed and unencrypted connection", "Rekayelt, és nem titkosított kapcsolat"), - ("Enter Remote ID", "Kérlek írd be a távoli ID-t"), - ("Enter your password", "Kérlek írd be a jelszavadat"), + ("Connected", "Csatlakozva"), + ("Direct and encrypted connection", "Közvetlen, és titkosított kapcsolat"), + ("Relayed and encrypted connection", "Továbbított, és titkosított kapcsolat"), + ("Direct and unencrypted connection", "Közvetlen, és nem titkosított kapcsolat"), + ("Relayed and unencrypted connection", "Továbbított, és nem titkosított kapcsolat"), + ("Enter Remote ID", "Távoli számítógép azonosítója"), + ("Enter your password", "Írja be a jelszavát"), ("Logging in...", "A belépés folyamatban..."), - ("Enable RDP session sharing", "Az RDP session megosztás engedélyezése"), - ("Auto Login", "Automatikus Login"), - ("Enable Direct IP Access", "Direkt IP elérés engedélyezése"), + ("Enable RDP session sharing", "RDP-munkamenet-megosztás engedélyezése"), + ("Auto Login", "Automatikus bejelentkezés"), + ("Enable Direct IP Access", "Közvetlen IP-elérés engedélyezése"), ("Rename", "Átnevezés"), - ("Space", "Hely"), - ("Create Desktop Shortcut", "Asztali Parancsikon Lértehozása"), - ("Change Path", "Útvonal Megváltoztatása"), - ("Create Folder", "Mappa Készítése"), - ("Please enter the folder name", "Kérlek írd be a mappa nevét"), - ("Fix it", "Kérlek javísd meg"), - ("Warning", "Figyelem"), - ("Login screen using Wayland is not supported", "A belépési kijelzővel a Wayland használata nem támogatott"), + ("Space", ""), + ("Create Desktop Shortcut", "Asztali parancsikon létrehozása"), + ("Change Path", "Elérési út módosítása"), + ("Create Folder", "Mappa létrehozás"), + ("Please enter the folder name", "Kérjük, adja meg a mappa nevét"), + ("Fix it", "Javítás"), + ("Warning", "Figyelmeztetés"), + ("Login screen using Wayland is not supported", "Bejelentkezéskori Wayland használata nem támogatott"), ("Reboot required", "Újraindítás szükséges"), - ("Unsupported display server ", "Nem támogatott kijelző szerver"), + ("Unsupported display server ", "Nem támogatott megjelenítő szerver"), ("x11 expected", "x11-re számítottt"), - ("Port", ""), + ("Port", "Port"), ("Settings", "Beállítások"), ("Username", "Felhasználónév"), ("Invalid port", "Érvénytelen port"), - ("Closed manually by the peer", "A kapcsolat manuálisan be lett zárva a másik fél álltal"), + ("Closed manually by the peer", "A kapcsolatot a másik fél manuálisan bezárta"), ("Enable remote configuration modification", "Távoli konfiguráció módosítás engedélyezése"), ("Run without install", "Futtatás feltelepítés nélkül"), - ("Always connected via relay", "Mindig relay által kapcsolódott"), - ("Always connect via relay", "Mindig relay által kapcsolódik"), - ("whitelist_tip", "Csak a fehérlistán lévő címek érhetnek el"), + ("Always connected via relay", "Mindig közvetítőn keresztül csatlakozik"), + ("Always connect via relay", "Mindig közvetítőn keresztüli csatlakozás"), + ("whitelist_tip", "Csak az engedélyezési listán szereplő címek csatlakozhatnak"), ("Login", "Belépés"), ("Logout", "Kilépés"), ("Tags", "Tagok"), - ("Search ID", "ID keresés"), - ("Current Wayland display server is not supported", "Jelenleg a Wayland display szerver nem támogatott"), - ("whitelist_sep", "Ide jönnek a címek, vesző, pontosvessző, space, vagy új sorral elválasztva"), - ("Add ID", "ID Hozzáadása"), - ("Add Tag", "Tag Hozzáadása"), - ("Unselect all tags", "Az összes tag kiválasztásának törlése"), + ("Search ID", "Azonosító keresése..."), + ("Current Wayland display server is not supported", "A Wayland display szerver nem támogatott"), + ("whitelist_sep", "A címeket veszővel, pontosvesszővel, szóközzel, vagy új sorral válassza el"), + ("Add ID", "Azonosító hozzáadása"), + ("Add Tag", "Címke hozzáadása"), + ("Unselect all tags", "A címkék kijelölésének megszüntetése"), ("Network error", "Hálózati hiba"), - ("Username missed", "A felhasználónév kimaradt"), - ("Password missed", "A jelszó kimaradt"), + ("Username missed", "Üres felhasználónév"), + ("Password missed", "Üres jelszó"), ("Wrong credentials", "Hibás felhasználónév vagy jelszó"), - ("Edit Tag", "A tag(ok) szerkeztése"), + ("Edit Tag", "Címke szerkesztése"), ("Unremember Password", "A jelszó megjegyzésének törlése"), ("Favorites", "Kedvencek"), ("Add to Favorites", "Hozzáadás a kedvencekhez"), - ("Remove from Favorites", "Eltávolítás a kedvencektől"), + ("Remove from Favorites", "Eltávolítás a kedvencekből"), ("Empty", "Üres"), - ("Invalid folder name", "Helytelen fájlnév"), - ("Socks5 Proxy", "Socks5-ös Proxy"), - ("Hostname", "Hostnév"), - ("Discovered", "Felfedezés"), - ("install_daemon_tip", "Ahhoz hogy a RustDesk bootkor elinduljon, telepítened kell a rendszer szolgáltatást."), - ("Remote ID", "Távoli ID"), + ("Invalid folder name", "Helytelen mappa név"), + ("Socks5 Proxy", "Socks5 Proxy"), + ("Hostname", "Kiszolgáló név"), + ("Discovered", "Felfedezett"), + ("install_daemon_tip", "Az automatikus indításhoz szükséges a szolgáltatás telepítése"), + ("Remote ID", "Távoli azonosító"), ("Paste", "Beillesztés"), - ("Paste here?", "Beillesztés ide?"), - ("Are you sure to close the connection?", "Biztos vagy benne hogy be szeretnéd zárni a kapcsolatot?"), + ("Paste here?", "Beilleszti ide?"), + ("Are you sure to close the connection?", "Biztos, hogy bezárja a kapcsolatot?"), ("Download new version", "Új verzó letöltése"), ("Touch mode", "Érintési mód bekapcsolása"), ("Mouse mode", "Egérhasználati mód bekapcsolása"), - ("One-Finger Tap", "Egyújas érintés"), - ("Left Mouse", "Baloldali Egér"), - ("One-Long Tap", "Egy hosszú érintés"), - ("Two-Finger Tap", "Két újas érintés"), - ("Right Mouse", "Jobboldali Egér"), - ("One-Finger Move", "Egyújas mozgatás"), - ("Double Tap & Move", "Kétszeri érintés, és Mozgatás"), - ("Mouse Drag", "Egérrel való húzás"), + ("One-Finger Tap", "Egyujjas érintés"), + ("Left Mouse", "Bal egér gomb"), + ("One-Long Tap", "Hosszú érintés"), + ("Two-Finger Tap", "Kétujjas érintés"), + ("Right Mouse", "Jobb egér gomb"), + ("One-Finger Move", "Egyujjas mozgatás"), + ("Double Tap & Move", "Dupla érintés, és mozgatás"), + ("Mouse Drag", "Mozgatás egérrel"), ("Three-Finger vertically", "Három ujj függőlegesen"), ("Mouse Wheel", "Egérgörgő"), - ("Two-Finger Move", "Kátújas mozgatás"), - ("Canvas Move", "Nézet Mozgatása"), - ("Pinch to Zoom", "Húzd össze a nagyításhoz"), - ("Canvas Zoom", "Nézet Nagyítása"), + ("Two-Finger Move", "Kátujjas mozgatás"), + ("Canvas Move", "Nézet mozgatása"), + ("Pinch to Zoom", "Kétujjas nagyítás"), + ("Canvas Zoom", "Nézet nagyítása"), ("Reset canvas", "Nézet visszaállítása"), - ("No permission of file transfer", "Nincs jogod fájl transzer indításához"), + ("No permission of file transfer", "Nincs engedély a fájlátvitelre"), ("Note", "Megyjegyzés"), ("Connection", "Kapcsolat"), ("Share Screen", "Képernyőmegosztás"), - ("CLOSE", "LETILT"), - ("OPEN", "ENGEDÉLYEZ"), + ("CLOSE", "BEZÁRÁS"), + ("OPEN", "MEGNYITÁS"), ("Chat", "Chat"), ("Total", "Összes"), - ("items", "Tárgyak"), - ("Selected", "Kiválasztott"), + ("items", "elemek"), + ("Selected", "Kijelölt"), ("Screen Capture", "Képernyőrögzítés"), - ("Input Control", "Input Kontrol"), - ("Audio Capture", "Audió Rögzítés"), - ("File Connection", "Fájlkapcsolat"), - ("Screen Connection", "Új Vizuális Kapcsolat"), - ("Do you accept?", "Elfogadod?"), - ("Open System Setting", "Rendszer beállítások megnyitása"), - ("How to get Android input permission?", "Hogyan állíthatok be Android input jogokat?"), - ("android_input_permission_tip1", "Ahhoz hogy egy távoli eszköz kontolálhassa az Android eszközödet egérrel vagy érintéssel, jogot kell adnod a RustDesk-nek, hogy használja az \"Elérhetőségi\" szolgáltatást."), - ("android_input_permission_tip2", "Kérlek navigálj a rendszer beállításaihoz, keresd meg vagy írd be hogy [Feltelepített Szolgáltatások], és kapcsold be a [RustDesk Input] szolgáltatást."), - ("android_new_connection_tip", "Új kontrollálási kérés érkezett, amely irányítani szeretné az eszközöded."), - ("android_service_will_start_tip", "A \"Képernyőrögzítés\" engedélyezése automatikusan elindítja majd a szolgáltatást, amely megengedi más eszközöknek hogy kérést kezdeményezzenek az eszköz felé."), - ("android_stop_service_tip", "A szolgáltatás bezárása automatikusan szétkapcsol minden létező kapcsolatot."), - ("android_version_audio_tip", "A jelenlegi Android verzió nem támogatja a hangrögzítést, kérlek frissíts legalább Android 10-re, vagy egy újabb verzióra."), - ("android_start_service_tip", "Nyomj a [Szolgáltatás Indítása] opcióra, vagy adj [Képernyőrözítési] jogot az applikációnak hogy elindítsd a képernyőmegosztó szolgáltatást."), - ("Account", ""), + ("Input Control", "Távoli vezérlés"), + ("Audio Capture", "Hangrögzítés"), + ("File Connection", "Fájlátvitel"), + ("Screen Connection", "Képátvitel"), + ("Do you accept?", "Elfogadja?"), + ("Open System Setting", "Rendszerbeállítások megnyitása"), + ("How to get Android input permission?", "Hogyan állíthatok be Android beviteli engedélyt?"), + ("android_input_permission_tip1", "A távoli vezérléshez kérjük engedélyezze a \"Kisegítő lehetőség\" lehetőséget."), + ("android_input_permission_tip2", "A következő rendszerbeállítások oldalon a letöltött alkalmazások menüponton belül, kapcsolja be a [RustDesk Input] szolgáltatást."), + ("android_new_connection_tip", "Új kérés érkezett mely vezérelni szeretné az eszközét"), + ("android_service_will_start_tip", "A \"Képernyőrögzítés\" bekapcsolásával automatikus elindul a szolgáltatás, lehetővé téve, hogy más eszközök csatlakozási kérelmet küldhessenek"), + ("android_stop_service_tip", "A szolgáltatás leállítása automatikusan szétkapcsol minden létező kapcsolatot."), + ("android_version_audio_tip", "A jelenlegi Android verzió nem támogatja a hangrögzítést, frissítsen legalább Android 10-re, vagy egy újabb verzióra."), + ("android_start_service_tip", "Nyomjon a [Szolgáltatás indítása] gombra, vagy adjon [Képernyőrözítési] engedélyt az applikációnak hogy elindítsa a képernyőmegosztó szolgáltatást."), + ("Account", "Fiók"), ("Overwrite", "Felülírás"), - ("This file exists, skip or overwrite this file?", "Ez a fájl már létezik, skippeljünk, vagy felülírjuk ezt a fájlt?"), + ("This file exists, skip or overwrite this file?", "Ez a fájl már létezik, kihagyja vagy felülírja ezt a fájlt?"), ("Quit", "Kilépés"), ("doc_mac_permission", "https://rustdesk.com/docs/hu/manual/mac/#enable-permissions"), ("Help", "Segítség"), ("Failed", "Sikertelen"), ("Succeeded", "Sikeres"), - ("Someone turns on privacy mode, exit", "Valaki bekacsolta a privát módot, lépj ki"), + ("Someone turns on privacy mode, exit", "Valaki bekacsolta az inkognitó módot, lépjen ki"), ("Unsupported", "Nem támogatott"), ("Peer denied", "Elutasítva a távoli fél álltal"), - ("Please install plugins", "Kérlek telepítsd a pluginokat"), + ("Please install plugins", "Kérem telepítse a bővítményeket"), ("Peer exit", "A távoli fél kilépett"), - ("Failed to turn off", "Nem tudtuk kikapcsolni"), + ("Failed to turn off", "Nem sikerült kikapcsolni"), ("Turned off", "Kikapcsolva"), - ("In privacy mode", "Belépés a privát módba"), - ("Out privacy mode", "Kilépés a privát módból"), + ("In privacy mode", "Belépés inkognitó módba"), + ("Out privacy mode", "Kilépés inkognitó módból"), ("Language", "Nyelv"), - ("Keep RustDesk background service", ""), - ("Ignore Battery Optimizations", ""), - ("android_open_battery_optimizations_tip", ""), - ("Connection not allowed", ""), + ("Keep RustDesk background service", "RustDesk futtatása a háttérben"), + ("Ignore Battery Optimizations", "Akkumulátorkímélő figyelmen kívűl hagyása"), + ("android_open_battery_optimizations_tip", "Ha le szeretné tiltani ezt a funkciót, lépjen a RustDesk alkalmazás beállítási oldalára, keresse meg az [Akkumulátorkímélő] lehetőséget és válassza a nincs korlátozás lehetőséget."), + ("Connection not allowed", "A csatlakozás nem engedélyezett"), ("Legacy mode", ""), ("Map mode", ""), - ("Translate mode", ""), - ("Use temporary password", ""), - ("Use permanent password", ""), - ("Use both passwords", ""), - ("Set permanent password", ""), - ("Set temporary password length", ""), - ("Enable Remote Restart", ""), - ("Allow remote restart", ""), - ("Restart Remote Device", ""), - ("Are you sure you want to restart", ""), - ("Restarting Remote Device", ""), - ("remote_restarting_tip", ""), - ("Copied", ""), - ("Exit Fullscreen", "Lépjen ki a teljes képernyőről"), + ("Translate mode", "Fordító mód"), + ("Use temporary password", "Ideiglenes jelszó használata"), + ("Use permanent password", "Állandó jelszó használata"), + ("Use both passwords", "Mindkét jelszó használata"), + ("Set permanent password", "Állandó jelszó beállítása"), + ("Set temporary password length", "Ideiglenes jelszó hosszának beállítása"), + ("Enable Remote Restart", "Távoli újraindítás engedélyezése"), + ("Allow remote restart", "Távoli újraindítás engedélyezése"), + ("Restart Remote Device", "Távoli eszköz újraindítása"), + ("Are you sure you want to restart", "Biztos szeretné újraindítani?"), + ("Restarting Remote Device", "Távoli eszköz újraindítása..."), + ("remote_restarting_tip", "A távoli eszköz újraindul, zárja be ezt az üzenetet, csatlakozzon újra, állandó jelszavával"), + ("Copied", "Másolva"), + ("Exit Fullscreen", "Kilépés teljes képernyős módból"), ("Fullscreen", "Teljes képernyő"), ("Mobile Actions", "mobil műveletek"), - ("Select Monitor", "Válassza a Monitor lehetőséget"), + ("Select Monitor", "Válasszon képernyőt"), ("Control Actions", "Irányítási műveletek"), ("Display Settings", "Megjelenítési beállítások"), - ("Ratio", "Hányados"), + ("Ratio", "Arány"), ("Image Quality", "Képminőség"), ("Scroll Style", "Görgetési stílus"), ("Show Menubar", "Menüsor megjelenítése"), - ("Hide Menubar", "menüsor elrejtése"), + ("Hide Menubar", "Menüsor elrejtése"), ("Direct Connection", "Közvetlen kapcsolat"), - ("Relay Connection", "Relé csatlakozás"), + ("Relay Connection", "Közvetett csatlakozás"), ("Secure Connection", "Biztonságos kapcsolat"), ("Insecure Connection", "Nem biztonságos kapcsolat"), ("Scale original", "Eredeti méretarány"), - ("Scale adaptive", "Skála adaptív"), - ("General", ""), - ("Security", ""), - ("Account", ""), - ("Theme", ""), - ("Dark Theme", ""), - ("Dark", ""), - ("Light", ""), + ("Scale adaptive", "Adaptív méretarány"), + ("General", "Általános"), + ("Security", "Biztonság"), + ("Account", "Fiók"), + ("Theme", "Téma"), + ("Dark Theme", "Sötét téma"), + ("Dark", "Sötét"), + ("Light", "Világos"), ("Follow System", ""), - ("Enable hardware codec", ""), - ("Unlock Security Settings", ""), - ("Enable Audio", ""), - ("Temporary Password Length", ""), - ("Unlock Network Settings", ""), - ("Server", ""), - ("Direct IP Access", ""), - ("Proxy", ""), - ("Port", ""), - ("Apply", ""), - ("Disconnect all devices?", ""), - ("Clear", ""), - ("Audio Input Device", ""), - ("Deny remote access", ""), - ("Use IP Whitelisting", ""), - ("Network", ""), - ("Enable RDP", ""), + ("Enable hardware codec", "Hardveres kodek engedélyezése"), + ("Unlock Security Settings", "Biztonsági beállítások feloldása"), + ("Enable Audio", "Hang engedélyezése"), + ("Temporary Password Length", "Ideiglenes jelszó hossza"), + ("Unlock Network Settings", "Hálózati beállítások feloldása"), + ("Server", "Szerver"), + ("Direct IP Access", "Közvetlen IP hozzáférés"), + ("Proxy", "Proxy"), + ("Port", "Port"), + ("Apply", "Alkalmaz"), + ("Disconnect all devices?", "Leválasztja az összes eszközt?"), + ("Clear", "Tisztítás"), + ("Audio Input Device", "Audio bemeneti eszköz"), + ("Deny remote access", "Távoli hozzáférés megtagadása"), + ("Use IP Whitelisting", "Engedélyezési lista használata"), + ("Network", "Hálózat"), + ("Enable RDP", "RDP engedélyezése"), ("Pin menubar", "Menüsor rögzítése"), ("Unpin menubar", "Menüsor rögzítésének feloldása"), - ("Recording", ""), - ("Directory", ""), - ("Automatically record incoming sessions", ""), - ("Change", ""), - ("Start session recording", ""), - ("Stop session recording", ""), - ("Enable Recording Session", ""), - ("Allow recording session", ""), - ("Enable LAN Discovery", ""), - ("Deny LAN Discovery", ""), - ("Write a message", ""), + ("Recording", "Felvétel"), + ("Directory", "Könyvtár"), + ("Automatically record incoming sessions", "A bejövő munkamenetek automatikus rögzítése"), + ("Change", "Változtatás"), + ("Start session recording", "Munkamenet rögzítés indítása"), + ("Stop session recording", "Munkamenet rögzítés leállítása"), + ("Enable Recording Session", "Munkamenet rögzítés engedélyezése"), + ("Allow recording session", "Munkamenet rögzítés engedélyezése"), + ("Enable LAN Discovery", "Felfedezés enegedélyezése"), + ("Deny LAN Discovery", "Felfedezés tiltása"), + ("Write a message", "Üzenet írása"), ("Prompt", ""), - ("elevation_prompt", ""), - ("uac_warning", ""), - ("elevated_foreground_window_warning", ""), - ("Disconnected", ""), - ("Other", ""), - ("Confirm before closing multiple tabs", ""), - ("Keyboard Settings", ""), - ("Custom", ""), - ("Full Access", ""), - ("Screen Share", ""), + ("elevation_prompt", "A szoftver jogosultságnövelés nélküli futtatása problémákat okozhat, ha távoli felhasználók bizonyos ablakokat működtetnek."), + ("uac_warning", "Kérjük, várja meg, amíg a távoli felhasználó elfogadja az UAC párbeszédpanelt. A probléma elkerülése érdekében javasoljuk, hogy telepítse a szoftvert a távoli eszközre, vagy futtassa rendszergazdai jogosultságokkal."), + ("elevated_foreground_window_warning", "Átmenetileg nem tudja használni az egeret és a billentyűzetet, mert a távoli asztal aktuális ablakának működéséhez magasabb jogosultság szükséges, ezért kérheti a távoli felhasználót, hogy minimalizálja az aktuális ablakot. A probléma elkerülése érdekében javasoljuk, hogy telepítse a szoftvert a távoli eszközre, vagy futtassa rendszergazdai jogosultságokkal."), + ("Disconnected", "Szétkapcsolva"), + ("Other", "Egyéb"), + ("Confirm before closing multiple tabs", "Biztos, hogy bezárja az összes lapot?"), + ("Keyboard Settings", "Billentyűzet beállítások"), + ("Custom", "Egyedi"), + ("Full Access", "Teljes hozzáférés"), + ("Screen Share", "Képernyőmegosztás"), ("Wayland requires Ubuntu 21.04 or higher version.", "A Waylandhoz Ubuntu 21.04 vagy újabb verzió szükséges."), ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "A Wayland a Linux disztró magasabb verzióját igényli. Próbálja ki az X11 desktopot, vagy változtassa meg az operációs rendszert."), - ("JumpLink", "View"), - ("Please Select the screen to be shared(Operate on the peer side).", "Kérjük, válassza ki a megosztani kívánt képernyőt (a társoldalon működjön)."), - ("Show RustDesk", ""), - ("This PC", ""), - ("or", ""), - ("Continue with", ""), + ("JumpLink", "Hiperhivatkozás"), + ("Please Select the screen to be shared(Operate on the peer side).", "Kérjük, válassza ki a megosztani kívánt képernyőt."), + ("Show RustDesk", "A RustDesk megjelenítése"), + ("This PC", "Ez a számítógép"), + ("or", "vagy"), + ("Continue with", "Folytatás a következővel"), ].iter().cloned().collect(); } From 589181bf839662034a77882379d7a300a9c07937 Mon Sep 17 00:00:00 2001 From: jimmyGALLAND <64364019+jimmyGALLAND@users.noreply.github.com> Date: Mon, 14 Nov 2022 21:48:46 +0100 Subject: [PATCH 028/116] Update fr.rs --- src/lang/fr.rs | 92 +++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/src/lang/fr.rs b/src/lang/fr.rs index a64fd6028..fc738c2b6 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -19,20 +19,20 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Recent Sessions", "Sessions récentes"), ("Address Book", "Carnet d'adresses"), ("Confirmation", "Confirmation"), - ("TCP Tunneling", "Tunneling TCP"), + ("TCP Tunneling", "Tunnel TCP"), ("Remove", "Supprimer"), ("Refresh random password", "Actualiser le mot de passe aléatoire"), ("Set your own password", "Définir votre propre mot de passe"), ("Enable Keyboard/Mouse", "Activer le contrôle clavier/souris"), ("Enable Clipboard", "Activer la synchronisation du presse-papier"), ("Enable File Transfer", "Activer le transfert de fichiers"), - ("Enable TCP Tunneling", "Activer le tunneling TCP"), + ("Enable TCP Tunneling", "Activer le tunnel TCP"), ("IP Whitelisting", "Liste blanche IP"), ("ID/Relay Server", "ID/Serveur Relais"), ("Import Server Config", "Importer la configuration du serveur"), - ("Export Server Config", ""), + ("Export Server Config", "Exporter la configuration du serveur"), ("Import server configuration successfully", "Configuration du serveur importée avec succès"), - ("Export server configuration successfully", ""), + ("Export server configuration successfully", "Configuration du serveur exportée avec succès"), ("Invalid server configuration", "Configuration du serveur non valide"), ("Clipboard is empty", "Presse-papier vide"), ("Stop service", "Arrêter le service"), @@ -41,9 +41,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("About", "À propos de"), ("Mute", "Muet"), ("Audio Input", "Entrée audio"), - ("Enhancements", ""), - ("Hardware Codec", ""), - ("Adaptive Bitrate", ""), + ("Enhancements", "Améliorations"), + ("Hardware Codec", "Transcodage matériel"), + ("Adaptive Bitrate", "Débit adaptatif"), ("ID Server", "Serveur ID"), ("Relay Server", "Serveur relais"), ("API Server", "Serveur API"), @@ -74,7 +74,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Successful", "Succès"), ("Connected, waiting for image...", "Connecté, en attente de transmission d'image..."), ("Name", "Nom"), - ("Type", "Taper"), + ("Type", "Type"), ("Modified", "Modifié"), ("Size", "Taille"), ("Show Hidden Files", "Afficher les fichiers cachés"), @@ -89,8 +89,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Delete", "Supprimer"), ("Properties", "Propriétés"), ("Multi Select", "Choix multiple"), - ("Select All", ""), - ("Unselect All", ""), + ("Select All", "Tout sélectionner"), + ("Unselect All", "Tout déselectionner"), ("Empty Directory", "Répertoire vide"), ("Not an empty directory", "Pas un répertoire vide"), ("Are you sure you want to delete this file?", "Voulez-vous vraiment supprimer ce fichier?"), @@ -116,9 +116,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Good image quality", "Bonne qualité d'image"), ("Balanced", "Qualité d'image normale"), ("Optimize reaction time", "Optimiser le temps de réaction"), - ("Custom", ""), + ("Custom", "Personnalisé"), ("Show remote cursor", "Afficher le curseur distant"), - ("Show quality monitor", ""), + ("Show quality monitor", "Afficher le moniteur de qualité"), ("Disable clipboard", "Désactiver le presse-papier"), ("Lock after session end", "Verrouiller l'ordinateur distant après la déconnexion"), ("Insert", "Insérer"), @@ -137,9 +137,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Set Password", "Définir le mot de passe"), ("OS Password", "Mot de passe du système d'exploitation"), ("install_tip", "Vous utilisez une version non installée. En raison des restrictions UAC, en tant que terminal contrôlé, dans certains cas, il ne sera pas en mesure de contrôler la souris et le clavier ou d'enregistrer l'écran. Veuillez cliquer sur le bouton ci-dessous pour installer RustDesk au système pour éviter la question ci-dessus."), - ("Click to upgrade", "Cliquez pour mettre à niveau"), - ("Click to download", "Cliquez pour télécharger"), - ("Click to update", "Cliquez pour mettre à jour"), + ("Click to upgrade", "Cliquer pour mettre à niveau"), + ("Click to download", "Cliquer pour télécharger"), + ("Click to update", "Cliquer pour mettre à jour"), ("Configure", "Configurer"), ("config_acc", "Afin de pouvoir contrôler votre bureau à distance, veuillez donner l'autorisation \"accessibilité\" à RustDesk."), ("config_screen", "Afin de pouvoir accéder à votre bureau à distance, veuillez donner à RustDesk l'autorisation \"enregistrement d'écran\"."), @@ -161,8 +161,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Action", "Action"), ("Add", "Ajouter"), ("Local Port", "Port local"), - ("Local Address", ""), - ("Change Local Port", ""), + ("Local Address", "Adresse locale"), + ("Change Local Port", "Changer le port local"), ("setup_server_tip", "Si vous avez besoin d'une vitesse de connexion plus rapide, vous pouvez choisir de créer votre propre serveur"), ("Too short, at least 6 characters.", "Trop court, au moins 6 caractères."), ("The confirmation is not identical.", "Les deux entrées ne correspondent pas"), @@ -179,8 +179,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Relayed and encrypted connection", "Connexion relais chiffrée"), ("Direct and unencrypted connection", "Connexion directe non chiffrée"), ("Relayed and unencrypted connection", "Connexion relais non chiffrée"), - ("Enter Remote ID", "Entrez l'ID de l'appareil à distance"), - ("Enter your password", "Entrez votre mot de passe"), + ("Enter Remote ID", "Entrer l'ID de l'appareil à distance"), + ("Enter your password", "Entrer votre mot de passe"), ("Logging in...", "Se connecter..."), ("Enable RDP session sharing", "Activer le partage de session RDP"), ("Auto Login", "Connexion automatique (le verrouillage ne sera effectif qu'après la désactivation du premier paramètre)"), @@ -191,12 +191,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Change Path", "Changer de chemin"), ("Create Folder", "Créer un dossier"), ("Please enter the folder name", "Veuillez saisir le nom du dossier"), - ("Fix it", "Réparez-le"), + ("Fix it", "Réparer"), ("Warning", "Avertissement"), ("Login screen using Wayland is not supported", "L'écran de connexion utilisant Wayland n'est pas pris en charge"), ("Reboot required", "Redémarrage pour prendre effet"), ("Unsupported display server ", "Le serveur d'affichage actuel n'est pas pris en charge"), - ("x11 expected", "Veuillez passer à x11"), + ("x11 expected", "x11 requis"), ("Port", "Port"), ("Settings", "Paramètres"), ("Username", " Nom d'utilisateur"), @@ -230,7 +230,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Socks5 Proxy", "Socks5 Agents"), ("Hostname", "Nom d'hôte"), ("Discovered", "Découvert"), - ("install_daemon_tip", "Pour démarrer au démarrage, vous devez installer le service système."), + ("install_daemon_tip", "Pour une exécution au démarrage du système, vous devez installer le service système."), ("Remote ID", "ID de l'appareil à distance"), ("Paste", "Coller"), ("Paste here?", "Coller ici ?"), @@ -239,8 +239,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Touch mode", "Mode tactile"), ("Mouse mode", "Mode souris"), ("One-Finger Tap", "Tapez d'un doigt"), - ("Left Mouse", "Souris gauche"), - ("One-Long Tap", "Un long robinet"), + ("Left Mouse", "Bouton gauche de la souris"), + ("One-Long Tap", "Un touché long"), ("Two-Finger Tap", "Tapez à deux doigts"), ("Right Mouse", "Bouton droit de la souris"), ("One-Finger Move", "Mouvement à un doigt"), @@ -249,10 +249,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Three-Finger vertically", "Trois doigts verticalement"), ("Mouse Wheel", "Roulette de la souris"), ("Two-Finger Move", "Mouvement à deux doigts"), - ("Canvas Move", "Déplacement de la toile"), + ("Canvas Move", "Déplacer la vue"), ("Pinch to Zoom", "Pincer pour zoomer"), - ("Canvas Zoom", "Zoom sur la toile"), - ("Reset canvas", "Réinitialiser le canevas"), + ("Canvas Zoom", "Zoom sur la vue"), + ("Reset canvas", "Réinitialiser la vue"), ("No permission of file transfer", "Aucune autorisation de transfert de fichiers"), ("Note", "Noter"), ("Connection", "Connexion"), @@ -303,11 +303,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", "Mode hérité"), ("Map mode", ""), ("Translate mode", ""), - ("Use temporary password", "Utiliser mot de passe temporaire"), - ("Use permanent password", "Utiliser mot de passe permanent"), - ("Use both passwords", "Utiliser tous les mots de passe"), - ("Set permanent password", "Définir mot de passe permanent"), - ("Set temporary password length", "Définir la longueur mot de passe temporaire"), + ("Use temporary password", "Utiliser un mot de passe temporaire"), + ("Use permanent password", "Utiliser un mot de passe permanent"), + ("Use both passwords", "Utiliser les mots de passe temporaire et permanent"), + ("Set permanent password", "Définir le mot de passe permanent"), + ("Set temporary password length", "Définir la longueur du mot de passe temporaire"), ("Enable Remote Restart", "Activer le redémarrage à distance"), ("Allow remote restart", "Autoriser le redémarrage à distance"), ("Restart Remote Device", "Redémarrer l'appareil à distance"), @@ -340,7 +340,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Dark", "Sombre"), ("Light", "Clair"), ("Follow System", "Suivi système"), - ("Enable hardware codec", "Activer le codec matériel"), + ("Enable hardware codec", "Activer le transcodage matériel"), ("Unlock Security Settings", "Déverrouiller les configurations de sécurité"), ("Enable Audio", "Activer l'audio"), ("Temporary Password Length", "Longueur mot de passe temporaire"), @@ -359,7 +359,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable RDP", "Activer RDP"), ("Pin menubar", "Épingler la barre de menus"), ("Unpin menubar", "Détacher la barre de menu"), - ("Recording", "Enregistrement en cours"), + ("Recording", "Enregistrement"), ("Directory", "Répertoire"), ("Automatically record incoming sessions", "Enregistrement automatique des session entrantes"), ("Change", "Modifier"), @@ -374,20 +374,20 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", ""), ("uac_warning", ""), ("elevated_foreground_window_warning", ""), - ("Disconnected", ""), - ("Other", ""), - ("Confirm before closing multiple tabs", ""), - ("Keyboard Settings", ""), - ("Custom", ""), - ("Full Access", ""), - ("Screen Share", ""), + ("Disconnected", "Déconnecté"), + ("Other", "Divers"), + ("Confirm before closing multiple tabs", "Confirmer avant de fermer plusieurs onglets"), + ("Keyboard Settings", "Configuration clavier"), + ("Custom", "Personnalisé"), + ("Full Access", "Accès total"), + ("Screen Share", "Partage d'écran"), ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland nécessite Ubuntu 21.04 ou une version supérieure."), ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland nécessite une version supérieure de la distribution Linux. Veuillez essayer le bureau X11 ou changer votre système d'exploitation."), - ("JumpLink", "View"), + ("JumpLink", "Afficher"), ("Please Select the screen to be shared(Operate on the peer side).", "Veuillez sélectionner l'écran à partager (opérer du côté pair)."), - ("Show RustDesk", ""), - ("This PC", ""), - ("or", ""), - ("Continue with", ""), + ("Show RustDesk", "Afficher RustDesk"), + ("This PC", "Ce PC"), + ("or", "ou"), + ("Continue with", "Continuer avec"), ].iter().cloned().collect(); } From b5d108bc0dd6a6852ebb0cbb80db543752dec368 Mon Sep 17 00:00:00 2001 From: Raul Reis <43497070+RaulReisDev@users.noreply.github.com> Date: Mon, 14 Nov 2022 22:42:43 +0000 Subject: [PATCH 029/116] Update pt_PT.rs updates and corrections --- src/lang/pt_PT.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index b99cb9db0..49679bfd4 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -30,7 +30,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("IP Whitelisting", "Whitelist de IP"), ("ID/Relay Server", "Servidor ID/Relay"), ("Import Server Config", "Importar Configuração do Servidor"), - ("Export Server Config", ""), + ("Export Server Config", "Exportar Configuração do Servidor"), ("Import server configuration successfully", "Configuração do servidor importada com sucesso"), ("Export server configuration successfully", ""), ("Invalid server configuration", "Configuração do servidor inválida"), @@ -39,7 +39,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Change ID", "Alterar ID"), ("Website", "Website"), ("About", "Sobre"), - ("Mute", "Emudecer"), + ("Mute", "Silenciar"), ("Audio Input", "Entrada de Áudio"), ("Enhancements", "Melhorias"), ("Hardware Codec", ""), @@ -89,8 +89,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Delete", "Apagar"), ("Properties", "Propriedades"), ("Multi Select", "Selecção Múltipla"), - ("Select All", ""), - ("Unselect All", ""), + ("Select All", "Selecionar tudo"), + ("Unselect All", "Desmarcar todos"), ("Empty Directory", "Directório Vazio"), ("Not an empty directory", "Directório não está vazio"), ("Are you sure you want to delete this file?", "Tem certeza que deseja apagar este ficheiro?"), @@ -116,7 +116,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Good image quality", "Qualidade visual boa"), ("Balanced", "Equilibrada"), ("Optimize reaction time", "Optimizar tempo de reacção"), - ("Custom", ""), + ("Custom", "Personalizado"), ("Show remote cursor", "Mostrar cursor remoto"), ("Show quality monitor", ""), ("Disable clipboard", "Desabilitar área de transferência"), @@ -137,7 +137,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Set Password", "Definir palavra-chave"), ("OS Password", "Senha do SO"), ("install_tip", "Devido ao UAC, o RustDesk não funciona correctamente em alguns casos. Para evitar o UAC, por favor clique no botão abaixo para instalar o RustDesk no sistema."), - ("Click to upgrade", ""), + ("Click to upgrade", "Clique para atualizar"), ("Click to download", "Clique para carregar"), ("Click to update", "Clique para fazer a actualização"), ("Configure", "Configurar"), @@ -161,8 +161,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Action", "Acção"), ("Add", "Adicionar"), ("Local Port", "Porta Local"), - ("Local Address", ""), - ("Change Local Port", ""), + ("Local Address", "Endereço local"), + ("Change Local Port", "Alterar porta local"), ("setup_server_tip", "Para uma ligação mais rápida, por favor configure seu próprio servidor"), ("Too short, at least 6 characters.", "Muito curto, pelo menos 6 caracteres."), ("The confirmation is not identical.", "A confirmação não é idêntica."), @@ -197,7 +197,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Reboot required", "Reinicialização necessária"), ("Unsupported display server ", "Servidor de display não suportado"), ("x11 expected", "x11 em falha"), - ("Port", ""), + ("Port", "Porta"), ("Settings", "Configurações"), ("Username", "Nome de utilizador"), ("Invalid port", "Porta inválida"), @@ -250,13 +250,13 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Mouse Wheel", "Roda do rato"), ("Two-Finger Move", "Mover com dois dedos"), ("Canvas Move", "Mover Tela"), - ("Pinch to Zoom", "Beliscar para Zoom"), + ("Pinch to Zoom", "Clique para ampliar"), ("Canvas Zoom", "Zoom na Tela"), ("Reset canvas", "Reiniciar tela"), ("No permission of file transfer", "Sem permissões de transferência de ficheiro"), ("Note", "Nota"), ("Connection", "Ligação"), - ("Share Screen", "Partilhar ecran"), + ("Share Screen", "Partilhar ecrã"), ("CLOSE", "FECHAR"), ("OPEN", "ABRIR"), ("Chat", "Conversar"), @@ -374,12 +374,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", ""), ("uac_warning", ""), ("elevated_foreground_window_warning", ""), - ("Disconnected", ""), - ("Other", ""), - ("Confirm before closing multiple tabs", ""), - ("Keyboard Settings", ""), + ("Disconnected", "Desconectado"), + ("Other", "Outro"), + ("Confirm before closing multiple tabs", "Confirme antes de fechar vários separadores"), + ("Keyboard Settings", "Configurações do teclado"), ("Custom", ""), - ("Full Access", ""), + ("Full Access", "Controlo total"), ("Screen Share", ""), ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland requer Ubuntu 21.04 ou versão superior."), ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland requer uma versão superior da distribuição linux. Por favor, tente o desktop X11 ou mude seu sistema operacional."), From 8e1545b43231ecff341aeac86ca553ffdd003f3e Mon Sep 17 00:00:00 2001 From: 21pages Date: Thu, 10 Nov 2022 10:27:13 +0800 Subject: [PATCH 030/116] portable service Signed-off-by: 21pages --- Cargo.lock | 75 +- Cargo.toml | 2 + flutter/lib/desktop/pages/server_page.dart | 88 ++- flutter/lib/models/model.dart | 3 + flutter/lib/models/server_model.dart | 10 + libs/scrap/src/common/dxgi.rs | 2 +- libs/scrap/src/common/vpxcodec.rs | 6 +- src/core_main.rs | 12 + src/flutter.rs | 6 +- src/flutter_ffi.rs | 8 + src/ipc.rs | 14 + src/lang/cn.rs | 1 + src/lang/cs.rs | 1 + src/lang/da.rs | 1 + src/lang/de.rs | 1 + src/lang/eo.rs | 1 + src/lang/es.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/pl.rs | 1 + src/lang/pt_PT.rs | 1 + src/lang/ptbr.rs | 1 + src/lang/ru.rs | 1 + src/lang/sk.rs | 1 + src/lang/template.rs | 1 + src/lang/tr.rs | 1 + src/lang/tw.rs | 1 + src/lang/ua.rs | 1 + src/lang/vn.rs | 1 + src/platform/windows.rs | 8 +- src/server.rs | 5 + src/server/connection.rs | 57 +- src/server/input_service.rs | 43 +- src/server/portable_service.rs | 779 +++++++++++++++++++++ src/server/video_qos.rs | 6 +- src/server/video_service.rs | 42 +- src/ui/cm.css | 2 +- src/ui/cm.rs | 14 + src/ui/cm.tis | 45 +- src/ui_cm_interface.rs | 34 + src/ui_interface.rs | 5 +- 46 files changed, 1217 insertions(+), 72 deletions(-) create mode 100644 src/server/portable_service.rs diff --git a/Cargo.lock b/Cargo.lock index 00916eabd..67a471cef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1253,7 +1253,7 @@ dependencies = [ "libc", "memalloc", "system-configuration", - "windows", + "windows 0.30.0", ] [[package]] @@ -4413,6 +4413,8 @@ dependencies = [ "serde_derive", "serde_json 1.0.85", "sha2", + "shared_memory", + "shutdown_hooks", "simple_rc", "sys-locale", "sysinfo", @@ -4761,12 +4763,31 @@ dependencies = [ "digest", ] +[[package]] +name = "shared_memory" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba8593196da75d9dc4f69349682bd4c2099f8cde114257d1ef7ef1b33d1aba54" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "nix 0.23.1", + "rand 0.8.5", + "win-sys", +] + [[package]] name = "shlex" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" +[[package]] +name = "shutdown_hooks" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6057adedbec913419c92996f395ba69931acbd50b7d56955394cd3f7bedbfa45" + [[package]] name = "signal-hook" version = "0.3.14" @@ -5844,6 +5865,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" +[[package]] +name = "win-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b7b128a98c1cfa201b09eb49ba285887deb3cbe7466a98850eb1adabb452be5" +dependencies = [ + "windows 0.34.0", +] + [[package]] name = "winapi" version = "0.2.8" @@ -5909,6 +5939,19 @@ dependencies = [ "windows_x86_64_msvc 0.30.0", ] +[[package]] +name = "windows" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45296b64204227616fdbf2614cefa4c236b98ee64dfaaaa435207ed99fe7829f" +dependencies = [ + "windows_aarch64_msvc 0.34.0", + "windows_i686_gnu 0.34.0", + "windows_i686_msvc 0.34.0", + "windows_x86_64_gnu 0.34.0", + "windows_x86_64_msvc 0.34.0", +] + [[package]] name = "windows-service" version = "0.4.0" @@ -5959,6 +6002,12 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29277a4435d642f775f63c7d1faeb927adba532886ce0287bd985bffb16b6bca" +[[package]] +name = "windows_aarch64_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" + [[package]] name = "windows_aarch64_msvc" version = "0.36.1" @@ -5977,6 +6026,12 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1145e1989da93956c68d1864f32fb97c8f561a8f89a5125f6a2b7ea75524e4b8" +[[package]] +name = "windows_i686_gnu" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" + [[package]] name = "windows_i686_gnu" version = "0.36.1" @@ -5995,6 +6050,12 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4a09e3a0d4753b73019db171c1339cd4362c8c44baf1bcea336235e955954a6" +[[package]] +name = "windows_i686_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" + [[package]] name = "windows_i686_msvc" version = "0.36.1" @@ -6013,6 +6074,12 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ca64fcb0220d58db4c119e050e7af03c69e6f4f415ef69ec1773d9aab422d5a" +[[package]] +name = "windows_x86_64_gnu" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" + [[package]] name = "windows_x86_64_gnu" version = "0.36.1" @@ -6031,6 +6098,12 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08cabc9f0066848fef4bc6a1c1668e6efce38b661d2aeec75d18d8617eebb5f1" +[[package]] +name = "windows_x86_64_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" + [[package]] name = "windows_x86_64_msvc" version = "0.36.1" diff --git a/Cargo.toml b/Cargo.toml index 5dc54d58b..689e1a989 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -92,6 +92,8 @@ winreg = "0.10" windows-service = "0.4" virtual_display = { path = "libs/virtual_display" } impersonate_system = { git = "https://github.com/21pages/impersonate-system" } +shared_memory = "0.12.4" +shutdown_hooks = "0.1.0" [target.'cfg(target_os = "macos")'.dependencies] objc = "0.2" diff --git a/flutter/lib/desktop/pages/server_page.dart b/flutter/lib/desktop/pages/server_page.dart index e344575c7..aac6ee017 100644 --- a/flutter/lib/desktop/pages/server_page.dart +++ b/flutter/lib/desktop/pages/server_page.dart @@ -501,11 +501,46 @@ class _CmControlPanel extends StatelessWidget { } buildAuthorized(BuildContext context) { + final bool canElevate = bind.cmCanElevate(); + final model = Provider.of(context); + final offstage = !(canElevate && model.showElevation); + final width = offstage ? 200.0 : 100.0; return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ + Offstage( + offstage: offstage, + child: Ink( + width: width, + height: 40, + decoration: BoxDecoration( + color: Colors.green[700], + borderRadius: BorderRadius.circular(10)), + child: InkWell( + onTap: () => + checkClickTime(client.id, () => handleElevate(context)), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.security_sharp, + color: Colors.white, + ), + Text( + translate("Elevate"), + style: TextStyle(color: Colors.white), + ), + ], + )), + ), + ), + Offstage( + offstage: offstage, + child: SizedBox( + width: 30, + )), Ink( - width: 200, + width: width, height: 40, decoration: BoxDecoration( color: Colors.redAccent, borderRadius: BorderRadius.circular(10)), @@ -552,11 +587,50 @@ class _CmControlPanel extends StatelessWidget { } buildUnAuthorized(BuildContext context) { + final bool canElevate = bind.cmCanElevate(); + final model = Provider.of(context); + final offstage = !(canElevate && model.showElevation); + final width = offstage ? 100.0 : 85.0; + final spacerWidth = offstage ? 30.0 : 5.0; return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ + Offstage( + offstage: offstage, + child: Ink( + height: 40, + width: width, + decoration: BoxDecoration( + color: Colors.green[700], + borderRadius: BorderRadius.circular(10)), + child: InkWell( + onTap: () => checkClickTime(client.id, () { + handleAccept(context); + handleElevate(context); + windowManager.minimize(); + }), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.security_sharp, + color: Colors.white, + ), + Text( + translate("Accept"), + style: TextStyle(color: Colors.white), + ), + ], + )), + ), + ), + Offstage( + offstage: offstage, + child: SizedBox( + width: spacerWidth, + )), Ink( - width: 100, + width: width, height: 40, decoration: BoxDecoration( color: MyTheme.accent, borderRadius: BorderRadius.circular(10)), @@ -576,10 +650,10 @@ class _CmControlPanel extends StatelessWidget { )), ), SizedBox( - width: 30, + width: spacerWidth, ), Ink( - width: 100, + width: width, height: 40, decoration: BoxDecoration( color: Colors.transparent, @@ -611,6 +685,12 @@ class _CmControlPanel extends StatelessWidget { model.sendLoginResponse(client, true); } + void handleElevate(BuildContext context) { + final model = Provider.of(context, listen: false); + model.setShowElevation(false); + bind.cmElevatePortable(connId: client.id); + } + void handleClose(BuildContext context) async { await bind.cmRemoveDisconnectedConnection(connId: client.id); if (await bind.cmGetClientsLength() == 0) { diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index d7fc414d5..fb4f8b4f4 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -192,6 +192,9 @@ class FfiModel with ChangeNotifier { } } else if (name == 'alias') { handleAliasChanged(evt); + } else if (name == 'show_elevation') { + final show = evt['show'].toString() == 'true'; + parent.target?.serverModel.setShowElevation(show); } }; } diff --git a/flutter/lib/models/server_model.dart b/flutter/lib/models/server_model.dart index d407ca51b..1c0d1cbdd 100644 --- a/flutter/lib/models/server_model.dart +++ b/flutter/lib/models/server_model.dart @@ -27,6 +27,7 @@ class ServerModel with ChangeNotifier { bool _inputOk = false; bool _audioOk = false; bool _fileOk = false; + bool _showElevation = true; int _connectStatus = 0; // Rendezvous Server status String _verificationMethod = ""; String _temporaryPasswordLength = ""; @@ -51,6 +52,8 @@ class ServerModel with ChangeNotifier { bool get fileOk => _fileOk; + bool get showElevation => _showElevation; + int get connectStatus => _connectStatus; String get verificationMethod { @@ -530,6 +533,13 @@ class ServerModel with ChangeNotifier { final index = _clients.indexWhere((client) => client.id == id); tabController.jumpTo(index); } + + void setShowElevation(bool show) { + if (_showElevation != show) { + _showElevation = show; + notifyListeners(); + } + } } class Client { diff --git a/libs/scrap/src/common/dxgi.rs b/libs/scrap/src/common/dxgi.rs index 963f39de1..287d85880 100644 --- a/libs/scrap/src/common/dxgi.rs +++ b/libs/scrap/src/common/dxgi.rs @@ -61,7 +61,7 @@ impl TraitCapturer for Capturer { } } -pub struct Frame<'a>(&'a [u8]); +pub struct Frame<'a>(pub &'a [u8]); impl<'a> ops::Deref for Frame<'a> { type Target = [u8]; diff --git a/libs/scrap/src/common/vpxcodec.rs b/libs/scrap/src/common/vpxcodec.rs index 47b3df3a6..5164886a1 100644 --- a/libs/scrap/src/common/vpxcodec.rs +++ b/libs/scrap/src/common/vpxcodec.rs @@ -4,7 +4,7 @@ use hbb_common::anyhow::{anyhow, Context}; use hbb_common::message_proto::{EncodedVideoFrame, EncodedVideoFrames, Message, VideoFrame}; -use hbb_common::{ResultType, get_time}; +use hbb_common::{get_time, ResultType}; use crate::codec::EncoderApi; use crate::STRIDE_ALIGN; @@ -233,7 +233,9 @@ impl EncoderApi for VpxEncoder { impl VpxEncoder { pub fn encode(&mut self, pts: i64, data: &[u8], stride_align: usize) -> Result { - assert!(2 * data.len() >= 3 * self.width * self.height); + if 2 * data.len() < 3 * self.width * self.height { + return Err(Error::FailedCall("len not enough".to_string())); + } let mut image = Default::default(); call_vpx_ptr!(vpx_img_wrap( diff --git a/src/core_main.rs b/src/core_main.rs index 443ef92ea..889015c0d 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -80,6 +80,11 @@ pub fn core_main() -> Option> { .ok(); } } + #[cfg(windows)] + if !crate::platform::is_installed() && (_is_elevate || _is_run_as_system) { + crate::platform::elevate_or_run_as_system(click_setup, _is_elevate, _is_run_as_system); + return None; + } if args.is_empty() { std::thread::spawn(move || crate::start_server(false)); } else { @@ -128,6 +133,13 @@ pub fn core_main() -> Option> { } else if args[0] == "--tray" { crate::tray::start_tray(); return None; + } else if args[0] == "--portable-service" { + crate::platform::elevate_or_run_as_system( + click_setup, + _is_elevate, + _is_run_as_system, + ); + return None; } } if args[0] == "--remove" { diff --git a/src/flutter.rs b/src/flutter.rs index 91b2ce7e5..a69473e5a 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -406,7 +406,7 @@ pub fn session_start_(id: &str, event_stream: StreamSink) -> ResultTy *session.event_stream.write().unwrap() = Some(event_stream); let session = session.clone(); std::thread::spawn(move || { - // if flutter : disable keyboard listen + // if flutter : disable keyboard listen crate::client::disable_keyboard_listening(); io_loop(session); }); @@ -469,6 +469,10 @@ pub mod connection_manager { fn change_language(&self) { self.push_event("language", vec![]); } + + fn show_elevation(&self, show: bool) { + self.push_event("show_elevation", vec![("show", &show.to_string())]); + } } impl FlutterHandler { diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 3a2e3f58e..856c4ed21 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -1010,6 +1010,14 @@ pub fn cm_switch_permission(conn_id: i32, name: String, enabled: bool) { crate::ui_cm_interface::switch_permission(conn_id, name, enabled) } +pub fn cm_can_elevate() -> SyncReturn { + SyncReturn(crate::ui_cm_interface::can_elevate()) +} + +pub fn cm_elevate_portable(conn_id: i32) { + crate::ui_cm_interface::elevate_portable(conn_id); +} + pub fn main_get_icon() -> String { #[cfg(not(any(target_os = "android", target_os = "ios", feature = "cli")))] return ui_interface::get_icon(); diff --git a/src/ipc.rs b/src/ipc.rs index 229bcf166..d2d57f8c9 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -130,6 +130,19 @@ pub enum DataControl { }, } +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(tag = "t", content = "c")] +pub enum DataPortableService { + Ping, + Pong, + ConnCount(Option), + Mouse(Vec), + Key(Vec), + RequestStart, + WillClose, + CmShowElevation(bool), +} + #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(tag = "t", content = "c")] pub enum Data { @@ -187,6 +200,7 @@ pub enum Data { Language(String), Empty, Disconnected, + DataPortableService(DataPortableService), } #[tokio::main(flavor = "current_thread")] diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 7240f2a91..b622123a0 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", "此电脑"), ("or", "或"), ("Continue with", "使用"), + ("Elevate", "提权"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index b51cb69e9..5c086bfb2 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", ""), ("or", ""), ("Continue with", ""), + ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index c4d633b9b..90670804a 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", ""), ("or", ""), ("Continue with", ""), + ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index 9eb90ebcd..6ebea6b2e 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", ""), ("or", ""), ("Continue with", ""), + ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index e7a35d937..2dce72f6e 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", ""), ("or", ""), ("Continue with", ""), + ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index 2eef088c3..2e70a5194 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", "Este PC"), ("or", "o"), ("Continue with", "Continuar con"), + ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index fc738c2b6..811ec911d 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", "Ce PC"), ("or", "ou"), ("Continue with", "Continuer avec"), + ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index 6a75b6958..863fa3739 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", "Ez a számítógép"), ("or", "vagy"), ("Continue with", "Folytatás a következővel"), + ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 6f328f127..78fccc9f3 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", ""), ("or", ""), ("Continue with", ""), + ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 75e7859ed..35c09a0b2 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", ""), ("or", ""), ("Continue with", ""), + ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 0e6931379..21344eb11 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", ""), ("or", ""), ("Continue with", ""), + ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index 601db354d..3b7269023 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", ""), ("or", ""), ("Continue with", ""), + ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 359e14f55..1dc505807 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", ""), ("or", ""), ("Continue with", ""), + ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index 382b254f0..7ed98913c 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", ""), ("or", ""), ("Continue with", ""), + ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 49679bfd4..8b4c980f6 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", ""), ("or", ""), ("Continue with", ""), + ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index 3a60dc313..0d5594ea9 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", "Este PC"), ("or", "ou"), ("Continue with", "Continuar com"), + ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 7d7b0c6ad..22c246f86 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", "Этот компьютер"), ("or", "или"), ("Continue with", "Продолжить с"), + ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 4dfd8b02e..618ede5cd 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", ""), ("or", ""), ("Continue with", ""), + ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index 7c1f18df3..4ff8f9b87 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", ""), ("or", ""), ("Continue with", ""), + ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index f856182f3..6fb89a09f 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", ""), ("or", ""), ("Continue with", ""), + ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index 6a196feb7..1150199cd 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", ""), ("or", ""), ("Continue with", ""), + ("Elevate", "提權"), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index 95d19b26b..cc0ef6536 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", ""), ("or", ""), ("Continue with", ""), + ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index c95498ca8..9773d7655 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", ""), ("or", ""), ("Continue with", ""), + ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 97dfbcc25..b418d0904 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -63,7 +63,7 @@ pub fn get_cursor() -> ResultType> { unsafe { let mut ci: CURSORINFO = mem::MaybeUninit::uninit().assume_init(); ci.cbSize = std::mem::size_of::() as _; - if GetCursorInfo(&mut ci) == FALSE { + if crate::portable_service::client::get_cursor_info(&mut ci) == FALSE { return Err(io::Error::last_os_error().into()); } if ci.flags & CURSOR_SHOWING == 0 { @@ -1542,9 +1542,11 @@ pub fn elevate_or_run_as_system(is_setup: bool, is_elevate: bool, is_run_as_syst } else { "--run-as-system" }; - if is_root() { - log::debug!("portable run as system user"); + if is_run_as_system { + log::info!("run portable service"); + crate::portable_service::server::run_portable_service(); + } } else { match is_elevated(None) { Ok(elevated) => { diff --git a/src/server.rs b/src/server.rs index 6e549c9f4..7e00532fe 100644 --- a/src/server.rs +++ b/src/server.rs @@ -49,6 +49,8 @@ pub const NAME_POS: &'static str = ""; } mod connection; +#[cfg(windows)] +pub mod portable_service; mod service; mod video_qos; pub mod video_service; @@ -60,6 +62,7 @@ type ConnMap = HashMap; lazy_static::lazy_static! { pub static ref CHILD_PROCESS: Childs = Default::default(); + pub static ref CONN_COUNT: Arc> = Default::default(); } pub struct Server { @@ -259,6 +262,7 @@ impl Server { } } self.connections.insert(conn.id(), conn); + *CONN_COUNT.lock().unwrap() = self.connections.len(); } pub fn remove_connection(&mut self, conn: &ConnInner) { @@ -266,6 +270,7 @@ impl Server { s.on_unsubscribe(conn.id()); } self.connections.remove(&conn.id()); + *CONN_COUNT.lock().unwrap() = self.connections.len(); } pub fn close_connections(&mut self) { diff --git a/src/server/connection.rs b/src/server/connection.rs index 891c48888..c77f6ebd7 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -236,8 +236,12 @@ impl Connection { #[cfg(not(any(target_os = "android", target_os = "ios")))] std::thread::spawn(move || Self::handle_input(rx_input, tx_cloned)); let mut second_timer = time::interval(Duration::from_secs(1)); + #[cfg(windows)] let mut last_uac = false; + #[cfg(windows)] let mut last_foreground_window_elevated = false; + #[cfg(windows)] + let is_installed = crate::platform::is_installed(); loop { tokio::select! { @@ -341,6 +345,12 @@ impl Connection { }; conn.send(msg_out).await; } + #[cfg(windows)] + ipc::Data::DataPortableService(ipc::DataPortableService::RequestStart) => { + if let Err(e) = crate::portable_service::client::start_portable_service() { + log::error!("Failed to start portable service from cm:{:?}", e); + } + } _ => {} } }, @@ -417,23 +427,36 @@ impl Connection { } }, _ = second_timer.tick() => { - let uac = crate::video_service::IS_UAC_RUNNING.lock().unwrap().clone(); - if last_uac != uac { - last_uac = uac; - let mut misc = Misc::new(); - misc.set_uac(uac); - let mut msg = Message::new(); - msg.set_misc(misc); - conn.inner.send(msg.into()); - } - let foreground_window_elevated = crate::video_service::IS_FOREGROUND_WINDOW_ELEVATED.lock().unwrap().clone(); - if last_foreground_window_elevated != foreground_window_elevated { - last_foreground_window_elevated = foreground_window_elevated; - let mut misc = Misc::new(); - misc.set_foreground_window_elevated(foreground_window_elevated); - let mut msg = Message::new(); - msg.set_misc(misc); - conn.inner.send(msg.into()); + #[cfg(windows)] + { + use crate::portable_service::client::{PORTABLE_SERVICE_STATUS, PortableServiceStatus::*}; + let uac = crate::video_service::IS_UAC_RUNNING.lock().unwrap().clone(); + if last_uac != uac { + last_uac = uac; + if PORTABLE_SERVICE_STATUS.lock().unwrap().clone() == NotStarted { + let mut misc = Misc::new(); + misc.set_uac(uac); + let mut msg = Message::new(); + msg.set_misc(misc); + conn.inner.send(msg.into()); + } + } + let foreground_window_elevated = crate::video_service::IS_FOREGROUND_WINDOW_ELEVATED.lock().unwrap().clone(); + if last_foreground_window_elevated != foreground_window_elevated { + last_foreground_window_elevated = foreground_window_elevated; + if PORTABLE_SERVICE_STATUS.lock().unwrap().clone() == NotStarted { + let mut misc = Misc::new(); + misc.set_foreground_window_elevated(foreground_window_elevated); + let mut msg = Message::new(); + msg.set_misc(misc); + conn.inner.send(msg.into()); + } + } + if !is_installed { + let show_elevation = PORTABLE_SERVICE_STATUS.lock().unwrap().clone() == NotStarted; + conn.send_to_cm(ipc::Data::DataPortableService(ipc::DataPortableService::CmShowElevation(show_elevation))); + + } } } _ = test_delay_timer.tick() => { diff --git a/src/server/input_service.rs b/src/server/input_service.rs index f2591df0b..af4b7d853 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -287,7 +287,23 @@ pub fn handle_mouse(evt: &MouseEvent, conn: i32) { QUEUE.exec_async(move || handle_mouse_(&evt, conn)); return; } - handle_mouse_(evt, conn); + if !active_mouse_(conn) { + return; + } + let evt_type = evt.mask & 0x7; + if evt_type == 0 { + let time = get_time(); + *LATEST_PEER_INPUT_CURSOR.lock().unwrap() = Input { + time, + conn, + x: evt.x, + y: evt.y, + }; + } + #[cfg(windows)] + crate::portable_service::client::handle_mouse(evt); + #[cfg(not(windows))] + handle_mouse_(evt); } pub fn fix_key_down_timeout_loop() { @@ -415,8 +431,7 @@ fn active_mouse_(conn: i32) -> bool { let lock = LATEST_PEER_INPUT_CURSOR.lock().unwrap(); (lock.x, lock.y) }; - let mut can_active = - in_actived_dist(last_in_x, x) && in_actived_dist(last_in_y, y); + let mut can_active = in_actived_dist(last_in_x, x) && in_actived_dist(last_in_y, y); // The cursor may not have been moved to last input position if system is busy now. // While this is not a common case, we check it again after some time later. if !can_active { @@ -425,8 +440,7 @@ fn active_mouse_(conn: i32) -> bool { std::thread::sleep(std::time::Duration::from_micros(10)); // Sleep here can also somehow suppress delay accumulation. if let Some((x2, y2)) = crate::get_cursor_pos() { - can_active = - in_actived_dist(last_in_x, x2) && in_actived_dist(last_in_y, y2); + can_active = in_actived_dist(last_in_x, x2) && in_actived_dist(last_in_y, y2); } } if !can_active { @@ -440,15 +454,11 @@ fn active_mouse_(conn: i32) -> bool { } } -fn handle_mouse_(evt: &MouseEvent, conn: i32) { +pub fn handle_mouse_(evt: &MouseEvent) { if EXITING.load(Ordering::SeqCst) { return; } - if !active_mouse_(conn) { - return; - } - #[cfg(windows)] crate::platform::windows::try_change_desktop(); let buttons = evt.mask >> 3; @@ -477,14 +487,6 @@ fn handle_mouse_(evt: &MouseEvent, conn: i32) { } match evt_type { 0 => { - let time = get_time(); - *LATEST_PEER_INPUT_CURSOR.lock().unwrap() = Input { - time, - conn, - x: evt.x, - y: evt.y, - }; - en.mouse_move_to(evt.x, evt.y); } 1 => match buttons { @@ -698,6 +700,9 @@ pub fn handle_key(evt: &KeyEvent) { QUEUE.exec_async(move || handle_key_(&evt)); return; } + #[cfg(windows)] + crate::portable_service::client::handle_key(evt); + #[cfg(not(windows))] handle_key_(evt); } @@ -949,7 +954,7 @@ fn legacy_keyboard_mode(evt: &KeyEvent) { } } -fn handle_key_(evt: &KeyEvent) { +pub fn handle_key_(evt: &KeyEvent) { if EXITING.load(Ordering::SeqCst) { return; } diff --git a/src/server/portable_service.rs b/src/server/portable_service.rs new file mode 100644 index 000000000..1de2a1c8b --- /dev/null +++ b/src/server/portable_service.rs @@ -0,0 +1,779 @@ +use core::slice; +use hbb_common::{ + allow_err, + anyhow::anyhow, + bail, + config::Config, + log, + message_proto::{KeyEvent, MouseEvent}, + protobuf::Message, + sleep, + tokio::{self, sync::mpsc}, + ResultType, +}; +use scrap::{Capturer, Frame, TraitCapturer}; +use shared_memory::*; +use std::{ + mem::size_of, + ops::{Deref, DerefMut}, + sync::{Arc, Mutex}, + time::Duration, +}; +use winapi::{ + shared::minwindef::{BOOL, FALSE, TRUE}, + um::winuser::{self, CURSORINFO, PCURSORINFO}, +}; + +use crate::{ + ipc::{self, new_listener, Connection, Data, DataPortableService}, + video_service::get_current_display, +}; + +use super::video_qos; + +const SIZE_COUNTER: usize = size_of::() * 2; +const FRAME_ALIGN: usize = 64; + +const ADDR_CURSOR_PARA: usize = 0; +const ADDR_CURSOR_COUNTER: usize = ADDR_CURSOR_PARA + size_of::(); + +const ADDR_CAPTURER_PARA: usize = ADDR_CURSOR_COUNTER + SIZE_COUNTER; +const ADDR_CAPTURE_FRAME_SIZE: usize = ADDR_CAPTURER_PARA + size_of::(); +const ADDR_CAPTURE_WOULDBLOCK: usize = ADDR_CAPTURE_FRAME_SIZE + size_of::(); +const ADDR_CAPTURE_FRAME_COUNTER: usize = ADDR_CAPTURE_WOULDBLOCK + size_of::(); + +const ADDR_CAPTURE_FRAME: usize = + (ADDR_CAPTURE_FRAME_COUNTER + SIZE_COUNTER + FRAME_ALIGN - 1) / FRAME_ALIGN * FRAME_ALIGN; + +const IPC_PROFIX: &str = "_portable_service"; +pub const SHMEM_NAME: &str = "_portable_service"; +const MAX_NACK: usize = 3; +const IPC_CONN_TIMEOUT: Duration = Duration::from_secs(3); + +pub enum PortableServiceStatus { + NonStart, + Running, +} + +impl Default for PortableServiceStatus { + fn default() -> Self { + Self::NonStart + } +} + +pub struct SharedMemory { + inner: Shmem, +} + +unsafe impl Send for SharedMemory {} +unsafe impl Sync for SharedMemory {} + +impl Deref for SharedMemory { + type Target = Shmem; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for SharedMemory { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl SharedMemory { + pub fn create(name: &str, size: usize) -> ResultType { + let flink = Self::flink(name.to_string()); + let shmem = match ShmemConf::new() + .size(size) + .flink(&flink) + .force_create_flink() + .create() + { + Ok(m) => m, + Err(ShmemError::LinkExists) => { + bail!( + "Unable to force create shmem flink {}, which should not happen.", + flink + ) + } + Err(e) => { + bail!("Unable to create shmem flink {} : {}", flink, e); + } + }; + log::info!("Create shared memory, size:{}, flink:{}", size, flink); + Self::set_all_perm(&flink); + Ok(SharedMemory { inner: shmem }) + } + + pub fn open_existing(name: &str) -> ResultType { + let flink = Self::flink(name.to_string()); + let shmem = match ShmemConf::new().flink(&flink).allow_raw(true).open() { + Ok(m) => m, + Err(e) => { + bail!("Unable to open existing shmem flink {} : {}", flink, e); + } + }; + log::info!("open existing shared memory, flink:{:?}", flink); + Ok(SharedMemory { inner: shmem }) + } + + pub fn write(&self, addr: usize, data: &[u8]) { + unsafe { + assert!(addr + data.len() <= self.inner.len()); + let ptr = self.inner.as_ptr().add(addr); + let shared_mem_slice = slice::from_raw_parts_mut(ptr, data.len()); + shared_mem_slice.copy_from_slice(data); + } + } + + fn flink(name: String) -> String { + let mut shmem_flink = format!("shared_memory{}", name); + if cfg!(windows) { + let df = "C:\\ProgramData"; + let df = if std::path::Path::new(df).exists() { + df.to_owned() + } else { + std::env::var("TEMP").unwrap_or("C:\\Windows\\TEMP".to_owned()) + }; + let df = format!("{}\\{}", df, *hbb_common::config::APP_NAME.read().unwrap()); + std::fs::create_dir(&df).ok(); + shmem_flink = format!("{}\\{}", df, shmem_flink); + } else { + shmem_flink = Config::ipc_path("").replace("ipc", "") + &shmem_flink; + } + return shmem_flink; + } + + fn set_all_perm(_p: &str) { + #[cfg(not(windows))] + { + use std::os::unix::fs::PermissionsExt; + std::fs::set_permissions(_p, std::fs::Permissions::from_mode(0o0777)).ok(); + } + } +} + +mod utils { + use core::slice; + use std::mem::size_of; + + pub fn i32_to_vec(i: i32) -> Vec { + i.to_ne_bytes().to_vec() + } + + pub fn ptr_to_i32(ptr: *const u8) -> i32 { + unsafe { + let v = slice::from_raw_parts(ptr, size_of::()); + i32::from_ne_bytes([v[0], v[1], v[2], v[3]]) + } + } + + pub fn counter_ready(counter: *const u8) -> bool { + unsafe { + let wptr = counter; + let rptr = counter.add(size_of::()); + let iw = ptr_to_i32(wptr); + let ir = ptr_to_i32(rptr); + if ir != iw { + std::ptr::copy_nonoverlapping(wptr, rptr as *mut _, size_of::()); + true + } else { + false + } + } + } + + pub fn increase_counter(ptr: *mut u8) { + unsafe { + let i = ptr_to_i32(ptr); + let v = i32_to_vec(i + 1); + std::ptr::copy_nonoverlapping(v.as_ptr(), ptr, size_of::()); + } + } + + pub fn align(v: usize, align: usize) -> usize { + (v + align - 1) / align * align + } +} + +// functions called in seperate SYSTEM user process. +pub mod server { + use hbb_common::tokio::time::Instant; + + use super::*; + + lazy_static::lazy_static! { + static ref EXIT: Arc> = Default::default(); + } + + pub fn run_portable_service() { + let shmem = Arc::new(SharedMemory::open_existing(SHMEM_NAME).unwrap()); + let shmem1 = shmem.clone(); + let shmem2 = shmem.clone(); + let mut threads = vec![]; + threads.push(std::thread::spawn(|| { + run_get_cursor_info(shmem1); + })); + threads.push(std::thread::spawn(|| { + run_capture(shmem2); + })); + threads.push(std::thread::spawn(|| { + run_ipc_server(); + })); + threads.push(std::thread::spawn(|| { + run_exit_check(); + })); + for th in threads.drain(..) { + th.join().unwrap(); + log::info!("all thread joined"); + } + } + + fn run_exit_check() { + loop { + if EXIT.lock().unwrap().clone() { + std::thread::sleep(Duration::from_secs(1)); + log::info!("exit from seperate check thread"); + std::process::exit(0); + } + std::thread::sleep(Duration::from_secs(1)); + } + } + + fn run_get_cursor_info(shmem: Arc) { + loop { + if EXIT.lock().unwrap().clone() { + break; + } + unsafe { + let para = shmem.as_ptr().add(ADDR_CURSOR_PARA) as *mut CURSORINFO; + (*para).cbSize = size_of::() as _; + let result = winuser::GetCursorInfo(para); + if result == TRUE { + utils::increase_counter(shmem.as_ptr().add(ADDR_CURSOR_COUNTER)); + } + } + // more frequent in case of `Error of mouse_cursor service` + std::thread::sleep(Duration::from_millis(15)); + } + } + + fn run_capture(shmem: Arc) { + let mut c = None; + let mut last_current_display = usize::MAX; + let mut last_use_yuv = false; + let mut last_timeout_ms: i32 = 33; + let mut spf = Duration::from_millis(last_timeout_ms as _); + loop { + if EXIT.lock().unwrap().clone() { + break; + } + let start = std::time::Instant::now(); + unsafe { + let para_ptr = shmem.as_ptr().add(ADDR_CAPTURER_PARA); + let para = para_ptr as *const CapturerPara; + let current_display = (*para).current_display; + let use_yuv = (*para).use_yuv; + let timeout_ms = (*para).timeout_ms; + if c.is_none() { + let use_yuv = true; + *crate::video_service::CURRENT_DISPLAY.lock().unwrap() = current_display; + let (_, _current, display) = get_current_display().unwrap(); + match Capturer::new(display, use_yuv) { + Ok(mut v) => { + c = { + last_current_display = current_display; + last_use_yuv = use_yuv; + // dxgi failed at loadFrame on my PC. + // to-do: try dxgi on another PC. + v.set_gdi(); + Some(v) + } + } + Err(e) => { + log::error!("Failed to create gdi capturer:{:?}", e); + std::thread::sleep(std::time::Duration::from_secs(1)); + continue; + } + } + } else { + if current_display != last_current_display || use_yuv != last_use_yuv { + log::info!( + "display:{}->{}, use_yuv:{}->{}", + last_current_display, + current_display, + last_use_yuv, + use_yuv + ); + c = None; + continue; + } + if timeout_ms != last_timeout_ms + && timeout_ms >= 1000 / video_qos::MAX_FPS as i32 + && timeout_ms <= 1000 / video_qos::MIN_FPS as i32 + { + last_timeout_ms = timeout_ms; + spf = Duration::from_millis(timeout_ms as _); + } + } + match c.as_mut().unwrap().frame(spf) { + Ok(f) => { + let len = f.0.len(); + let len_slice = utils::i32_to_vec(len as _); + shmem.write(ADDR_CAPTURE_FRAME_SIZE, &len_slice); + shmem.write(ADDR_CAPTURE_FRAME, f.0); + shmem.write(ADDR_CAPTURE_WOULDBLOCK, &utils::i32_to_vec(TRUE)); + utils::increase_counter(shmem.as_ptr().add(ADDR_CAPTURE_FRAME_COUNTER)); + } + Err(e) => { + if e.kind() != std::io::ErrorKind::WouldBlock { + log::error!("capture frame failed:{:?}", e); + crate::platform::try_change_desktop(); + c = None; + shmem.write(ADDR_CAPTURE_WOULDBLOCK, &utils::i32_to_vec(FALSE)); + continue; + } else { + shmem.write(ADDR_CAPTURE_WOULDBLOCK, &utils::i32_to_vec(TRUE)); + } + } + } + } + let elapsed = start.elapsed(); + if elapsed < spf { + std::thread::sleep(spf - elapsed); + } + } + } + + #[tokio::main(flavor = "current_thread")] + async fn run_ipc_server() { + use DataPortableService::*; + + let postfix = IPC_PROFIX; + let last_recv_time = Arc::new(Mutex::new(Instant::now())); + let mut interval = tokio::time::interval(Duration::from_secs(1)); + + match new_listener(postfix).await { + Ok(mut incoming) => loop { + tokio::select! { + Some(result) = incoming.next() => { + match result { + Ok(stream) => { + log::info!("Got new connection"); + let last_recv_time_cloned = last_recv_time.clone(); + tokio::spawn(async move { + let mut stream = Connection::new(stream); + let postfix = postfix.to_owned(); + let mut timer = tokio::time::interval(Duration::from_secs(1)); + let mut nack = 0; + let mut old_conn_count = 0; + loop { + tokio::select! { + res = stream.next() => { + if res.is_ok() { + *last_recv_time_cloned.lock().unwrap() = Instant::now(); + } + match res { + Err(err) => { + log::error!( + "ipc{} connection closed: {}", + postfix, + err + ); + *EXIT.lock().unwrap() = true; + break; + } + Ok(Some(Data::DataPortableService(data))) => match data { + Ping => { + allow_err!( + stream + .send(&Data::DataPortableService(Pong)) + .await + ); + } + Pong => { + nack = 0; + } + ConnCount(Some(n)) => { + if old_conn_count != 0 && n == 0 { + log::info!("Connection count decrease to 0, exit"); + stream.send(&Data::DataPortableService(WillClose)).await.ok(); + *EXIT.lock().unwrap() = true; + break; + } + old_conn_count = n; + } + Mouse(v) => { + if let Ok(evt) = MouseEvent::parse_from_bytes(&v) { + crate::input_service::handle_mouse_(&evt); + } + } + Key(v) => { + if let Ok(evt) = KeyEvent::parse_from_bytes(&v) { + crate::input_service::handle_key_(&evt); + } + } + _ => {} + }, + _ => {} + } + } + _ = timer.tick() => { + nack+=1; + if nack > MAX_NACK { + log::info!("max ping nack, exit"); + *EXIT.lock().unwrap() = true; + break; + } + stream.send(&Data::DataPortableService(Ping)).await.ok(); + stream.send(&Data::DataPortableService(ConnCount(None))).await.ok(); + } + } + } + }); + } + Err(err) => { + log::error!("Couldn't get portable client: {:?}", err); + *EXIT.lock().unwrap() = true; + } + } + } + _ = interval.tick() => { + if last_recv_time.lock().unwrap().elapsed() > IPC_CONN_TIMEOUT { + log::error!("receive data timeout"); + *EXIT.lock().unwrap() = true; + } + if EXIT.lock().unwrap().clone() { + break; + } + } + } + }, + Err(err) => { + log::error!("Failed to start cm ipc server: {}", err); + *EXIT.lock().unwrap() = true; + } + } + } +} + +// functions called in main process. +pub mod client { + use hbb_common::anyhow::Context; + + use super::*; + + lazy_static::lazy_static! { + pub static ref SHMEM: Arc>> = Default::default(); + pub static ref PORTABLE_SERVICE_STATUS: Arc> = Default::default(); + static ref SENDER : Mutex> = Mutex::new(client::start_ipc_client()); + } + + #[derive(Debug, Clone, Copy, PartialEq, Eq)] + pub enum PortableServiceStatus { + NotStarted, + Starting, + Running, + } + + impl Default for PortableServiceStatus { + fn default() -> Self { + Self::NotStarted + } + } + + pub(crate) fn start_portable_service() -> ResultType<()> { + if PORTABLE_SERVICE_STATUS.lock().unwrap().clone() == PortableServiceStatus::NotStarted { + if SHMEM.lock().unwrap().is_none() { + let displays = scrap::Display::all()?; + if displays.is_empty() { + bail!("no display available!"); + } + let mut max_pixel = 0; + let align = 64; + for d in displays { + let pixel = utils::align(d.width(), align) * utils::align(d.height(), align); + if max_pixel < pixel { + max_pixel = pixel; + } + } + let shmem_size = utils::align(ADDR_CAPTURE_FRAME + max_pixel * 4, align); + // os error 112, no enough space + *SHMEM.lock().unwrap() = Some(crate::portable_service::SharedMemory::create( + crate::portable_service::SHMEM_NAME, + shmem_size, + )?); + shutdown_hooks::add_shutdown_hook(drop_shmem); + } + if crate::common::run_me(vec!["--portable-service"]).is_err() { + *SHMEM.lock().unwrap() = None; + bail!("Failed to run portable service process"); + } + *PORTABLE_SERVICE_STATUS.lock().unwrap() = PortableServiceStatus::Starting; + let _sender = SENDER.lock().unwrap(); + } + Ok(()) + } + + extern "C" fn drop_shmem() { + log::info!("drop shared memory"); + *SHMEM.lock().unwrap() = None; + } + + pub struct CapturerPortable; + + impl CapturerPortable { + pub fn new(current_display: usize, use_yuv: bool) -> Self + where + Self: Sized, + { + Self::set_para(CapturerPara { + current_display, + use_yuv, + timeout_ms: 33, + }); + CapturerPortable {} + } + + fn set_para(para: CapturerPara) { + let mut option = SHMEM.lock().unwrap(); + let shmem = option.as_mut().unwrap(); + let para_ptr = ¶ as *const CapturerPara as *const u8; + let para_data; + unsafe { + para_data = slice::from_raw_parts(para_ptr, size_of::()); + } + shmem.write(ADDR_CAPTURER_PARA, para_data); + } + } + + impl TraitCapturer for CapturerPortable { + fn set_use_yuv(&mut self, use_yuv: bool) { + let mut option = SHMEM.lock().unwrap(); + let shmem = option.as_mut().unwrap(); + unsafe { + let para_ptr = shmem.as_ptr().add(ADDR_CAPTURER_PARA); + let para = para_ptr as *const CapturerPara; + if use_yuv != (*para).use_yuv { + Self::set_para(CapturerPara { + current_display: (*para).current_display, + use_yuv, + timeout_ms: (*para).timeout_ms, + }); + } + } + } + + fn frame<'a>(&'a mut self, timeout: Duration) -> std::io::Result> { + let mut option = SHMEM.lock().unwrap(); + let shmem = option.as_mut().unwrap(); + unsafe { + let base = shmem.as_ptr(); + let para_ptr = base.add(ADDR_CAPTURER_PARA); + let para = para_ptr as *const CapturerPara; + if timeout.as_millis() != (*para).timeout_ms as _ { + Self::set_para(CapturerPara { + current_display: (*para).current_display, + use_yuv: (*para).use_yuv, + timeout_ms: timeout.as_millis() as _, + }); + } + if utils::counter_ready(base.add(ADDR_CAPTURE_FRAME_COUNTER)) { + let frame_len_ptr = base.add(ADDR_CAPTURE_FRAME_SIZE); + let frame_len = utils::ptr_to_i32(frame_len_ptr); + let frame_ptr = base.add(ADDR_CAPTURE_FRAME); + let data = slice::from_raw_parts(frame_ptr, frame_len as usize); + Ok(Frame(data)) + } else { + let ptr = base.add(ADDR_CAPTURE_WOULDBLOCK); + let wouldblock = utils::ptr_to_i32(ptr); + if wouldblock == TRUE { + Err(std::io::Error::new( + std::io::ErrorKind::WouldBlock, + "wouldblock error".to_string(), + )) + } else { + Err(std::io::Error::new( + std::io::ErrorKind::Other, + "other error".to_string(), + )) + } + } + } + } + + fn is_gdi(&self) -> bool { + true + } + + fn set_gdi(&mut self) -> bool { + true + } + } + + pub(super) fn start_ipc_client() -> mpsc::UnboundedSender { + let (tx, rx) = mpsc::unbounded_channel::(); + std::thread::spawn(move || start_ipc_client_async(rx)); + tx + } + + #[tokio::main(flavor = "current_thread")] + async fn start_ipc_client_async(rx: mpsc::UnboundedReceiver) { + use DataPortableService::*; + let mut rx = rx; + let mut connect_failed = 0; + loop { + if PORTABLE_SERVICE_STATUS.lock().unwrap().clone() == PortableServiceStatus::NotStarted + { + sleep(1.).await; + continue; + } + if let Ok(mut c) = ipc::connect(1000, IPC_PROFIX).await { + let mut nack = 0; + let mut timer = tokio::time::interval(Duration::from_secs(1)); + loop { + tokio::select! { + res = c.next() => { + match res { + Err(err) => { + log::error!("ipc connection closed: {}", err); + break; + } + Ok(Some(Data::DataPortableService(data))) => { + match data { + Ping => { + c.send(&Data::DataPortableService(Pong)).await.ok(); + } + Pong => { + nack = 0; + *PORTABLE_SERVICE_STATUS.lock().unwrap() = PortableServiceStatus::Running; + }, + ConnCount(None) => { + let cnt = crate::server::CONN_COUNT.lock().unwrap().clone(); + c.send(&Data::DataPortableService(ConnCount(Some(cnt)))).await.ok(); + }, + WillClose => { + log::info!("portable service will close, set status to not started"); + *PORTABLE_SERVICE_STATUS.lock().unwrap() = PortableServiceStatus::NotStarted; + break; + } + _=>{} + } + } + _ => {} + } + } + _ = timer.tick() => { + nack+=1; + if nack > MAX_NACK { + // In fact, this will not happen, ipc will be closed before max nack. + log::error!("max ipc nack, set status to not started"); + *PORTABLE_SERVICE_STATUS.lock().unwrap() = PortableServiceStatus::NotStarted; + break; + } + c.send(&Data::DataPortableService(Ping)).await.ok(); + } + Some(data) = rx.recv() => { + allow_err!(c.send(&data).await); + } + + } + } + } else { + connect_failed += 1; + if connect_failed > IPC_CONN_TIMEOUT.as_secs() { + connect_failed = 0; + *PORTABLE_SERVICE_STATUS.lock().unwrap() = PortableServiceStatus::NotStarted; + log::info!( + "connect failed {} times, set status to not started", + connect_failed + ); + } + log::info!( + "client ip connect failed, status:{:?}", + PORTABLE_SERVICE_STATUS.lock().unwrap().clone(), + ); + } + sleep(1.).await; + } + } + + fn client_ipc_send(data: Data) -> ResultType<()> { + let sender = SENDER.lock().unwrap(); + sender + .send(data) + .map_err(|e| anyhow!("ipc send error:{:?}", e)) + } + + fn get_cursor_info_(shmem: &mut SharedMemory, pci: PCURSORINFO) -> BOOL { + unsafe { + let shmem_addr_para = shmem.as_ptr().add(ADDR_CURSOR_PARA); + if utils::counter_ready(shmem.as_ptr().add(ADDR_CURSOR_COUNTER)) { + std::ptr::copy_nonoverlapping(shmem_addr_para, pci as _, size_of::()); + return TRUE; + } + FALSE + } + } + + fn handle_mouse_(evt: &MouseEvent) -> ResultType<()> { + let mut v = vec![]; + evt.write_to_vec(&mut v)?; + client_ipc_send(Data::DataPortableService(DataPortableService::Mouse(v))) + } + + fn handle_key_(evt: &KeyEvent) -> ResultType<()> { + let mut v = vec![]; + evt.write_to_vec(&mut v)?; + client_ipc_send(Data::DataPortableService(DataPortableService::Key(v))) + } + + pub fn create_capturer( + current_display: usize, + display: scrap::Display, + use_yuv: bool, + ) -> ResultType> { + if PORTABLE_SERVICE_STATUS.lock().unwrap().clone() == PortableServiceStatus::Running { + log::info!("Create shared memeory capturer"); + return Ok(Box::new(CapturerPortable::new(current_display, use_yuv))); + } else { + log::debug!("Create capturer dxgi|gdi"); + return Ok(Box::new( + Capturer::new(display, use_yuv).with_context(|| "Failed to create capturer")?, + )); + } + } + + pub fn get_cursor_info(pci: PCURSORINFO) -> BOOL { + if PORTABLE_SERVICE_STATUS.lock().unwrap().clone() == PortableServiceStatus::Running { + get_cursor_info_(&mut SHMEM.lock().unwrap().as_mut().unwrap(), pci) + } else { + unsafe { winuser::GetCursorInfo(pci) } + } + } + + pub fn handle_mouse(evt: &MouseEvent) { + if PORTABLE_SERVICE_STATUS.lock().unwrap().clone() == PortableServiceStatus::Running { + handle_mouse_(evt).ok(); + } else { + crate::input_service::handle_mouse_(evt); + } + } + + pub fn handle_key(evt: &KeyEvent) { + if PORTABLE_SERVICE_STATUS.lock().unwrap().clone() == PortableServiceStatus::Running { + handle_key_(evt).ok(); + } else { + crate::input_service::handle_key_(evt); + } + } +} + +#[repr(C)] +struct CapturerPara { + current_display: usize, + use_yuv: bool, + timeout_ms: i32, +} diff --git a/src/server/video_qos.rs b/src/server/video_qos.rs index ba67d3fc4..d75596157 100644 --- a/src/server/video_qos.rs +++ b/src/server/video_qos.rs @@ -1,8 +1,8 @@ use super::*; use std::time::Duration; -const FPS: u8 = 30; -const MIN_FPS: u8 = 10; -const MAX_FPS: u8 = 120; +pub const FPS: u8 = 30; +pub const MIN_FPS: u8 = 10; +pub const MAX_FPS: u8 = 120; trait Percent { fn as_percent(&self) -> u32; } diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 81ab494e5..f48fefeec 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -19,6 +19,8 @@ // https://slhck.info/video/2017/03/01/rate-control.html use super::{video_qos::VideoQoS, *}; +#[cfg(windows)] +use crate::portable_service::client::{PortableServiceStatus, PORTABLE_SERVICE_STATUS}; use hbb_common::tokio::sync::{ mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, Mutex as TokioMutex, @@ -49,7 +51,7 @@ pub const SCRAP_X11_REF_URL: &str = "https://rustdesk.com/docs/en/manual/linux/# pub const NAME: &'static str = "video"; lazy_static::lazy_static! { - static ref CURRENT_DISPLAY: Arc> = Arc::new(Mutex::new(usize::MAX)); + pub static ref CURRENT_DISPLAY: Arc> = Arc::new(Mutex::new(usize::MAX)); static ref LAST_ACTIVE: Arc> = Arc::new(Mutex::new(Instant::now())); static ref SWITCH: Arc> = Default::default(); static ref FRAME_FETCHED_NOTIFIER: (UnboundedSender<(i32, Option)>, Arc)>>>) = { @@ -188,6 +190,7 @@ fn create_capturer( privacy_mode_id: i32, display: Display, use_yuv: bool, + current: usize, ) -> ResultType> { #[cfg(not(windows))] let c: Option> = None; @@ -244,17 +247,18 @@ fn create_capturer( } } - let c = match c { - Some(c1) => c1, + match c { + Some(c1) => return Ok(c1), None => { - let c1 = - Capturer::new(display, use_yuv).with_context(|| "Failed to create capturer")?; log::debug!("Create capturer dxgi|gdi"); - Box::new(c1) + #[cfg(windows)] + return crate::portable_service::client::create_capturer(current, display, use_yuv); + #[cfg(not(windows))] + return Ok(Box::new( + Capturer::new(display, use_yuv).with_context(|| "Failed to create capturer")?, + )); } }; - - Ok(c) } #[cfg(windows)] @@ -277,8 +281,8 @@ fn ensure_close_virtual_device() -> ResultType<()> { pub fn test_create_capturer(privacy_mode_id: i32, timeout_millis: u64) -> bool { let test_begin = Instant::now(); while test_begin.elapsed().as_millis() < timeout_millis as _ { - if let Ok((_, _, display)) = get_current_display() { - if let Ok(_) = create_capturer(privacy_mode_id, display, true) { + if let Ok((_, current, display)) = get_current_display() { + if let Ok(_) = create_capturer(privacy_mode_id, display, true, current) { return true; } } @@ -369,7 +373,7 @@ fn get_capturer(use_yuv: bool) -> ResultType { } else { log::info!("In privacy mode, the peer side cannot watch the screen"); } - let capturer = create_capturer(captuerer_privacy_mode_id, display, use_yuv)?; + let capturer = create_capturer(captuerer_privacy_mode_id, display, use_yuv, current)?; Ok(CapturerInfo { origin, width, @@ -468,6 +472,11 @@ fn run(sp: GenericService) -> ResultType<()> { let recorder: Arc>> = Default::default(); #[cfg(windows)] start_uac_elevation_check(); + #[cfg(windows)] + let portable_service_status = crate::portable_service::client::PORTABLE_SERVICE_STATUS + .lock() + .unwrap() + .clone(); #[cfg(target_os = "linux")] let mut would_block_count = 0u32; @@ -498,10 +507,17 @@ fn run(sp: GenericService) -> ResultType<()> { if codec_name != Encoder::current_hw_encoder_name() { bail!("SWITCH"); } + #[cfg(windows)] + if portable_service_status != PORTABLE_SERVICE_STATUS.lock().unwrap().clone() { + bail!("SWITCH"); + } check_privacy_mode_changed(&sp, c.privacy_mode_id)?; #[cfg(windows)] { - if crate::platform::windows::desktop_changed() { + if crate::platform::windows::desktop_changed() + && PORTABLE_SERVICE_STATUS.lock().unwrap().clone() + == PortableServiceStatus::NotStarted + { bail!("Desktop changed"); } } @@ -874,7 +890,7 @@ pub(super) fn get_current_display_2(mut all: Vec) -> ResultType<(usize, return Ok((n, current, all.remove(current))); } -fn get_current_display() -> ResultType<(usize, usize, Display)> { +pub fn get_current_display() -> ResultType<(usize, usize, Display)> { get_current_display_2(try_get_displays()?) } diff --git a/src/ui/cm.css b/src/ui/cm.css index fbbd58961..fccdb155f 100644 --- a/src/ui/cm.css +++ b/src/ui/cm.css @@ -68,7 +68,7 @@ div.permissions { } div.permissions > div { - size: 48px; + size: 42px; background: color(accent); } diff --git a/src/ui/cm.rs b/src/ui/cm.rs index 3472a184e..7c0e3fe24 100644 --- a/src/ui/cm.rs +++ b/src/ui/cm.rs @@ -51,6 +51,10 @@ impl InvokeUiCM for SciterHandler { fn change_language(&self) { // TODO } + + fn show_elevation(&self, show: bool) { + self.call("showElevation", &make_args!(show)); + } } impl SciterHandler { @@ -123,6 +127,14 @@ impl SciterConnectionManager { fn t(&self, name: String) -> String { crate::client::translate(name) } + + fn can_elevate(&self) -> bool { + crate::ui_cm_interface::can_elevate() + } + + fn elevate_portable(&self, id: i32) { + crate::ui_cm_interface::elevate_portable(id); + } } impl sciter::EventHandler for SciterConnectionManager { @@ -141,5 +153,7 @@ impl sciter::EventHandler for SciterConnectionManager { fn authorize(i32); fn switch_permission(i32, String, bool); fn send_msg(i32, String); + fn can_elevate(); + fn elevate_portable(i32); } } diff --git a/src/ui/cm.tis b/src/ui/cm.tis index 2b42b719c..5238ab91a 100644 --- a/src/ui/cm.tis +++ b/src/ui/cm.tis @@ -3,6 +3,7 @@ view.windowFrame = is_osx ? #extended : #solid; var body; var connections = []; var show_chat = false; +var show_elevation = true; class Body: Reactor.Component { @@ -27,6 +28,7 @@ class Body: Reactor.Component }; var right_style = show_chat ? "" : "display: none"; var disconnected = c.disconnected; + var show_elevation_btn = handler.can_elevate() && show_elevation; // below size:* is work around for Linux, it alreayd set in css, but not work, shit sciter return
@@ -55,10 +57,12 @@ class Body: Reactor.Component {c.port_forward ?
Port Forwarding: {c.port_forward}
: ""}
- {auth ? "" : } - {auth ? "" : } - {auth && !disconnected ? : ""} - {auth && disconnected ? : ""} + {!auth && show_elevation_btn ? : "" } + {auth ? "" : } + {auth ? "" : } + {auth && !disconnected && show_elevation_btn ? : "" } + {auth && !disconnected ? : ""} + {auth && disconnected ? : ""}
{c.is_file_transfer || c.port_forward ? "" :
{svg_chat}
}
@@ -144,6 +148,32 @@ class Body: Reactor.Component }); } + event click $(button#elevate_accept) { + var { cid, connection } = this; + checkClickTime(function() { + connection.authorized = true; + show_elevation = false; + body.update(); + handler.elevate_portable(cid); + handler.authorize(cid); + self.timer(30ms, function() { + view.windowState = View.WINDOW_MINIMIZED; + }); + }); + } + + event click $(button#elevate) { + var { cid, connection } = this; + checkClickTime(function() { + show_elevation = false; + body.update(); + handler.elevate_portable(cid); + self.timer(30ms, function() { + view.windowState = View.WINDOW_MINIMIZED; + }); + }); + } + event click $(button#dismiss) { var cid = this.cid; checkClickTime(function() { @@ -386,6 +416,13 @@ handler.newMessage = function(id, text) { update(); } +handler.showElevation = function(show) { + if (show != show_elevation) { + show_elevation = show; + update(); + } +} + view << event statechange { adjustBorder(); } diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 72225b3fb..b1e4db7f8 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -85,6 +85,8 @@ pub trait InvokeUiCM: Send + Clone + 'static + Sized { fn change_theme(&self, dark: String); fn change_language(&self); + + fn show_elevation(&self, show: bool); } impl Deref for ConnectionManager { @@ -171,6 +173,10 @@ impl ConnectionManager { self.ui_handler.remove_connection(id, close); } + + fn show_elevation(&self, show: bool) { + self.ui_handler.show_elevation(show); + } } #[inline] @@ -362,6 +368,9 @@ impl IpcTaskRunner { LocalConfig::set_option("lang".to_owned(), lang); self.cm.change_language(); } + Data::DataPortableService(ipc::DataPortableService::CmShowElevation(show)) => { + self.cm.show_elevation(show); + } _ => { } @@ -757,3 +766,28 @@ fn cm_inner_send(id: i32, data: Data) { } } } + +pub fn can_elevate() -> bool { + #[cfg(windows)] + { + use crate::portable_service::client::{ + PortableServiceStatus::NotStarted, PORTABLE_SERVICE_STATUS, + }; + return !crate::platform::is_installed() + && PORTABLE_SERVICE_STATUS.lock().unwrap().clone() == NotStarted; + } + #[cfg(not(windows))] + return false; +} + +pub fn elevate_portable(id: i32) { + #[cfg(windows)] + { + let lock = CLIENTS.read().unwrap(); + if let Some(s) = lock.get(&id) { + allow_err!(s.tx.send(ipc::Data::DataPortableService( + ipc::DataPortableService::RequestStart + ))); + } + } +} diff --git a/src/ui_interface.rs b/src/ui_interface.rs index a334fb6fb..0e443ad61 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -10,8 +10,7 @@ use hbb_common::password_security; use hbb_common::{ allow_err, config::{self, Config, LocalConfig, PeerConfig}, - directories_next, log, - sleep, + directories_next, log, sleep, tokio::{self, sync::mpsc, time}, }; @@ -376,7 +375,7 @@ pub fn is_installed() -> bool { #[cfg(any(target_os = "android", target_os = "ios"))] #[inline] -pub fn is_installed() -> bool { +pub fn is_installed() -> bool { false } From e186eec5df9b238def11dcf81af06cf26ae6dc55 Mon Sep 17 00:00:00 2001 From: 21pages Date: Thu, 10 Nov 2022 17:06:27 +0800 Subject: [PATCH 031/116] portable service: optimize flutter cm buttons Signed-off-by: 21pages --- flutter/lib/desktop/pages/server_page.dart | 264 +++++++++------------ 1 file changed, 112 insertions(+), 152 deletions(-) diff --git a/flutter/lib/desktop/pages/server_page.dart b/flutter/lib/desktop/pages/server_page.dart index aac6ee017..16abe0b64 100644 --- a/flutter/lib/desktop/pages/server_page.dart +++ b/flutter/lib/desktop/pages/server_page.dart @@ -76,7 +76,6 @@ class _DesktopServerPageState extends State mainAxisAlignment: MainAxisAlignment.start, children: [ Expanded(child: ConnectionManager()), - SizedBox.fromSize(size: Size(0, 15.0)), ], ), ), @@ -486,6 +485,8 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> { } } +const double bigMargin = 15; + class _CmControlPanel extends StatelessWidget { final Client client; @@ -503,180 +504,139 @@ class _CmControlPanel extends StatelessWidget { buildAuthorized(BuildContext context) { final bool canElevate = bind.cmCanElevate(); final model = Provider.of(context); - final offstage = !(canElevate && model.showElevation); - final width = offstage ? 200.0 : 100.0; - return Row( - mainAxisAlignment: MainAxisAlignment.center, + final showElevation = canElevate && model.showElevation; + return Column( + mainAxisAlignment: MainAxisAlignment.end, children: [ Offstage( - offstage: offstage, - child: Ink( - width: width, - height: 40, - decoration: BoxDecoration( - color: Colors.green[700], - borderRadius: BorderRadius.circular(10)), - child: InkWell( - onTap: () => - checkClickTime(client.id, () => handleElevate(context)), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.security_sharp, - color: Colors.white, - ), - Text( - translate("Elevate"), - style: TextStyle(color: Colors.white), - ), - ], - )), - ), + offstage: !showElevation, + child: buildButton(context, color: Colors.green[700], onClick: () { + handleElevate(context); + windowManager.minimize(); + }, + icon: Icon( + Icons.security_sharp, + color: Colors.white, + ), + text: 'Elevate', + textColor: Colors.white), ), - Offstage( - offstage: offstage, - child: SizedBox( - width: 30, - )), - Ink( - width: width, - height: 40, - decoration: BoxDecoration( - color: Colors.redAccent, borderRadius: BorderRadius.circular(10)), - child: InkWell( - onTap: () => - checkClickTime(client.id, () => handleDisconnect(context)), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - translate("Disconnect"), - style: TextStyle(color: Colors.white), - ), - ], - )), + Row( + children: [ + Expanded( + child: buildButton(context, + color: Colors.redAccent, + onClick: handleDisconnect, + text: 'Disconnect', + textColor: Colors.white)), + ], ) ], - ); + ) + .marginOnly(bottom: showElevation ? 0 : bigMargin) + .marginSymmetric(horizontal: showElevation ? 0 : bigMargin); } buildDisconnected(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Ink( - width: 200, - height: 40, - decoration: BoxDecoration( - color: MyTheme.accent, borderRadius: BorderRadius.circular(10)), - child: InkWell( - onTap: () => handleClose(context), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - translate("Close"), - style: TextStyle(color: Colors.white), - ), - ], - )), - ) + Expanded( + child: buildButton(context, + color: MyTheme.accent, + onClick: handleClose, + text: 'Close', + textColor: Colors.white)), ], - ); + ).marginOnly(bottom: 15).marginSymmetric(horizontal: bigMargin); } buildUnAuthorized(BuildContext context) { final bool canElevate = bind.cmCanElevate(); final model = Provider.of(context); - final offstage = !(canElevate && model.showElevation); - final width = offstage ? 100.0 : 85.0; - final spacerWidth = offstage ? 30.0 : 5.0; - return Row( - mainAxisAlignment: MainAxisAlignment.center, + final showElevation = canElevate && model.showElevation; + return Column( + mainAxisAlignment: MainAxisAlignment.end, children: [ Offstage( - offstage: offstage, - child: Ink( - height: 40, - width: width, - decoration: BoxDecoration( - color: Colors.green[700], - borderRadius: BorderRadius.circular(10)), - child: InkWell( - onTap: () => checkClickTime(client.id, () { - handleAccept(context); - handleElevate(context); - windowManager.minimize(); - }), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.security_sharp, - color: Colors.white, - ), - Text( - translate("Accept"), - style: TextStyle(color: Colors.white), - ), - ], - )), - ), + offstage: !showElevation, + child: buildButton(context, color: Colors.green[700], onClick: () { + handleAccept(context); + handleElevate(context); + windowManager.minimize(); + }, + text: 'Accept', + icon: Icon( + Icons.security_sharp, + color: Colors.white, + ), + textColor: Colors.white), ), - Offstage( - offstage: offstage, - child: SizedBox( - width: spacerWidth, - )), - Ink( - width: width, - height: 40, - decoration: BoxDecoration( - color: MyTheme.accent, borderRadius: BorderRadius.circular(10)), - child: InkWell( - onTap: () => checkClickTime(client.id, () { - handleAccept(context); - windowManager.minimize(); - }), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - translate("Accept"), - style: TextStyle(color: Colors.white), - ), - ], - )), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: buildButton(context, color: MyTheme.accent, onClick: () { + handleAccept(context); + windowManager.minimize(); + }, text: 'Accept', textColor: Colors.white)), + Expanded( + child: buildButton(context, + color: Colors.transparent, + border: Border.all(color: Colors.grey), + onClick: handleDisconnect, + text: 'Cancel', + textColor: null)), + ], ), - SizedBox( - width: spacerWidth, - ), - Ink( - width: width, - height: 40, - decoration: BoxDecoration( - color: Colors.transparent, - borderRadius: BorderRadius.circular(10), - border: Border.all(color: Colors.grey)), - child: InkWell( - onTap: () => - checkClickTime(client.id, () => handleDisconnect(context)), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - translate("Cancel"), - style: TextStyle(), - ), - ], - )), - ) ], - ); + ) + .marginOnly(bottom: showElevation ? 0 : bigMargin) + .marginSymmetric(horizontal: showElevation ? 0 : bigMargin); } - void handleDisconnect(BuildContext context) { + buildButton( + BuildContext context, { + required Color? color, + required Function() onClick, + Icon? icon, + BoxBorder? border, + required String text, + required Color? textColor, + }) { + Widget textWidget; + if (icon != null) { + textWidget = Text( + translate(text), + style: TextStyle(color: textColor), + textAlign: TextAlign.center, + ); + } else { + textWidget = Expanded( + child: Text( + translate(text), + style: TextStyle(color: textColor), + textAlign: TextAlign.center, + ), + ); + } + return Container( + height: 35, + decoration: BoxDecoration( + color: color, borderRadius: BorderRadius.circular(4), border: border), + child: InkWell( + onTap: () => checkClickTime(client.id, onClick), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Offstage(offstage: icon == null, child: icon), + textWidget, + ], + )), + ).marginAll(4); + } + + void handleDisconnect() { bind.cmCloseConnection(connId: client.id); } @@ -691,7 +651,7 @@ class _CmControlPanel extends StatelessWidget { bind.cmElevatePortable(connId: client.id); } - void handleClose(BuildContext context) async { + void handleClose() async { await bind.cmRemoveDisconnectedConnection(connId: client.id); if (await bind.cmGetClientsLength() == 0) { windowManager.close(); From 9f73b89f217f20924a4767f822fb0c0e11973dd3 Mon Sep 17 00:00:00 2001 From: 21pages Date: Fri, 11 Nov 2022 11:40:23 +0800 Subject: [PATCH 032/116] portable-service: exchange ipc server/client Signed-off-by: 21pages --- src/server/connection.rs | 48 ++-- src/server/portable_service.rs | 426 +++++++++++++++------------------ src/server/video_service.rs | 38 +-- src/ui_cm_interface.rs | 8 +- 4 files changed, 239 insertions(+), 281 deletions(-) diff --git a/src/server/connection.rs b/src/server/connection.rs index c77f6ebd7..8674c6d9d 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -429,31 +429,31 @@ impl Connection { _ = second_timer.tick() => { #[cfg(windows)] { - use crate::portable_service::client::{PORTABLE_SERVICE_STATUS, PortableServiceStatus::*}; - let uac = crate::video_service::IS_UAC_RUNNING.lock().unwrap().clone(); - if last_uac != uac { - last_uac = uac; - if PORTABLE_SERVICE_STATUS.lock().unwrap().clone() == NotStarted { - let mut misc = Misc::new(); - misc.set_uac(uac); - let mut msg = Message::new(); - msg.set_misc(misc); - conn.inner.send(msg.into()); - } - } - let foreground_window_elevated = crate::video_service::IS_FOREGROUND_WINDOW_ELEVATED.lock().unwrap().clone(); - if last_foreground_window_elevated != foreground_window_elevated { - last_foreground_window_elevated = foreground_window_elevated; - if PORTABLE_SERVICE_STATUS.lock().unwrap().clone() == NotStarted { - let mut misc = Misc::new(); - misc.set_foreground_window_elevated(foreground_window_elevated); - let mut msg = Message::new(); - msg.set_misc(misc); - conn.inner.send(msg.into()); - } - } if !is_installed { - let show_elevation = PORTABLE_SERVICE_STATUS.lock().unwrap().clone() == NotStarted; + let portable_service_running = crate::portable_service::client::PORTABLE_SERVICE_RUNNING.lock().unwrap().clone(); + let uac = crate::video_service::IS_UAC_RUNNING.lock().unwrap().clone(); + if last_uac != uac { + last_uac = uac; + if !portable_service_running { + let mut misc = Misc::new(); + misc.set_uac(uac); + let mut msg = Message::new(); + msg.set_misc(misc); + conn.inner.send(msg.into()); + } + } + let foreground_window_elevated = crate::video_service::IS_FOREGROUND_WINDOW_ELEVATED.lock().unwrap().clone(); + if last_foreground_window_elevated != foreground_window_elevated { + last_foreground_window_elevated = foreground_window_elevated; + if !portable_service_running { + let mut misc = Misc::new(); + misc.set_foreground_window_elevated(foreground_window_elevated); + let mut msg = Message::new(); + msg.set_misc(misc); + conn.inner.send(msg.into()); + } + } + let show_elevation = !portable_service_running; conn.send_to_cm(ipc::Data::DataPortableService(ipc::DataPortableService::CmShowElevation(show_elevation))); } diff --git a/src/server/portable_service.rs b/src/server/portable_service.rs index 1de2a1c8b..a666b56d5 100644 --- a/src/server/portable_service.rs +++ b/src/server/portable_service.rs @@ -7,7 +7,6 @@ use hbb_common::{ log, message_proto::{KeyEvent, MouseEvent}, protobuf::Message, - sleep, tokio::{self, sync::mpsc}, ResultType, }; @@ -17,7 +16,7 @@ use std::{ mem::size_of, ops::{Deref, DerefMut}, sync::{Arc, Mutex}, - time::Duration, + time::{Duration, Instant}, }; use winapi::{ shared::minwindef::{BOOL, FALSE, TRUE}, @@ -48,18 +47,6 @@ const ADDR_CAPTURE_FRAME: usize = const IPC_PROFIX: &str = "_portable_service"; pub const SHMEM_NAME: &str = "_portable_service"; const MAX_NACK: usize = 3; -const IPC_CONN_TIMEOUT: Duration = Duration::from_secs(3); - -pub enum PortableServiceStatus { - NonStart, - Running, -} - -impl Default for PortableServiceStatus { - fn default() -> Self { - Self::NonStart - } -} pub struct SharedMemory { inner: Shmem, @@ -200,8 +187,6 @@ mod utils { // functions called in seperate SYSTEM user process. pub mod server { - use hbb_common::tokio::time::Instant; - use super::*; lazy_static::lazy_static! { @@ -220,7 +205,7 @@ pub mod server { run_capture(shmem2); })); threads.push(std::thread::spawn(|| { - run_ipc_server(); + run_ipc_client(); })); threads.push(std::thread::spawn(|| { run_exit_check(); @@ -270,7 +255,7 @@ pub mod server { if EXIT.lock().unwrap().clone() { break; } - let start = std::time::Instant::now(); + let start = Instant::now(); unsafe { let para_ptr = shmem.as_ptr().add(ADDR_CAPTURER_PARA); let para = para_ptr as *const CapturerPara; @@ -278,7 +263,6 @@ pub mod server { let use_yuv = (*para).use_yuv; let timeout_ms = (*para).timeout_ms; if c.is_none() { - let use_yuv = true; *crate::video_service::CURRENT_DISPLAY.lock().unwrap() = current_display; let (_, _current, display) = get_current_display().unwrap(); match Capturer::new(display, use_yuv) { @@ -348,114 +332,78 @@ pub mod server { } #[tokio::main(flavor = "current_thread")] - async fn run_ipc_server() { + async fn run_ipc_client() { use DataPortableService::*; let postfix = IPC_PROFIX; - let last_recv_time = Arc::new(Mutex::new(Instant::now())); - let mut interval = tokio::time::interval(Duration::from_secs(1)); - match new_listener(postfix).await { - Ok(mut incoming) => loop { - tokio::select! { - Some(result) = incoming.next() => { - match result { - Ok(stream) => { - log::info!("Got new connection"); - let last_recv_time_cloned = last_recv_time.clone(); - tokio::spawn(async move { - let mut stream = Connection::new(stream); - let postfix = postfix.to_owned(); - let mut timer = tokio::time::interval(Duration::from_secs(1)); - let mut nack = 0; - let mut old_conn_count = 0; - loop { - tokio::select! { - res = stream.next() => { - if res.is_ok() { - *last_recv_time_cloned.lock().unwrap() = Instant::now(); - } - match res { - Err(err) => { - log::error!( - "ipc{} connection closed: {}", - postfix, - err - ); - *EXIT.lock().unwrap() = true; - break; - } - Ok(Some(Data::DataPortableService(data))) => match data { - Ping => { - allow_err!( - stream - .send(&Data::DataPortableService(Pong)) - .await - ); - } - Pong => { - nack = 0; - } - ConnCount(Some(n)) => { - if old_conn_count != 0 && n == 0 { - log::info!("Connection count decrease to 0, exit"); - stream.send(&Data::DataPortableService(WillClose)).await.ok(); - *EXIT.lock().unwrap() = true; - break; - } - old_conn_count = n; - } - Mouse(v) => { - if let Ok(evt) = MouseEvent::parse_from_bytes(&v) { - crate::input_service::handle_mouse_(&evt); - } - } - Key(v) => { - if let Ok(evt) = KeyEvent::parse_from_bytes(&v) { - crate::input_service::handle_key_(&evt); - } - } - _ => {} - }, - _ => {} - } - } - _ = timer.tick() => { - nack+=1; - if nack > MAX_NACK { - log::info!("max ping nack, exit"); - *EXIT.lock().unwrap() = true; - break; - } - stream.send(&Data::DataPortableService(Ping)).await.ok(); - stream.send(&Data::DataPortableService(ConnCount(None))).await.ok(); - } + match ipc::connect(1000, postfix).await { + Ok(mut stream) => { + let mut timer = tokio::time::interval(Duration::from_secs(1)); + let mut nack = 0; + loop { + tokio::select! { + res = stream.next() => { + match res { + Err(err) => { + log::error!( + "ipc{} connection closed: {}", + postfix, + err + ); + break; + } + Ok(Some(Data::DataPortableService(data))) => match data { + Ping => { + allow_err!( + stream + .send(&Data::DataPortableService(Pong)) + .await + ); + } + Pong => { + nack = 0; + } + ConnCount(Some(n)) => { + if n == 0 { + log::info!("Connnection count equals 0, exit"); + stream.send(&Data::DataPortableService(WillClose)).await.ok(); + break; } } - }); - } - Err(err) => { - log::error!("Couldn't get portable client: {:?}", err); - *EXIT.lock().unwrap() = true; + Mouse(v) => { + if let Ok(evt) = MouseEvent::parse_from_bytes(&v) { + crate::input_service::handle_mouse_(&evt); + } + } + Key(v) => { + if let Ok(evt) = KeyEvent::parse_from_bytes(&v) { + crate::input_service::handle_key_(&evt); + } + } + _ => {} + }, + _ => {} } } - } - _ = interval.tick() => { - if last_recv_time.lock().unwrap().elapsed() > IPC_CONN_TIMEOUT { - log::error!("receive data timeout"); - *EXIT.lock().unwrap() = true; - } - if EXIT.lock().unwrap().clone() { - break; + _ = timer.tick() => { + nack+=1; + if nack > MAX_NACK { + log::info!("max ping nack, exit"); + break; + } + stream.send(&Data::DataPortableService(Ping)).await.ok(); + stream.send(&Data::DataPortableService(ConnCount(None))).await.ok(); } } } - }, - Err(err) => { - log::error!("Failed to start cm ipc server: {}", err); - *EXIT.lock().unwrap() = true; + } + Err(e) => { + log::error!("Failed to connect portable service ipc:{:?}", e); } } + + *EXIT.lock().unwrap() = true; } } @@ -466,54 +414,46 @@ pub mod client { use super::*; lazy_static::lazy_static! { - pub static ref SHMEM: Arc>> = Default::default(); - pub static ref PORTABLE_SERVICE_STATUS: Arc> = Default::default(); - static ref SENDER : Mutex> = Mutex::new(client::start_ipc_client()); - } - - #[derive(Debug, Clone, Copy, PartialEq, Eq)] - pub enum PortableServiceStatus { - NotStarted, - Starting, - Running, - } - - impl Default for PortableServiceStatus { - fn default() -> Self { - Self::NotStarted - } + pub static ref PORTABLE_SERVICE_RUNNING: Arc> = Default::default(); + static ref SHMEM: Arc>> = Default::default(); + static ref SENDER : Mutex> = Mutex::new(client::start_ipc_server()); } pub(crate) fn start_portable_service() -> ResultType<()> { - if PORTABLE_SERVICE_STATUS.lock().unwrap().clone() == PortableServiceStatus::NotStarted { - if SHMEM.lock().unwrap().is_none() { - let displays = scrap::Display::all()?; - if displays.is_empty() { - bail!("no display available!"); - } - let mut max_pixel = 0; - let align = 64; - for d in displays { - let pixel = utils::align(d.width(), align) * utils::align(d.height(), align); - if max_pixel < pixel { - max_pixel = pixel; - } - } - let shmem_size = utils::align(ADDR_CAPTURE_FRAME + max_pixel * 4, align); - // os error 112, no enough space - *SHMEM.lock().unwrap() = Some(crate::portable_service::SharedMemory::create( - crate::portable_service::SHMEM_NAME, - shmem_size, - )?); - shutdown_hooks::add_shutdown_hook(drop_shmem); - } - if crate::common::run_me(vec!["--portable-service"]).is_err() { - *SHMEM.lock().unwrap() = None; - bail!("Failed to run portable service process"); - } - *PORTABLE_SERVICE_STATUS.lock().unwrap() = PortableServiceStatus::Starting; - let _sender = SENDER.lock().unwrap(); + if PORTABLE_SERVICE_RUNNING.lock().unwrap().clone() { + bail!("already running"); } + if SHMEM.lock().unwrap().is_none() { + let displays = scrap::Display::all()?; + if displays.is_empty() { + bail!("no display available!"); + } + let mut max_pixel = 0; + let align = 64; + for d in displays { + let pixel = utils::align(d.width(), align) * utils::align(d.height(), align); + if max_pixel < pixel { + max_pixel = pixel; + } + } + let shmem_size = utils::align(ADDR_CAPTURE_FRAME + max_pixel * 4, align); + // os error 112, no enough space + *SHMEM.lock().unwrap() = Some(crate::portable_service::SharedMemory::create( + crate::portable_service::SHMEM_NAME, + shmem_size, + )?); + shutdown_hooks::add_shutdown_hook(drop_shmem); + } + let mut option = SHMEM.lock().unwrap(); + let shmem = option.as_mut().unwrap(); + unsafe { + libc::memset(shmem.as_ptr() as _, 0, shmem.len() as _); + } + if crate::common::run_me(vec!["--portable-service"]).is_err() { + *SHMEM.lock().unwrap() = None; + bail!("Failed to run portable service process"); + } + let _sender = SENDER.lock().unwrap(); Ok(()) } @@ -613,94 +553,98 @@ pub mod client { } } - pub(super) fn start_ipc_client() -> mpsc::UnboundedSender { + pub(super) fn start_ipc_server() -> mpsc::UnboundedSender { let (tx, rx) = mpsc::unbounded_channel::(); - std::thread::spawn(move || start_ipc_client_async(rx)); + std::thread::spawn(move || start_ipc_server_async(rx)); tx } #[tokio::main(flavor = "current_thread")] - async fn start_ipc_client_async(rx: mpsc::UnboundedReceiver) { + async fn start_ipc_server_async(rx: mpsc::UnboundedReceiver) { use DataPortableService::*; - let mut rx = rx; - let mut connect_failed = 0; - loop { - if PORTABLE_SERVICE_STATUS.lock().unwrap().clone() == PortableServiceStatus::NotStarted - { - sleep(1.).await; - continue; - } - if let Ok(mut c) = ipc::connect(1000, IPC_PROFIX).await { - let mut nack = 0; - let mut timer = tokio::time::interval(Duration::from_secs(1)); - loop { - tokio::select! { - res = c.next() => { - match res { - Err(err) => { - log::error!("ipc connection closed: {}", err); - break; - } - Ok(Some(Data::DataPortableService(data))) => { - match data { - Ping => { - c.send(&Data::DataPortableService(Pong)).await.ok(); - } - Pong => { - nack = 0; - *PORTABLE_SERVICE_STATUS.lock().unwrap() = PortableServiceStatus::Running; - }, - ConnCount(None) => { - let cnt = crate::server::CONN_COUNT.lock().unwrap().clone(); - c.send(&Data::DataPortableService(ConnCount(Some(cnt)))).await.ok(); - }, - WillClose => { - log::info!("portable service will close, set status to not started"); - *PORTABLE_SERVICE_STATUS.lock().unwrap() = PortableServiceStatus::NotStarted; - break; - } - _=>{} - } - } - _ => {} - } - } - _ = timer.tick() => { - nack+=1; - if nack > MAX_NACK { - // In fact, this will not happen, ipc will be closed before max nack. - log::error!("max ipc nack, set status to not started"); - *PORTABLE_SERVICE_STATUS.lock().unwrap() = PortableServiceStatus::NotStarted; - break; - } - c.send(&Data::DataPortableService(Ping)).await.ok(); - } - Some(data) = rx.recv() => { - allow_err!(c.send(&data).await); - } + let rx = Arc::new(tokio::sync::Mutex::new(rx)); + let postfix = IPC_PROFIX; + match new_listener(postfix).await { + Ok(mut incoming) => loop { + { + tokio::select! { + Some(result) = incoming.next() => { + match result { + Ok(stream) => { + log::info!("Got portable service ipc connection"); + let rx_clone = rx.clone(); + tokio::spawn(async move { + let mut stream = Connection::new(stream); + let postfix = postfix.to_owned(); + let mut timer = tokio::time::interval(Duration::from_secs(1)); + let mut nack = 0; + let mut rx = rx_clone.lock().await; + loop { + tokio::select! { + res = stream.next() => { + match res { + Err(err) => { + log::info!( + "ipc{} connection closed: {}", + postfix, + err + ); + break; + } + Ok(Some(Data::DataPortableService(data))) => match data { + Ping => { + stream.send(&Data::DataPortableService(Pong)).await.ok(); + } + Pong => { + nack = 0; + *PORTABLE_SERVICE_RUNNING.lock().unwrap() = true; + }, + ConnCount(None) => { + let cnt = crate::server::CONN_COUNT.lock().unwrap().clone(); + stream.send(&Data::DataPortableService(ConnCount(Some(cnt)))).await.ok(); + }, + WillClose => { + log::info!("portable service will close"); + break; + } + _=>{} + } + _=>{} + } + } + _ = timer.tick() => { + nack+=1; + if nack > MAX_NACK { + // In fact, this will not happen, ipc will be closed before max nack. + log::error!("max ipc nack"); + break; + } + stream.send(&Data::DataPortableService(Ping)).await.ok(); + } + Some(data) = rx.recv() => { + allow_err!(stream.send(&data).await); + } + } + } + *PORTABLE_SERVICE_RUNNING.lock().unwrap() = false; + }); + } + Err(err) => { + log::error!("Couldn't get portable client: {:?}", err); + } + } + } } } - } else { - connect_failed += 1; - if connect_failed > IPC_CONN_TIMEOUT.as_secs() { - connect_failed = 0; - *PORTABLE_SERVICE_STATUS.lock().unwrap() = PortableServiceStatus::NotStarted; - log::info!( - "connect failed {} times, set status to not started", - connect_failed - ); - } - log::info!( - "client ip connect failed, status:{:?}", - PORTABLE_SERVICE_STATUS.lock().unwrap().clone(), - ); + }, + Err(err) => { + log::error!("Failed to start portable service ipc server: {}", err); } - sleep(1.).await; } } - fn client_ipc_send(data: Data) -> ResultType<()> { + fn ipc_send(data: Data) -> ResultType<()> { let sender = SENDER.lock().unwrap(); sender .send(data) @@ -721,21 +665,25 @@ pub mod client { fn handle_mouse_(evt: &MouseEvent) -> ResultType<()> { let mut v = vec![]; evt.write_to_vec(&mut v)?; - client_ipc_send(Data::DataPortableService(DataPortableService::Mouse(v))) + ipc_send(Data::DataPortableService(DataPortableService::Mouse(v))) } fn handle_key_(evt: &KeyEvent) -> ResultType<()> { let mut v = vec![]; evt.write_to_vec(&mut v)?; - client_ipc_send(Data::DataPortableService(DataPortableService::Key(v))) + ipc_send(Data::DataPortableService(DataPortableService::Key(v))) } pub fn create_capturer( current_display: usize, display: scrap::Display, use_yuv: bool, + portable_service_running: bool, ) -> ResultType> { - if PORTABLE_SERVICE_STATUS.lock().unwrap().clone() == PortableServiceStatus::Running { + if portable_service_running != PORTABLE_SERVICE_RUNNING.lock().unwrap().clone() { + log::info!("portable service status mismatch"); + } + if portable_service_running { log::info!("Create shared memeory capturer"); return Ok(Box::new(CapturerPortable::new(current_display, use_yuv))); } else { @@ -747,7 +695,7 @@ pub mod client { } pub fn get_cursor_info(pci: PCURSORINFO) -> BOOL { - if PORTABLE_SERVICE_STATUS.lock().unwrap().clone() == PortableServiceStatus::Running { + if PORTABLE_SERVICE_RUNNING.lock().unwrap().clone() { get_cursor_info_(&mut SHMEM.lock().unwrap().as_mut().unwrap(), pci) } else { unsafe { winuser::GetCursorInfo(pci) } @@ -755,7 +703,7 @@ pub mod client { } pub fn handle_mouse(evt: &MouseEvent) { - if PORTABLE_SERVICE_STATUS.lock().unwrap().clone() == PortableServiceStatus::Running { + if PORTABLE_SERVICE_RUNNING.lock().unwrap().clone() { handle_mouse_(evt).ok(); } else { crate::input_service::handle_mouse_(evt); @@ -763,7 +711,7 @@ pub mod client { } pub fn handle_key(evt: &KeyEvent) { - if PORTABLE_SERVICE_STATUS.lock().unwrap().clone() == PortableServiceStatus::Running { + if PORTABLE_SERVICE_RUNNING.lock().unwrap().clone() { handle_key_(evt).ok(); } else { crate::input_service::handle_key_(evt); diff --git a/src/server/video_service.rs b/src/server/video_service.rs index f48fefeec..43ce013f5 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -20,7 +20,7 @@ use super::{video_qos::VideoQoS, *}; #[cfg(windows)] -use crate::portable_service::client::{PortableServiceStatus, PORTABLE_SERVICE_STATUS}; +use crate::portable_service::client::PORTABLE_SERVICE_RUNNING; use hbb_common::tokio::sync::{ mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, Mutex as TokioMutex, @@ -191,6 +191,7 @@ fn create_capturer( display: Display, use_yuv: bool, current: usize, + _portable_service_running: bool, ) -> ResultType> { #[cfg(not(windows))] let c: Option> = None; @@ -252,7 +253,12 @@ fn create_capturer( None => { log::debug!("Create capturer dxgi|gdi"); #[cfg(windows)] - return crate::portable_service::client::create_capturer(current, display, use_yuv); + return crate::portable_service::client::create_capturer( + current, + display, + use_yuv, + _portable_service_running, + ); #[cfg(not(windows))] return Ok(Box::new( Capturer::new(display, use_yuv).with_context(|| "Failed to create capturer")?, @@ -282,7 +288,7 @@ pub fn test_create_capturer(privacy_mode_id: i32, timeout_millis: u64) -> bool { let test_begin = Instant::now(); while test_begin.elapsed().as_millis() < timeout_millis as _ { if let Ok((_, current, display)) = get_current_display() { - if let Ok(_) = create_capturer(privacy_mode_id, display, true, current) { + if let Ok(_) = create_capturer(privacy_mode_id, display, true, current, false) { return true; } } @@ -331,7 +337,7 @@ impl DerefMut for CapturerInfo { } } -fn get_capturer(use_yuv: bool) -> ResultType { +fn get_capturer(use_yuv: bool, portable_service_running: bool) -> ResultType { #[cfg(target_os = "linux")] { if !scrap::is_x11() { @@ -373,7 +379,13 @@ fn get_capturer(use_yuv: bool) -> ResultType { } else { log::info!("In privacy mode, the peer side cannot watch the screen"); } - let capturer = create_capturer(captuerer_privacy_mode_id, display, use_yuv, current)?; + let capturer = create_capturer( + captuerer_privacy_mode_id, + display, + use_yuv, + current, + portable_service_running, + )?; Ok(CapturerInfo { origin, width, @@ -393,8 +405,12 @@ fn run(sp: GenericService) -> ResultType<()> { // ensure_inited() is needed because release_resouce() may be called. #[cfg(target_os = "linux")] super::wayland::ensure_inited()?; + #[cfg(windows)] + let last_portable_service_running = PORTABLE_SERVICE_RUNNING.lock().unwrap().clone(); + #[cfg(not(windows))] + let last_portable_service_running = false; - let mut c = get_capturer(true)?; + let mut c = get_capturer(true, last_portable_service_running)?; let mut video_qos = VIDEO_QOS.lock().unwrap(); video_qos.set_size(c.width as _, c.height as _); @@ -472,11 +488,6 @@ fn run(sp: GenericService) -> ResultType<()> { let recorder: Arc>> = Default::default(); #[cfg(windows)] start_uac_elevation_check(); - #[cfg(windows)] - let portable_service_status = crate::portable_service::client::PORTABLE_SERVICE_STATUS - .lock() - .unwrap() - .clone(); #[cfg(target_os = "linux")] let mut would_block_count = 0u32; @@ -508,15 +519,14 @@ fn run(sp: GenericService) -> ResultType<()> { bail!("SWITCH"); } #[cfg(windows)] - if portable_service_status != PORTABLE_SERVICE_STATUS.lock().unwrap().clone() { + if last_portable_service_running != PORTABLE_SERVICE_RUNNING.lock().unwrap().clone() { bail!("SWITCH"); } check_privacy_mode_changed(&sp, c.privacy_mode_id)?; #[cfg(windows)] { if crate::platform::windows::desktop_changed() - && PORTABLE_SERVICE_STATUS.lock().unwrap().clone() - == PortableServiceStatus::NotStarted + && !PORTABLE_SERVICE_RUNNING.lock().unwrap().clone() { bail!("Desktop changed"); } diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index b1e4db7f8..26b26bf92 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -770,11 +770,11 @@ fn cm_inner_send(id: i32, data: Data) { pub fn can_elevate() -> bool { #[cfg(windows)] { - use crate::portable_service::client::{ - PortableServiceStatus::NotStarted, PORTABLE_SERVICE_STATUS, - }; return !crate::platform::is_installed() - && PORTABLE_SERVICE_STATUS.lock().unwrap().clone() == NotStarted; + && !crate::portable_service::client::PORTABLE_SERVICE_RUNNING + .lock() + .unwrap() + .clone(); } #[cfg(not(windows))] return false; From bee19bfe176c7032d59248182e1d7767037f7446 Mon Sep 17 00:00:00 2001 From: 21pages Date: Fri, 11 Nov 2022 20:44:16 +0800 Subject: [PATCH 033/116] portable-service: optimize sciter cm buttons Signed-off-by: 21pages --- src/ui/cm.css | 42 +++++++++++++++++++++++++++++++++--------- src/ui/cm.tis | 18 +++++++++++------- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/src/ui/cm.css b/src/ui/cm.css index fccdb155f..ff4d422e4 100644 --- a/src/ui/cm.css +++ b/src/ui/cm.css @@ -112,20 +112,44 @@ icon.recording { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAANpJREFUWEftltENAiEMhtsJ1NcynG6gI+gGugEOR591gppeQoIYSDBILxEeydH/57u2FMF4obE+TAOTwLoIhBDOAHBExG2n6rgR0akW640AM0sn4SWMiDycc7s8JjN7Ijro/k8NqAAR5RoeAPZxv2ggP9hCJiWZxtGbq3hqbJiBVHy4gVx8qAER8Yi4JFy6huVAKXemgb8icI+1b5KEitq0DOO/Nm1EEX1TK27p/bVvv36MOhl4EtHHbFF7jq8AoG1z08OAiFycczrkFNe6RrIet26NMQlMAuYEXiayryF/QQktAAAAAElFTkSuQmCC'); } -div.buttons { - width: *; - border-spacing: 0.5em; - text-align: center; +div.outer_buttons { + flow:vertical; + border-spacing:8; } -div.buttons button { - width: 80px; - height: 40px; - margin: 0.5em; +div.inner_buttons { + flow:horizontal; + border-spacing:8; +} + +button.control { + width: *; +} + +button.elevate { + background:green; +} + +button.elevate:active { + background: rgb(2, 104, 2); + border-color: color(hover-border); +} + +button.elevate>span { + flow:horizontal; + width: *; +} + +button.elevate>span>span { + margin-left:*; + margin-right:*; +} + +button.elevate>span>span>span { + vertical-align: middle; } button#disconnect { - width: 160px; background: color(blood-red); border: none; } diff --git a/src/ui/cm.tis b/src/ui/cm.tis index 5238ab91a..035b58650 100644 --- a/src/ui/cm.tis +++ b/src/ui/cm.tis @@ -4,6 +4,7 @@ var body; var connections = []; var show_chat = false; var show_elevation = true; +var svg_elevate = ; class Body: Reactor.Component { @@ -56,14 +57,17 @@ class Body: Reactor.Component } {c.port_forward ?
Port Forwarding: {c.port_forward}
: ""}
-
- {!auth && show_elevation_btn ? : "" } - {auth ? "" : } - {auth ? "" : } - {auth && !disconnected && show_elevation_btn ? : "" } - {auth && !disconnected ? : ""} - {auth && disconnected ? : ""} +
+ {!auth && !disconnected && show_elevation_btn ? : "" } + {auth && !disconnected && show_elevation_btn ? : "" } +
+ {!auth ? : "" } + {!auth ? : "" } +
+ {auth && !disconnected ? : "" } + {auth && disconnected ? : "" }
+
{c.is_file_transfer || c.port_forward ? "" :
{svg_chat}
}
From 4d492cb2c6bf83f904625a9c87de99115b23f905 Mon Sep 17 00:00:00 2001 From: 21pages Date: Sat, 12 Nov 2022 17:18:26 +0800 Subject: [PATCH 034/116] portable-service: fix set capture para dead lock Signed-off-by: 21pages --- src/server/portable_service.rs | 45 ++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/src/server/portable_service.rs b/src/server/portable_service.rs index a666b56d5..d78038ecd 100644 --- a/src/server/portable_service.rs +++ b/src/server/portable_service.rs @@ -469,17 +469,20 @@ pub mod client { where Self: Sized, { - Self::set_para(CapturerPara { - current_display, - use_yuv, - timeout_ms: 33, - }); + let mut option = SHMEM.lock().unwrap(); + let shmem = option.as_mut().unwrap(); + Self::set_para( + shmem, + CapturerPara { + current_display, + use_yuv, + timeout_ms: 33, + }, + ); CapturerPortable {} } - fn set_para(para: CapturerPara) { - let mut option = SHMEM.lock().unwrap(); - let shmem = option.as_mut().unwrap(); + fn set_para(shmem: &mut SharedMemory, para: CapturerPara) { let para_ptr = ¶ as *const CapturerPara as *const u8; let para_data; unsafe { @@ -497,11 +500,14 @@ pub mod client { let para_ptr = shmem.as_ptr().add(ADDR_CAPTURER_PARA); let para = para_ptr as *const CapturerPara; if use_yuv != (*para).use_yuv { - Self::set_para(CapturerPara { - current_display: (*para).current_display, - use_yuv, - timeout_ms: (*para).timeout_ms, - }); + Self::set_para( + shmem, + CapturerPara { + current_display: (*para).current_display, + use_yuv, + timeout_ms: (*para).timeout_ms, + }, + ); } } } @@ -514,11 +520,14 @@ pub mod client { let para_ptr = base.add(ADDR_CAPTURER_PARA); let para = para_ptr as *const CapturerPara; if timeout.as_millis() != (*para).timeout_ms as _ { - Self::set_para(CapturerPara { - current_display: (*para).current_display, - use_yuv: (*para).use_yuv, - timeout_ms: timeout.as_millis() as _, - }); + Self::set_para( + shmem, + CapturerPara { + current_display: (*para).current_display, + use_yuv: (*para).use_yuv, + timeout_ms: timeout.as_millis() as _, + }, + ); } if utils::counter_ready(base.add(ADDR_CAPTURE_FRAME_COUNTER)) { let frame_len_ptr = base.add(ADDR_CAPTURE_FRAME_SIZE); From 8c529a1159dc98b2c3d9866a03c15d56b062023d Mon Sep 17 00:00:00 2001 From: 21pages Date: Sun, 13 Nov 2022 16:33:22 +0800 Subject: [PATCH 035/116] portable-service: add yuv set flag to fix start splash Signed-off-by: 21pages --- src/server/portable_service.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/server/portable_service.rs b/src/server/portable_service.rs index d78038ecd..9256c9a71 100644 --- a/src/server/portable_service.rs +++ b/src/server/portable_service.rs @@ -261,7 +261,13 @@ pub mod server { let para = para_ptr as *const CapturerPara; let current_display = (*para).current_display; let use_yuv = (*para).use_yuv; + let use_yuv_set = (*para).use_yuv_set; let timeout_ms = (*para).timeout_ms; + if !use_yuv_set { + c = None; + std::thread::sleep(spf); + continue; + } if c.is_none() { *crate::video_service::CURRENT_DISPLAY.lock().unwrap() = current_display; let (_, _current, display) = get_current_display().unwrap(); @@ -476,6 +482,7 @@ pub mod client { CapturerPara { current_display, use_yuv, + use_yuv_set: false, timeout_ms: 33, }, ); @@ -499,16 +506,15 @@ pub mod client { unsafe { let para_ptr = shmem.as_ptr().add(ADDR_CAPTURER_PARA); let para = para_ptr as *const CapturerPara; - if use_yuv != (*para).use_yuv { - Self::set_para( - shmem, - CapturerPara { - current_display: (*para).current_display, - use_yuv, - timeout_ms: (*para).timeout_ms, - }, - ); - } + Self::set_para( + shmem, + CapturerPara { + current_display: (*para).current_display, + use_yuv, + use_yuv_set: true, + timeout_ms: (*para).timeout_ms, + }, + ); } } @@ -525,6 +531,7 @@ pub mod client { CapturerPara { current_display: (*para).current_display, use_yuv: (*para).use_yuv, + use_yuv_set: (*para).use_yuv_set, timeout_ms: timeout.as_millis() as _, }, ); @@ -732,5 +739,6 @@ pub mod client { struct CapturerPara { current_display: usize, use_yuv: bool, + use_yuv_set: bool, timeout_ms: i32, } From 3f77b6bc6498e92f5b132bbdefba7059c21c2325 Mon Sep 17 00:00:00 2001 From: 21pages Date: Sun, 13 Nov 2022 17:01:09 +0800 Subject: [PATCH 036/116] portable service: sync capture counter to make continuous frame, which will decrease fps Signed-off-by: 21pages --- src/server/portable_service.rs | 41 +++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/src/server/portable_service.rs b/src/server/portable_service.rs index 9256c9a71..9e3f11bc7 100644 --- a/src/server/portable_service.rs +++ b/src/server/portable_service.rs @@ -172,11 +172,28 @@ mod utils { } } - pub fn increase_counter(ptr: *mut u8) { + pub fn counter_equal(counter: *const u8) -> bool { unsafe { - let i = ptr_to_i32(ptr); - let v = i32_to_vec(i + 1); - std::ptr::copy_nonoverlapping(v.as_ptr(), ptr, size_of::()); + let wptr = counter; + let rptr = counter.add(size_of::()); + let iw = ptr_to_i32(wptr); + let ir = ptr_to_i32(rptr); + iw == ir + } + } + + pub fn increase_counter(counter: *mut u8) { + unsafe { + let wptr = counter; + let rptr = counter.add(size_of::()); + let iw = ptr_to_i32(counter); + let ir = ptr_to_i32(counter); + let v = i32_to_vec(iw + 1); + std::ptr::copy_nonoverlapping(v.as_ptr(), wptr, size_of::()); + if ir == iw + 1 { + let v = i32_to_vec(iw); + std::ptr::copy_nonoverlapping(v.as_ptr(), rptr, size_of::()); + } } } @@ -212,7 +229,7 @@ pub mod server { })); for th in threads.drain(..) { th.join().unwrap(); - log::info!("all thread joined"); + log::info!("thread joined"); } } @@ -251,11 +268,11 @@ pub mod server { let mut last_use_yuv = false; let mut last_timeout_ms: i32 = 33; let mut spf = Duration::from_millis(last_timeout_ms as _); + let mut first_frame_captured = false; loop { if EXIT.lock().unwrap().clone() { break; } - let start = Instant::now(); unsafe { let para_ptr = shmem.as_ptr().add(ADDR_CAPTURER_PARA); let para = para_ptr as *const CapturerPara; @@ -276,6 +293,7 @@ pub mod server { c = { last_current_display = current_display; last_use_yuv = use_yuv; + first_frame_captured = false; // dxgi failed at loadFrame on my PC. // to-do: try dxgi on another PC. v.set_gdi(); @@ -308,6 +326,12 @@ pub mod server { spf = Duration::from_millis(timeout_ms as _); } } + if first_frame_captured { + if !utils::counter_equal(shmem.as_ptr().add(ADDR_CAPTURE_FRAME_COUNTER)) { + std::thread::sleep(spf); + continue; + } + } match c.as_mut().unwrap().frame(spf) { Ok(f) => { let len = f.0.len(); @@ -316,6 +340,7 @@ pub mod server { shmem.write(ADDR_CAPTURE_FRAME, f.0); shmem.write(ADDR_CAPTURE_WOULDBLOCK, &utils::i32_to_vec(TRUE)); utils::increase_counter(shmem.as_ptr().add(ADDR_CAPTURE_FRAME_COUNTER)); + first_frame_captured = true; } Err(e) => { if e.kind() != std::io::ErrorKind::WouldBlock { @@ -330,10 +355,6 @@ pub mod server { } } } - let elapsed = start.elapsed(); - if elapsed < spf { - std::thread::sleep(spf - elapsed); - } } } From 45bfb0e22e4440080bfdd7927ff3358adf0a288e Mon Sep 17 00:00:00 2001 From: 21pages Date: Sun, 13 Nov 2022 18:38:24 +0800 Subject: [PATCH 037/116] portable-service: run background Signed-off-by: 21pages --- src/platform/windows.rs | 21 +++++++++++++++++++++ src/server/portable_service.rs | 7 ++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/platform/windows.rs b/src/platform/windows.rs index b418d0904..34f132894 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -1480,6 +1480,27 @@ pub fn get_user_token(session_id: u32, as_user: bool) -> HANDLE { } } +pub fn run_background(exe: &str, arg: &str) -> ResultType { + let wexe = wide_string(exe); + let warg; + unsafe { + let ret = ShellExecuteW( + NULL as _, + NULL as _, + wexe.as_ptr() as _, + if arg.is_empty() { + NULL as _ + } else { + warg = wide_string(arg); + warg.as_ptr() as _ + }, + NULL as _, + SW_HIDE, + ); + return Ok(ret as i32 > 32); + } +} + pub fn run_uac(exe: &str, arg: &str) -> ResultType { let wop = wide_string("runas"); let wexe = wide_string(exe); diff --git a/src/server/portable_service.rs b/src/server/portable_service.rs index 9e3f11bc7..54f7a92dd 100644 --- a/src/server/portable_service.rs +++ b/src/server/portable_service.rs @@ -476,7 +476,12 @@ pub mod client { unsafe { libc::memset(shmem.as_ptr() as _, 0, shmem.len() as _); } - if crate::common::run_me(vec!["--portable-service"]).is_err() { + if crate::platform::run_background( + &std::env::current_exe()?.to_string_lossy().to_string(), + "--portable-service", + ) + .is_err() + { *SHMEM.lock().unwrap() = None; bail!("Failed to run portable service process"); } From abd665153b331de07646eb3499130a4af7906627 Mon Sep 17 00:00:00 2001 From: 21pages Date: Sun, 13 Nov 2022 20:15:38 +0800 Subject: [PATCH 038/116] portable-service: try dxgi before gdi, which not controlled by video_service Signed-off-by: 21pages --- src/server/portable_service.rs | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/server/portable_service.rs b/src/server/portable_service.rs index 54f7a92dd..48cdcbe51 100644 --- a/src/server/portable_service.rs +++ b/src/server/portable_service.rs @@ -47,6 +47,7 @@ const ADDR_CAPTURE_FRAME: usize = const IPC_PROFIX: &str = "_portable_service"; pub const SHMEM_NAME: &str = "_portable_service"; const MAX_NACK: usize = 3; +const MAX_DXGI_FAIL_TIME: usize = 5; pub struct SharedMemory { inner: Shmem, @@ -269,6 +270,7 @@ pub mod server { let mut last_timeout_ms: i32 = 33; let mut spf = Duration::from_millis(last_timeout_ms as _); let mut first_frame_captured = false; + let mut dxgi_failed_times = 0; loop { if EXIT.lock().unwrap().clone() { break; @@ -294,9 +296,10 @@ pub mod server { last_current_display = current_display; last_use_yuv = use_yuv; first_frame_captured = false; - // dxgi failed at loadFrame on my PC. - // to-do: try dxgi on another PC. - v.set_gdi(); + if dxgi_failed_times > MAX_DXGI_FAIL_TIME { + dxgi_failed_times = 0; + v.set_gdi(); + } Some(v) } } @@ -341,14 +344,26 @@ pub mod server { shmem.write(ADDR_CAPTURE_WOULDBLOCK, &utils::i32_to_vec(TRUE)); utils::increase_counter(shmem.as_ptr().add(ADDR_CAPTURE_FRAME_COUNTER)); first_frame_captured = true; + dxgi_failed_times = 0; } Err(e) => { if e.kind() != std::io::ErrorKind::WouldBlock { - log::error!("capture frame failed:{:?}", e); - crate::platform::try_change_desktop(); - c = None; - shmem.write(ADDR_CAPTURE_WOULDBLOCK, &utils::i32_to_vec(FALSE)); - continue; + // DXGI_ERROR_INVALID_CALL after each success on Microsoft GPU driver + // log::error!("capture frame failed:{:?}", e); + if crate::platform::windows::desktop_changed() { + crate::platform::try_change_desktop(); + c = None; + std::thread::sleep(spf); + continue; + } + if !c.as_ref().unwrap().is_gdi() { + dxgi_failed_times += 1; + } + if dxgi_failed_times > MAX_DXGI_FAIL_TIME { + c = None; + shmem.write(ADDR_CAPTURE_WOULDBLOCK, &utils::i32_to_vec(FALSE)); + std::thread::sleep(spf); + } } else { shmem.write(ADDR_CAPTURE_WOULDBLOCK, &utils::i32_to_vec(TRUE)); } @@ -512,6 +527,7 @@ pub mod client { timeout_ms: 33, }, ); + shmem.write(ADDR_CAPTURE_WOULDBLOCK, &utils::i32_to_vec(TRUE)); CapturerPortable {} } @@ -586,6 +602,7 @@ pub mod client { } } + // control by itself fn is_gdi(&self) -> bool { true } From ca8cb5a3b0f74af7c2c9764905b0239a27135963 Mon Sep 17 00:00:00 2001 From: 21pages Date: Tue, 15 Nov 2022 16:49:55 +0800 Subject: [PATCH 039/116] portable-service: better prompt message Signed-off-by: 21pages --- flutter/lib/common.dart | 21 ++++++---- flutter/lib/desktop/pages/remote_page.dart | 2 +- .../lib/desktop/widgets/remote_menubar.dart | 2 +- .../lib/mobile/pages/file_manager_page.dart | 3 +- flutter/lib/mobile/pages/remote_page.dart | 4 +- flutter/lib/mobile/widgets/dialog.dart | 6 +-- flutter/lib/models/model.dart | 11 ++++- src/client/io_loop.rs | 42 ++++++++++--------- src/flutter.rs | 7 +++- src/lang/cn.rs | 5 +-- src/lang/cs.rs | 5 +-- src/lang/da.rs | 5 +-- src/lang/de.rs | 5 +-- src/lang/en.rs | 4 +- src/lang/eo.rs | 5 +-- src/lang/es.rs | 5 +-- src/lang/fa.rs | 5 +-- src/lang/fr.rs | 5 +-- src/lang/hu.rs | 5 +-- src/lang/id.rs | 5 +-- src/lang/it.rs | 5 +-- src/lang/ja.rs | 5 +-- src/lang/ko.rs | 5 +-- src/lang/kz.rs | 5 +-- src/lang/pl.rs | 5 +-- src/lang/pt_PT.rs | 5 +-- src/lang/ptbr.rs | 5 +-- src/lang/ru.rs | 5 +-- src/lang/sk.rs | 5 +-- src/lang/template.rs | 5 +-- src/lang/tr.rs | 5 +-- src/lang/tw.rs | 5 +-- src/lang/ua.rs | 5 +-- src/lang/vn.rs | 5 +-- src/server/connection.rs | 9 ++-- src/ui/common.tis | 8 ++++ src/ui/remote.rs | 9 +++- src/ui_session_interface.rs | 7 ++-- 38 files changed, 131 insertions(+), 124 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 93fe0fee5..483aba384 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -627,7 +627,7 @@ class CustomAlertDialog extends StatelessWidget { } } -void msgBox(String type, String title, String text, String link, +void msgBox(String id, String type, String title, String text, String link, OverlayDialogManager dialogManager, {bool? hasCancel}) { dialogManager.dismissAll(); @@ -672,14 +672,17 @@ void msgBox(String type, String title, String text, String link, if (link.isNotEmpty) { buttons.insert(0, msgBoxButton(translate('JumpLink'), jumplink)); } - dialogManager.show((setState, close) => CustomAlertDialog( - title: _msgBoxTitle(title), - content: SelectableText(translate(text), - style: const TextStyle(fontSize: 15)), - actions: buttons, - onSubmit: hasOk ? submit : null, - onCancel: hasCancel == true ? cancel : null, - )); + dialogManager.show( + (setState, close) => CustomAlertDialog( + title: _msgBoxTitle(title), + content: + SelectableText(translate(text), style: const TextStyle(fontSize: 15)), + actions: buttons, + onSubmit: hasOk ? submit : null, + onCancel: hasCancel == true ? cancel : null, + ), + tag: '$id-$type-$title-$text-$link', + ); } Widget msgBoxButton(String text, void Function() onPressed) { diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index 2b8c99940..dae3fa612 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -163,7 +163,7 @@ class _RemotePageState extends State super.build(context); return WillPopScope( onWillPop: () async { - clientClose(_ffi.dialogManager); + clientClose(widget.id, _ffi.dialogManager); return false; }, child: MultiProvider(providers: [ diff --git a/flutter/lib/desktop/widgets/remote_menubar.dart b/flutter/lib/desktop/widgets/remote_menubar.dart index 75311c4c5..cdbeb0bed 100644 --- a/flutter/lib/desktop/widgets/remote_menubar.dart +++ b/flutter/lib/desktop/widgets/remote_menubar.dart @@ -489,7 +489,7 @@ class _RemoteMenubarState extends State { return IconButton( tooltip: translate('Close'), onPressed: () { - clientClose(widget.ffi.dialogManager); + clientClose(widget.id, widget.ffi.dialogManager); }, icon: const Icon( Icons.close, diff --git a/flutter/lib/mobile/pages/file_manager_page.dart b/flutter/lib/mobile/pages/file_manager_page.dart index 3221cdbaa..6e5c91484 100644 --- a/flutter/lib/mobile/pages/file_manager_page.dart +++ b/flutter/lib/mobile/pages/file_manager_page.dart @@ -63,7 +63,8 @@ class _FileManagerPageState extends State { leading: Row(children: [ IconButton( icon: Icon(Icons.close), - onPressed: () => clientClose(gFFI.dialogManager)), + onPressed: () => + clientClose(widget.id, gFFI.dialogManager)), ]), centerTitle: true, title: ToggleSwitch( diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index 07304d2d3..719b7dc28 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -223,7 +223,7 @@ class _RemotePageState extends State { return WillPopScope( onWillPop: () async { - clientClose(gFFI.dialogManager); + clientClose(widget.id, gFFI.dialogManager); return false; }, child: getRawPointerAndKeyBody(Scaffold( @@ -304,7 +304,7 @@ class _RemotePageState extends State { color: Colors.white, icon: Icon(Icons.clear), onPressed: () { - clientClose(gFFI.dialogManager); + clientClose(widget.id, gFFI.dialogManager); }, ) ] + diff --git a/flutter/lib/mobile/widgets/dialog.dart b/flutter/lib/mobile/widgets/dialog.dart index 03b36ecf3..96f96658a 100644 --- a/flutter/lib/mobile/widgets/dialog.dart +++ b/flutter/lib/mobile/widgets/dialog.dart @@ -5,9 +5,9 @@ import '../../common.dart'; import '../../models/model.dart'; import '../../models/platform_model.dart'; -void clientClose(OverlayDialogManager dialogManager) { - msgBox( - '', 'Close', 'Are you sure to close the connection?', '', dialogManager); +void clientClose(String id, OverlayDialogManager dialogManager) { + msgBox(id, '', 'Close', 'Are you sure to close the connection?', '', + dialogManager); } void showSuccess() { diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index fb4f8b4f4..a39bc7d08 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -195,6 +195,8 @@ class FfiModel with ChangeNotifier { } else if (name == 'show_elevation') { final show = evt['show'].toString() == 'true'; parent.target?.serverModel.setShowElevation(show); + } else if (name == 'cancel_msgbox') { + cancelMsgBox(evt, peerId); } }; } @@ -231,6 +233,13 @@ class FfiModel with ChangeNotifier { notifyListeners(); } + cancelMsgBox(Map evt, String id) { + if (parent.target == null) return; + final dialogManager = parent.target!.dialogManager; + final tag = '$id-${evt['tag']}'; + dialogManager.dismissByTag(tag); + } + /// Handle the message box event based on [evt] and [id]. handleMsgBox(Map evt, String id) { if (parent.target == null) return; @@ -256,7 +265,7 @@ class FfiModel with ChangeNotifier { showMsgBox(String id, String type, String title, String text, String link, bool hasRetry, OverlayDialogManager dialogManager, {bool? hasCancel}) { - msgBox(type, title, text, link, dialogManager, hasCancel: hasCancel); + msgBox(id, type, title, text, link, dialogManager, hasCancel: hasCancel); _timer?.cancel(); if (hasRetry) { _timer = Timer(Duration(seconds: _reconnects), () { diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 04d1d4d29..6eb443103 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -20,18 +20,14 @@ use hbb_common::fs::{ use hbb_common::message_proto::permission_info::Permission; use hbb_common::protobuf::Message as _; use hbb_common::rendezvous_proto::ConnType; +#[cfg(windows)] +use hbb_common::tokio::sync::Mutex as TokioMutex; use hbb_common::tokio::{ self, sync::mpsc, time::{self, Duration, Instant, Interval}, }; -#[cfg(windows)] -use hbb_common::tokio::sync::Mutex as TokioMutex; -use hbb_common::{ - allow_err, - message_proto::*, - sleep, -}; +use hbb_common::{allow_err, message_proto::*, sleep}; use hbb_common::{fs, log, Stream}; use std::collections::HashMap; @@ -998,23 +994,31 @@ impl Remote { } } Some(misc::Union::Uac(uac)) => { + let msgtype = "custom-uac-nocancel"; + let title = "Prompt"; + let text = "Please wait for confirmation of UAC..."; + let link = ""; if uac { - self.handler.msgbox( - "custom-uac-nocancel", - "Warning", - "uac_warning", - "", - ); + self.handler.msgbox(msgtype, title, text, link); + } else { + self.handler + .cancel_msgbox( + &format!("{}-{}-{}-{}", msgtype, title, text, link,), + ); } } Some(misc::Union::ForegroundWindowElevated(elevated)) => { + let msgtype = "custom-elevated-foreground-nocancel"; + let title = "Prompt"; + let text = "elevated_foreground_window_tip"; + let link = ""; if elevated { - self.handler.msgbox( - "custom-elevated-foreground-nocancel", - "Warning", - "elevated_foreground_window_warning", - "", - ); + self.handler.msgbox(msgtype, title, text, link); + } else { + self.handler + .cancel_msgbox( + &format!("{}-{}-{}-{}", msgtype, title, text, link,), + ); } } _ => {} diff --git a/src/flutter.rs b/src/flutter.rs index a69473e5a..9c4208625 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -228,8 +228,7 @@ impl InvokeUiSession for FlutterHandler { id: i32, entries: &Vec, path: String, - #[allow(unused_variables)] - is_local: bool, + #[allow(unused_variables)] is_local: bool, only_count: bool, ) { // TODO opt @@ -327,6 +326,10 @@ impl InvokeUiSession for FlutterHandler { ); } + fn cancel_msgbox(&self, tag: &str) { + self.push_event("cancel_msgbox", vec![("tag", tag)]); + } + fn new_message(&self, msg: String) { self.push_event("chat_client_mode", vec![("text", &msg)]); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index b622123a0..68c5dbf60 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", "拒绝局域网发现"), ("Write a message", "输入聊天消息"), ("Prompt", "提示"), - ("elevation_prompt", "以当前用户权限运行软件,可能导致远端在访问本机时,没有足够的权限来操作部分窗口。"), - ("uac_warning", "暂时无法访问远端设备,因为远端设备正在请求用户账户权限,请等待对方关闭UAC窗口。为避免这个问题,建议在远端设备上安装或者以管理员权限运行本软件。"), - ("elevated_foreground_window_warning", "暂时无法使用鼠标键盘,因为远端桌面的当前窗口需要更高的权限才能操作, 可以请求对方最小化当前窗口。为避免这个问题,建议在远端设备上安装或者以管理员权限运行本软件。"), + ("Please wait for confirmation of UAC...", "请等待对方确认UAC..."), + ("elevated_foreground_window_tip", "远端桌面的当前窗口需要更高的权限才能操作, 暂时无法使用鼠标键盘, 可以请求对方最小化当前窗口, 或者在连接管理窗口点击提升。为避免这个问题,建议在远端设备上安装本软件。"), ("Disconnected", "会话已结束"), ("Other", "其他"), ("Confirm before closing multiple tabs", "关闭多个标签页时向您确认"), diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 5c086bfb2..98bb9c5d3 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", ""), ("Write a message", ""), ("Prompt", ""), - ("elevation_prompt", ""), - ("uac_warning", ""), - ("elevated_foreground_window_warning", ""), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", ""), ("Other", ""), ("Confirm before closing multiple tabs", ""), diff --git a/src/lang/da.rs b/src/lang/da.rs index 90670804a..b98e5ba3f 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", "Afvis LAN Discovery"), ("Write a message", "Skriv en besked"), ("Prompt", ""), - ("elevation_prompt", ""), - ("uac_warning", ""), - ("elevated_foreground_window_warning", ""), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", "Afbrudt"), ("Other", ""), ("Confirm before closing multiple tabs", ""), diff --git a/src/lang/de.rs b/src/lang/de.rs index 6ebea6b2e..1e8083915 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", "LAN-Erkennung verbieten"), ("Write a message", "Nachricht schreiben"), ("Prompt", ""), - ("elevation_prompt", ""), - ("uac_warning", ""), - ("elevated_foreground_window_warning", ""), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", ""), ("Other", ""), ("Confirm before closing multiple tabs", ""), diff --git a/src/lang/en.rs b/src/lang/en.rs index 3415fa463..ee68d4431 100644 --- a/src/lang/en.rs +++ b/src/lang/en.rs @@ -30,9 +30,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("android_open_battery_optimizations_tip", "If you want to disable this feature, please go to the next RustDesk application settings page, find and enter [Battery], Uncheck [Unrestricted]"), ("remote_restarting_tip", "Remote device is restarting, please close this message box and reconnect with permanent password after a while"), ("Are you sure to close the connection?", "Are you sure you want to close the connection?"), - ("elevation_prompt", "Running software without privilege elevation may cause problems when remote users operate certain windows."), - ("uac_warning", "Temporarily denied access due to elevation request, please wait for the remote user to accept the UAC dialog. To avoid this problem, it is recommended to install the software on the remote device or run it with administrator privileges."), - ("elevated_foreground_window_warning", "Temporarily unable to use the mouse and keyboard, because the current window of the remote desktop requires higher privilege to operate, you can request the remote user to minimize the current window. To avoid this problem, it is recommended to install the software on the remote device or run it with administrator privileges."), + ("elevated_foreground_window_tip", "The current window of the remote desktop requires higher privilege to operate, so it's unable to use the mouse and keyboard temporarily. You can request the remote user to minimize the current window, or click elevation button on the connection management window. To avoid this problem, it is recommended to install the software on the remote device."), ("JumpLink", "View"), ("Stop service", "Stop Service"), ("or", ""), diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 2dce72f6e..93394a91f 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", ""), ("Write a message", ""), ("Prompt", ""), - ("elevation_prompt", ""), - ("uac_warning", ""), - ("elevated_foreground_window_warning", ""), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", ""), ("Other", ""), ("Confirm before closing multiple tabs", ""), diff --git a/src/lang/es.rs b/src/lang/es.rs index 2e70a5194..a00009b78 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", "Denegar descubrimiento de LAN"), ("Write a message", "Escribir un mensaje"), ("Prompt", ""), - ("elevation_prompt", ""), - ("uac_warning", ""), - ("elevated_foreground_window_warning", ""), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", "Desconectado"), ("Other", "Otro"), ("Confirm before closing multiple tabs", "Confirmar antes de cerrar múltiples pestañas"), diff --git a/src/lang/fa.rs b/src/lang/fa.rs index f9a15dc9e..b6c3d002b 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", "غیر فعالسازی جستجو در شبکه"), ("Write a message", "یک پیام بنویسید"), ("Prompt", ""), - ("elevation_prompt", "اجرای نرم‌افزار بدون افزایش امتیاز می‌تواند باعث ایجاد مشکلاتی در هنگام کار کردن کاربران راه دور با ویندوزهای خاص شود"), - ("uac_warning", "به دلیل درخواست دسترسی سطح بالا، به طور موقت از دسترسی رد شد. منتظر بمانید تا کاربر راه دور گفتگوی UAC را بپذیرد. برای جلوگیری از این مشکل، توصیه می شود نرم افزار را روی دستگاه از راه دور نصب کنید یا آن را با دسترسی مدیر اجرا کنید."), - ("elevated_foreground_window_warning", "به طور موقت استفاده از ماوس و صفحه کلید امکان پذیر نیست زیرا پنجره دسکتاپ از راه دور فعلی برای کار کردن به دسترسی های بالاتر نیاز دارد، می توانید از کاربر راه دور بخواهید که پنجره فعلی را به حداقل برساند. برای جلوگیری از این مشکل، توصیه می شود نرم افزار را روی یک دستگاه راه دور نصب کنید یا آن را با دسترسی مدیر اجرا کنید"), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", "قطع ارتباط"), ("Other", "دیگر"), ("Confirm before closing multiple tabs", "بستن چندین برگه را تأیید کنید"), diff --git a/src/lang/fr.rs b/src/lang/fr.rs index 811ec911d..ff4e2e083 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", "Interdir la découverte réseau local"), ("Write a message", "Ecrire un message"), ("Prompt", ""), - ("elevation_prompt", ""), - ("uac_warning", ""), - ("elevated_foreground_window_warning", ""), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", "Déconnecté"), ("Other", "Divers"), ("Confirm before closing multiple tabs", "Confirmer avant de fermer plusieurs onglets"), diff --git a/src/lang/hu.rs b/src/lang/hu.rs index 863fa3739..9bd5de216 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", "Felfedezés tiltása"), ("Write a message", "Üzenet írása"), ("Prompt", ""), - ("elevation_prompt", "A szoftver jogosultságnövelés nélküli futtatása problémákat okozhat, ha távoli felhasználók bizonyos ablakokat működtetnek."), - ("uac_warning", "Kérjük, várja meg, amíg a távoli felhasználó elfogadja az UAC párbeszédpanelt. A probléma elkerülése érdekében javasoljuk, hogy telepítse a szoftvert a távoli eszközre, vagy futtassa rendszergazdai jogosultságokkal."), - ("elevated_foreground_window_warning", "Átmenetileg nem tudja használni az egeret és a billentyűzetet, mert a távoli asztal aktuális ablakának működéséhez magasabb jogosultság szükséges, ezért kérheti a távoli felhasználót, hogy minimalizálja az aktuális ablakot. A probléma elkerülése érdekében javasoljuk, hogy telepítse a szoftvert a távoli eszközre, vagy futtassa rendszergazdai jogosultságokkal."), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", "Szétkapcsolva"), ("Other", "Egyéb"), ("Confirm before closing multiple tabs", "Biztos, hogy bezárja az összes lapot?"), diff --git a/src/lang/id.rs b/src/lang/id.rs index 78fccc9f3..7d4ae1634 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", "Tolak Penemuan LAN"), ("Write a message", "Menulis pesan"), ("Prompt", ""), - ("elevation_prompt", ""), - ("uac_warning", ""), - ("elevated_foreground_window_warning", ""), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", "Terputus"), ("Other", "Lainnya"), ("Confirm before closing multiple tabs", "Konfirmasi sebelum menutup banyak tab"), diff --git a/src/lang/it.rs b/src/lang/it.rs index 35c09a0b2..3490a9b77 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", ""), ("Write a message", ""), ("Prompt", ""), - ("elevation_prompt", ""), - ("uac_warning", ""), - ("elevated_foreground_window_warning", ""), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", ""), ("Other", ""), ("Confirm before closing multiple tabs", ""), diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 21344eb11..2953f80cd 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", ""), ("Write a message", ""), ("Prompt", ""), - ("elevation_prompt", ""), - ("uac_warning", ""), - ("elevated_foreground_window_warning", ""), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", ""), ("Other", "他の"), ("Confirm before closing multiple tabs", "同時に複数のタブを閉じる前に確認する"), diff --git a/src/lang/ko.rs b/src/lang/ko.rs index 3b7269023..2473ef2de 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", ""), ("Write a message", ""), ("Prompt", ""), - ("elevation_prompt", ""), - ("uac_warning", ""), - ("elevated_foreground_window_warning", ""), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", ""), ("Other", ""), ("Confirm before closing multiple tabs", ""), diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 1dc505807..1ce728db3 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", ""), ("Write a message", ""), ("Prompt", ""), - ("elevation_prompt", ""), - ("uac_warning", ""), - ("elevated_foreground_window_warning", ""), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", ""), ("Other", ""), ("Confirm before closing multiple tabs", ""), diff --git a/src/lang/pl.rs b/src/lang/pl.rs index 7ed98913c..3bcc464c6 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", "Zablokuj Wykrywanie LAN"), ("Write a message", "Napisz wiadomość"), ("Prompt", "Monit"), - ("elevation_prompt", "Monit o podwyższeniu uprawnień"), - ("uac_warning", "Ostrzeżenie UAC"), - ("elevated_foreground_window_warning", "Pierwszoplanowe okno ostrzeżenia o podwyższeniu uprawnień"), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", "Rozłączone"), ("Other", "Inne"), ("Confirm before closing multiple tabs", "Potwierdź przed zamknięciem wielu kart"), diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 8b4c980f6..e7bb0e73c 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", ""), ("Write a message", ""), ("Prompt", ""), - ("elevation_prompt", ""), - ("uac_warning", ""), - ("elevated_foreground_window_warning", ""), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", "Desconectado"), ("Other", "Outro"), ("Confirm before closing multiple tabs", "Confirme antes de fechar vários separadores"), diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index 0d5594ea9..bc35cfcb2 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", "Negar descoberta da LAN"), ("Write a message", "Escrever uma mensagem"), ("Prompt", "Prompt de comando"), - ("elevation_prompt", "Prompt de comando (Admin)"), - ("uac_warning", "Aviso UAC"), - ("elevated_foreground_window_warning", "Aviso de janela de primeiro plano elevado"), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", "Desconectado"), ("Other", "Outro"), ("Confirm before closing multiple tabs", "Confirmar antes de fechar múltiplas abas"), diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 22c246f86..9e9a60829 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", "Запретить обнаружение в локальной сети"), ("Write a message", "Написать сообщение"), ("Prompt", "Подсказка"), - ("elevation_prompt", "Запуск программного обеспечения без повышения привилегий может вызвать проблемы, когда удалённые пользователи работают с определёнными окнами."), - ("uac_warning", "Временно отказано в доступе из-за запроса на повышение прав. Подождите, пока удалённый пользователь примет диалоговое окно UAC. Чтобы избежать этой проблемы, рекомендуется устанавливать программное обеспечение на удалённое устройство или запускать его с правами администратора."), - ("elevated_foreground_window_warning", "Временно невозможно использовать мышь и клавиатуру, поскольку текущее окно удалённого рабочего стола требует более высоких привилегий для работы, вы можете попросить удалённого пользователя свернуть текущее окно. Чтобы избежать этой проблемы, рекомендуется устанавливать программное обеспечение на удалённое устройство или запускать его с правами администратора."), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", "Отключено"), ("Other", "Другое"), ("Confirm before closing multiple tabs", "Подтверждение закрытия несколько вкладок"), diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 618ede5cd..3970ef3b9 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", ""), ("Write a message", ""), ("Prompt", ""), - ("elevation_prompt", ""), - ("uac_warning", ""), - ("elevated_foreground_window_warning", ""), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", ""), ("Other", ""), ("Confirm before closing multiple tabs", ""), diff --git a/src/lang/template.rs b/src/lang/template.rs index 4ff8f9b87..d9fd7b9bb 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", ""), ("Write a message", ""), ("Prompt", ""), - ("elevation_prompt", ""), - ("uac_warning", ""), - ("elevated_foreground_window_warning", ""), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", ""), ("Other", ""), ("Confirm before closing multiple tabs", ""), diff --git a/src/lang/tr.rs b/src/lang/tr.rs index 6fb89a09f..cd2c8b269 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", ""), ("Write a message", ""), ("Prompt", ""), - ("elevation_prompt", ""), - ("uac_warning", ""), - ("elevated_foreground_window_warning", ""), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", ""), ("Other", ""), ("Confirm before closing multiple tabs", ""), diff --git a/src/lang/tw.rs b/src/lang/tw.rs index 1150199cd..da57cf07c 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", "拒絕局域網發現"), ("Write a message", "輸入聊天消息"), ("Prompt", "提示"), - ("elevation_prompt", "以當前用戶權限運行軟件,可能導致遠端在訪問本機時,沒有足夠的權限來操作部分窗口。"), - ("uac_warning", "暂时无法访问远端设备,因为远端设备正在请求用户账户权限,请等待对方关闭UAC窗口。为避免这个问题,建议在远端设备上安装或者以管理员权限运行本软件。"), - ("elevated_foreground_window_warning", "暫時無法使用鼠標鍵盤,因為遠端桌面的當前窗口需要更高的權限才能操作, 可以請求對方最小化當前窗口。為避免這個問題,建議在遠端設備上安裝或者以管理員權限運行本軟件。"), + ("Please wait for confirmation of UAC...", "請等待對方確認UAC"), + ("elevated_foreground_window_tip", "遠端桌面的當前窗口需要更高的權限才能操作, 暫時無法使用鼠標鍵盤, 可以請求對方最小化當前窗口, 或者在連接管理窗口點擊提升。為避免這個問題,建議在遠端設備上安裝本軟件。"), ("Disconnected", "會話已結束"), ("Other", "其他"), ("Confirm before closing multiple tabs", "關閉多個分頁前跟我確認"), diff --git a/src/lang/ua.rs b/src/lang/ua.rs index cc0ef6536..10119d1e2 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", "Заборонити виявлення локальної мережі"), ("Write a message", "Написати повідомлення"), ("Prompt", ""), - ("elevation_prompt", ""), - ("uac_warning", ""), - ("elevated_foreground_window_warning", ""), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", ""), ("Other", ""), ("Confirm before closing multiple tabs", ""), diff --git a/src/lang/vn.rs b/src/lang/vn.rs index 9773d7655..8bb164a8f 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -371,9 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", ""), ("Write a message", ""), ("Prompt", ""), - ("elevation_prompt", ""), - ("uac_warning", ""), - ("elevated_foreground_window_warning", ""), + ("Please wait for confirmation of UAC...", ""), + ("elevated_foreground_window_tip", ""), ("Disconnected", ""), ("Other", ""), ("Confirm before closing multiple tabs", ""), diff --git a/src/server/connection.rs b/src/server/connection.rs index 8674c6d9d..cb2ddc2c6 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -26,12 +26,9 @@ use hbb_common::{ use scrap::android::call_main_service_mouse_input; use serde_json::{json, value::Value}; use sha2::{Digest, Sha256}; -use std::sync::{ - atomic::AtomicI64, - mpsc as std_mpsc, -}; #[cfg(not(any(target_os = "android", target_os = "ios")))] use std::sync::atomic::Ordering; +use std::sync::{atomic::AtomicI64, mpsc as std_mpsc}; #[cfg(not(any(target_os = "android", target_os = "ios")))] use system_shutdown; @@ -434,7 +431,7 @@ impl Connection { let uac = crate::video_service::IS_UAC_RUNNING.lock().unwrap().clone(); if last_uac != uac { last_uac = uac; - if !portable_service_running { + if !uac || !portable_service_running{ let mut misc = Misc::new(); misc.set_uac(uac); let mut msg = Message::new(); @@ -445,7 +442,7 @@ impl Connection { let foreground_window_elevated = crate::video_service::IS_FOREGROUND_WINDOW_ELEVATED.lock().unwrap().clone(); if last_foreground_window_elevated != foreground_window_elevated { last_foreground_window_elevated = foreground_window_elevated; - if !portable_service_running { + if !foreground_window_elevated || !portable_service_running { let mut misc = Misc::new(); misc.set_foreground_window_elevated(foreground_window_elevated); let mut msg = Message::new(); diff --git a/src/ui/common.tis b/src/ui/common.tis index 76e0fb84e..7507d4895 100644 --- a/src/ui/common.tis +++ b/src/ui/common.tis @@ -232,6 +232,7 @@ class ChatBox: Reactor.Component { /******************** start of msgbox ****************************************/ var remember_password = false; +var last_msgbox_tag = ""; function msgbox(type, title, content, link="", callback=null, height=180, width=500, hasRetry=false, contentStyle="") { $(body).scrollTo(0, 0); if (!type) { @@ -264,6 +265,7 @@ function msgbox(type, title, content, link="", callback=null, height=180, width= } else if (type.indexOf("custom") < 0 && !is_port_forward && !callback) { callback = function() { view.close(); } } + last_msgbox_tag = type + "-" + title + "-" + content + "-" + link; $(#msgbox).content(); } @@ -276,6 +278,12 @@ handler.msgbox = function(type, title, text, link = "", hasRetry=false) { self.timer(60ms, function() { msgbox(type, title, text, link, null, 180, 500, hasRetry); }); } +handler.cancel_msgbox = function(tag) { + if (last_msgbox_tag == tag) { + closeMsgbox(); + } +} + var reconnectTimeout = 1000; handler.msgbox_retry = function(type, title, text, link, hasRetry) { handler.msgbox(type, title, text, link, hasRetry); diff --git a/src/ui/remote.rs b/src/ui/remote.rs index 62df85250..66b46cf85 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -231,7 +231,14 @@ impl InvokeUiSession for SciterHandler { } fn msgbox(&self, msgtype: &str, title: &str, text: &str, link: &str, retry: bool) { - self.call2("msgbox_retry", &make_args!(msgtype, title, text, link, retry)); + self.call2( + "msgbox_retry", + &make_args!(msgtype, title, text, link, retry), + ); + } + + fn cancel_msgbox(&self, tag: &str) { + self.call("cancel_msgbox", &make_args!(tag)); } fn new_message(&self, msg: String) { diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index 4467fee00..5119a6e1b 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -1,11 +1,11 @@ -#[cfg(not(any(target_os = "android", target_os = "ios")))] -use crate::client::{get_key_state, SERVER_KEYBOARD_ENABLED}; use crate::client::io_loop::Remote; use crate::client::{ check_if_retry, handle_hash, handle_login_from_ui, handle_test_delay, input_os_password, load_config, send_mouse, start_video_audio_threads, FileManager, Key, LoginConfigHandler, QualityStatus, KEY_MAP, }; +#[cfg(not(any(target_os = "android", target_os = "ios")))] +use crate::client::{get_key_state, SERVER_KEYBOARD_ENABLED}; #[cfg(target_os = "linux")] use crate::common::IS_X11; use crate::{client::Data, client::Interface}; @@ -15,9 +15,9 @@ use hbb_common::rendezvous_proto::ConnType; use hbb_common::tokio::{self, sync::mpsc}; use hbb_common::{allow_err, message_proto::*}; use hbb_common::{fs, get_version_number, log, Stream}; +use rdev::{Event, EventType, EventType::*, Key as RdevKey}; #[cfg(not(any(target_os = "android", target_os = "ios")))] use rdev::{Keyboard as RdevKeyboard, KeyboardState}; -use rdev::{Event, EventType, EventType::*, Key as RdevKey}; use std::collections::{HashMap, HashSet}; use std::ops::{Deref, DerefMut}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; @@ -1120,6 +1120,7 @@ pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default { fn msgbox(&self, msgtype: &str, title: &str, text: &str, link: &str, retry: bool); #[cfg(any(target_os = "android", target_os = "ios"))] fn clipboard(&self, content: String); + fn cancel_msgbox(&self, tag: &str); } impl Deref for Session { From 8328869c11b80b3dc568e2f35fcd8d05d0f31f40 Mon Sep 17 00:00:00 2001 From: Peeveck <118300943+Peeveck@users.noreply.github.com> Date: Tue, 15 Nov 2022 21:35:39 +0100 Subject: [PATCH 040/116] Update pl.rs --- src/lang/pl.rs | 52 +++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/lang/pl.rs b/src/lang/pl.rs index 382b254f0..2e7e7dc46 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -7,7 +7,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Password", "Hasło"), ("Ready", "Gotowe"), ("Established", "Nawiązano"), - ("connecting_status", "Status połączenia"), + ("connecting_status", "Łączenie"), ("Enable Service", "Włącz usługę"), ("Start Service", "Uruchom usługę"), ("Service is running", "Usługa uruchomiona"), @@ -30,9 +30,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("IP Whitelisting", "Biała lista IP"), ("ID/Relay Server", "Serwer ID/Pośredniczący"), ("Import Server Config", "Importuj konfigurację serwera"), - ("Export Server Config", ""), - ("Import server configuration successfully", "Importowanie konfiguracji serwera powiodło się"), - ("Export server configuration successfully", ""), + ("Export Server Config", "Eksportuj konfigurację serwera"), + ("Import server configuration successfully", "Import konfiguracji serwera zakończono pomyślnie"), + ("Export server configuration successfully", "Eksport konfiguracji serwera zakończono pomyślnie"), ("Invalid server configuration", "Nieprawidłowa konfiguracja serwera"), ("Clipboard is empty", "Schowek jest pusty"), ("Stop service", "Zatrzymaj usługę"), @@ -47,7 +47,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("ID Server", "Serwer ID"), ("Relay Server", "Serwer pośredniczący"), ("API Server", "Serwer API"), - ("invalid_http", "Nieprawidłowy żądanie http"), + ("invalid_http", "Nieprawidłowe żądanie http"), ("Invalid IP", "Nieprawidłowe IP"), ("id_change_tip", "Nowy ID może być złożony z małych i dużych liter a-zA-z, cyfry 0-9 oraz _ (podkreślenie). Pierwszym znakiem powinna być litera a-zA-Z, a całe ID powinno składać się z 6 do 16 znaków."), ("Invalid format", "Nieprawidłowy format"), @@ -72,7 +72,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please try 1 minute later", "Spróbuj za minutę"), ("Login Error", "Błąd logowania"), ("Successful", "Sukces"), - ("Connected, waiting for image...", "Połączono, czekam na obraz..."), + ("Connected, waiting for image...", "Połączono, oczekiwanie na obraz..."), ("Name", "Nazwa"), ("Type", "Typ"), ("Modified", "Zmodyfikowany"), @@ -95,8 +95,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Not an empty directory", "Katalog nie jest pusty"), ("Are you sure you want to delete this file?", "Czy na pewno chcesz usunąć ten plik?"), ("Are you sure you want to delete this empty directory?", "Czy na pewno chcesz usunać ten pusty katalog?"), - ("Are you sure you want to delete the file of this directory?", "Czy na pewno chcesz usunąć pliki z tego katalog?"), - ("Do this for all conflicts", "Zrób to dla wszystkich konfliktów"), + ("Are you sure you want to delete the file of this directory?", "Czy na pewno chcesz usunąć pliki z tego katalogu?"), + ("Do this for all conflicts", "wykonaj dla wszystkich konfliktów"), ("This is irreversible!", "To jest nieodwracalne!"), ("Deleting", "Usuwanie"), ("files", "pliki"), @@ -121,15 +121,15 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show quality monitor", "Pokazuj jakość monitora"), ("Disable clipboard", "Wyłącz schowek"), ("Lock after session end", "Zablokuj po zakończeniu sesji"), - ("Insert", "Wstaw"), - ("Insert Lock", "Wstaw blokadę"), + ("Insert", "Wyślij"), + ("Insert Lock", "Wyślij Zablokuj"), ("Refresh", "Odśwież"), ("ID does not exist", "ID nie istnieje"), ("Failed to connect to rendezvous server", "Nie udało się połączyć z serwerem połączeń"), ("Please try later", "Spróbuj później"), ("Remote desktop is offline", "Zdalny pulpit jest offline"), ("Key mismatch", "Niezgodność klucza"), - ("Timeout", "Przekroczenie czasu"), + ("Timeout", "Przekroczono czas oczekiwania"), ("Failed to connect to relay server", "Nie udało się połączyć z serwerem pośredniczącym"), ("Failed to connect via rendezvous server", "Nie udało się połączyć przez serwer połączeń"), ("Failed to connect via relay server", "Nie udało się połączyć przez serwer pośredniczący"), @@ -195,7 +195,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Warning", "Ostrzeżenie"), ("Login screen using Wayland is not supported", "Ekran logowania korzystający z Wayland nie jest obsługiwany"), ("Reboot required", "Wymagany ponowne uruchomienie"), - ("Unsupported display server ", "Nieobsługiwany serwer wyświetlania "), + ("Unsupported display server ", "Nieobsługiwany serwer wyświetlania"), ("x11 expected", "Wymagany jest X11"), ("Port", "Port"), ("Settings", "Ustawienia"), @@ -206,19 +206,19 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Run without install", "Uruchom bez instalacji"), ("Always connected via relay", "Zawsze połączony pośrednio"), ("Always connect via relay", "Zawsze łącz pośrednio"), - ("whitelist_tip", "Podpowiedź do białej listy"), + ("whitelist_tip", "Zezwlaj na łączenie z tym komputerem tylko z adresów IP znajdujących się na białej liście"), ("Login", "Zaloguj"), ("Logout", "Wyloguj"), ("Tags", "Tagi"), ("Search ID", "Szukaj ID"), ("Current Wayland display server is not supported", "Obecny serwer wyświetlania Wayland nie jest obsługiwany"), - ("whitelist_sep", "Seperator białej listy"), + ("whitelist_sep", "Oddzielone przecinkiem, średnikiem, spacją lub w nowej linii"), ("Add ID", "Dodaj ID"), ("Add Tag", "Dodaj Tag"), ("Unselect all tags", "Odznacz wszystkie tagi"), ("Network error", "Błąd sieci"), - ("Username missed", "Brak użytkownika"), - ("Password missed", "Brak hasła"), + ("Username missed", "Nieprawidłowe nazwa użytkownika"), + ("Password missed", "Nieprawidłowe hasło"), ("Wrong credentials", "Błędne dane uwierzytelniające"), ("Edit Tag", "Edytuj tag"), ("Unremember Password", "Zapomnij hasło"), @@ -226,7 +226,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Add to Favorites", "Dodaj do ulubionych"), ("Remove from Favorites", "Usuń z ulubionych"), ("Empty", "Pusty"), - ("Invalid folder name", "Błędna nazwa folderu"), + ("Invalid folder name", "Nieprawidłowa nazwa folderu"), ("Socks5 Proxy", "Socks5 Proxy"), ("Hostname", "Nazwa hosta"), ("Discovered", "Wykryte"), @@ -242,12 +242,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Left Mouse", "Lewy klik myszy"), ("One-Long Tap", "Przytrzymaj jednym palcem"), ("Two-Finger Tap", "Dotknij dwoma palcami"), - ("Right Mouse", "Prawy klik myszy"), - ("One-Finger Move", "Ruch jednym palcem"), + ("Right Mouse", "Prawy przycisk myszy"), + ("One-Finger Move", "Przesuń jednym palcem"), ("Double Tap & Move", "Dotknij dwukrotnie i przesuń"), ("Mouse Drag", "Przeciągnij myszą"), - ("Three-Finger vertically", "Trzy palce wertykalnie"), - ("Mouse Wheel", "Skrol myszy"), + ("Three-Finger vertically", "Trzy palce pionowo"), + ("Mouse Wheel", "Kółko myszy"), ("Two-Finger Move", "Ruch dwoma palcami"), ("Canvas Move", "Ruch ekranu"), ("Pinch to Zoom", "Uszczypnij, aby powiększyć"), @@ -289,7 +289,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Someone turns on privacy mode, exit", "Ktoś włącza tryb prywatności, wyjdź"), ("Unsupported", "Niewspierane"), ("Peer denied", "Odmowa dostępu"), - ("Please install plugins", "Zainstaluj plugin"), + ("Please install plugins", "Zainstaluj wtyczkę"), ("Peer exit", "Wyjście peer"), ("Failed to turn off", "Nie udało się wyłączyć"), ("Turned off", "Wyłączony"), @@ -385,9 +385,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland wymaga wyższej wersji dystrybucji Linuksa. Wypróbuj pulpit X11 lub zmień system operacyjny."), ("JumpLink", "View"), ("Please Select the screen to be shared(Operate on the peer side).", "Wybierz ekran do udostępnienia (działaj po stronie równorzędnej)."), - ("Show RustDesk", ""), - ("This PC", ""), - ("or", ""), - ("Continue with", ""), + ("Show RustDesk", "Pokaż RustDesk"), + ("This PC", "Ten komputer"), + ("or", "albo"), + ("Continue with", "Kontynuuj z"), ].iter().cloned().collect(); } From 2a65d948aabbd9ac807ecfac9be999a8afc2aadc Mon Sep 17 00:00:00 2001 From: 21pages Date: Wed, 16 Nov 2022 13:15:05 +0800 Subject: [PATCH 041/116] portable-service: little fix Signed-off-by: 21pages --- src/lang/pl.rs | 2 +- src/server/input_service.rs | 14 +++++++------- src/server/portable_service.rs | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lang/pl.rs b/src/lang/pl.rs index 0e2616a80..ffe94432d 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -387,7 +387,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show RustDesk", "Pokaż RustDesk"), ("This PC", "Ten komputer"), ("or", "albo"), - ("Continue with", "Kontynuuj z"),""), + ("Continue with", "Kontynuuj z"), ("Elevate", ""), ].iter().cloned().collect(); } diff --git a/src/server/input_service.rs b/src/server/input_service.rs index af4b7d853..af9441ae4 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -280,13 +280,6 @@ fn get_modifier_state(key: Key, en: &mut Enigo) -> bool { } pub fn handle_mouse(evt: &MouseEvent, conn: i32) { - #[cfg(target_os = "macos")] - if !*IS_SERVER { - // having GUI, run main GUI thread, otherwise crash - let evt = evt.clone(); - QUEUE.exec_async(move || handle_mouse_(&evt, conn)); - return; - } if !active_mouse_(conn) { return; } @@ -300,6 +293,13 @@ pub fn handle_mouse(evt: &MouseEvent, conn: i32) { y: evt.y, }; } + #[cfg(target_os = "macos")] + if !*IS_SERVER { + // having GUI, run main GUI thread, otherwise crash + let evt = evt.clone(); + QUEUE.exec_async(move || handle_mouse_(&evt)); + return; + } #[cfg(windows)] crate::portable_service::client::handle_mouse(evt); #[cfg(not(windows))] diff --git a/src/server/portable_service.rs b/src/server/portable_service.rs index 48cdcbe51..21b501f1e 100644 --- a/src/server/portable_service.rs +++ b/src/server/portable_service.rs @@ -16,7 +16,7 @@ use std::{ mem::size_of, ops::{Deref, DerefMut}, sync::{Arc, Mutex}, - time::{Duration, Instant}, + time::Duration, }; use winapi::{ shared::minwindef::{BOOL, FALSE, TRUE}, From 44b89f574b9a320dd9e5a6bcfc728db0c7f2149b Mon Sep 17 00:00:00 2001 From: fufesou Date: Tue, 15 Nov 2022 22:35:10 +0800 Subject: [PATCH 042/116] fix cursor image && hotx,hoty, debug win Signed-off-by: fufesou --- flutter/lib/models/model.dart | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index a39bc7d08..1c7c6cafa 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -696,6 +696,8 @@ class CursorData { final img2.Image? image; double scale; Uint8List? data; + final double hotxOrigin; + final double hotyOrigin; double hotx; double hoty; final int width; @@ -707,11 +709,12 @@ class CursorData { required this.image, required this.scale, required this.data, - required this.hotx, - required this.hoty, + required this.hotxOrigin, + required this.hotyOrigin, required this.width, required this.height, - }); + }) : hotx = hotxOrigin * scale, + hoty = hotxOrigin * scale; int _doubleToInt(double v) => (v * 10e6).round().toInt(); @@ -731,16 +734,14 @@ class CursorData { image!, width: (width * scale).toInt(), height: (height * scale).toInt(), + interpolation: img2.Interpolation.cubic, ) .getBytes(format: img2.Format.bgra); } } this.scale = scale; - if (hotx > 0 && hoty > 0) { - // default cursor data - hotx = (width * scale) / 2; - hoty = (height * scale) / 2; - } + hotx = hotxOrigin * scale; + hoty = hotyOrigin * scale; return scale; } @@ -811,8 +812,6 @@ class CursorModel with ChangeNotifier { if (_defaultCache == null) { Uint8List data; double scale = 1.0; - double hotx = (defaultCursorImage!.width * scale) / 2; - double hoty = (defaultCursorImage!.height * scale) / 2; if (Platform.isWindows) { data = defaultCursorImage!.getBytes(format: img2.Format.bgra); } else { @@ -825,8 +824,8 @@ class CursorModel with ChangeNotifier { image: defaultCursorImage?.clone(), scale: scale, data: data, - hotx: hotx, - hoty: hoty, + hotxOrigin: defaultCursorImage!.width / 2, + hotyOrigin: defaultCursorImage!.height / 2, width: defaultCursorImage!.width, height: defaultCursorImage!.height, ); @@ -996,10 +995,8 @@ class CursorModel with ChangeNotifier { image: Platform.isWindows ? img2.Image.fromBytes(w, h, data) : null, scale: 1.0, data: data, - hotx: 0, - hoty: 0, - // hotx: _hotx, - // hoty: _hoty, + hotxOrigin: _hotx, + hotyOrigin: _hoty, width: w, height: h, ); From 46423614c803778ab73b1c5d949acc58270eff8b Mon Sep 17 00:00:00 2001 From: fufesou Date: Tue, 15 Nov 2022 23:02:50 +0800 Subject: [PATCH 043/116] change cursor resize interpolation to linear Signed-off-by: fufesou --- flutter/lib/models/model.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 1c7c6cafa..6734bd8fb 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -734,7 +734,7 @@ class CursorData { image!, width: (width * scale).toInt(), height: (height * scale).toInt(), - interpolation: img2.Interpolation.cubic, + interpolation: img2.Interpolation.linear, ) .getBytes(format: img2.Format.bgra); } From 658c539730668f1ff74551308322f93c9a04c8a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Fahri=20Uzun?= Date: Wed, 16 Nov 2022 12:11:24 +0300 Subject: [PATCH 044/116] Updated tr.rs --- src/lang/tr.rs | 134 ++++++++++++++++++++++++------------------------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/src/lang/tr.rs b/src/lang/tr.rs index cd2c8b269..01aa7ff07 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -41,9 +41,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("About", "Hakkında"), ("Mute", "Sustur"), ("Audio Input", "Ses Girişi"), - ("Enhancements", ""), - ("Hardware Codec", ""), - ("Adaptive Bitrate", ""), + ("Enhancements", "Geliştirmeler"), + ("Hardware Codec", "Donanımsal Codec"), + ("Adaptive Bitrate", "Uyarlanabilir Bit Hızı"), ("ID Server", "ID Sunucu"), ("Relay Server", "Relay Sunucu"), ("API Server", "API Sunucu"), @@ -89,8 +89,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Delete", "Sil"), ("Properties", "Özellikler"), ("Multi Select", "Çoklu Seçim"), - ("Select All", ""), - ("Unselect All", ""), + ("Select All", "Tümünü Seç"), + ("Unselect All", "Tüm Seçimi Kaldır"), ("Empty Directory", "Boş Klasör"), ("Not an empty directory", "Klasör boş değil"), ("Are you sure you want to delete this file?", "Bu dosyayı silmek istediğinize emin misiniz?"), @@ -116,9 +116,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Good image quality", "İyi görüntü kalitesi"), ("Balanced", "Dengelenmiş"), ("Optimize reaction time", "Tepki süresini optimize et"), - ("Custom", ""), + ("Custom", "Özel"), ("Show remote cursor", "Uzaktaki fare imlecini göster"), - ("Show quality monitor", ""), + ("Show quality monitor", "Kalite monitörünü göster"), ("Disable clipboard", "Hafızadaki kopyalanmışları engelle"), ("Lock after session end", "Bağlantıdan sonra kilitle"), ("Insert", "Ekle"), @@ -161,8 +161,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Action", "Eylem"), ("Add", "Ekle"), ("Local Port", "Yerel Port"), - ("Local Address", ""), - ("Change Local Port", ""), + ("Local Address", "Yerel Adres"), + ("Change Local Port", "Yerel Port'u Değiştir"), ("setup_server_tip", "Daha hızlı bağlantı için kendi sunucunuzu kurun"), ("Too short, at least 6 characters.", "Çok kısa en az 6 karakter gerekli."), ("The confirmation is not identical.", "Doğrulama yapılamadı."), @@ -197,7 +197,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Reboot required", "Yeniden başlatma gerekli"), ("Unsupported display server ", "Desteklenmeyen görüntü sunucusu"), ("x11 expected", "x11 bekleniyor"), - ("Port", ""), + ("Port", "Port"), ("Settings", "Ayarlar"), ("Username", "Kullanıcı Adı"), ("Invalid port", "Geçersiz port"), @@ -278,7 +278,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("android_stop_service_tip", "Hizmetin kapatılması, kurulan tüm bağlantıları otomatik olarak kapatacaktır."), ("android_version_audio_tip", "Mevcut Android sürümü ses yakalamayı desteklemiyor, lütfen Android 10 veya sonraki bir sürüme yükseltin."), ("android_start_service_tip", "Ekran paylaşım hizmetini başlatmak için [Hizmeti Başlat] veya AÇ [Ekran Yakalama] iznine dokunun."), - ("Account", ""), + ("Account", "Hesap"), ("Overwrite", "üzerine yaz"), ("This file exists, skip or overwrite this file?", "Bu dosya var, bu dosya atlansın veya üzerine yazılsın mı?"), ("Quit", "Çıkış"), @@ -300,21 +300,21 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Ignore Battery Optimizations", ""), ("android_open_battery_optimizations_tip", ""), ("Connection not allowed", "bağlantıya izin verilmedi"), - ("Legacy mode", ""), - ("Map mode", ""), - ("Translate mode", ""), + ("Legacy mode", "Eski mod"), + ("Map mode", "Haritalama modu"), + ("Translate mode", "Çeviri modu"), ("Use temporary password", "Geçici şifre kullan"), ("Use permanent password", "Kalıcı şifre kullan"), ("Use both passwords", "İki şifreyide kullan"), ("Set permanent password", "Kalıcı şifre oluştur"), - ("Set temporary password length", ""), + ("Set temporary password length", "Geçici şifre oluştur"), ("Enable Remote Restart", "Uzaktan yeniden başlatmayı aktif et"), ("Allow remote restart", "Uzaktan yeniden başlatmaya izin ver"), ("Restart Remote Device", "Uzaktaki cihazı yeniden başlat"), ("Are you sure you want to restart", "Yeniden başlatmak istediğinize emin misin?"), ("Restarting Remote Device", "Uzaktan yeniden başlatılıyor"), - ("remote_restarting_tip", ""), - ("Copied", ""), + ("remote_restarting_tip", "remote_restarting_tip"), + ("Copied", "Kopyalandı"), ("Exit Fullscreen", "Tam ekrandan çık"), ("Fullscreen", "Tam ekran"), ("Mobile Actions", "Mobil İşlemler"), @@ -332,62 +332,62 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Insecure Connection", "Güvenli Bağlantı"), ("Scale original", "Orijinali ölçeklendir"), ("Scale adaptive", "Ölçek uyarlanabilir"), - ("General", ""), - ("Security", ""), - ("Account", ""), - ("Theme", ""), - ("Dark Theme", ""), - ("Dark", ""), - ("Light", ""), - ("Follow System", ""), - ("Enable hardware codec", ""), - ("Unlock Security Settings", ""), - ("Enable Audio", ""), - ("Temporary Password Length", ""), - ("Unlock Network Settings", ""), - ("Server", ""), - ("Direct IP Access", ""), - ("Proxy", ""), - ("Port", ""), - ("Apply", ""), - ("Disconnect all devices?", ""), - ("Clear", ""), - ("Audio Input Device", ""), - ("Deny remote access", ""), - ("Use IP Whitelisting", ""), - ("Network", ""), - ("Enable RDP", ""), + ("General", "Genel"), + ("Security", "Güvenlik"), + ("Account", "Hesap"), + ("Theme", "Tema"), + ("Dark Theme", "Koyu Tema"), + ("Dark", "Koyu"), + ("Light", "Açık"), + ("Follow System", "Sisteme Uy"), + ("Enable hardware codec", "Donanımsal codec aktif et"), + ("Unlock Security Settings", "Güvenlik Ayarlarını Aç"), + ("Enable Audio", "Sesi Aktif Et"), + ("Temporary Password Length", "Geçici Şifre Uzunluğu"), + ("Unlock Network Settings", "Ağ Ayarlarını Aç"), + ("Server", "Sunucu"), + ("Direct IP Access", "Direk IP Erişimi"), + ("Proxy", "Vekil"), + ("Port", "Port"), + ("Apply", "Uygula"), + ("Disconnect all devices?", "Tüm cihazların bağlantısını kes?"), + ("Clear", "Temizle"), + ("Audio Input Device", "Ses Giriş Aygıtı"), + ("Deny remote access", "Uzak erişime izin verme"), + ("Use IP Whitelisting", "IP Beyaz Listeyi Kullan"), + ("Network", "Ağ"), + ("Enable RDP", "RDP Aktif Et"), ("Pin menubar", "Menü çubuğunu sabitle"), ("Unpin menubar", "Menü çubuğunun sabitlemesini kaldır"), - ("Recording", ""), - ("Directory", ""), - ("Automatically record incoming sessions", ""), - ("Change", ""), - ("Start session recording", ""), - ("Stop session recording", ""), - ("Enable Recording Session", ""), - ("Allow recording session", ""), - ("Enable LAN Discovery", ""), - ("Deny LAN Discovery", ""), - ("Write a message", ""), + ("Recording", "Kayıt Ediliyor"), + ("Directory", "Klasör"), + ("Automatically record incoming sessions", "Gelen oturumları otomatik olarak kayıt et"), + ("Change", "Değiştir"), + ("Start session recording", "Oturum kaydını başlat"), + ("Stop session recording", "Oturum kaydını sonlandır"), + ("Enable Recording Session", "Kayıt Oturumunu Aktif Et"), + ("Allow recording session", "Oturum kaydına izin ver"), + ("Enable LAN Discovery", "Yerel Ağ Keşfine İzin Ver"), + ("Deny LAN Discovery", "Yerl Ağ Keşfine İzin Verme"), + ("Write a message", "Bir mesaj yazın"), ("Prompt", ""), - ("Please wait for confirmation of UAC...", ""), - ("elevated_foreground_window_tip", ""), - ("Disconnected", ""), - ("Other", ""), - ("Confirm before closing multiple tabs", ""), - ("Keyboard Settings", ""), - ("Custom", ""), - ("Full Access", ""), - ("Screen Share", ""), + ("Please wait for confirmation of UAC...", "UAC onayı için lütfen bekleyiniz..."), + ("elevated_foreground_window_tip", "elevated_foreground_window_tip"), + ("Disconnected", "Bağlantı Kesildi"), + ("Other", "Diğer"), + ("Confirm before closing multiple tabs", "Çoklu sekmeleri kapatmadan önce onayla"), + ("Keyboard Settings", "Klavye Ayarları"), + ("Custom", "Özel"), + ("Full Access", "Tam Erişim"), + ("Screen Share", "Ekran Paylaşımı"), ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland, Ubuntu 21.04 veya daha yüksek bir sürüm gerektirir."), ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland, linux dağıtımının daha yüksek bir sürümünü gerektirir. Lütfen X11 masaüstünü deneyin veya işletim sisteminizi değiştirin."), ("JumpLink", "View"), ("Please Select the screen to be shared(Operate on the peer side).", "Lütfen paylaşılacak ekranı seçiniz (Ekran tarafında çalıştırın)."), - ("Show RustDesk", ""), - ("This PC", ""), - ("or", ""), - ("Continue with", ""), - ("Elevate", ""), + ("Show RustDesk", "RustDesk'i Göster"), + ("This PC", "Bu PC"), + ("or", "veya"), + ("Continue with", "bununla devam et"), + ("Elevate", "Yükseltme"), ].iter().cloned().collect(); } From 50dc2a4d73cb300d0994dd9cd64ca017e108383c Mon Sep 17 00:00:00 2001 From: csf Date: Wed, 16 Nov 2022 18:53:32 +0900 Subject: [PATCH 045/116] fix: sending file from local to remote (keep send_raw) --- libs/hbb_common/src/fs.rs | 15 +++++---------- src/client/io_loop.rs | 2 +- src/server/connection.rs | 3 ++- src/ui_cm_interface.rs | 32 ++++++++++++++++++-------------- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/libs/hbb_common/src/fs.rs b/libs/hbb_common/src/fs.rs index 6cc795a0d..dd8a7530e 100644 --- a/libs/hbb_common/src/fs.rs +++ b/libs/hbb_common/src/fs.rs @@ -380,7 +380,7 @@ impl TransferJob { } } - pub async fn write(&mut self, block: FileTransferBlock, raw: Option<&[u8]>) -> ResultType<()> { + pub async fn write(&mut self, block: FileTransferBlock) -> ResultType<()> { if block.id != self.id { bail!("Wrong id"); } @@ -402,20 +402,15 @@ impl TransferJob { let path = format!("{}.download", get_string(&path)); self.file = Some(File::create(&path).await?); } - let data = if let Some(data) = raw { - data - } else { - &block.data - }; if block.compressed { - let tmp = decompress(data); + let tmp = decompress(&block.data); self.file.as_mut().unwrap().write_all(&tmp).await?; self.finished_size += tmp.len() as u64; } else { - self.file.as_mut().unwrap().write_all(data).await?; - self.finished_size += data.len() as u64; + self.file.as_mut().unwrap().write_all(&block.data).await?; + self.finished_size += block.data.len() as u64; } - self.transferred += data.len() as u64; + self.transferred += block.data.len() as u64; Ok(()) } diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 04d1d4d29..447b89290 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -925,7 +925,7 @@ impl Remote { block.file_num ); if let Some(job) = fs::get_job(block.id, &mut self.write_jobs) { - if let Err(_err) = job.write(block, None).await { + if let Err(_err) = job.write(block).await { // to-do: add "skip" for writing job } self.update_jobs_status(); diff --git a/src/server/connection.rs b/src/server/connection.rs index 3644066e2..891c48888 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -1609,7 +1609,8 @@ async fn start_ipc( file_num, data, compressed}) = data { - stream.send(&Data::FS(ipc::FS::WriteBlock{id, file_num, data, compressed})).await?; + stream.send(&Data::FS(ipc::FS::WriteBlock{id, file_num, data: Bytes::new(), compressed})).await?; + stream.send_raw(data).await?; } else { stream.send(&data).await?; } diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 72225b3fb..e8668a2ab 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -1,3 +1,5 @@ +#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] +use std::iter::FromIterator; #[cfg(windows)] use std::sync::Arc; use std::{ @@ -8,8 +10,6 @@ use std::{ RwLock, }, }; -#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] -use std::iter::FromIterator; #[cfg(windows)] use clipboard::{cliprdr::CliprdrClientContext, empty_clipboard, set_conn_enabled, ContextSend}; @@ -337,8 +337,15 @@ impl IpcTaskRunner { Data::ChatMessage { text } => { self.cm.new_message(self.conn_id, text); } - Data::FS(fs) => { - handle_fs(fs, &mut write_jobs, &self.tx).await; + Data::FS(mut fs) => { + if let ipc::FS::WriteBlock { id, file_num, data: _, compressed } = fs { + if let Ok(bytes) = self.stream.next_raw().await { + fs = ipc::FS::WriteBlock{id, file_num, data:bytes.into(), compressed}; + handle_fs(fs, &mut write_jobs, &self.tx).await; + } + } else { + handle_fs(fs, &mut write_jobs, &self.tx).await; + } } #[cfg(windows)] Data::ClipbaordFile(_clip) => { @@ -588,16 +595,13 @@ async fn handle_fs(fs: ipc::FS, write_jobs: &mut Vec, tx: &Unbo } => { if let Some(job) = fs::get_job(id, write_jobs) { if let Err(err) = job - .write( - FileTransferBlock { - id, - file_num, - data, - compressed, - ..Default::default() - }, - None, - ) + .write(FileTransferBlock { + id, + file_num, + data, + compressed, + ..Default::default() + }) .await { send_raw(fs::new_error(id, err, file_num), &tx); From a98e655cc765f9599918b74bfa2d8a5374ad5f2d Mon Sep 17 00:00:00 2001 From: csf Date: Wed, 16 Nov 2022 18:59:13 +0900 Subject: [PATCH 046/116] remove unused log --- src/client/io_loop.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 447b89290..3e691da95 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -919,11 +919,6 @@ impl Remote { } } Some(file_response::Union::Block(block)) => { - log::info!( - "file response block, file id:{}, file num: {}", - block.id, - block.file_num - ); if let Some(job) = fs::get_job(block.id, &mut self.write_jobs) { if let Err(_err) = job.write(block).await { // to-do: add "skip" for writing job From 9a70725090501cf8e27f3bf7c52abd20a7572459 Mon Sep 17 00:00:00 2001 From: fufesou Date: Wed, 16 Nov 2022 18:07:58 +0800 Subject: [PATCH 047/116] Add peer option: zoom cursor & show menubar on conn Signed-off-by: fufesou --- flutter/lib/common/shared_state.dart | 22 ++++++++++ flutter/lib/desktop/pages/remote_page.dart | 41 +++++++++++++++---- .../lib/desktop/widgets/remote_menubar.dart | 22 +++++++++- flutter/lib/models/model.dart | 35 ++++++++++------ src/lang/cn.rs | 1 + src/lang/cs.rs | 1 + src/lang/da.rs | 1 + src/lang/de.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/pl.rs | 1 + src/lang/pt_PT.rs | 1 + src/lang/ptbr.rs | 1 + src/lang/ru.rs | 1 + src/lang/sk.rs | 1 + src/lang/template.rs | 1 + src/lang/tr.rs | 1 + src/lang/tw.rs | 1 + src/lang/ua.rs | 1 + src/lang/vn.rs | 1 + 28 files changed, 121 insertions(+), 23 deletions(-) diff --git a/flutter/lib/common/shared_state.dart b/flutter/lib/common/shared_state.dart index 5ae618dfe..ebac18dac 100644 --- a/flutter/lib/common/shared_state.dart +++ b/flutter/lib/common/shared_state.dart @@ -202,6 +202,28 @@ class RemoteCountState { static RxInt find() => Get.find(tag: tag()); } +class PeerBoolOption { + static String tag(String id, String opt) => 'peer_{$opt}_$id'; + + static void init(String id, String opt, bool Function() init_getter) { + final key = tag(id, opt); + if (!Get.isRegistered(tag: key)) { + final RxBool value = RxBool(init_getter()); + Get.put(value, tag: key); + } + } + + static void delete(String id, String opt) { + final key = tag(id, opt); + if (Get.isRegistered(tag: key)) { + Get.delete(tag: key); + } + } + + static RxBool find(String id, String opt) => + Get.find(tag: tag(id, opt)); +} + class PeerStringOption { static String tag(String id, String opt) => 'peer_{$opt}_$id'; diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index dae3fa612..117a0ab02 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -51,6 +51,7 @@ class _RemotePageState extends State String keyboardMode = "legacy"; final _cursorOverImage = false.obs; late RxBool _showRemoteCursor; + late RxBool _zoomCursor; late RxBool _remoteCursorMoved; late RxBool _keyboardEnabled; @@ -68,6 +69,10 @@ class _RemotePageState extends State KeyboardEnabledState.init(id); ShowRemoteCursorState.init(id); RemoteCursorMovedState.init(id); + final optZoomCursor = 'zoom-cursor'; + PeerBoolOption.init(id, optZoomCursor, + () => bind.sessionGetToggleOptionSync(id: id, arg: optZoomCursor)); + _zoomCursor = PeerBoolOption.find(id, optZoomCursor); _showRemoteCursor = ShowRemoteCursorState.find(id); _keyboardEnabled = KeyboardEnabledState.find(id); _remoteCursorMoved = RemoteCursorMovedState.find(id); @@ -216,6 +221,7 @@ class _RemotePageState extends State }); return ImagePaint( id: widget.id, + zoomCursor: _zoomCursor, cursorOverImage: _cursorOverImage, keyboardEnabled: _keyboardEnabled, remoteCursorMoved: _remoteCursorMoved, @@ -233,6 +239,7 @@ class _RemotePageState extends State visible: _showRemoteCursor.isTrue && _remoteCursorMoved.isTrue, child: CursorPaint( id: widget.id, + zoomCursor: _zoomCursor, )))); paints.add(QualityMonitor(_ffi.qualityMonitorModel)); paints.add(RemoteMenubar( @@ -253,6 +260,7 @@ class _RemotePageState extends State class ImagePaint extends StatefulWidget { final String id; + final Rx zoomCursor; final Rx cursorOverImage; final Rx keyboardEnabled; final Rx remoteCursorMoved; @@ -261,6 +269,7 @@ class ImagePaint extends StatefulWidget { ImagePaint( {Key? key, required this.id, + required this.zoomCursor, required this.cursorOverImage, required this.keyboardEnabled, required this.remoteCursorMoved, @@ -277,6 +286,7 @@ class _ImagePaintState extends State { final ScrollController _vertical = ScrollController(); String get id => widget.id; + Rx get zoomCursor => widget.zoomCursor; Rx get cursorOverImage => widget.cursorOverImage; Rx get keyboardEnabled => widget.keyboardEnabled; Rx get remoteCursorMoved => widget.remoteCursorMoved; @@ -357,7 +367,7 @@ class _ImagePaintState extends State { if (cache == null) { return MouseCursor.defer; } else { - final key = cache.updateGetKey(scale); + final key = cache.updateGetKey(scale, zoomCursor.value); cursor.addKey(key); return FlutterCustomMemoryImageCursor( pixbuf: cache.data, @@ -500,8 +510,13 @@ class _ImagePaintState extends State { class CursorPaint extends StatelessWidget { final String id; + final RxBool zoomCursor; - const CursorPaint({Key? key, required this.id}) : super(key: key); + const CursorPaint({ + Key? key, + required this.id, + required this.zoomCursor, + }) : super(key: key); @override Widget build(BuildContext context) { @@ -516,13 +531,21 @@ class CursorPaint extends StatelessWidget { hoty = m.defaultImage!.height / 2; } } - return CustomPaint( - painter: ImagePainter( - image: m.image ?? m.defaultImage, - x: m.x - hotx + c.x / c.scale, - y: m.y - hoty + c.y / c.scale, - scale: c.scale), - ); + return zoomCursor.isTrue + ? CustomPaint( + painter: ImagePainter( + image: m.image ?? m.defaultImage, + x: m.x - hotx + c.x / c.scale, + y: m.y - hoty + c.y / c.scale, + scale: c.scale), + ) + : CustomPaint( + painter: ImagePainter( + image: m.image ?? m.defaultImage, + x: (m.x - hotx) * c.scale + c.x, + y: (m.y - hoty) * c.scale + c.y, + scale: 1.0), + ); } } diff --git a/flutter/lib/desktop/widgets/remote_menubar.dart b/flutter/lib/desktop/widgets/remote_menubar.dart index cdbeb0bed..6db5a7fb7 100644 --- a/flutter/lib/desktop/widgets/remote_menubar.dart +++ b/flutter/lib/desktop/widgets/remote_menubar.dart @@ -47,7 +47,8 @@ class MenubarState { } _initSet(bool s, bool p) { - show = RxBool(s); + // Show remubar when connection is established. + show = RxBool(true); _pin = RxBool(p); } @@ -1109,6 +1110,25 @@ class _RemoteMenubarState extends State { ); }()); + /// Show remote cursor + displayMenu.add(() { + final opt = 'zoom-cursor'; + final state = PeerBoolOption.find(widget.id, opt); + return MenuEntrySwitch2( + switchType: SwitchType.scheckbox, + text: translate('Zoom cursor'), + getter: () { + return state; + }, + setter: (bool v) async { + state.value = v; + await bind.sessionToggleOption(id: widget.id, value: opt); + }, + padding: padding, + dismissOnClicked: true, + ); + }()); + /// Show quality monitor displayMenu.add(MenuEntrySwitch( switchType: SwitchType.scheckbox, diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 6734bd8fb..a074bf266 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -718,35 +718,44 @@ class CursorData { int _doubleToInt(double v) => (v * 10e6).round().toInt(); - double _checkUpdateScale(double scale) { - // Update data if scale changed. - if (Platform.isWindows) { - final tgtWidth = (width * scale).toInt(); - final tgtHeight = (width * scale).toInt(); - if (tgtWidth < kMinCursorSize || tgtHeight < kMinCursorSize) { - double sw = kMinCursorSize.toDouble() / width; - double sh = kMinCursorSize.toDouble() / height; - scale = sw < sh ? sh : sw; + double _checkUpdateScale(double scale, bool shouldScale) { + double oldScale = this.scale; + if (!shouldScale) { + scale = 1.0; + } else { + // Update data if scale changed. + if (Platform.isWindows) { + final tgtWidth = (width * scale).toInt(); + final tgtHeight = (width * scale).toInt(); + if (tgtWidth < kMinCursorSize || tgtHeight < kMinCursorSize) { + double sw = kMinCursorSize.toDouble() / width; + double sh = kMinCursorSize.toDouble() / height; + scale = sw < sh ? sh : sw; + } } - if (_doubleToInt(this.scale) != _doubleToInt(scale)) { + } + + if (Platform.isWindows) { + if (_doubleToInt(oldScale) != _doubleToInt(scale)) { data = img2 .copyResize( image!, width: (width * scale).toInt(), height: (height * scale).toInt(), - interpolation: img2.Interpolation.linear, + interpolation: img2.Interpolation.average, ) .getBytes(format: img2.Format.bgra); } } + this.scale = scale; hotx = hotxOrigin * scale; hoty = hotyOrigin * scale; return scale; } - String updateGetKey(double scale) { - scale = _checkUpdateScale(scale); + String updateGetKey(double scale, bool shouldScale) { + scale = _checkUpdateScale(scale, shouldScale); return '${peerId}_${id}_${_doubleToInt(width * scale)}_${_doubleToInt(height * scale)}'; } } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 68c5dbf60..16bbdb590 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", "或"), ("Continue with", "使用"), ("Elevate", "提权"), + ("Zoom cursor", "缩放鼠标"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 98bb9c5d3..0f262cd25 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index b98e5ba3f..c7362e26f 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index 1e8083915..acc22a461 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 93394a91f..206229859 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index a00009b78..d0c569eff 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", "o"), ("Continue with", "Continuar con"), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index b6c3d002b..b602bd404 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -388,5 +388,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", "This PC"), ("or", "یا"), ("Continue with", "ادامه با"), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index ff4e2e083..f4ff46cdf 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", "ou"), ("Continue with", "Continuer avec"), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index 9bd5de216..aaad2e9f9 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", "vagy"), ("Continue with", "Folytatás a következővel"), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 7d4ae1634..96e7d38f4 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 3490a9b77..fc6b936bf 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 2953f80cd..1ff301bba 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index 2473ef2de..aa6c01e3d 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 1ce728db3..05055d1a3 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index ffe94432d..c62007778 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", "albo"), ("Continue with", "Kontynuuj z"), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index e7bb0e73c..ca0fcead9 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index bc35cfcb2..41459404b 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", "ou"), ("Continue with", "Continuar com"), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 9e9a60829..b5d747f9d 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", "или"), ("Continue with", "Продолжить с"), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 3970ef3b9..0844c8442 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index d9fd7b9bb..9f1779119 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index cd2c8b269..6b625b63a 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index da57cf07c..900f25ccd 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", "提權"), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index 10119d1e2..b336b1e36 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index 8bb164a8f..c21fe8aa8 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } From dcd2d93fcb9c864775cb591d67f9fcf6d9a050c8 Mon Sep 17 00:00:00 2001 From: ivanbea Date: Wed, 16 Nov 2022 11:26:53 +0100 Subject: [PATCH 048/116] add catalan translation ca.rs add catalan translation ca.rs --- src/lang/ca.rs | 393 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 393 insertions(+) create mode 100644 src/lang/ca.rs diff --git a/src/lang/ca.rs b/src/lang/ca.rs new file mode 100644 index 000000000..1958b5b94 --- /dev/null +++ b/src/lang/ca.rs @@ -0,0 +1,393 @@ +lazy_static::lazy_static! { +pub static ref T: std::collections::HashMap<&'static str, &'static str> = + [ + ("Status", "Estat"), + ("Your Desktop", "EL teu escriptori"), + ("desk_tip", "Pots accedir al teu escriptori amb aquest ID i contrasenya."), + ("Password", "Contrasenya"), + ("Ready", "Llest"), + ("Established", "Establert"), + ("connecting_status", "Connexió a la xarxa RustDesk en progrés..."), + ("Enable Service", "Habilitar Servei"), + ("Start Service", "Iniciar Servei"), + ("Service is running", "El servei s'està executant"), + ("Service is not running", "El servei no s'està executant"), + ("not_ready_status", "No està llest. Comprova la teva connexió"), + ("Control Remote Desktop", "Controlar escriptori remot"), + ("Transfer File", "Transferir arxiu"), + ("Connect", "Connectar"), + ("Recent Sessions", "Sessions recents"), + ("Address Book", "Directori"), + ("Confirmation", "Confirmació"), + ("TCP Tunneling", "Túnel TCP"), + ("Remove", "Eliminar"), + ("Refresh random password", "Actualitzar contrasenya aleatòria"), + ("Set your own password", "Estableix la teva pròpia contrasenya"), + ("Enable Keyboard/Mouse", "Habilitar teclat/ratolí"), + ("Enable Clipboard", "Habilitar portapapers"), + ("Enable File Transfer", "Habilitar transferència d'arxius"), + ("Enable TCP Tunneling", "Habilitar túnel TCP"), + ("IP Whitelisting", "Direccions IP admeses"), + ("ID/Relay Server", "Servidor ID/Relay"), + ("Import Server Config", "Importar configuració de servidor"), + ("Export Server Config", "Exportar configuració del servidor"), + ("Import server configuration successfully", "Configuració de servidor importada amb èxit"), + ("Export server configuration successfully", "Configuració de servidor exportada con èxit"), + ("Invalid server configuration", "Configuració de servidor incorrecta"), + ("Clipboard is empty", "El portapapers està buit"), + ("Stop service", "Aturar servei"), + ("Change ID", "Canviar ID"), + ("Website", "Lloc web"), + ("About", "Sobre"), + ("Mute", "Silenciar"), + ("Audio Input", "Entrada d'àudio"), + ("Enhancements", "Millores"), + ("Hardware Codec", "Còdec de hardware"), + ("Adaptive Bitrate", "Tasa de bits adaptativa"), + ("ID Server", "Servidor de IDs"), + ("Relay Server", "Servidor Relay"), + ("API Server", "Servidor API"), + ("invalid_http", "ha de començar amb http:// o https://"), + ("Invalid IP", "IP incorrecta"), + ("id_change_tip", "Només pots utilitzar caràcters a-z, A-Z, 0-9 e _ (guionet baix). El primer caràcter ha de ser a-z o A-Z. La longitut ha d'estar entre 6 i 16 caràcters."), + ("Invalid format", "Format incorrecte"), + ("server_not_support", "Encara no és compatible amb el servidor"), + ("Not available", "No disponible"), + ("Too frequent", "Massa comú"), + ("Cancel", "Cancel·lar"), + ("Skip", "Saltar"), + ("Close", "Tancar"), + ("Retry", "Reintentar"), + ("OK", ""), + ("Password Required", "Es necessita la contrasenya"), + ("Please enter your password", "Si us plau, introdueixi la seva contrasenya"), + ("Remember password", "Recordar contrasenya"), + ("Wrong Password", "Contrasenya incorrecta"), + ("Do you want to enter again?", "Vol tornar a entrar?"), + ("Connection Error", "Error de connexió"), + ("Error", ""), + ("Reset by the peer", "Reestablert pel peer"), + ("Connecting...", "Connectant..."), + ("Connection in progress. Please wait.", "Connexió en procés. Esperi."), + ("Please try 1 minute later", "Torni a provar-ho d'aquí un minut"), + ("Login Error", "Error d'inicio de sessió"), + ("Successful", "Exitós"), + ("Connected, waiting for image...", "Connectant, esperant imatge..."), + ("Name", "Nom"), + ("Type", "Tipus"), + ("Modified", "Modificat"), + ("Size", "Grandària"), + ("Show Hidden Files", "Mostrar arxius ocults"), + ("Receive", "Rebre"), + ("Send", "Enviar"), + ("Refresh File", "Actualitzar arxiu"), + ("Local", ""), + ("Remote", "Remot"), + ("Remote Computer", "Ordinador remot"), + ("Local Computer", "Ordinador local"), + ("Confirm Delete", "Confirma eliminació"), + ("Delete", "Eliminar"), + ("Properties", "Propietats"), + ("Multi Select", "Selecció múltiple"), + ("Select All", "Selecciona-ho Tot"), + ("Unselect All", "Deselecciona-ho Tot"), + ("Empty Directory", "Directori buit"), + ("Not an empty directory", "No és un directori buit"), + ("Are you sure you want to delete this file?", "Estàs segur que vols eliminar aquest arxiu?"), + ("Are you sure you want to delete this empty directory?", "Estàs segur que vols eliminar aquest directori buit?"), + ("Are you sure you want to delete the file of this directory?", "Estàs segur que vols eliminar aquest arxiu d'aquest directori?"), + ("Do this for all conflicts", "Fes això per a tots els conflictes"), + ("This is irreversible!", "Això és irreversible!"), + ("Deleting", "Eliminant"), + ("files", "arxius"), + ("Waiting", "Esperant"), + ("Finished", "Acabat"), + ("Speed", "Velocitat"), + ("Custom Image Quality", "Qualitat d'imatge personalitzada"), + ("Privacy mode", "Mode privat"), + ("Block user input", "Bloquejar entrada d'usuari"), + ("Unblock user input", "Desbloquejar entrada d'usuari"), + ("Adjust Window", "Ajustar finestra"), + ("Original", "Original"), + ("Shrink", "Reduir"), + ("Stretch", "Estirar"), + ("Scrollbar", "Barra de desplaçament"), + ("ScrollAuto", "Desplaçament automàtico"), + ("Good image quality", "Bona qualitat d'imatge"), + ("Balanced", "Equilibrat"), + ("Optimize reaction time", "Optimitzar el temps de reacció"), + ("Custom", "Personalitzat"), + ("Show remote cursor", "Mostrar cursor remot"), + ("Show quality monitor", "Mostrar qualitat del monitor"), + ("Disable clipboard", "Deshabilitar portapapers"), + ("Lock after session end", "Bloquejar després del final de la sessió"), + ("Insert", "Inserir"), + ("Insert Lock", "Inserir bloqueig"), + ("Refresh", "Actualitzar"), + ("ID does not exist", "L'ID no existeix"), + ("Failed to connect to rendezvous server", "No es pot connectar al servidor rendezvous"), + ("Please try later", "Siusplau provi-ho més tard"), + ("Remote desktop is offline", "L'escriptori remot està desconecctat"), + ("Key mismatch", "La clau no coincideix"), + ("Timeout", "Temps esgotat"), + ("Failed to connect to relay server", "No es pot connectar al servidor de relay"), + ("Failed to connect via rendezvous server", "No es pot connectar a través del servidor de rendezvous"), + ("Failed to connect via relay server", "No es pot connectar a través del servidor de relay"), + ("Failed to make direct connection to remote desktop", "No s'ha pogut establir una connexió directa amb l'escriptori remot"), + ("Set Password", "Configurar la contrasenya"), + ("OS Password", "contrasenya del sistema operatiu"), + ("install_tip", ""), + ("Click to upgrade", "Clicar per actualitzar"), + ("Click to download", "Clicar per descarregar"), + ("Click to update", "Clicar per refrescar"), + ("Configure", "Configurar"), + ("config_acc", ""), + ("config_screen", ""), + ("Installing ...", "Instal·lant ..."), + ("Install", "Instal·lar"), + ("Installation", "Instal·lació"), + ("Installation Path", "Ruta d'instal·lació"), + ("Create start menu shortcuts", "Crear accessos directes al menú d'inici"), + ("Create desktop icon", "Crear icona d'escriptori"), + ("agreement_tip", ""), + ("Accept and Install", "Acceptar i instal·lar"), + ("End-user license agreement", "Acord de llicència d'usuario final"), + ("Generating ...", "Generant ..."), + ("Your installation is lower version.", "La seva instal·lació és una versión inferior."), + ("not_close_tcp_tip", ""), + ("Listening ...", "Escoltant..."), + ("Remote Host", "Hoste remot"), + ("Remote Port", "Port remot"), + ("Action", "Acció"), + ("Add", "Afegirr"), + ("Local Port", "Port local"), + ("Local Address", "Adreça Local"), + ("Change Local Port", "Canviar Port Local"), + ("setup_server_tip", ""), + ("Too short, at least 6 characters.", "Massa curt, almenys 6 caràcters."), + ("The confirmation is not identical.", "La confirmación no coincideix."), + ("Permissions", "Permisos"), + ("Accept", "Acceptar"), + ("Dismiss", "Cancel·lar"), + ("Disconnect", "Desconnectar"), + ("Allow using keyboard and mouse", "Permetre l'ús del teclat i ratolí"), + ("Allow using clipboard", "Permetre usar portapapers"), + ("Allow hearing sound", "Permetre escoltar so"), + ("Allow file copy and paste", "Permetre copiar i enganxar arxius"), + ("Connected", "Connectat"), + ("Direct and encrypted connection", "Connexió directa i xifrada"), + ("Relayed and encrypted connection", "connexió retransmesa i xifrada"), + ("Direct and unencrypted connection", "connexió directa i sense xifrar"), + ("Relayed and unencrypted connection", "connexió retransmesa i sense xifrar"), + ("Enter Remote ID", "Introduixi l'ID remot"), + ("Enter your password", "Introdueixi la seva contrasenya"), + ("Logging in...", "Iniciant sessió..."), + ("Enable RDP session sharing", "Habilitar l'ús compartit de sessions RDP"), + ("Auto Login", "Inici de sessió automàtic"), + ("Enable Direct IP Access", "Habilitar accés IP directe"), + ("Rename", "Renombrar"), + ("Space", "Espai"), + ("Create Desktop Shortcut", "Crear accés directe a l'escriptori"), + ("Change Path", "Cnviar ruta"), + ("Create Folder", "Crear carpeta"), + ("Please enter the folder name", "Indiqui el nom de la carpeta"), + ("Fix it", "Soluciona-ho"), + ("Warning", "Avís"), + ("Login screen using Wayland is not supported", "La pantalla d'inici de sessió amb Wayland no és compatible"), + ("Reboot required", "Cal reiniciar"), + ("Unsupported display server ", "Servidor de visualització no compatible"), + ("x11 expected", "x11 necessari"), + ("Port", ""), + ("Settings", "Ajustaments"), + ("Username", " Nom d'usuari"), + ("Invalid port", "Port incorrecte"), + ("Closed manually by the peer", "Tancat manualment pel peer"), + ("Enable remote configuration modification", "Habilitar modificació remota de configuració"), + ("Run without install", "Executar sense instal·lar"), + ("Always connected via relay", "Connectat sempre a través de relay"), + ("Always connect via relay", "Connecta sempre a través de relay"), + ("whitelist_tip", ""), + ("Login", "Inicia sessió"), + ("Logout", "Sortir"), + ("Tags", ""), + ("Search ID", "Cerca ID"), + ("Current Wayland display server is not supported", "El servidor de visualització actual de Wayland no és compatible"), + ("whitelist_sep", ""), + ("Add ID", "Afegir ID"), + ("Add Tag", "Afegir tag"), + ("Unselect all tags", "Deseleccionar tots els tags"), + ("Network error", "Error de xarxa"), + ("Username missed", "Nom d'usuari oblidat"), + ("Password missed", "Contrasenya oblidada"), + ("Wrong credentials", "Credencials incorrectes"), + ("Edit Tag", "Editar tag"), + ("Unremember Password", "Contrasenya oblidada"), + ("Favorites", "Preferits"), + ("Add to Favorites", "Afegir a preferits"), + ("Remove from Favorites", "Treure de preferits"), + ("Empty", "Buit"), + ("Invalid folder name", "Nom de carpeta incorrecte"), + ("Socks5 Proxy", "Proxy Socks5"), + ("Hostname", ""), + ("Discovered", "Descobert"), + ("install_daemon_tip", ""), + ("Remote ID", "ID remot"), + ("Paste", "Enganxar"), + ("Paste here?", "Enganxar aquí?"), + ("Are you sure to close the connection?", "Estàs segur que vols tancar la connexió?"), + ("Download new version", "Descarregar nova versió"), + ("Touch mode", "Mode tàctil"), + ("Mouse mode", "Mode ratolí"), + ("One-Finger Tap", "Toqui amb un dit"), + ("Left Mouse", "Ratolí esquerra"), + ("One-Long Tap", "Toc llarg"), + ("Two-Finger Tap", "Toqui amb dos dits"), + ("Right Mouse", "Botó dret"), + ("One-Finger Move", "Moviment amb un dir"), + ("Double Tap & Move", "Toqui dos cops i mogui"), + ("Mouse Drag", "Arrastri amb el ratolí"), + ("Three-Finger vertically", "Tres dits verticalment"), + ("Mouse Wheel", "Roda del ratolí"), + ("Two-Finger Move", "Moviment amb dos dits"), + ("Canvas Move", "Moviment del llenç"), + ("Pinch to Zoom", "Pessiga per fer zoom"), + ("Canvas Zoom", "Ampliar llenç"), + ("Reset canvas", "Reestablir llenç"), + ("No permission of file transfer", "No tens permís de transferència de fitxers"), + ("Note", "Nota"), + ("Connection", "connexió"), + ("Share Screen", "Compartir pantalla"), + ("CLOSE", "TANCAR"), + ("OPEN", "OBRIR"), + ("Chat", "Xat"), + ("Total", "Total"), + ("items", "ítems"), + ("Selected", "Seleccionat"), + ("Screen Capture", "Captura de pantalla"), + ("Input Control", "Control d'entrada"), + ("Audio Capture", "Captura d'àudio"), + ("File Connection", "connexió d'arxius"), + ("Screen Connection", "connexió de pantalla"), + ("Do you accept?", "Acceptes?"), + ("Open System Setting", "Configuració del sistema obert"), + ("How to get Android input permission?", "Com obtenir el permís d'entrada d'Android?"), + ("android_input_permission_tip1", "Per a que un dispositiu remot controli el seu dispositiu Android amb el ratolí o tocs, cal permetre que RustDesk utilitzi el servei d' \"Accesibilitat\"."), + ("android_input_permission_tip2", "Vagi a la pàgina de [Serveis instal·lats], activi el servici [RustDesk Input]."), + ("android_new_connection_tip", "S'ha rebut una nova sol·licitud de control per al dispositiu actual."), + ("android_service_will_start_tip", "Habilitar la captura de pantalla iniciarà el servei automàticament, i permetrà que altres dispositius sol·licitin una connexió des d'aquest dispositiu."), + ("android_stop_service_tip", "Tancar el servei tancarà totes les connexions establertes."), + ("android_version_audio_tip", "La versión actual de Android no admet la captura d'àudio, actualizi a Android 10 o superior."), + ("android_start_service_tip", "Toqui el permís [Iniciar servei] o OBRIR [Captura de pantalla] per iniciar el servei d'ús compartit de pantalla."), + ("Account", "Compte"), + ("Overwrite", "Sobreescriure"), + ("This file exists, skip or overwrite this file?", "Aquest arxiu ja existeix, ometre o sobreescriure l'arxiu?"), + ("Quit", "Sortir"), + ("doc_mac_permission", "https://rustdesk.com/docs/en/manual/mac/#enable-permissions"), + ("Help", "Ajuda"), + ("Failed", "Ha fallat"), + ("Succeeded", "Aconseguit"), + ("Someone turns on privacy mode, exit", "Algú ha activat el mode de privacitat, surti"), + ("Unsupported", "No suportat"), + ("Peer denied", "Peer denegat"), + ("Please install plugins", "Instal·li complements"), + ("Peer exit", "El peer ha sortit"), + ("Failed to turn off", "Error en apagar"), + ("Turned off", "Apagat"), + ("In privacy mode", "En mode de privacitat"), + ("Out privacy mode", "Fora del mode de privacitat"), + ("Language", "Idioma"), + ("Keep RustDesk background service", "Mantenir RustDesk com a servei en segon pla"), + ("Ignore Battery Optimizations", "Ignorar optimizacions de la bateria"), + ("android_open_battery_optimizations_tip", ""), + ("Connection not allowed", "Connexió no disponible"), + ("Legacy mode", "Mode heretat"), + ("Map mode", "Mode mapa"), + ("Translate mode", "Mode traduit"), + ("Use temporary password", "Utilitzar contrasenya temporal"), + ("Use permanent password", "Utilitzar contrasenya permament"), + ("Use both passwords", "Utilitzar ambdues contrasenyas"), + ("Set permanent password", "Establir contrasenya permament"), + ("Set temporary password length", "Establir llargada de la contrasenya temporal"), + ("Enable Remote Restart", "Activar reinici remot"), + ("Allow remote restart", "Permetre reinici remot"), + ("Restart Remote Device", "Reiniciar dispositiu"), + ("Are you sure you want to restart", "Està segur que vol reiniciar?"), + ("Restarting Remote Device", "Reiniciant dispositiu remot"), + ("remote_restarting_tip", "Dispositiu remot reiniciant, tanqui aquest missatge i tornis a connectar amb la contrasenya."), + ("Copied", "Copiat"), + ("Exit Fullscreen", "Sortir de la pantalla completa"), + ("Fullscreen", "Pantalla completa"), + ("Mobile Actions", "Accions mòbils"), + ("Select Monitor", "Seleccionar monitor"), + ("Control Actions", "Accions de control"), + ("Display Settings", "Configuració de pantalla"), + ("Ratio", "Relació"), + ("Image Quality", "Qualitat d'imatge"), + ("Scroll Style", "Estil de desplaçament"), + ("Show Menubar", "Mostra barra de menú"), + ("Hide Menubar", "Amaga barra de menú"), + ("Direct Connection", "Connexió directa"), + ("Relay Connection", "Connexió Relay"), + ("Secure Connection", "Connexió segura"), + ("Insecure Connection", "Connexió insegura"), + ("Scale original", "Escala original"), + ("Scale adaptive", "Escala adaptativa"), + ("General", ""), + ("Security", "Seguritat"), + ("Account", "Compte"), + ("Theme", "Tema"), + ("Dark Theme", "Tema Fosc"), + ("Dark", "Fosc"), + ("Light", "Clar"), + ("Follow System", "Tema del sistema"), + ("Enable hardware codec", "Habilitar còdec per hardware"), + ("Unlock Security Settings", "Desbloquejar ajustaments de seguritat"), + ("Enable Audio", "Habilitar àudio"), + ("Temporary Password Length", "Longitut de Contrasenya Temporal"), + ("Unlock Network Settings", "Desbloquejar Ajustaments de Xarxa"), + ("Server", "Servidor"), + ("Direct IP Access", "Accés IP Directe"), + ("Proxy", ""), + ("Port", ""), + ("Apply", "Aplicar"), + ("Disconnect all devices?", "Desconnectar tots els dispositius?"), + ("Clear", "Netejar"), + ("Audio Input Device", "Dispositiu d'entrada d'àudio"), + ("Deny remote access", "Denegar accés remot"), + ("Use IP Whitelisting", "Utilitza llista de IPs admeses"), + ("Network", "Xarxa"), + ("Enable RDP", "Habilitar RDP"), + ("Pin menubar", "Bloqueja barra de menú"), + ("Unpin menubar", "Desbloquejar barra de menú"), + ("Recording", "Gravant"), + ("Directory", "Directori"), + ("Automatically record incoming sessions", "Gravació automàtica de sessions entrants"), + ("Change", "Canviar"), + ("Start session recording", "Començar gravació de sessió"), + ("Stop session recording", "Aturar gravació de sessió"), + ("Enable Recording Session", "Habilitar gravació de sessió"), + ("Allow recording session", "Permetre gravació de sessió"), + ("Enable LAN Discovery", "Habilitar descobriment de LAN"), + ("Deny LAN Discovery", "Denegar descobriment de LAN"), + ("Write a message", "Escriure un missatge"), + ("Prompt", ""), + ("elevation_prompt", ""), + ("uac_warning", ""), + ("elevated_foreground_window_warning", ""), + ("Disconnected", "Desconnectat"), + ("Other", "Altre"), + ("Confirm before closing multiple tabs", "Confirmar abans de tancar múltiples pestanyes"), + ("Keyboard Settings", "Ajustaments de teclat"), + ("Custom", "Personalitzat"), + ("Full Access", "Acces complet"), + ("Screen Share", "Compartir pantalla"), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland requereix Ubuntu 21.04 o una versió superior."), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland requereix una versió superior de la distribución de Linux. Provi l'escriptori X11 o canvïi el seu sistema operatiu."), + ("JumpLink", "Veure"), + ("Please Select the screen to be shared(Operate on the peer side).", "Seleccioni la pantalla que es compartirà (Operar al costat del peer)."), + ("Show RustDesk", "Mostrar RustDesk"), + ("This PC", "Aquest PC"), + ("or", "o"), + ("Continue with", "Continuar amb"), + ].iter().cloned().collect(); +} From 0c854e8c121ebdbfbc8297d72580eabcf6ff4c9c Mon Sep 17 00:00:00 2001 From: ivanbea Date: Wed, 16 Nov 2022 11:28:37 +0100 Subject: [PATCH 049/116] update lang.rs to add catalan update lang.rs to add catalan --- src/lang.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lang.rs b/src/lang.rs index db59e9f54..4579ca893 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -24,6 +24,7 @@ mod vn; mod kz; mod ua; mod fa; +mod ca; lazy_static::lazy_static! { pub static ref LANGS: Value = @@ -51,6 +52,7 @@ lazy_static::lazy_static! { ("kz", "Қазақ"), ("ua", "Українська"), ("fa", "فارسی"), + ("ca", "català"), ]); } @@ -102,6 +104,7 @@ pub fn translate_locale(name: String, locale: &str) -> String { "kz" => kz::T.deref(), "ua" => ua::T.deref(), "fa" => fa::T.deref(), + "ca" => ca::T.deref(), _ => en::T.deref(), }; if let Some(v) = m.get(&name as &str) { From 628dcf89746bd43b3530be3d1c953b7ccc2ccf3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Be=C3=A0?= Date: Wed, 16 Nov 2022 13:36:57 +0100 Subject: [PATCH 050/116] Update lang.rs --- src/lang.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang.rs b/src/lang.rs index 4579ca893..30ce2d372 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -52,7 +52,7 @@ lazy_static::lazy_static! { ("kz", "Қазақ"), ("ua", "Українська"), ("fa", "فارسی"), - ("ca", "català"), + ("ca", "Català"), ]); } From c802b1e95dbbe4f329969c1a9d03cad296ed7853 Mon Sep 17 00:00:00 2001 From: fufesou Date: Wed, 16 Nov 2022 19:49:52 +0800 Subject: [PATCH 051/116] fix window border width whenn fullscreen Signed-off-by: fufesou --- flutter/lib/desktop/pages/remote_tab_page.dart | 14 +++++++++----- flutter/lib/models/model.dart | 2 +- flutter/lib/models/state_model.dart | 4 +++- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index 5e49895f4..f6ebc0f86 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -116,12 +116,14 @@ class _ConnectionTabPageState extends State { @override Widget build(BuildContext context) { - final tabWidget = Container( - decoration: BoxDecoration( + final tabWidget = Obx( + () => Container( + decoration: BoxDecoration( border: Border.all( color: MyTheme.color(context).border!, - width: kWindowBorderWidth)), - child: Scaffold( + width: stateGlobal.windowBorderWidth.value), + ), + child: Scaffold( backgroundColor: Theme.of(context).backgroundColor, body: DesktopTab( controller: tabController, @@ -182,7 +184,9 @@ class _ConnectionTabPageState extends State { ); } }), - )), + ), + ), + ), ); return Platform.isMacOS ? tabWidget diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index a074bf266..eca94d5e5 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -593,7 +593,7 @@ class CanvasModel with ChangeNotifier { return parent.target?.ffiModel.display.height ?? defaultHeight; } - double get windowBorderWidth => stateGlobal.windowBorderWidth; + double get windowBorderWidth => stateGlobal.windowBorderWidth.value; double get tabBarHeight => stateGlobal.tabBarHeight; Size get size { diff --git a/flutter/lib/models/state_model.dart b/flutter/lib/models/state_model.dart index dab21fcb6..1ceee2fe0 100644 --- a/flutter/lib/models/state_model.dart +++ b/flutter/lib/models/state_model.dart @@ -8,14 +8,15 @@ class StateGlobal { bool _fullscreen = false; final RxBool _showTabBar = true.obs; final RxDouble _resizeEdgeSize = 8.0.obs; + final RxDouble _windowBorderWidth = RxDouble(kWindowBorderWidth); final RxBool showRemoteMenuBar = false.obs; int get windowId => _windowId; bool get fullscreen => _fullscreen; double get tabBarHeight => fullscreen ? 0 : kDesktopRemoteTabBarHeight; - double get windowBorderWidth => fullscreen ? 0 : kWindowBorderWidth; RxBool get showTabBar => _showTabBar; RxDouble get resizeEdgeSize => _resizeEdgeSize; + RxDouble get windowBorderWidth => _windowBorderWidth; setWindowId(int id) => _windowId = id; setFullscreen(bool v) { @@ -24,6 +25,7 @@ class StateGlobal { _showTabBar.value = !_fullscreen; _resizeEdgeSize.value = fullscreen ? kFullScreenEdgeSize : kWindowEdgeSize; + _windowBorderWidth.value = fullscreen ? 0 : kWindowBorderWidth; WindowController.fromWindowId(windowId).setFullscreen(_fullscreen); } } From 9946a5fc63c58efe218f2c8b5afe516cadc46d0f Mon Sep 17 00:00:00 2001 From: "Miguel F. G" <116861809+flusheDData@users.noreply.github.com> Date: Wed, 16 Nov 2022 17:41:29 +0100 Subject: [PATCH 052/116] Update es.rs New items. --- src/lang/es.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lang/es.rs b/src/lang/es.rs index d0c569eff..ca866641a 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -388,7 +388,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", "Este PC"), ("or", "o"), ("Continue with", "Continuar con"), - ("Elevate", ""), - ("Zoom cursor", ""), + ("Elevate", "Elevar"), + ("Zoom cursor", "Ampliar cursor"), ].iter().cloned().collect(); } From 2e58f072b0d2afbfc841238576b9d06c1af766de Mon Sep 17 00:00:00 2001 From: Kingtous Date: Thu, 17 Nov 2022 10:58:23 +0800 Subject: [PATCH 053/116] feat: add RPM build --- .github/workflows/flutter-nightly.yml | 36 ++++++++++++++++++--------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/.github/workflows/flutter-nightly.yml b/.github/workflows/flutter-nightly.yml index fdbced00a..62637a259 100644 --- a/.github/workflows/flutter-nightly.yml +++ b/.github/workflows/flutter-nightly.yml @@ -120,6 +120,13 @@ jobs: - name: Checkout source code uses: actions/checkout@v3 + - name: Get build target triple + uses: jungwinter/split@v2 + id: build-target-triple + with: + separator: '-' + msg: ${{ matrix.job.target }} + - name: Install prerequisites run: | case ${{ matrix.job.target }} in @@ -250,19 +257,24 @@ jobs: files: | res/rustdesk*.zst - # - name: build RPM package - # id: rpm - # uses: Kingtous/rustdesk-rpmbuild@master - # with: - # spec_file: "res/rpm-flutter.spec" + - name: Make RPM package + shell: bash + if: ${{ matrix.job.extra-build-args == '' }} + run: | + sudo apt install -y rpm + pushd ~/rpmbuild/RPMS/${{ steps.build-target-triple.outputs._0 }} + for name in rustdesk*??.rpm; do + mv "$name" "${name%%.rpm}-fedora28-centos8.rpm" + done - # - name: Publish fedora28/centos8 package - # uses: softprops/action-gh-release@v1 - # with: - # prerelease: true - # tag_name: ${{ env.TAG_NAME }} - # files: | - # ${{ steps.rpm.outputs.rpm_dir_path }}/* + - name: Publish fedora28/centos8 package + if: ${{ matrix.job.extra-build-args == '' }} + uses: softprops/action-gh-release@v1 + with: + prerelease: true + tag_name: ${{ env.TAG_NAME }} + files: | + ~/rpmbuild/RPMS/${{ steps.build-target-triple.outputs._0 }}/* build-flatpak: name: Build Flatpak From 19ea51d07cb51aab531f6611231825ce40848b43 Mon Sep 17 00:00:00 2001 From: Kingtous Date: Thu, 17 Nov 2022 11:16:27 +0800 Subject: [PATCH 054/116] fix: rpm flutter build fix: fedora nightly build --- .github/workflows/flutter-nightly.yml | 3 ++- res/rpm-flutter.spec | 21 ++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/flutter-nightly.yml b/.github/workflows/flutter-nightly.yml index 62637a259..f2391e77e 100644 --- a/.github/workflows/flutter-nightly.yml +++ b/.github/workflows/flutter-nightly.yml @@ -262,6 +262,7 @@ jobs: if: ${{ matrix.job.extra-build-args == '' }} run: | sudo apt install -y rpm + HBB=`pwd` rpmbuild ./res/rpm-flutter.spec -bb pushd ~/rpmbuild/RPMS/${{ steps.build-target-triple.outputs._0 }} for name in rustdesk*??.rpm; do mv "$name" "${name%%.rpm}-fedora28-centos8.rpm" @@ -274,7 +275,7 @@ jobs: prerelease: true tag_name: ${{ env.TAG_NAME }} files: | - ~/rpmbuild/RPMS/${{ steps.build-target-triple.outputs._0 }}/* + /home/runner/rpmbuild/RPMS/${{ steps.build-target-triple.outputs._0 }}/*.rpm build-flatpak: name: Build Flatpak diff --git a/res/rpm-flutter.spec b/res/rpm-flutter.spec index a01926baa..2ba1cbfa4 100644 --- a/res/rpm-flutter.spec +++ b/res/rpm-flutter.spec @@ -3,8 +3,8 @@ Version: 1.2.0 Release: 0 Summary: RPM package License: GPL-3.0 -Requires: gtk3 libxcb libxdo libXfixes pipewire alsa-lib curl libappindicator libvdpau1 libva2 - +Requires: gtk3 libxcb libxdo libXfixes pipewire alsa-lib curl libappindicator-gtk3 libvdpau libva +Provides: libdesktop_drop_plugin.so()(64bit), libdesktop_multi_window_plugin.so()(64bit), libflutter_custom_cursor_plugin.so()(64bit), libflutter_linux_gtk.so()(64bit), libscreen_retriever_plugin.so()(64bit), libtray_manager_plugin.so()(64bit), liburl_launcher_linux_plugin.so()(64bit), libwindow_manager_plugin.so()(64bit), libwindow_size_plugin.so()(64bit) %description The best open-source remote desktop client software, written in Rust. @@ -19,17 +19,14 @@ The best open-source remote desktop client software, written in Rust. %install -mkdir -p "${buildroot}/usr/lib/rustdesk" && cp -r ${HBB}/flutter/build/linux/x64/release/bundle/* -t "${buildroot}/usr/lib/rustdesk" -mkdir -p "${buildroot}/usr/bin" -pushd ${buildroot} && ln -s /usr/lib/rustdesk/rustdesk usr/bin/rustdesk && popd -install -Dm 644 $HBB/res/rustdesk.service -t "${buildroot}/usr/share/rustdesk/files" -install -Dm 644 $HBB/res/rustdesk.desktop -t "${buildroot}/usr/share/rustdesk/files" -install -Dm 644 $HBB/res/rustdesk-link.desktop -t "${buildroot}/usr/share/rustdesk/files" -install -Dm 644 $HBB/res/128x128@2x.png "${buildroot}/usr/share/rustdesk/files/rustdesk.png" - +mkdir -p "%{buildroot}/usr/lib/rustdesk" && cp -r ${HBB}/flutter/build/linux/x64/release/bundle/* -t "%{buildroot}/usr/lib/rustdesk" +mkdir -p "%{buildroot}/usr/bin" +install -Dm 644 $HBB/res/rustdesk.service -t "%{buildroot}/usr/share/rustdesk/files" +install -Dm 644 $HBB/res/rustdesk.desktop -t "%{buildroot}/usr/share/rustdesk/files" +install -Dm 644 $HBB/res/rustdesk-link.desktop -t "%{buildroot}/usr/share/rustdesk/files" +install -Dm 644 $HBB/res/128x128@2x.png "%{buildroot}/usr/share/rustdesk/files/rustdesk.png" %files -/usr/bin/rustdesk /usr/lib/rustdesk/* /usr/share/rustdesk/files/rustdesk.service /usr/share/rustdesk/files/rustdesk.png @@ -56,6 +53,7 @@ esac cp /usr/share/rustdesk/files/rustdesk.service /etc/systemd/system/rustdesk.service cp /usr/share/rustdesk/files/rustdesk.desktop /usr/share/applications/ cp /usr/share/rustdesk/files/rustdesk-link.desktop /usr/share/applications/ +ln -s /usr/lib/rustdesk/rustdesk /usr/bin/rustdesk systemctl daemon-reload systemctl enable rustdesk systemctl start rustdesk @@ -80,6 +78,7 @@ case "$1" in # for uninstall rm /usr/share/applications/rustdesk.desktop || true rm /usr/share/applications/rustdesk-link.desktop || true + rm /usr/bin/rustdesk || true update-desktop-database ;; 1) From 403861c3cef67e3b5fe776e677581bf7c2db210f Mon Sep 17 00:00:00 2001 From: Kingtous Date: Thu, 17 Nov 2022 15:54:33 +0800 Subject: [PATCH 055/116] fix: multi window existence on taskbar --- flutter/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index ed7fad5dd..e76855f62 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -63,7 +63,7 @@ dependencies: desktop_multi_window: git: url: https://github.com/Kingtous/rustdesk_desktop_multi_window - ref: fc14252a5e32236b68a91df0be12d9950c525069 + ref: 9b4c5ac1aec2c4d1bdabb4dd29e4bc3b75c76a79 freezed_annotation: ^2.0.3 tray_manager: git: From 1e2429b2a9f14da690c29df30eec19f123b9a1b8 Mon Sep 17 00:00:00 2001 From: KoalaBear84 Date: Thu, 17 Nov 2022 08:57:53 +0100 Subject: [PATCH 056/116] Update desktop_setting_page.dart MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use real copyright symbol © --- flutter/lib/desktop/pages/desktop_setting_page.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index ab8f76ca5..009b784ad 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -1075,7 +1075,7 @@ class _AboutState extends State<_About> { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'Copyright © 2022 Purslane Ltd.\n$license', + 'Copyright © 2022 Purslane Ltd.\n$license', style: const TextStyle(color: Colors.white), ), const Text( From d24e7b25ab0cad68f3d1acb2d2ddc83c6ce9aaa5 Mon Sep 17 00:00:00 2001 From: Kingtous Date: Thu, 17 Nov 2022 16:36:07 +0800 Subject: [PATCH 057/116] feat: add build date --- Cargo.toml | 1 + flutter/lib/desktop/pages/desktop_setting_page.dart | 5 ++++- libs/hbb_common/src/lib.rs | 10 +++++++--- src/flutter_ffi.rs | 4 ++++ 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 689e1a989..836bd07d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,6 +67,7 @@ rdev = { git = "https://github.com/asur4s/rdev" } url = { version = "2.1", features = ["serde"] } reqwest = { version = "0.11", features = ["blocking", "json", "rustls-tls"], default-features=false } +chrono = "0.4.23" [target.'cfg(not(any(target_os = "android", target_os = "linux")))'.dependencies] cpal = "0.13.5" diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index 009b784ad..b4c69a6a6 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -1029,10 +1029,12 @@ class _AboutState extends State<_About> { return _futureBuilder(future: () async { final license = await bind.mainGetLicense(); final version = await bind.mainGetVersion(); - return {'license': license, 'version': version}; + final buildDate = await bind.mainGetBuildDate(); + return {'license': license, 'version': version, 'buildDate': buildDate}; }(), hasData: (data) { final license = data['license'].toString(); final version = data['version'].toString(); + final buildDate = data['buildDate'].toString(); const linkStyle = TextStyle(decoration: TextDecoration.underline); final scrollController = ScrollController(); return DesktopScrollWrapper( @@ -1048,6 +1050,7 @@ class _AboutState extends State<_About> { height: 8.0, ), Text('Version: $version').marginSymmetric(vertical: 4.0), + Text('Build Date: $buildDate').marginSymmetric(vertical: 4.0), InkWell( onTap: () { launchUrlString('https://rustdesk.com/privacy'); diff --git a/libs/hbb_common/src/lib.rs b/libs/hbb_common/src/lib.rs index 02acfd9ff..ae564685f 100644 --- a/libs/hbb_common/src/lib.rs +++ b/libs/hbb_common/src/lib.rs @@ -161,19 +161,23 @@ pub fn get_version_from_url(url: &str) -> String { } pub fn gen_version() { + use std::io::prelude::*; let mut file = File::create("./src/version.rs").unwrap(); for line in read_lines("Cargo.toml").unwrap() { if let Ok(line) = line { let ab: Vec<&str> = line.split("=").map(|x| x.trim()).collect(); if ab.len() == 2 && ab[0] == "version" { - use std::io::prelude::*; - file.write_all(format!("pub const VERSION: &str = {};", ab[1]).as_bytes()) + file.write_all(format!("pub const VERSION: &str = {};\n", ab[1]).as_bytes()) .ok(); - file.sync_all().ok(); break; } } } + // generate build date + let build_date = format!("{}", chrono::Local::now().format("%Y-%m-%d %H:%M")); + file.write_all(format!("pub const BUILD_DATE: &str = \"{}\";", build_date).as_bytes()) + .ok(); + file.sync_all().ok(); } fn read_lines

(filename: P) -> io::Result>> diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 856c4ed21..8627168a4 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -1025,6 +1025,10 @@ pub fn main_get_icon() -> String { return String::new(); } +pub fn main_get_build_date() -> String { + crate::BUILD_DATE.to_string() +} + #[no_mangle] unsafe extern "C" fn translate(name: *const c_char, locale: *const c_char) -> *const c_char { let name = CStr::from_ptr(name); From d804ae4e230c5290e335613b548175422bdf7243 Mon Sep 17 00:00:00 2001 From: neoGalaxy88 Date: Thu, 17 Nov 2022 11:53:49 +0100 Subject: [PATCH 058/116] Update it.rs --- src/lang/it.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/lang/it.rs b/src/lang/it.rs index fc6b936bf..731b5643d 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -113,12 +113,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Stretch", "Allarga"), ("Scrollbar", "Barra di scorrimento"), ("ScrollAuto", "Scorri automaticamente"), - ("Good image quality", "Buona qualità immagine"), + ("Good image quality", "Qualità immagine migliore"), ("Balanced", "Bilanciato"), ("Optimize reaction time", "Ottimizza il tempo di reazione"), - ("Custom", ""), + ("Custom", "Personalizza"), ("Show remote cursor", "Mostra il cursore remoto"), - ("Show quality monitor", ""), + ("Show quality monitor", "Visualizza qualità video"), ("Disable clipboard", "Disabilita appunti"), ("Lock after session end", "Blocca al termine della sessione"), ("Insert", "Inserisci"), @@ -161,8 +161,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Action", "Azione"), ("Add", "Aggiungi"), ("Local Port", "Porta locale"), - ("Local Address", ""), - ("Change Local Port", ""), + ("Local Address", "Indirizzo locale"), + ("Change Local Port", "Cambia porta locale"), ("setup_server_tip", "Per una connessione più veloce, configura un tuo server"), ("Too short, at least 6 characters.", "Troppo breve, almeno 6 caratteri"), ("The confirmation is not identical.", "La conferma non corrisponde"), @@ -197,7 +197,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Reboot required", "Riavvio necessario"), ("Unsupported display server ", "Display server non supportato"), ("x11 expected", "x11 necessario"), - ("Port", ""), + ("Port", "Porta"), ("Settings", "Impostazioni"), ("Username", " Nome utente"), ("Invalid port", "Porta non valida"), @@ -314,7 +314,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Are you sure you want to restart", "Sei sicuro di voler riavviare?"), ("Restarting Remote Device", "Il dispositivo remoto si sta riavviando"), ("remote_restarting_tip", "Riavviare il dispositivo remoto"), - ("Copied", ""), + ("Copied", "Copiato"), ("Exit Fullscreen", "Esci dalla modalità schermo intero"), ("Fullscreen", "A schermo intero"), ("Mobile Actions", "Azioni mobili"), @@ -332,11 +332,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Insecure Connection", "Connessione insicura"), ("Scale original", "Scala originale"), ("Scale adaptive", "Scala adattiva"), - ("General", ""), - ("Security", ""), - ("Account", ""), - ("Theme", ""), - ("Dark Theme", ""), + ("General", "Generale"), + ("Security", "Sicurezza"), + ("Account", "Account"), + ("Theme", "Tema"), + ("Dark Theme", "Tema Scuro"), ("Dark", ""), ("Light", ""), ("Follow System", ""), From 75d8168070b76c4f9051817b6b6eea3abdc05a2e Mon Sep 17 00:00:00 2001 From: fufesou Date: Thu, 17 Nov 2022 18:52:27 +0800 Subject: [PATCH 059/116] enable rust default option Signed-off-by: fufesou --- .../lib/desktop/pages/remote_tab_page.dart | 11 +-- .../lib/desktop/widgets/remote_menubar.dart | 96 +++++++------------ flutter/lib/mobile/pages/remote_page.dart | 4 +- flutter/lib/models/model.dart | 6 +- libs/hbb_common/src/config.rs | 62 +++++++++++- src/client.rs | 15 ++- src/flutter_ffi.rs | 30 +++++- src/server/video_service.rs | 8 +- src/ui_session_interface.rs | 12 ++- 9 files changed, 162 insertions(+), 82 deletions(-) diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index f6ebc0f86..df8256496 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -246,13 +246,12 @@ class _ConnectionTabPageState extends State { dismissOnClicked: true, ), ], - curOptionGetter: () async { - return await bind.sessionGetOption(id: key, arg: 'view-style') ?? - 'adaptive'; - }, + curOptionGetter: () async => + // null means peer id is not found, which there's no need to care about + await bind.sessionGetViewStyle(id: key) ?? '', optionSetter: (String oldValue, String newValue) async { - await bind.sessionPeerOption( - id: key, name: "view-style", value: newValue); + await bind.sessionSetViewStyle( + id: key, value: newValue); ffi.canvasModel.updateViewStyle(); cancelFunc(); }, diff --git a/flutter/lib/desktop/widgets/remote_menubar.dart b/flutter/lib/desktop/widgets/remote_menubar.dart index 6db5a7fb7..ed69f3e65 100644 --- a/flutter/lib/desktop/widgets/remote_menubar.dart +++ b/flutter/lib/desktop/widgets/remote_menubar.dart @@ -22,7 +22,7 @@ import './popup_menu.dart'; import './material_mod_popup_menu.dart' as mod_menu; class MenubarState { - final kStoreKey = "remoteMenubarState"; + final kStoreKey = 'remoteMenubarState'; late RxBool show; late RxBool _pin; @@ -195,7 +195,7 @@ class _RemoteMenubarState extends State { } _updateScreen() async { - final v = await DesktopMultiWindow.invokeMethod(0, "get_window_info", ""); + final v = await DesktopMultiWindow.invokeMethod(0, 'get_window_info', ''); final String valueStr = v; if (valueStr.isEmpty) { _screen = null; @@ -322,7 +322,7 @@ class _RemoteMenubarState extends State { child: Obx(() { RxInt display = CurrentDisplayState.find(widget.id); return Text( - "${display.value + 1}/${pi.displays.length}", + '${display.value + 1}/${pi.displays.length}', style: const TextStyle( color: _MenubarTheme.commonColor, fontSize: 8), ); @@ -595,10 +595,10 @@ class _RemoteMenubarState extends State { )); } } - if (perms["restart"] != false && - (pi.platform == "Linux" || - pi.platform == "Windows" || - pi.platform == "Mac OS")) { + if (perms['restart'] != false && + (pi.platform == 'Linux' || + pi.platform == 'Windows' || + pi.platform == 'Mac OS')) { displayMenu.add(MenuEntryButton( childBuilder: (TextStyle? style) => Text( translate('Restart Remote Device'), @@ -629,14 +629,14 @@ class _RemoteMenubarState extends State { displayMenu.add(MenuEntryButton( childBuilder: (TextStyle? style) => Obx(() => Text( translate( - '${BlockInputState.find(widget.id).value ? "Unb" : "B"}lock user input'), + '${BlockInputState.find(widget.id).value ? 'Unb' : 'B'}lock user input'), style: style, )), proc: () { RxBool blockInput = BlockInputState.find(widget.id); bind.sessionToggleOption( id: widget.id, - value: '${blockInput.value ? "un" : ""}block-input'); + value: '${blockInput.value ? 'un' : ''}block-input'); blockInput.value = !blockInput.value; }, padding: padding, @@ -671,7 +671,7 @@ class _RemoteMenubarState extends State { // ClipboardData? data = // await Clipboard.getData(Clipboard.kTextPlain); // if (data != null && data.text != null) { - // bind.sessionInputString(id: widget.id, value: data.text ?? ""); + // bind.sessionInputString(id: widget.id, value: data.text ?? ''); // } // }(); // }, @@ -679,18 +679,6 @@ class _RemoteMenubarState extends State { // dismissOnClicked: true, // )); // } - - displayMenu.add(MenuEntryButton( - childBuilder: (TextStyle? style) => Text( - translate('Reset canvas'), - style: style, - ), - proc: () { - widget.ffi.cursorModel.reset(); - }, - padding: padding, - dismissOnClicked: true, - )); } return displayMenu; @@ -740,14 +728,11 @@ class _RemoteMenubarState extends State { dismissOnClicked: true, ), ], - curOptionGetter: () async { - return await bind.sessionGetOption( - id: widget.id, arg: 'view-style') ?? - 'adaptive'; - }, + curOptionGetter: () async => + // null means peer id is not found, which there's no need to care about + await bind.sessionGetViewStyle(id: widget.id) ?? '', optionSetter: (String oldValue, String newValue) async { - await bind.sessionPeerOption( - id: widget.id, name: "view-style", value: newValue); + await bind.sessionSetViewStyle(id: widget.id, value: newValue); widget.ffi.canvasModel.updateViewStyle(); }, padding: padding, @@ -768,14 +753,11 @@ class _RemoteMenubarState extends State { dismissOnClicked: true, ), ], - curOptionGetter: () async { - return await bind.sessionGetOption( - id: widget.id, arg: 'scroll-style') ?? - ''; - }, + curOptionGetter: () async => + // null means peer id is not found, which there's no need to care about + await bind.sessionGetScrollStyle(id: widget.id) ?? '', optionSetter: (String oldValue, String newValue) async { - await bind.sessionPeerOption( - id: widget.id, name: "scroll-style", value: newValue); + await bind.sessionSetScrollStyle(id: widget.id, value: newValue); widget.ffi.canvasModel.updateScrollStyle(); }, padding: padding, @@ -805,12 +787,9 @@ class _RemoteMenubarState extends State { value: 'custom', dismissOnClicked: true), ], - curOptionGetter: () async { - String quality = - await bind.sessionGetImageQuality(id: widget.id) ?? 'balanced'; - if (quality == '') quality = 'balanced'; - return quality; - }, + curOptionGetter: () async => + // null means peer id is not found, which there's no need to care about + await bind.sessionGetImageQuality(id: widget.id) ?? '', optionSetter: (String oldValue, String newValue) async { if (oldValue != newValue) { await bind.sessionSetImageQuality(id: widget.id, value: newValue); @@ -1075,14 +1054,14 @@ class _RemoteMenubarState extends State { } return list; }, - curOptionGetter: () async { - return await bind.sessionGetOption( - id: widget.id, arg: 'codec-preference') ?? - 'auto'; - }, + curOptionGetter: () async => + // null means peer id is not found, which there's no need to care about + await bind.sessionGetOption( + id: widget.id, arg: 'codec-preference') ?? + '', optionSetter: (String oldValue, String newValue) async { await bind.sessionPeerOption( - id: widget.id, name: "codec-preference", value: newValue); + id: widget.id, name: 'codec-preference', value: newValue); bind.sessionChangePreferCodec(id: widget.id); }, padding: padding, @@ -1195,9 +1174,8 @@ class _RemoteMenubarState extends State { MenuEntryRadioOption(text: translate('Legacy mode'), value: 'legacy'), MenuEntryRadioOption(text: translate('Map mode'), value: 'map'), ], - curOptionGetter: () async { - return await bind.sessionGetKeyboardName(id: widget.id); - }, + curOptionGetter: () async => + await bind.sessionGetKeyboardName(id: widget.id), optionSetter: (String oldValue, String newValue) async { await bind.sessionSetKeyboardMode( id: widget.id, keyboardMode: newValue); @@ -1229,16 +1207,16 @@ class _RemoteMenubarState extends State { void showSetOSPassword( String id, bool login, OverlayDialogManager dialogManager) async { final controller = TextEditingController(); - var password = await bind.sessionGetOption(id: id, arg: "os-password") ?? ""; - var autoLogin = await bind.sessionGetOption(id: id, arg: "auto-login") != ""; + var password = await bind.sessionGetOption(id: id, arg: 'os-password') ?? ''; + var autoLogin = await bind.sessionGetOption(id: id, arg: 'auto-login') != ''; controller.text = password; dialogManager.show((setState, close) { submit() { var text = controller.text.trim(); - bind.sessionPeerOption(id: id, name: "os-password", value: text); + bind.sessionPeerOption(id: id, name: 'os-password', value: text); bind.sessionPeerOption( - id: id, name: "auto-login", value: autoLogin ? 'Y' : ''); - if (text != "" && login) { + id: id, name: 'auto-login', value: autoLogin ? 'Y' : ''); + if (text != '' && login) { bind.sessionInputOsPassword(id: id, value: text); } close(); @@ -1285,7 +1263,7 @@ void showAuditDialog(String id, dialogManager) async { dialogManager.show((setState, close) { submit() { var text = controller.text.trim(); - if (text != "") { + if (text != '') { bind.sessionSendNote(id: id, note: text); } close(); @@ -1324,11 +1302,11 @@ void showAuditDialog(String id, dialogManager) async { keyboardType: TextInputType.multiline, textInputAction: TextInputAction.newline, decoration: const InputDecoration.collapsed( - hintText: "input note here", + hintText: 'input note here', ), // inputFormatters: [ // LengthLimitingTextInputFormatter(16), - // // FilteringTextInputFormatter(RegExp(r"[a-zA-z][a-zA-z0-9\_]*"), allow: true) + // // FilteringTextInputFormatter(RegExp(r'[a-zA-z][a-zA-z0-9\_]*'), allow: true) // ], maxLines: null, maxLength: 256, diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index 719b7dc28..b48e9960a 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -474,7 +474,7 @@ class _RemotePageState extends State { }, onTwoFingerScaleEnd: (d) { _scale = 1; - bind.sessionPeerOption(id: widget.id, name: "view-style", value: ""); + bind.sessionSetViewStyle(id: widget.id, value: ""); }, onThreeFingerVerticalDragUpdate: gFFI.ffiModel.isPeerAndroid ? null @@ -1001,7 +1001,7 @@ void showOptions( setState(() { viewStyle = value; bind - .sessionPeerOption(id: id, name: "view-style", value: value) + .sessionSetViewStyle(id: id, value: value) .then((_) => gFFI.canvasModel.updateViewStyle()); }); } diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index eca94d5e5..cae4485cb 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -413,7 +413,7 @@ class ImageModel with ChangeNotifier { await initializeCursorAndCanvas(parent.target!); } if (parent.target?.ffiModel.isPeerAndroid ?? false) { - bind.sessionPeerOption(id: id, name: 'view-style', value: 'adaptive'); + bind.sessionSetViewStyle(id: id, value: 'adaptive'); parent.target?.canvasModel.updateViewStyle(); } } @@ -535,7 +535,7 @@ class CanvasModel with ChangeNotifier { double get scrollY => _scrollY; updateViewStyle() async { - final style = await bind.sessionGetOption(id: id, arg: 'view-style'); + final style = await bind.sessionGetViewStyle(id: id); if (style == null) { return; } @@ -561,7 +561,7 @@ class CanvasModel with ChangeNotifier { } updateScrollStyle() async { - final style = await bind.sessionGetOption(id: id, arg: 'scroll-style'); + final style = await bind.sessionGetScrollStyle(id: id); if (style == 'scrollbar') { _scrollStyle = ScrollStyle.scrollbar; _scrollX = 0.0; diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index a7836cef7..f4b6661b4 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -9,6 +9,7 @@ use std::{ use anyhow::Result; use rand::Rng; +use serde as de; use serde_derive::{Deserialize, Serialize}; use sodiumoxide::crypto::sign; @@ -79,6 +80,26 @@ pub const RS_PUB_KEY: &'static str = "OeVuKk5nlHiXp+APNn0Y3pC1Iwpwn44JGqrQCsWqmB pub const RENDEZVOUS_PORT: i32 = 21116; pub const RELAY_PORT: i32 = 21117; +macro_rules! serde_field_string { + ($default_func:ident, $de_func:ident, $default_expr:expr) => { + fn $default_func() -> String { + $default_expr + } + + fn $de_func<'de, D>(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + let s: &str = de::Deserialize::deserialize(deserializer)?; + Ok(if s.is_empty() { + Self::$default_func() + } else { + s.to_owned() + }) + } + }; +} + #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum NetworkType { Direct, @@ -141,9 +162,20 @@ pub struct PeerConfig { pub size_ft: Size, #[serde(default)] pub size_pf: Size, - #[serde(default)] - pub view_style: String, // original (default), scale - #[serde(default)] + #[serde( + default = "PeerConfig::default_view_style", + deserialize_with = "PeerConfig::deserialize_view_style" + )] + pub view_style: String, + #[serde( + default = "PeerConfig::default_scroll_style", + deserialize_with = "PeerConfig::deserialize_scroll_style" + )] + pub scroll_style: String, + #[serde( + default = "PeerConfig::default_image_quality", + deserialize_with = "PeerConfig::deserialize_image_quality" + )] pub image_quality: String, #[serde(default)] pub custom_image_quality: Vec, @@ -167,7 +199,10 @@ pub struct PeerConfig { pub show_quality_monitor: bool, // The other scalar value must before this - #[serde(default)] + #[serde( + default, + deserialize_with = "PeerConfig::deserialize_options" + )] pub options: HashMap, // Various data for flutter ui #[serde(default)] @@ -400,7 +435,9 @@ impl Config { #[cfg(target_os = "macos")] let org = ORG.read().unwrap().clone(); // /var/root for root - if let Some(project) = directories_next::ProjectDirs::from("", &org, &*APP_NAME.read().unwrap()) { + if let Some(project) = + directories_next::ProjectDirs::from("", &org, &*APP_NAME.read().unwrap()) + { let mut path = patch(project.config_dir().to_path_buf()); path.push(p); return path; @@ -896,6 +933,21 @@ impl PeerConfig { } Default::default() } + + serde_field_string!(default_view_style, deserialize_view_style, "original".to_owned()); + serde_field_string!(default_scroll_style, deserialize_scroll_style, "scrollauto".to_owned()); + serde_field_string!(default_image_quality, deserialize_image_quality, "balanced".to_owned()); + + fn deserialize_options<'de, D>(deserializer: D) -> Result, D::Error> + where + D: de::Deserializer<'de>, + { + let mut mp: HashMap = de::Deserialize::deserialize(deserializer)?; + if !mp.contains_key("codec-preference") { + mp.insert("codec-preference".to_owned(), "auto".to_owned()); + } + Ok(mp) + } } #[derive(Debug, Default, Serialize, Deserialize, Clone)] diff --git a/src/client.rs b/src/client.rs index a938702b3..657c50572 100644 --- a/src/client.rs +++ b/src/client.rs @@ -974,6 +974,8 @@ impl LoginConfigHandler { self.save_config(config); } + //to-do: too many dup code below. + /// Save view style to the current config. /// /// # Arguments @@ -985,13 +987,24 @@ impl LoginConfigHandler { self.save_config(config); } + /// Save scroll style to the current config. + /// + /// # Arguments + /// + /// * `value` - The view style to be saved. + pub fn save_scroll_style(&mut self, value: String) { + let mut config = self.load_config(); + config.scroll_style = value; + self.save_config(config); + } + /// Set a ui config of flutter for handler's [`PeerConfig`]. /// /// # Arguments /// /// * `k` - key of option /// * `v` - value of option - pub fn set_ui_flutter(&mut self, k: String, v: String) { + pub fn save_ui_flutter(&mut self, k: String, v: String) { let mut config = self.load_config(); config.ui_flutter.insert(k, v); self.save_config(config); diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 8627168a4..520efea70 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -170,7 +170,7 @@ pub fn session_get_flutter_config(id: String, k: String) -> Option { pub fn session_set_flutter_config(id: String, k: String, v: String) { if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { - session.set_flutter_config(k, v); + session.save_flutter_config(k, v); } } @@ -182,6 +182,34 @@ pub fn set_local_flutter_config(k: String, v: String) { ui_interface::set_local_flutter_config(k, v); } +pub fn session_get_view_style(id: String) -> Option { + if let Some(session) = SESSIONS.read().unwrap().get(&id) { + Some(session.get_view_style()) + } else { + None + } +} + +pub fn session_set_view_style(id: String, value: String) { + if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { + session.save_view_style(value); + } +} + +pub fn session_get_scroll_style(id: String) -> Option { + if let Some(session) = SESSIONS.read().unwrap().get(&id) { + Some(session.get_scroll_style()) + } else { + None + } +} + +pub fn session_set_scroll_style(id: String, value: String) { + if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { + session.save_scroll_style(value); + } +} + pub fn session_get_image_quality(id: String) -> Option { if let Some(session) = SESSIONS.read().unwrap().get(&id) { Some(session.get_image_quality()) diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 43ce013f5..3ccc3af39 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -25,12 +25,16 @@ use hbb_common::tokio::sync::{ mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, Mutex as TokioMutex, }; +#[cfg(not(windows))] +use scrap::Capturer; use scrap::{ codec::{Encoder, EncoderCfg, HwEncoderConfig}, record::{Recorder, RecorderContext}, vpxcodec::{VpxEncoderConfig, VpxVideoCodecId}, - Capturer, Display, TraitCapturer, + Display, TraitCapturer, }; +#[cfg(windows)] +use std::sync::Once; use std::{ collections::HashSet, io::ErrorKind::WouldBlock, @@ -38,8 +42,6 @@ use std::{ time::{self, Duration, Instant}, }; #[cfg(windows)] -use std::sync::Once; -#[cfg(windows)] use virtual_display; pub const SCRAP_UBUNTU_HIGHER_REQUIRED: &str = "Wayland requires Ubuntu 21.04 or higher version."; diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index 5119a6e1b..9b00730e5 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -79,6 +79,10 @@ impl Session { self.lc.read().unwrap().view_style.clone() } + pub fn get_scroll_style(&self) -> String { + self.lc.read().unwrap().scroll_style.clone() + } + pub fn get_image_quality(&self) -> String { self.lc.read().unwrap().image_quality.clone() } @@ -99,8 +103,12 @@ impl Session { self.lc.write().unwrap().save_view_style(value); } - pub fn set_flutter_config(&mut self, k: String, v: String) { - self.lc.write().unwrap().set_ui_flutter(k, v); + pub fn save_scroll_style(&mut self, value: String) { + self.lc.write().unwrap().save_scroll_style(value); + } + + pub fn save_flutter_config(&mut self, k: String, v: String) { + self.lc.write().unwrap().save_ui_flutter(k, v); } pub fn get_flutter_config(&self, k: String) -> String { From 4963dcf673e886923b3dd3351434b0e10042d3fa Mon Sep 17 00:00:00 2001 From: fufesou Date: Thu, 17 Nov 2022 19:32:59 +0800 Subject: [PATCH 060/116] fix init custom_fps option Signed-off-by: fufesou --- src/client.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/client.rs b/src/client.rs index 657c50572..c98561967 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1140,6 +1140,9 @@ impl LoginConfigHandler { msg.custom_image_quality = quality << 8; n += 1; } + if let Some(custom_fps) = self.options.get("custom-fps") { + msg.custom_fps = custom_fps.parse().unwrap_or(30); + } if self.get_toggle_option("show-remote-cursor") { msg.show_remote_cursor = BoolOption::Yes.into(); n += 1; From 4bd1a39ac461605e27144cacb0401a40740e7f03 Mon Sep 17 00:00:00 2001 From: fufesou Date: Thu, 17 Nov 2022 20:24:17 +0800 Subject: [PATCH 061/116] fix big init resizeEdgeSize Signed-off-by: fufesou --- Cargo.lock | 5 +++-- flutter/lib/models/state_model.dart | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 67a471cef..49fcc3dce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -620,9 +620,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.22" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" +checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" dependencies = [ "iana-time-zone", "js-sys", @@ -4362,6 +4362,7 @@ dependencies = [ "bytes", "cc", "cfg-if 1.0.0", + "chrono", "clap 3.2.17", "clipboard", "cocoa", diff --git a/flutter/lib/models/state_model.dart b/flutter/lib/models/state_model.dart index 1ceee2fe0..bc80fdf0e 100644 --- a/flutter/lib/models/state_model.dart +++ b/flutter/lib/models/state_model.dart @@ -7,7 +7,7 @@ class StateGlobal { int _windowId = -1; bool _fullscreen = false; final RxBool _showTabBar = true.obs; - final RxDouble _resizeEdgeSize = 8.0.obs; + final RxDouble _resizeEdgeSize = RxDouble(kWindowEdgeSize); final RxDouble _windowBorderWidth = RxDouble(kWindowBorderWidth); final RxBool showRemoteMenuBar = false.obs; From eab059d3de7dc11a03722430dbff56bff7280fa6 Mon Sep 17 00:00:00 2001 From: solokot Date: Thu, 17 Nov 2022 16:06:36 +0300 Subject: [PATCH 062/116] Updated ru.rs --- src/lang/ru.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lang/ru.rs b/src/lang/ru.rs index b5d747f9d..4920c2826 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -136,7 +136,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Failed to make direct connection to remote desktop", "Не удалось установить прямое подключение к удалённому рабочему столу"), ("Set Password", "Установить пароль"), ("OS Password", "Пароль ОС"), - ("install_tip", "В некоторых случаях из-за UAC RustDesk может работать некорректно на удалённом узле. Чтобы избежать UAC, нажмите кнопку ниже, чтобы установить RustDesk в системе."), + ("install_tip", "В некоторых случаях из-за UAC RustDesk может работать неправильно на удалённом узле. Чтобы избежать UAC, нажмите кнопку ниже, чтобы установить RustDesk в системе."), ("Click to upgrade", "Нажмите, чтобы проверить наличие обновлений"), ("Click to download", "Нажмите, чтобы скачать"), ("Click to update", "Нажмите, чтобы обновить"), @@ -371,8 +371,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", "Запретить обнаружение в локальной сети"), ("Write a message", "Написать сообщение"), ("Prompt", "Подсказка"), - ("Please wait for confirmation of UAC...", ""), - ("elevated_foreground_window_tip", ""), + ("Please wait for confirmation of UAC...", "Дождитесь подтверждения UAC..."), + ("elevated_foreground_window_tip", "Текущее окно удалённого рабочего стола требует более высоких привилегий для работы, поэтому временно невозможно использовать мышь и клавиатуру. Можно попросить удалённого пользователя свернуть текущее окно или нажать кнопку повышения прав в окне управления подключением. Чтобы избежать этой проблемы в дальнейшем, рекомендуется выполнить установку программного обеспечения на удалённом устройстве."), ("Disconnected", "Отключено"), ("Other", "Другое"), ("Confirm before closing multiple tabs", "Подтверждение закрытия несколько вкладок"), @@ -388,7 +388,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", "Этот компьютер"), ("or", "или"), ("Continue with", "Продолжить с"), - ("Elevate", ""), - ("Zoom cursor", ""), + ("Elevate", "Повысить"), + ("Zoom cursor", "Масштабировать курсор"), ].iter().cloned().collect(); } From 752d84ffb0fca52bd9bb1f2691c685fab5c7712e Mon Sep 17 00:00:00 2001 From: fufesou Date: Fri, 18 Nov 2022 10:19:55 +0800 Subject: [PATCH 063/116] fix remember peer card view type Signed-off-by: fufesou --- flutter/lib/common/widgets/peer_tab_page.dart | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/flutter/lib/common/widgets/peer_tab_page.dart b/flutter/lib/common/widgets/peer_tab_page.dart index 9129e4711..523230810 100644 --- a/flutter/lib/common/widgets/peer_tab_page.dart +++ b/flutter/lib/common/widgets/peer_tab_page.dart @@ -28,14 +28,16 @@ class _PeerTabPageState extends State setPeer() { final index = bind.getLocalFlutterConfig(k: 'peer-tab-index'); - if (index == '') return; - _tabIndex.value = int.parse(index); + if (index != '') { + _tabIndex.value = int.parse(index); + } final uiType = bind.getLocalFlutterConfig(k: 'peer-card-ui-type'); - if (uiType == '') return; - peerCardUiType.value = int.parse(uiType) == PeerUiType.list.index - ? PeerUiType.list - : PeerUiType.grid; + if (uiType != '') { + peerCardUiType.value = int.parse(uiType) == PeerUiType.list.index + ? PeerUiType.list + : PeerUiType.grid; + } } // hard code for now From ea5bff63fc8b3718fe9bf70500cf094879e58e85 Mon Sep 17 00:00:00 2001 From: fufesou Date: Fri, 18 Nov 2022 10:21:25 +0800 Subject: [PATCH 064/116] remove unused sized box widget Signed-off-by: fufesou --- flutter/lib/desktop/pages/remote_page.dart | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index 117a0ab02..1aca198c2 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -321,12 +321,10 @@ class _ImagePaintState extends State { if (c.scrollStyle == ScrollStyle.scrollbar) { final imageWidth = c.getDisplayWidth() * s; final imageHeight = c.getDisplayHeight() * s; - final imageWidget = SizedBox( - width: imageWidth, - height: imageHeight, - child: CustomPaint( - painter: ImagePainter(image: m.image, x: 0, y: 0, scale: s), - )); + final imageWidget = CustomPaint( + size: Size(imageWidth, imageHeight), + painter: ImagePainter(image: m.image, x: 0, y: 0, scale: s), + ); return NotificationListener( onNotification: (notification) { @@ -350,13 +348,10 @@ class _ImagePaintState extends State { Size(imageWidth, imageHeight))), ); } else { - final imageWidget = SizedBox( - width: c.size.width, - height: c.size.height, - child: CustomPaint( - painter: - ImagePainter(image: m.image, x: c.x / s, y: c.y / s, scale: s), - )); + final imageWidget = CustomPaint( + size: Size(c.size.width, c.size.height), + painter: ImagePainter(image: m.image, x: c.x / s, y: c.y / s, scale: s), + ); return mouseRegion(child: _buildListener(imageWidget)); } } From 3ad46908e9b874fd0b1fef0b1125e4e01828e4c5 Mon Sep 17 00:00:00 2001 From: Kingtous Date: Thu, 17 Nov 2022 17:26:46 +0800 Subject: [PATCH 065/116] fix: window overflow after restore from fullscreen related: https://github.com/leanflutter/window_manager/issues/131 --- flutter/lib/models/state_model.dart | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/flutter/lib/models/state_model.dart b/flutter/lib/models/state_model.dart index bc80fdf0e..53f1a19b1 100644 --- a/flutter/lib/models/state_model.dart +++ b/flutter/lib/models/state_model.dart @@ -1,4 +1,7 @@ +import 'dart:io'; + import 'package:desktop_multi_window/desktop_multi_window.dart'; +import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../consts.dart'; @@ -26,7 +29,20 @@ class StateGlobal { _resizeEdgeSize.value = fullscreen ? kFullScreenEdgeSize : kWindowEdgeSize; _windowBorderWidth.value = fullscreen ? 0 : kWindowBorderWidth; - WindowController.fromWindowId(windowId).setFullscreen(_fullscreen); + WindowController.fromWindowId(windowId) + .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 newRect = Rect.fromLTWH( + frame.left, frame.top, frame.width + 1, frame.height + 1); + await WindowController.fromWindowId(windowId).setFrame(newRect); + }); + } + }); } } From 931ebc86bc2f0a25f5a819109de35d608ce84fbb Mon Sep 17 00:00:00 2001 From: 21pages Date: Fri, 18 Nov 2022 11:56:32 +0800 Subject: [PATCH 066/116] fix api server setting error Signed-off-by: 21pages --- flutter/lib/desktop/pages/desktop_setting_page.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index b4c69a6a6..c03371a64 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -864,7 +864,7 @@ class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin { } } if (apiServer.isNotEmpty) { - if (!apiServer.startsWith('http://') || + if (!apiServer.startsWith('http://') && !apiServer.startsWith('https://')) { apiErrMsg.value = '${translate("API Server")}: ${translate("invalid_http")}'; From 01997704542aa9c49274f0dde91196a99bcbec96 Mon Sep 17 00:00:00 2001 From: 21pages Date: Wed, 16 Nov 2022 20:32:22 +0800 Subject: [PATCH 067/116] portable-service: add quick_start feature and ci Signed-off-by: 21pages --- .github/workflows/flutter-nightly.yml | 9 +++++---- Cargo.toml | 1 + build.py | 7 +++++++ src/core_main.rs | 9 ++++++++- src/platform/windows.rs | 7 +++++++ src/server/portable_service.rs | 7 +++++-- 6 files changed, 33 insertions(+), 7 deletions(-) diff --git a/.github/workflows/flutter-nightly.yml b/.github/workflows/flutter-nightly.yml index f2391e77e..074eafe08 100644 --- a/.github/workflows/flutter-nightly.yml +++ b/.github/workflows/flutter-nightly.yml @@ -15,7 +15,7 @@ env: jobs: build-for-windows: - name: ${{ matrix.job.target }} (${{ matrix.job.os }}) + name: ${{ matrix.job.target }} (${{ matrix.job.os }}) ${{ matrix.job.suffix }} runs-on: ${{ matrix.job.os }} strategy: fail-fast: false @@ -23,7 +23,8 @@ jobs: job: # - { target: i686-pc-windows-msvc , os: windows-2019 } # - { target: x86_64-pc-windows-gnu , os: windows-2019 } - - { target: x86_64-pc-windows-msvc , os: windows-2019 } + - { target: x86_64-pc-windows-msvc , os: windows-2019, suffix: "" , extra-build-args: "" } + - { target: x86_64-pc-windows-msvc , os: windows-2019, suffix: "-qs", extra-build-args: "--quick_start" } steps: - name: Checkout source code uses: actions/checkout@v3 @@ -83,13 +84,13 @@ jobs: shell: bash - name: Build rustdesk - run: python3 .\build.py --portable --hwcodec --flutter + run: python3 .\build.py --portable --hwcodec --flutter ${{ matrix.job.extra-build-args }} - name: Rename rustdesk shell: bash run: | for name in rustdesk*??-install.exe; do - mv "$name" "${name%%-install.exe}-${{ matrix.job.target }}.exe" + mv "$name" "${name%%-install.exe}-${{ matrix.job.target }}${{ matrix.job.suffix }}.exe" done - name: Publish Release diff --git a/Cargo.toml b/Cargo.toml index 836bd07d4..44df74952 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ flutter = ["flutter_rust_bridge"] default = ["use_dasp"] hwcodec = ["scrap/hwcodec"] mediacodec = ["scrap/mediacodec"] +quick_start = [] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/build.py b/build.py index c907334ce..a887ff070 100755 --- a/build.py +++ b/build.py @@ -81,6 +81,11 @@ def make_parser(): action='store_true', help='Build windows portable' ) + parser.add_argument( + '--quick_start', + action='store_true', + help='Windows quick start portable' + ) parser.add_argument( '--flatpak', action='store_true', @@ -189,6 +194,8 @@ def get_features(args): features = ['inline'] if windows: features.extend(get_rc_features(args)) + if args.quick_start: + features.append('quick_start') if args.hwcodec: features.append('hwcodec') if args.flutter: diff --git a/src/core_main.rs b/src/core_main.rs index 889015c0d..bd9680ffb 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -81,6 +81,13 @@ pub fn core_main() -> Option> { } } #[cfg(windows)] + #[cfg(feature = "quick_start")] + if !crate::platform::is_installed() && args.is_empty() && !_is_elevate && !_is_run_as_system { + if let Err(e) = crate::portable_service::client::start_portable_service() { + log::error!("Failed to start portable service:{:?}", e); + } + } + #[cfg(windows)] if !crate::platform::is_installed() && (_is_elevate || _is_run_as_system) { crate::platform::elevate_or_run_as_system(click_setup, _is_elevate, _is_run_as_system); return None; @@ -276,7 +283,7 @@ fn core_main_invoke_new_connection(mut args: std::env::Args) -> Option ResultType<()> { pub fn elevate_or_run_as_system(is_setup: bool, is_elevate: bool, is_run_as_system: bool) { // avoid possible run recursively due to failed run. + log::info!( + "elevate:{}->{:?}, run_as_system:{}->{}", + is_elevate, + is_elevated(None), + is_run_as_system, + crate::username(), + ); let arg_elevate = if is_setup { "--noinstall --elevate" } else { diff --git a/src/server/portable_service.rs b/src/server/portable_service.rs index 21b501f1e..64d6c017b 100644 --- a/src/server/portable_service.rs +++ b/src/server/portable_service.rs @@ -406,8 +406,9 @@ pub mod server { Pong => { nack = 0; } - ConnCount(Some(n)) => { - if n == 0 { + ConnCount(Some(_n)) => { + #[cfg(not(feature = "quick_start"))] + if _n == 0 { log::info!("Connnection count equals 0, exit"); stream.send(&Data::DataPortableService(WillClose)).await.ok(); break; @@ -435,6 +436,7 @@ pub mod server { break; } stream.send(&Data::DataPortableService(Ping)).await.ok(); + #[cfg(not(feature = "quick_start"))] stream.send(&Data::DataPortableService(ConnCount(None))).await.ok(); } } @@ -462,6 +464,7 @@ pub mod client { } pub(crate) fn start_portable_service() -> ResultType<()> { + log::info!("start portable service"); if PORTABLE_SERVICE_RUNNING.lock().unwrap().clone() { bail!("already running"); } From f986236a61309df89f2287561ce0b441a09c9aec Mon Sep 17 00:00:00 2001 From: 21pages Date: Fri, 18 Nov 2022 17:07:03 +0800 Subject: [PATCH 068/116] portable service: fix clean shared memory, at_exit not called at flutter Signed-off-by: 21pages --- flutter/lib/desktop/pages/connection_page.dart | 3 +++ src/flutter_ffi.rs | 11 ++++++++++- src/server/portable_service.rs | 4 ++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index fc5b8e574..f73c6b0da 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -90,6 +90,9 @@ class _ConnectionPageState extends State Get.forceAppUpdate(); } isWindowMinisized = false; + } else if (eventName == 'close') { + // called more then one time + bind.mainOnMainWindowClose(); } } diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 520efea70..b947fad47 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -619,7 +619,11 @@ pub fn main_set_peer_option_sync(id: String, key: String, value: String) -> Sync } pub fn main_set_peer_alias(id: String, alias: String) { - main_broadcast_message(&HashMap::from([("name", "alias"), ("id", &id), ("alias", &alias)])); + main_broadcast_message(&HashMap::from([ + ("name", "alias"), + ("id", &id), + ("alias", &alias), + ])); set_peer_option(id, "alias".to_owned(), alias) } @@ -1173,6 +1177,11 @@ pub fn main_account_auth_result() -> String { account_auth_result() } +pub fn main_on_main_window_close() { + #[cfg(windows)] + crate::portable_service::client::drop_portable_service_shared_memory(); +} + #[cfg(target_os = "android")] pub mod server_side { use jni::{ diff --git a/src/server/portable_service.rs b/src/server/portable_service.rs index 64d6c017b..861b04b3d 100644 --- a/src/server/portable_service.rs +++ b/src/server/portable_service.rs @@ -487,7 +487,7 @@ pub mod client { crate::portable_service::SHMEM_NAME, shmem_size, )?); - shutdown_hooks::add_shutdown_hook(drop_shmem); + shutdown_hooks::add_shutdown_hook(drop_portable_service_shared_memory); } let mut option = SHMEM.lock().unwrap(); let shmem = option.as_mut().unwrap(); @@ -507,7 +507,7 @@ pub mod client { Ok(()) } - extern "C" fn drop_shmem() { + pub extern "C" fn drop_portable_service_shared_memory() { log::info!("drop shared memory"); *SHMEM.lock().unwrap() = None; } From 26e8355528d91e186a6d48de8dfbcbb1a947b2af Mon Sep 17 00:00:00 2001 From: fufesou Date: Fri, 18 Nov 2022 13:33:54 +0800 Subject: [PATCH 069/116] dynamic library - win virtual display Signed-off-by: fufesou --- Cargo.lock | 2 +- Cargo.toml | 2 +- build.py | 6 ++++ libs/clipboard/build.rs | 2 +- libs/virtual_display/Cargo.toml | 4 +++ libs/virtual_display/build.rs | 4 +-- libs/virtual_display/src/lib.rs | 9 +++++ src/server.rs | 2 ++ src/server/video_service.rs | 2 +- src/server/virtual_display.rs | 64 +++++++++++++++++++++++++++++++++ 10 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 src/server/virtual_display.rs diff --git a/Cargo.lock b/Cargo.lock index 49fcc3dce..0e892aa31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4391,6 +4391,7 @@ dependencies = [ "lazy_static", "libappindicator", "libc", + "libloading", "libpulse-binding", "libpulse-simple-binding", "mac_address", @@ -4424,7 +4425,6 @@ dependencies = [ "trayicon", "url", "uuid", - "virtual_display", "whoami", "winapi 0.3.9", "windows-service", diff --git a/Cargo.toml b/Cargo.toml index 836bd07d4..a3758c861 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,6 +65,7 @@ flutter_rust_bridge = { git = "https://github.com/SoLongAndThanksForAllThePizza/ errno = "0.2.8" rdev = { git = "https://github.com/asur4s/rdev" } url = { version = "2.1", features = ["serde"] } +libloading = "0.7" reqwest = { version = "0.11", features = ["blocking", "json", "rustls-tls"], default-features=false } chrono = "0.4.23" @@ -91,7 +92,6 @@ winit = "0.26" winapi = { version = "0.3", features = ["winuser"] } winreg = "0.10" windows-service = "0.4" -virtual_display = { path = "libs/virtual_display" } impersonate_system = { git = "https://github.com/21pages/impersonate-system" } shared_memory = "0.12.4" shutdown_hooks = "0.1.0" diff --git a/build.py b/build.py index c907334ce..48eaf1bc0 100755 --- a/build.py +++ b/build.py @@ -280,6 +280,7 @@ def build_flutter_windows(version, features): exit(-1) os.chdir('flutter') os.system('flutter build windows --release') + shutil.copy2('target/release/deps/virtual_display.dll', flutter_win_target_dir) os.chdir('..') os.chdir('libs/portable') os.system('pip3 install -r requirements.txt') @@ -316,6 +317,11 @@ def main(): os.system('python3 res/inline-sciter.py') portable = args.portable if windows: + # build virtual display dynamic library + os.chdir('libs/virtual_display') + os.system('cargo build --release') + os.chdir('../..') + if flutter: build_flutter_windows(version, features) return diff --git a/libs/clipboard/build.rs b/libs/clipboard/build.rs index b5c547637..7eb52c75b 100644 --- a/libs/clipboard/build.rs +++ b/libs/clipboard/build.rs @@ -18,7 +18,7 @@ fn build_c_impl() { if build.get_compiler().is_like_msvc() { build.define("WIN32", ""); // build.define("_AMD64_", ""); - build.flag("-Zi"); + build.flag("-Z7"); build.flag("-GR-"); // build.flag("-std:c++11"); } else { diff --git a/libs/virtual_display/Cargo.toml b/libs/virtual_display/Cargo.toml index 8d0b65171..d0b63b454 100644 --- a/libs/virtual_display/Cargo.toml +++ b/libs/virtual_display/Cargo.toml @@ -3,6 +3,10 @@ name = "virtual_display" version = "0.1.0" edition = "2021" +[lib] +name = "virtual_display" +crate-type = ["cdylib", "staticlib", "rlib"] + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [build-dependencies] diff --git a/libs/virtual_display/build.rs b/libs/virtual_display/build.rs index 177d92371..29c3dd5d4 100644 --- a/libs/virtual_display/build.rs +++ b/libs/virtual_display/build.rs @@ -13,7 +13,7 @@ fn build_c_impl() { if build.get_compiler().is_like_msvc() { build.define("WIN32", ""); - build.flag("-Zi"); + build.flag("-Z7"); build.flag("-GR-"); // build.flag("-std:c++11"); } else { @@ -24,7 +24,7 @@ fn build_c_impl() { } #[cfg(target_os = "windows")] - build.compile("xxx"); + build.compile("win_virtual_display"); #[cfg(target_os = "windows")] println!("cargo:rerun-if-changed=src/win10/IddController.c"); diff --git a/libs/virtual_display/src/lib.rs b/libs/virtual_display/src/lib.rs index 9f71fd6da..7ffcc679f 100644 --- a/libs/virtual_display/src/lib.rs +++ b/libs/virtual_display/src/lib.rs @@ -11,6 +11,7 @@ lazy_static::lazy_static! { static ref MONITOR_PLUGIN: Mutex> = Mutex::new(Vec::new()); } +#[no_mangle] pub fn download_driver() -> ResultType<()> { #[cfg(windows)] let _download_url = win10::DRIVER_DOWNLOAD_URL; @@ -22,6 +23,7 @@ pub fn download_driver() -> ResultType<()> { Ok(()) } +#[no_mangle] pub fn install_update_driver(_reboot_required: &mut bool) -> ResultType<()> { #[cfg(windows)] let install_path = win10::DRIVER_INSTALL_PATH; @@ -62,6 +64,7 @@ pub fn install_update_driver(_reboot_required: &mut bool) -> ResultType<()> { Ok(()) } +#[no_mangle] pub fn uninstall_driver(_reboot_required: &mut bool) -> ResultType<()> { #[cfg(windows)] let install_path = win10::DRIVER_INSTALL_PATH; @@ -96,6 +99,7 @@ pub fn uninstall_driver(_reboot_required: &mut bool) -> ResultType<()> { Ok(()) } +#[no_mangle] pub fn is_device_created() -> bool { #[cfg(windows)] return *H_SW_DEVICE.lock().unwrap() != 0; @@ -103,6 +107,7 @@ pub fn is_device_created() -> bool { return false; } +#[no_mangle] pub fn create_device() -> ResultType<()> { if is_device_created() { return Ok(()); @@ -120,6 +125,7 @@ pub fn create_device() -> ResultType<()> { Ok(()) } +#[no_mangle] pub fn close_device() { #[cfg(windows)] unsafe { @@ -129,6 +135,7 @@ pub fn close_device() { } } +#[no_mangle] pub fn plug_in_monitor() -> ResultType<()> { #[cfg(windows)] unsafe { @@ -149,6 +156,7 @@ pub fn plug_in_monitor() -> ResultType<()> { Ok(()) } +#[no_mangle] pub fn plug_out_monitor() -> ResultType<()> { #[cfg(windows)] unsafe { @@ -169,6 +177,7 @@ pub fn plug_out_monitor() -> ResultType<()> { Ok(()) } +#[no_mangle] pub fn update_monitor_modes() -> ResultType<()> { #[cfg(windows)] unsafe { diff --git a/src/server.rs b/src/server.rs index 7e00532fe..bf81468ce 100644 --- a/src/server.rs +++ b/src/server.rs @@ -53,6 +53,8 @@ mod connection; pub mod portable_service; mod service; mod video_qos; +#[cfg(windows)] +mod virtual_display; pub mod video_service; use hbb_common::tcp::new_listener; diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 3ccc3af39..0597ac956 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -42,7 +42,7 @@ use std::{ time::{self, Duration, Instant}, }; #[cfg(windows)] -use virtual_display; +use super::virtual_display; pub const SCRAP_UBUNTU_HIGHER_REQUIRED: &str = "Wayland requires Ubuntu 21.04 or higher version."; pub const SCRAP_OTHER_VERSION_OR_X11_REQUIRED: &str = diff --git a/src/server/virtual_display.rs b/src/server/virtual_display.rs new file mode 100644 index 000000000..23071326b --- /dev/null +++ b/src/server/virtual_display.rs @@ -0,0 +1,64 @@ +#![allow(dead_code)] + +use hbb_common::{bail, ResultType}; +use std::sync::{Arc, Mutex}; + +const LIB_NAME_VIRTUAL_DISPLAY: &str = "virtual_display"; + +lazy_static::lazy_static! { + static ref LIB_VIRTUAL_DISPLAY: Arc>> = { + #[cfg(target_os = "windows")] + let libname = format!("{}.dll", LIB_NAME_VIRTUAL_DISPLAY); + #[cfg(target_os = "linux")] + let libname = format!("lib{}.so", LIB_NAME_VIRTUAL_DISPLAY); + #[cfg(target_os = "macos")] + let libname = format!("lib{}.dylib", LIB_NAME_VIRTUAL_DISPLAY); + Arc::new(Mutex::new(unsafe { libloading::Library::new(libname) })) + }; +} + +pub(super) fn is_device_created() -> bool { + match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { + Ok(lib) => unsafe { + match lib.get:: bool>>(b"is_device_created") { + Ok(func) => func(), + Err(..) => false, + } + }, + Err(..) => false, + } +} + +macro_rules! def_func_result { + ($func:ident, $name: tt) => { + pub(super) fn $func() -> ResultType<()> { + match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { + Ok(lib) => unsafe { + match lib.get:: ResultType<()>>>($name.as_bytes()) { + Ok(func) => func(), + Err(..) => bail!("Failed to load func {}", $name), + } + }, + Err(e) => bail!("Failed to load library {}, {}", LIB_NAME_VIRTUAL_DISPLAY, e), + } + } + }; +} + +def_func_result!(create_device, "create_device"); + +pub(super) fn close_device() { + match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { + Ok(lib) => unsafe { + match lib.get::>(b"close_device") { + Ok(func) => func(), + Err(..) => {}, + } + }, + Err(..) => {}, + } +} + +def_func_result!(plug_in_monitor, "plug_in_monitor"); +def_func_result!(plug_out_monitor, "plug_out_monitor"); +def_func_result!(update_monitor_modes, "update_monitor_modes"); From 27e7b5722255ab297077d9f3252f2099b00ef2ff Mon Sep 17 00:00:00 2001 From: fufesou Date: Fri, 18 Nov 2022 14:52:01 +0800 Subject: [PATCH 070/116] move virtual display to lib workspace Signed-off-by: fufesou --- Cargo.lock | 20 +- Cargo.toml | 4 +- build.py | 6 +- libs/virtual_display/Cargo.lock | 1358 +++++++++++++++++ libs/virtual_display/Cargo.toml | 12 +- libs/virtual_display/README.md | 31 +- libs/virtual_display/dylib/Cargo.toml | 19 + libs/virtual_display/dylib/README.md | 32 + libs/virtual_display/{ => dylib}/build.rs | 0 libs/virtual_display/dylib/src/lib.rs | 201 +++ .../{ => dylib}/src/win10/IddController.c | 0 .../{ => dylib}/src/win10/IddController.h | 0 .../{ => dylib}/src/win10/Public.h | 0 .../{ => dylib}/src/win10/idd.rs | 0 .../{ => dylib}/src/win10/mod.rs | 0 libs/virtual_display/src/lib.rs | 248 +-- src/server.rs | 2 - src/server/video_service.rs | 2 +- src/server/virtual_display.rs | 64 - 19 files changed, 1702 insertions(+), 297 deletions(-) create mode 100644 libs/virtual_display/Cargo.lock create mode 100644 libs/virtual_display/dylib/Cargo.toml create mode 100644 libs/virtual_display/dylib/README.md rename libs/virtual_display/{ => dylib}/build.rs (100%) create mode 100644 libs/virtual_display/dylib/src/lib.rs rename libs/virtual_display/{ => dylib}/src/win10/IddController.c (100%) rename libs/virtual_display/{ => dylib}/src/win10/IddController.h (100%) rename libs/virtual_display/{ => dylib}/src/win10/Public.h (100%) rename libs/virtual_display/{ => dylib}/src/win10/idd.rs (100%) rename libs/virtual_display/{ => dylib}/src/win10/mod.rs (100%) delete mode 100644 src/server/virtual_display.rs diff --git a/Cargo.lock b/Cargo.lock index 0e892aa31..07cb346b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1392,6 +1392,18 @@ version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" +[[package]] +name = "dylib_virtual_display" +version = "0.1.0" +dependencies = [ + "cc", + "hbb_common", + "lazy_static", + "serde 1.0.144", + "serde_derive", + "thiserror", +] + [[package]] name = "ed25519" version = "1.5.2" @@ -4391,7 +4403,6 @@ dependencies = [ "lazy_static", "libappindicator", "libc", - "libloading", "libpulse-binding", "libpulse-simple-binding", "mac_address", @@ -4425,6 +4436,7 @@ dependencies = [ "trayicon", "url", "uuid", + "virtual_display", "whoami", "winapi 0.3.9", "windows-service", @@ -5555,12 +5567,10 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" name = "virtual_display" version = "0.1.0" dependencies = [ - "cc", + "dylib_virtual_display", "hbb_common", "lazy_static", - "serde 1.0.144", - "serde_derive", - "thiserror", + "libloading", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index a3758c861..6375bce26 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,7 +65,6 @@ flutter_rust_bridge = { git = "https://github.com/SoLongAndThanksForAllThePizza/ errno = "0.2.8" rdev = { git = "https://github.com/asur4s/rdev" } url = { version = "2.1", features = ["serde"] } -libloading = "0.7" reqwest = { version = "0.11", features = ["blocking", "json", "rustls-tls"], default-features=false } chrono = "0.4.23" @@ -92,6 +91,7 @@ winit = "0.26" winapi = { version = "0.3", features = ["winuser"] } winreg = "0.10" windows-service = "0.4" +virtual_display = { path = "libs/virtual_display" } impersonate_system = { git = "https://github.com/21pages/impersonate-system" } shared_memory = "0.12.4" shutdown_hooks = "0.1.0" @@ -126,7 +126,7 @@ jni = "0.19" flutter_rust_bridge = { git = "https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge" } [workspace] -members = ["libs/scrap", "libs/hbb_common", "libs/enigo", "libs/clipboard", "libs/virtual_display", "libs/simple_rc", "libs/portable"] +members = ["libs/scrap", "libs/hbb_common", "libs/enigo", "libs/clipboard", "libs/virtual_display", "libs/virtual_display/dylib", "libs/simple_rc", "libs/portable"] [package.metadata.winres] LegalCopyright = "Copyright © 2022 Purslane, Inc." diff --git a/build.py b/build.py index 48eaf1bc0..a95c64dc1 100755 --- a/build.py +++ b/build.py @@ -280,8 +280,8 @@ def build_flutter_windows(version, features): exit(-1) os.chdir('flutter') os.system('flutter build windows --release') - shutil.copy2('target/release/deps/virtual_display.dll', flutter_win_target_dir) os.chdir('..') + shutil.copy2('target/release/deps/dylib_virtual_display.dll', flutter_win_target_dir) os.chdir('libs/portable') os.system('pip3 install -r requirements.txt') os.system( @@ -318,9 +318,9 @@ def main(): portable = args.portable if windows: # build virtual display dynamic library - os.chdir('libs/virtual_display') + os.chdir('libs/virtual_display/dylib') os.system('cargo build --release') - os.chdir('../..') + os.chdir('../../..') if flutter: build_flutter_windows(version, features) diff --git a/libs/virtual_display/Cargo.lock b/libs/virtual_display/Cargo.lock new file mode 100644 index 000000000..22fa681b2 --- /dev/null +++ b/libs/virtual_display/Cargo.lock @@ -0,0 +1,1358 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" +dependencies = [ + "memchr", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bumpalo" +version = "3.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" + +[[package]] +name = "bytes" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" +dependencies = [ + "serde", +] + +[[package]] +name = "cc" +version = "1.0.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-integer", + "num-traits", + "time", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "confy" +version = "0.4.0" +source = "git+https://github.com/open-trade/confy#630cc28a396cb7d01eefdd9f3824486fe4d8554b" +dependencies = [ + "directories-next", + "serde", + "thiserror", + "toml", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "cxx" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97abf9f0eca9e52b7f81b945524e76710e6cb2366aead23b7d4fbf72e281f888" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cc32cc5fea1d894b77d269ddb9f192110069a8a9c1f1d441195fba90553dea3" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca220e4794c934dc6b1207c3b42856ad4c302f2df1712e9f8d2eec5afaacf1f" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b846f081361125bfc8dc9d3940c84e1fd83ba54bbca7b17cd29483c828be0704" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "directories-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dylib_virtual_display" +version = "0.1.0" +dependencies = [ + "cc", + "hbb_common", + "lazy_static", + "serde", + "serde_derive", + "thiserror", +] + +[[package]] +name = "ed25519" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9c280362032ea4203659fc489832d0204ef09f247a0506f170dafcac08c369" +dependencies = [ + "signature", +] + +[[package]] +name = "either" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "fastrand" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +dependencies = [ + "instant", +] + +[[package]] +name = "filetime" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys", +] + +[[package]] +name = "futures" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" + +[[package]] +name = "futures-executor" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" + +[[package]] +name = "futures-macro" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" + +[[package]] +name = "futures-task" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" + +[[package]] +name = "futures-util" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hbb_common" +version = "0.1.0" +dependencies = [ + "anyhow", + "bytes", + "chrono", + "confy", + "directories-next", + "dirs-next", + "env_logger", + "filetime", + "futures", + "futures-util", + "lazy_static", + "log", + "mac_address", + "machine-uid", + "protobuf", + "protobuf-codegen", + "rand", + "regex", + "serde", + "serde_derive", + "socket2 0.3.19", + "sodiumoxide", + "tokio", + "tokio-socks", + "tokio-util", + "winapi", + "zstd", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "iana-time-zone" +version = "0.1.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + +[[package]] +name = "indexmap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "jobserver" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libsodium-sys" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b779387cd56adfbc02ea4a668e704f729be8d6a6abd2c27ca5ee537849a92fd" +dependencies = [ + "cc", + "libc", + "pkg-config", + "walkdir", +] + +[[package]] +name = "link-cplusplus" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +dependencies = [ + "cc", +] + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "mac_address" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b238e3235c8382b7653c6408ed1b08dd379bdb9fdf990fb0bbae3db2cc0ae963" +dependencies = [ + "nix", + "winapi", +] + +[[package]] +name = "machine-uid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f1595709b0a7386bcd56ba34d250d626e5503917d05d32cdccddcd68603e212" +dependencies = [ + "winreg", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mio" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", +] + +[[package]] +name = "nix" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", + "memoffset", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "pin-project" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "protobuf" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55bad9126f378a853655831eb7363b7b01b81d19f8cb1218861086ca4a1a61e" +dependencies = [ + "bytes", + "once_cell", + "protobuf-support", + "thiserror", +] + +[[package]] +name = "protobuf-codegen" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd418ac3c91caa4032d37cb80ff0d44e2ebe637b2fb243b6234bf89cdac4901" +dependencies = [ + "anyhow", + "once_cell", + "protobuf", + "protobuf-parse", + "regex", + "tempfile", + "thiserror", +] + +[[package]] +name = "protobuf-parse" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d39b14605eaa1f6a340aec7f320b34064feb26c93aec35d6a9a2272a8ddfa49" +dependencies = [ + "anyhow", + "indexmap", + "log", + "protobuf", + "protobuf-support", + "tempfile", + "thiserror", + "which", +] + +[[package]] +name = "protobuf-support" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d4d7b8601c814cfb36bcebb79f0e61e45e1e93640cf778837833bbed05c372" +dependencies = [ + "thiserror", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "scratch" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" + +[[package]] +name = "serde" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" + +[[package]] +name = "serde_derive" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" + +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "socket2" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +dependencies = [ + "cfg-if", + "libc", + "winapi", +] + +[[package]] +name = "socket2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "sodiumoxide" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e26be3acb6c2d9a7aac28482586a7856436af4cfe7100031d219de2d2ecb0028" +dependencies = [ + "ed25519", + "libc", + "libsodium-sys", + "serde", +] + +[[package]] +name = "syn" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "tokio" +version = "1.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.4.7", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-socks" +version = "0.5.1-1" +source = "git+https://github.com/open-trade/tokio-socks#7034e79263ce25c348be072808d7601d82cd892d" +dependencies = [ + "bytes", + "either", + "futures-core", + "futures-sink", + "futures-util", + "pin-project", + "thiserror", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-util" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "futures-sink", + "futures-util", + "hashbrown", + "pin-project-lite", + "slab", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "virtual_display" +version = "0.1.0" +dependencies = [ + "dylib_virtual_display", + "hbb_common", + "lazy_static", + "libloading", +] + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + +[[package]] +name = "which" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b" +dependencies = [ + "either", + "libc", + "once_cell", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" + +[[package]] +name = "winreg" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" +dependencies = [ + "winapi", +] + +[[package]] +name = "zstd" +version = "0.9.2+zstd.1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2390ea1bf6c038c39674f22d95f0564725fc06034a47129179810b2fc58caa54" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "4.1.3+zstd.1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e99d81b99fb3c2c2c794e3fe56c305c63d5173a16a46b5850b07c935ffc7db79" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "1.6.2+zstd.1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2daf2f248d9ea44454bfcb2516534e8b8ad2fc91bf818a1885495fc42bc8ac9f" +dependencies = [ + "cc", + "libc", +] diff --git a/libs/virtual_display/Cargo.toml b/libs/virtual_display/Cargo.toml index d0b63b454..88e065206 100644 --- a/libs/virtual_display/Cargo.toml +++ b/libs/virtual_display/Cargo.toml @@ -3,18 +3,10 @@ name = "virtual_display" version = "0.1.0" edition = "2021" -[lib] -name = "virtual_display" -crate-type = ["cdylib", "staticlib", "rlib"] - # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[build-dependencies] -cc = "1.0" - [dependencies] -thiserror = "1.0.30" lazy_static = "1.4" -serde = "1.0" -serde_derive = "1.0" +libloading = "0.7" hbb_common = { path = "../hbb_common" } +dylib_virtual_display = { path = "./dylib" } diff --git a/libs/virtual_display/README.md b/libs/virtual_display/README.md index d5a1a0862..86b7b2ea2 100644 --- a/libs/virtual_display/README.md +++ b/libs/virtual_display/README.md @@ -1,32 +1,3 @@ # virtual display -Virtual display may be used on computers that do not have a monitor. - -[Development reference](https://github.com/pavlobu/deskreen/discussions/86) - -## windows - -### win10 - -Win10 provides [Indirect Display Driver Model](https://msdn.microsoft.com/en-us/library/windows/hardware/mt761968(v=vs.85).aspx). - -This lib uses [this project](https://github.com/fufesou/RustDeskIddDriver) as the driver. - - -**NOTE**: Versions before Win10 1607. Try follow [this method](https://github.com/fanxiushu/xdisp_virt/tree/master/indirect_display). - - -#### tested platforms - -- [x] 19041 -- [x] 19043 - -### win7 - -TODO - -[WDDM](https://docs.microsoft.com/en-us/windows-hardware/drivers/display/windows-vista-display-driver-model-design-guide). - -## X11 - -## OSX +[doc](./dylib/README.md) diff --git a/libs/virtual_display/dylib/Cargo.toml b/libs/virtual_display/dylib/Cargo.toml new file mode 100644 index 000000000..fee4e3e4f --- /dev/null +++ b/libs/virtual_display/dylib/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "dylib_virtual_display" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "staticlib", "rlib"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[build-dependencies] +cc = "1.0" + +[dependencies] +thiserror = "1.0.30" +lazy_static = "1.4" +serde = "1.0" +serde_derive = "1.0" +hbb_common = { path = "../../hbb_common" } diff --git a/libs/virtual_display/dylib/README.md b/libs/virtual_display/dylib/README.md new file mode 100644 index 000000000..d5a1a0862 --- /dev/null +++ b/libs/virtual_display/dylib/README.md @@ -0,0 +1,32 @@ +# virtual display + +Virtual display may be used on computers that do not have a monitor. + +[Development reference](https://github.com/pavlobu/deskreen/discussions/86) + +## windows + +### win10 + +Win10 provides [Indirect Display Driver Model](https://msdn.microsoft.com/en-us/library/windows/hardware/mt761968(v=vs.85).aspx). + +This lib uses [this project](https://github.com/fufesou/RustDeskIddDriver) as the driver. + + +**NOTE**: Versions before Win10 1607. Try follow [this method](https://github.com/fanxiushu/xdisp_virt/tree/master/indirect_display). + + +#### tested platforms + +- [x] 19041 +- [x] 19043 + +### win7 + +TODO + +[WDDM](https://docs.microsoft.com/en-us/windows-hardware/drivers/display/windows-vista-display-driver-model-design-guide). + +## X11 + +## OSX diff --git a/libs/virtual_display/build.rs b/libs/virtual_display/dylib/build.rs similarity index 100% rename from libs/virtual_display/build.rs rename to libs/virtual_display/dylib/build.rs diff --git a/libs/virtual_display/dylib/src/lib.rs b/libs/virtual_display/dylib/src/lib.rs new file mode 100644 index 000000000..7ffcc679f --- /dev/null +++ b/libs/virtual_display/dylib/src/lib.rs @@ -0,0 +1,201 @@ +#[cfg(windows)] +pub mod win10; + +use hbb_common::{bail, lazy_static, ResultType}; +use std::{path::Path, sync::Mutex}; + +lazy_static::lazy_static! { + // If device is uninstalled though "Device Manager" Window. + // Rustdesk is unable to handle device any more... + static ref H_SW_DEVICE: Mutex = Mutex::new(0); + static ref MONITOR_PLUGIN: Mutex> = Mutex::new(Vec::new()); +} + +#[no_mangle] +pub fn download_driver() -> ResultType<()> { + #[cfg(windows)] + let _download_url = win10::DRIVER_DOWNLOAD_URL; + #[cfg(target_os = "linux")] + let _download_url = ""; + + // process download and report progress + + Ok(()) +} + +#[no_mangle] +pub fn install_update_driver(_reboot_required: &mut bool) -> ResultType<()> { + #[cfg(windows)] + let install_path = win10::DRIVER_INSTALL_PATH; + #[cfg(not(windows))] + let install_path = ""; + + let abs_path = Path::new(install_path).canonicalize()?; + if !abs_path.exists() { + bail!("{} not exists", install_path) + } + + #[cfg(windows)] + unsafe { + { + // Device must be created before install driver. + // https://github.com/fufesou/RustDeskIddDriver/issues/1 + if let Err(e) = create_device() { + bail!("{}", e); + } + + let full_install_path: Vec = abs_path + .to_string_lossy() + .as_ref() + .encode_utf16() + .chain(Some(0).into_iter()) + .collect(); + + let mut reboot_required_tmp = win10::idd::FALSE; + if win10::idd::InstallUpdate(full_install_path.as_ptr() as _, &mut reboot_required_tmp) + == win10::idd::FALSE + { + bail!("{}", win10::get_last_msg()?); + } + *_reboot_required = reboot_required_tmp == win10::idd::TRUE; + } + } + + Ok(()) +} + +#[no_mangle] +pub fn uninstall_driver(_reboot_required: &mut bool) -> ResultType<()> { + #[cfg(windows)] + let install_path = win10::DRIVER_INSTALL_PATH; + #[cfg(not(windows))] + let install_path = ""; + + let abs_path = Path::new(install_path).canonicalize()?; + if !abs_path.exists() { + bail!("{} not exists", install_path) + } + + #[cfg(windows)] + unsafe { + { + let full_install_path: Vec = abs_path + .to_string_lossy() + .as_ref() + .encode_utf16() + .chain(Some(0).into_iter()) + .collect(); + + let mut reboot_required_tmp = win10::idd::FALSE; + if win10::idd::Uninstall(full_install_path.as_ptr() as _, &mut reboot_required_tmp) + == win10::idd::FALSE + { + bail!("{}", win10::get_last_msg()?); + } + *_reboot_required = reboot_required_tmp == win10::idd::TRUE; + } + } + + Ok(()) +} + +#[no_mangle] +pub fn is_device_created() -> bool { + #[cfg(windows)] + return *H_SW_DEVICE.lock().unwrap() != 0; + #[cfg(not(windows))] + return false; +} + +#[no_mangle] +pub fn create_device() -> ResultType<()> { + if is_device_created() { + return Ok(()); + } + #[cfg(windows)] + unsafe { + let mut lock_device = H_SW_DEVICE.lock().unwrap(); + let mut h_sw_device = *lock_device as win10::idd::HSWDEVICE; + if win10::idd::DeviceCreate(&mut h_sw_device) == win10::idd::FALSE { + bail!("{}", win10::get_last_msg()?); + } else { + *lock_device = h_sw_device as u64; + } + } + Ok(()) +} + +#[no_mangle] +pub fn close_device() { + #[cfg(windows)] + unsafe { + win10::idd::DeviceClose(*H_SW_DEVICE.lock().unwrap() as win10::idd::HSWDEVICE); + *H_SW_DEVICE.lock().unwrap() = 0; + MONITOR_PLUGIN.lock().unwrap().clear(); + } +} + +#[no_mangle] +pub fn plug_in_monitor() -> ResultType<()> { + #[cfg(windows)] + unsafe { + let monitor_index = 0 as u32; + let mut plug_in_monitors = MONITOR_PLUGIN.lock().unwrap(); + for i in 0..plug_in_monitors.len() { + if let Some(d) = plug_in_monitors.get(i) { + if *d == monitor_index { + return Ok(()); + } + }; + } + if win10::idd::MonitorPlugIn(monitor_index, 0, 30) == win10::idd::FALSE { + bail!("{}", win10::get_last_msg()?); + } + (*plug_in_monitors).push(monitor_index); + } + Ok(()) +} + +#[no_mangle] +pub fn plug_out_monitor() -> ResultType<()> { + #[cfg(windows)] + unsafe { + let monitor_index = 0 as u32; + if win10::idd::MonitorPlugOut(monitor_index) == win10::idd::FALSE { + bail!("{}", win10::get_last_msg()?); + } + let mut plug_in_monitors = MONITOR_PLUGIN.lock().unwrap(); + for i in 0..plug_in_monitors.len() { + if let Some(d) = plug_in_monitors.get(i) { + if *d == monitor_index { + plug_in_monitors.remove(i); + break; + } + }; + } + } + Ok(()) +} + +#[no_mangle] +pub fn update_monitor_modes() -> ResultType<()> { + #[cfg(windows)] + unsafe { + let monitor_index = 0 as u32; + let mut modes = vec![win10::idd::MonitorMode { + width: 1920, + height: 1080, + sync: 60, + }]; + if win10::idd::FALSE + == win10::idd::MonitorModesUpdate( + monitor_index as win10::idd::UINT, + modes.len() as win10::idd::UINT, + modes.as_mut_ptr(), + ) + { + bail!("{}", win10::get_last_msg()?); + } + } + Ok(()) +} diff --git a/libs/virtual_display/src/win10/IddController.c b/libs/virtual_display/dylib/src/win10/IddController.c similarity index 100% rename from libs/virtual_display/src/win10/IddController.c rename to libs/virtual_display/dylib/src/win10/IddController.c diff --git a/libs/virtual_display/src/win10/IddController.h b/libs/virtual_display/dylib/src/win10/IddController.h similarity index 100% rename from libs/virtual_display/src/win10/IddController.h rename to libs/virtual_display/dylib/src/win10/IddController.h diff --git a/libs/virtual_display/src/win10/Public.h b/libs/virtual_display/dylib/src/win10/Public.h similarity index 100% rename from libs/virtual_display/src/win10/Public.h rename to libs/virtual_display/dylib/src/win10/Public.h diff --git a/libs/virtual_display/src/win10/idd.rs b/libs/virtual_display/dylib/src/win10/idd.rs similarity index 100% rename from libs/virtual_display/src/win10/idd.rs rename to libs/virtual_display/dylib/src/win10/idd.rs diff --git a/libs/virtual_display/src/win10/mod.rs b/libs/virtual_display/dylib/src/win10/mod.rs similarity index 100% rename from libs/virtual_display/src/win10/mod.rs rename to libs/virtual_display/dylib/src/win10/mod.rs diff --git a/libs/virtual_display/src/lib.rs b/libs/virtual_display/src/lib.rs index 7ffcc679f..47b11d74a 100644 --- a/libs/virtual_display/src/lib.rs +++ b/libs/virtual_display/src/lib.rs @@ -1,201 +1,89 @@ #[cfg(windows)] -pub mod win10; +pub use dylib_virtual_display::win10; -use hbb_common::{bail, lazy_static, ResultType}; -use std::{path::Path, sync::Mutex}; +use hbb_common::{bail, ResultType}; +use std::sync::{Arc, Mutex}; + +const LIB_NAME_VIRTUAL_DISPLAY: &str = "virtual_display"; lazy_static::lazy_static! { - // If device is uninstalled though "Device Manager" Window. - // Rustdesk is unable to handle device any more... - static ref H_SW_DEVICE: Mutex = Mutex::new(0); - static ref MONITOR_PLUGIN: Mutex> = Mutex::new(Vec::new()); + static ref LIB_VIRTUAL_DISPLAY: Arc>> = { + #[cfg(target_os = "windows")] + let libname = format!("{}.dll", LIB_NAME_VIRTUAL_DISPLAY); + #[cfg(target_os = "linux")] + let libname = format!("lib{}.so", LIB_NAME_VIRTUAL_DISPLAY); + #[cfg(target_os = "macos")] + let libname = format!("lib{}.dylib", LIB_NAME_VIRTUAL_DISPLAY); + Arc::new(Mutex::new(unsafe { libloading::Library::new(libname) })) + }; } -#[no_mangle] -pub fn download_driver() -> ResultType<()> { - #[cfg(windows)] - let _download_url = win10::DRIVER_DOWNLOAD_URL; - #[cfg(target_os = "linux")] - let _download_url = ""; - - // process download and report progress - - Ok(()) -} - -#[no_mangle] -pub fn install_update_driver(_reboot_required: &mut bool) -> ResultType<()> { - #[cfg(windows)] - let install_path = win10::DRIVER_INSTALL_PATH; - #[cfg(not(windows))] - let install_path = ""; - - let abs_path = Path::new(install_path).canonicalize()?; - if !abs_path.exists() { - bail!("{} not exists", install_path) - } - - #[cfg(windows)] - unsafe { - { - // Device must be created before install driver. - // https://github.com/fufesou/RustDeskIddDriver/issues/1 - if let Err(e) = create_device() { - bail!("{}", e); - } - - let full_install_path: Vec = abs_path - .to_string_lossy() - .as_ref() - .encode_utf16() - .chain(Some(0).into_iter()) - .collect(); - - let mut reboot_required_tmp = win10::idd::FALSE; - if win10::idd::InstallUpdate(full_install_path.as_ptr() as _, &mut reboot_required_tmp) - == win10::idd::FALSE - { - bail!("{}", win10::get_last_msg()?); - } - *_reboot_required = reboot_required_tmp == win10::idd::TRUE; - } - } - - Ok(()) -} - -#[no_mangle] -pub fn uninstall_driver(_reboot_required: &mut bool) -> ResultType<()> { - #[cfg(windows)] - let install_path = win10::DRIVER_INSTALL_PATH; - #[cfg(not(windows))] - let install_path = ""; - - let abs_path = Path::new(install_path).canonicalize()?; - if !abs_path.exists() { - bail!("{} not exists", install_path) - } - - #[cfg(windows)] - unsafe { - { - let full_install_path: Vec = abs_path - .to_string_lossy() - .as_ref() - .encode_utf16() - .chain(Some(0).into_iter()) - .collect(); - - let mut reboot_required_tmp = win10::idd::FALSE; - if win10::idd::Uninstall(full_install_path.as_ptr() as _, &mut reboot_required_tmp) - == win10::idd::FALSE - { - bail!("{}", win10::get_last_msg()?); - } - *_reboot_required = reboot_required_tmp == win10::idd::TRUE; - } - } - - Ok(()) -} - -#[no_mangle] pub fn is_device_created() -> bool { - #[cfg(windows)] - return *H_SW_DEVICE.lock().unwrap() != 0; - #[cfg(not(windows))] - return false; + match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { + Ok(lib) => unsafe { + match lib.get:: bool>>(b"is_device_created") { + Ok(func) => func(), + Err(..) => false, + } + }, + Err(..) => false, + } } -#[no_mangle] -pub fn create_device() -> ResultType<()> { - if is_device_created() { - return Ok(()); - } - #[cfg(windows)] - unsafe { - let mut lock_device = H_SW_DEVICE.lock().unwrap(); - let mut h_sw_device = *lock_device as win10::idd::HSWDEVICE; - if win10::idd::DeviceCreate(&mut h_sw_device) == win10::idd::FALSE { - bail!("{}", win10::get_last_msg()?); - } else { - *lock_device = h_sw_device as u64; - } - } - Ok(()) -} - -#[no_mangle] pub fn close_device() { - #[cfg(windows)] - unsafe { - win10::idd::DeviceClose(*H_SW_DEVICE.lock().unwrap() as win10::idd::HSWDEVICE); - *H_SW_DEVICE.lock().unwrap() = 0; - MONITOR_PLUGIN.lock().unwrap().clear(); + match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { + Ok(lib) => unsafe { + match lib.get::>(b"close_device") { + Ok(func) => func(), + Err(..) => {} + } + }, + Err(..) => {} } } -#[no_mangle] -pub fn plug_in_monitor() -> ResultType<()> { - #[cfg(windows)] - unsafe { - let monitor_index = 0 as u32; - let mut plug_in_monitors = MONITOR_PLUGIN.lock().unwrap(); - for i in 0..plug_in_monitors.len() { - if let Some(d) = plug_in_monitors.get(i) { - if *d == monitor_index { - return Ok(()); - } - }; +macro_rules! def_func_result { + ($func:ident, $name: tt) => { + pub fn $func() -> ResultType<()> { + match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { + Ok(lib) => unsafe { + match lib.get:: ResultType<()>>>($name.as_bytes()) { + Ok(func) => func(), + Err(..) => bail!("Failed to load func {}", $name), + } + }, + Err(e) => bail!("Failed to load library {}, {}", LIB_NAME_VIRTUAL_DISPLAY, e), + } } - if win10::idd::MonitorPlugIn(monitor_index, 0, 30) == win10::idd::FALSE { - bail!("{}", win10::get_last_msg()?); - } - (*plug_in_monitors).push(monitor_index); - } - Ok(()) + }; } -#[no_mangle] -pub fn plug_out_monitor() -> ResultType<()> { - #[cfg(windows)] - unsafe { - let monitor_index = 0 as u32; - if win10::idd::MonitorPlugOut(monitor_index) == win10::idd::FALSE { - bail!("{}", win10::get_last_msg()?); - } - let mut plug_in_monitors = MONITOR_PLUGIN.lock().unwrap(); - for i in 0..plug_in_monitors.len() { - if let Some(d) = plug_in_monitors.get(i) { - if *d == monitor_index { - plug_in_monitors.remove(i); - break; - } - }; - } +pub fn install_update_driver(reboot_required: &mut bool) -> ResultType<()> { + match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { + Ok(lib) => unsafe { + match lib.get:: ResultType<()>>>(b"install_update_driver") { + Ok(func) => func(reboot_required), + Err(..) => bail!("Failed to load func install_update_driver"), + } + }, + Err(e) => bail!("Failed to load library {}, {}", LIB_NAME_VIRTUAL_DISPLAY, e), } - Ok(()) } -#[no_mangle] -pub fn update_monitor_modes() -> ResultType<()> { - #[cfg(windows)] - unsafe { - let monitor_index = 0 as u32; - let mut modes = vec![win10::idd::MonitorMode { - width: 1920, - height: 1080, - sync: 60, - }]; - if win10::idd::FALSE - == win10::idd::MonitorModesUpdate( - monitor_index as win10::idd::UINT, - modes.len() as win10::idd::UINT, - modes.as_mut_ptr(), - ) - { - bail!("{}", win10::get_last_msg()?); - } +pub fn uninstall_driver(reboot_required: &mut bool) -> ResultType<()> { + match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { + Ok(lib) => unsafe { + match lib.get:: ResultType<()>>>(b"uninstall_driver") { + Ok(func) => func(reboot_required), + Err(..) => bail!("Failed to load func uninstall_driver"), + } + }, + Err(e) => bail!("Failed to load library {}, {}", LIB_NAME_VIRTUAL_DISPLAY, e), } - Ok(()) } + +def_func_result!(download_driver, "download_driver"); +def_func_result!(create_device, "create_device"); +def_func_result!(plug_in_monitor, "plug_in_monitor"); +def_func_result!(plug_out_monitor, "plug_out_monitor"); +def_func_result!(update_monitor_modes, "update_monitor_modes"); diff --git a/src/server.rs b/src/server.rs index bf81468ce..7e00532fe 100644 --- a/src/server.rs +++ b/src/server.rs @@ -53,8 +53,6 @@ mod connection; pub mod portable_service; mod service; mod video_qos; -#[cfg(windows)] -mod virtual_display; pub mod video_service; use hbb_common::tcp::new_listener; diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 0597ac956..3ccc3af39 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -42,7 +42,7 @@ use std::{ time::{self, Duration, Instant}, }; #[cfg(windows)] -use super::virtual_display; +use virtual_display; pub const SCRAP_UBUNTU_HIGHER_REQUIRED: &str = "Wayland requires Ubuntu 21.04 or higher version."; pub const SCRAP_OTHER_VERSION_OR_X11_REQUIRED: &str = diff --git a/src/server/virtual_display.rs b/src/server/virtual_display.rs deleted file mode 100644 index 23071326b..000000000 --- a/src/server/virtual_display.rs +++ /dev/null @@ -1,64 +0,0 @@ -#![allow(dead_code)] - -use hbb_common::{bail, ResultType}; -use std::sync::{Arc, Mutex}; - -const LIB_NAME_VIRTUAL_DISPLAY: &str = "virtual_display"; - -lazy_static::lazy_static! { - static ref LIB_VIRTUAL_DISPLAY: Arc>> = { - #[cfg(target_os = "windows")] - let libname = format!("{}.dll", LIB_NAME_VIRTUAL_DISPLAY); - #[cfg(target_os = "linux")] - let libname = format!("lib{}.so", LIB_NAME_VIRTUAL_DISPLAY); - #[cfg(target_os = "macos")] - let libname = format!("lib{}.dylib", LIB_NAME_VIRTUAL_DISPLAY); - Arc::new(Mutex::new(unsafe { libloading::Library::new(libname) })) - }; -} - -pub(super) fn is_device_created() -> bool { - match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { - Ok(lib) => unsafe { - match lib.get:: bool>>(b"is_device_created") { - Ok(func) => func(), - Err(..) => false, - } - }, - Err(..) => false, - } -} - -macro_rules! def_func_result { - ($func:ident, $name: tt) => { - pub(super) fn $func() -> ResultType<()> { - match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { - Ok(lib) => unsafe { - match lib.get:: ResultType<()>>>($name.as_bytes()) { - Ok(func) => func(), - Err(..) => bail!("Failed to load func {}", $name), - } - }, - Err(e) => bail!("Failed to load library {}, {}", LIB_NAME_VIRTUAL_DISPLAY, e), - } - } - }; -} - -def_func_result!(create_device, "create_device"); - -pub(super) fn close_device() { - match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { - Ok(lib) => unsafe { - match lib.get::>(b"close_device") { - Ok(func) => func(), - Err(..) => {}, - } - }, - Err(..) => {}, - } -} - -def_func_result!(plug_in_monitor, "plug_in_monitor"); -def_func_result!(plug_out_monitor, "plug_out_monitor"); -def_func_result!(update_monitor_modes, "update_monitor_modes"); From aa3b8ca084babcb451ea73dc18843a49ff1d88eb Mon Sep 17 00:00:00 2001 From: fufesou Date: Fri, 18 Nov 2022 15:51:33 +0800 Subject: [PATCH 071/116] virtual display remove static links Signed-off-by: fufesou --- Cargo.lock | 1 - build.py | 5 -- libs/virtual_display/Cargo.toml | 1 - .../{ => dylib}/examples/idd_controller.rs | 2 +- libs/virtual_display/dylib/src/lib.rs | 6 ++ libs/virtual_display/src/lib.rs | 68 ++++++++++++++----- 6 files changed, 59 insertions(+), 24 deletions(-) rename libs/virtual_display/{ => dylib}/examples/idd_controller.rs (98%) diff --git a/Cargo.lock b/Cargo.lock index 07cb346b8..9eb270683 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5567,7 +5567,6 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" name = "virtual_display" version = "0.1.0" dependencies = [ - "dylib_virtual_display", "hbb_common", "lazy_static", "libloading", diff --git a/build.py b/build.py index a95c64dc1..07c571b11 100755 --- a/build.py +++ b/build.py @@ -317,11 +317,6 @@ def main(): os.system('python3 res/inline-sciter.py') portable = args.portable if windows: - # build virtual display dynamic library - os.chdir('libs/virtual_display/dylib') - os.system('cargo build --release') - os.chdir('../../..') - if flutter: build_flutter_windows(version, features) return diff --git a/libs/virtual_display/Cargo.toml b/libs/virtual_display/Cargo.toml index 88e065206..c700bd12a 100644 --- a/libs/virtual_display/Cargo.toml +++ b/libs/virtual_display/Cargo.toml @@ -9,4 +9,3 @@ edition = "2021" lazy_static = "1.4" libloading = "0.7" hbb_common = { path = "../hbb_common" } -dylib_virtual_display = { path = "./dylib" } diff --git a/libs/virtual_display/examples/idd_controller.rs b/libs/virtual_display/dylib/examples/idd_controller.rs similarity index 98% rename from libs/virtual_display/examples/idd_controller.rs rename to libs/virtual_display/dylib/examples/idd_controller.rs index 7d5677724..c9a3fbbab 100644 --- a/libs/virtual_display/examples/idd_controller.rs +++ b/libs/virtual_display/dylib/examples/idd_controller.rs @@ -1,5 +1,5 @@ #[cfg(windows)] -use virtual_display::win10::{idd, DRIVER_INSTALL_PATH}; +use dylib_virtual_display::win10::{idd, DRIVER_INSTALL_PATH}; #[cfg(windows)] use std::{ diff --git a/libs/virtual_display/dylib/src/lib.rs b/libs/virtual_display/dylib/src/lib.rs index 7ffcc679f..4a95e3461 100644 --- a/libs/virtual_display/dylib/src/lib.rs +++ b/libs/virtual_display/dylib/src/lib.rs @@ -11,6 +11,12 @@ lazy_static::lazy_static! { static ref MONITOR_PLUGIN: Mutex> = Mutex::new(Vec::new()); } +#[no_mangle] +#[cfg(windows)] +pub fn get_dirver_install_path() -> &'static str { + win10::DRIVER_INSTALL_PATH +} + #[no_mangle] pub fn download_driver() -> ResultType<()> { #[cfg(windows)] diff --git a/libs/virtual_display/src/lib.rs b/libs/virtual_display/src/lib.rs index 47b11d74a..cd9402c69 100644 --- a/libs/virtual_display/src/lib.rs +++ b/libs/virtual_display/src/lib.rs @@ -1,24 +1,52 @@ -#[cfg(windows)] -pub use dylib_virtual_display::win10; - use hbb_common::{bail, ResultType}; use std::sync::{Arc, Mutex}; -const LIB_NAME_VIRTUAL_DISPLAY: &str = "virtual_display"; +const LIB_NAME_VIRTUAL_DISPLAY: &str = "dylib_virtual_display"; lazy_static::lazy_static! { static ref LIB_VIRTUAL_DISPLAY: Arc>> = { - #[cfg(target_os = "windows")] - let libname = format!("{}.dll", LIB_NAME_VIRTUAL_DISPLAY); - #[cfg(target_os = "linux")] - let libname = format!("lib{}.so", LIB_NAME_VIRTUAL_DISPLAY); - #[cfg(target_os = "macos")] - let libname = format!("lib{}.dylib", LIB_NAME_VIRTUAL_DISPLAY); - Arc::new(Mutex::new(unsafe { libloading::Library::new(libname) })) + Arc::new(Mutex::new(unsafe { libloading::Library::new(get_lib_name()) })) }; } +#[cfg(target_os = "windows")] +fn get_lib_name() -> String { + format!("{}.dll", LIB_NAME_VIRTUAL_DISPLAY) +} + +#[cfg(target_os = "linux")] +fn get_lib_name() -> String { + format!("lib{}.so", LIB_NAME_VIRTUAL_DISPLAY) +} + +#[cfg(target_os = "macos")] +fn get_lib_name() -> String { + format!("lib{}.dylib", LIB_NAME_VIRTUAL_DISPLAY) +} + +fn try_reload_lib() { + let mut lock = LIB_VIRTUAL_DISPLAY.lock().unwrap(); + if lock.is_err() { + *lock = unsafe { libloading::Library::new(get_lib_name()) }; + } +} + +#[cfg(windows)] +pub fn get_dirver_install_path() -> ResultType<&'static str> { + try_reload_lib(); + match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { + Ok(lib) => unsafe { + match lib.get:: &'static str>>(b"get_dirver_install_path") { + Ok(func) => Ok(func()), + Err(e) => bail!("Failed to load func get_dirver_install_path, {}", e), + } + }, + Err(e) => bail!("Failed to load library {}, {}", LIB_NAME_VIRTUAL_DISPLAY, e), + } +} + pub fn is_device_created() -> bool { + try_reload_lib(); match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { Ok(lib) => unsafe { match lib.get:: bool>>(b"is_device_created") { @@ -31,6 +59,7 @@ pub fn is_device_created() -> bool { } pub fn close_device() { + try_reload_lib(); match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { Ok(lib) => unsafe { match lib.get::>(b"close_device") { @@ -45,11 +74,12 @@ pub fn close_device() { macro_rules! def_func_result { ($func:ident, $name: tt) => { pub fn $func() -> ResultType<()> { + try_reload_lib(); match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { Ok(lib) => unsafe { match lib.get:: ResultType<()>>>($name.as_bytes()) { Ok(func) => func(), - Err(..) => bail!("Failed to load func {}", $name), + Err(e) => bail!("Failed to load func {}, {}", $name, e), } }, Err(e) => bail!("Failed to load library {}, {}", LIB_NAME_VIRTUAL_DISPLAY, e), @@ -59,11 +89,14 @@ macro_rules! def_func_result { } pub fn install_update_driver(reboot_required: &mut bool) -> ResultType<()> { + try_reload_lib(); match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { Ok(lib) => unsafe { - match lib.get:: ResultType<()>>>(b"install_update_driver") { + match lib.get:: ResultType<()>>>( + b"install_update_driver", + ) { Ok(func) => func(reboot_required), - Err(..) => bail!("Failed to load func install_update_driver"), + Err(e) => bail!("Failed to load func install_update_driver, {}", e), } }, Err(e) => bail!("Failed to load library {}, {}", LIB_NAME_VIRTUAL_DISPLAY, e), @@ -71,11 +104,14 @@ pub fn install_update_driver(reboot_required: &mut bool) -> ResultType<()> { } pub fn uninstall_driver(reboot_required: &mut bool) -> ResultType<()> { + try_reload_lib(); match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { Ok(lib) => unsafe { - match lib.get:: ResultType<()>>>(b"uninstall_driver") { + match lib + .get:: ResultType<()>>>(b"uninstall_driver") + { Ok(func) => func(reboot_required), - Err(..) => bail!("Failed to load func uninstall_driver"), + Err(e) => bail!("Failed to load func uninstall_driver, {}", e), } }, Err(e) => bail!("Failed to load library {}, {}", LIB_NAME_VIRTUAL_DISPLAY, e), From 3e9d992db333869bccf0ce94239758ea1d2c1bac Mon Sep 17 00:00:00 2001 From: fufesou Date: Fri, 18 Nov 2022 17:09:52 +0800 Subject: [PATCH 072/116] build dylib Signed-off-by: fufesou --- build.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build.py b/build.py index 07c571b11..a95c64dc1 100755 --- a/build.py +++ b/build.py @@ -317,6 +317,11 @@ def main(): os.system('python3 res/inline-sciter.py') portable = args.portable if windows: + # build virtual display dynamic library + os.chdir('libs/virtual_display/dylib') + os.system('cargo build --release') + os.chdir('../../..') + if flutter: build_flutter_windows(version, features) return From 03ae220f714b504db38481b6a928af4f7ef64464 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Fri, 18 Nov 2022 18:36:25 +0800 Subject: [PATCH 073/116] macos tray --- src/core_main.rs | 3 ++- src/tray.rs | 32 ++++++++++++++++++++++++++++++++ src/ui.rs | 7 +------ src/ui/macos.rs | 28 +--------------------------- 4 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/core_main.rs b/src/core_main.rs index 889015c0d..31b2ae118 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -163,7 +163,8 @@ pub fn core_main() -> Option> { #[cfg(target_os = "macos")] { std::thread::spawn(move || crate::start_server(true)); - // to-do: for flutter, starting tray not ready yet, or we can reuse sciter's tray implementation. + crate::tray::make_tray(); + return None; } #[cfg(target_os = "linux")] { diff --git a/src/tray.rs b/src/tray.rs index 30bdc5a59..5064d96dc 100644 --- a/src/tray.rs +++ b/src/tray.rs @@ -173,3 +173,35 @@ fn is_service_stoped() -> bool { false } } + +#[cfg(target_os = "macos")] +pub fn make_tray() { + use tray_item::TrayItem; + let mode = dark_light::detect(); + let mut icon_path = ""; + match mode { + dark_light::Mode::Dark => { + icon_path = "mac-tray-light.png"; + }, + dark_light::Mode::Light => { + icon_path = "mac-tray-dark.png"; + }, + } + if let Ok(mut tray) = TrayItem::new(&crate::get_app_name(), icon_path) { + tray.add_label(&format!( + "{} {}", + crate::get_app_name(), + crate::lang::translate("Service is running".to_owned()) + )) + .ok(); + + let inner = tray.inner_mut(); + inner.add_quit_item(&crate::lang::translate("Quit".to_owned())); + inner.display(); + } else { + loop { + std::thread::sleep(std::time::Duration::from_secs(3)); + } + } +} + diff --git a/src/ui.rs b/src/ui.rs index 2d7f8d70a..904d3ae2b 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -63,12 +63,7 @@ fn check_connect_status( pub fn start(args: &mut [String]) { #[cfg(target_os = "macos")] - if args.len() == 1 && args[0] == "--server" { - macos::make_tray(); - return; - } else { - macos::show_dock(); - } + macos::show_dock(); #[cfg(all(target_os = "linux", feature = "inline"))] { #[cfg(feature = "appimage")] diff --git a/src/ui/macos.rs b/src/ui/macos.rs index 3c7a7dcd0..488d1afc8 100644 --- a/src/ui/macos.rs +++ b/src/ui/macos.rs @@ -233,33 +233,7 @@ pub fn make_tray() { unsafe { set_delegate(None); } - use tray_item::TrayItem; - let mode = dark_light::detect(); - let mut icon_path = ""; - match mode { - dark_light::Mode::Dark => { - icon_path = "mac-tray-light.png"; - }, - dark_light::Mode::Light => { - icon_path = "mac-tray-dark.png"; - }, - } - if let Ok(mut tray) = TrayItem::new(&crate::get_app_name(), icon_path) { - tray.add_label(&format!( - "{} {}", - crate::get_app_name(), - crate::lang::translate("Service is running".to_owned()) - )) - .ok(); - - let inner = tray.inner_mut(); - inner.add_quit_item(&crate::lang::translate("Quit".to_owned())); - inner.display(); - } else { - loop { - std::thread::sleep(std::time::Duration::from_secs(3)); - } - } + crate::tray::make_tray(); } pub fn check_main_window() { From af68800f45357de52662f8144d09696c58c42c10 Mon Sep 17 00:00:00 2001 From: fufesou Date: Fri, 18 Nov 2022 18:46:00 +0800 Subject: [PATCH 074/116] remove redundant conditions Signed-off-by: fufesou --- src/client/io_loop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 86a9e2f2e..6ad4f96d6 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -1187,7 +1187,7 @@ impl Remote { #[cfg(windows)] fn handle_cliprdr_msg(&self, clip: hbb_common::message_proto::Cliprdr) { if !self.handler.lc.read().unwrap().disable_clipboard { - #[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] + #[cfg(feature = "flutter")] if let Some(hbb_common::message_proto::cliprdr::Union::FormatList(_)) = &clip.union { if self.client_conn_id != clipboard::get_client_conn_id(&crate::flutter::get_cur_session_id()) From 1af6f81e409908826dab5fdfdb5314d34c04bcaa Mon Sep 17 00:00:00 2001 From: NicKoehler <53040044+NicKoehler@users.noreply.github.com> Date: Fri, 18 Nov 2022 12:50:39 +0100 Subject: [PATCH 075/116] Update it.rs added italian strings --- src/lang/it.rs | 108 ++++++++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/src/lang/it.rs b/src/lang/it.rs index 731b5643d..469a9c5ae 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -30,9 +30,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("IP Whitelisting", "IP autorizzati"), ("ID/Relay Server", "Server ID/Relay"), ("Import Server Config", "Importa configurazione Server"), - ("Export Server Config", ""), + ("Export Server Config", "Esporta configurazione Server"), ("Import server configuration successfully", "Configurazione Server importata con successo"), - ("Export server configuration successfully", ""), + ("Export server configuration successfully", "Configurazione Server esportata con successo"), ("Invalid server configuration", "Configurazione Server non valida"), ("Clipboard is empty", "Gli appunti sono vuoti"), ("Stop service", "Arresta servizio"), @@ -89,8 +89,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Delete", "Eliminare"), ("Properties", "Proprietà"), ("Multi Select", "Selezione multipla"), - ("Select All", ""), - ("Unselect All", ""), + ("Select All", "Seleziona tutto"), + ("Unselect All", "Deseleziona tutto"), ("Empty Directory", "Directory vuota"), ("Not an empty directory", "Non una directory vuota"), ("Are you sure you want to delete this file?", "Vuoi davvero eliminare questo file?"), @@ -296,13 +296,13 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("In privacy mode", "In modalità privacy"), ("Out privacy mode", "Fuori modalità privacy"), ("Language", "Linguaggio"), - ("Keep RustDesk background service", ""), - ("Ignore Battery Optimizations", ""), + ("Keep RustDesk background service", "Mantieni il servizio di RustDesk in background"), + ("Ignore Battery Optimizations", "Ignora le ottimizzazioni della batteria"), ("android_open_battery_optimizations_tip", ""), ("Connection not allowed", "Connessione non consentita"), - ("Legacy mode", ""), - ("Map mode", ""), - ("Translate mode", ""), + ("Legacy mode", "Modalità legacy"), + ("Map mode", "Modalità mappa"), + ("Translate mode", "Modalità di traduzione"), ("Use temporary password", "Usa password temporanea"), ("Use permanent password", "Usa password permanente"), ("Use both passwords", "Usa entrambe le password"), @@ -318,7 +318,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Exit Fullscreen", "Esci dalla modalità schermo intero"), ("Fullscreen", "A schermo intero"), ("Mobile Actions", "Azioni mobili"), - ("Select Monitor", "Seleziona Monitora"), + ("Select Monitor", "Seleziona schermo"), ("Control Actions", "Azioni di controllo"), ("Display Settings", "Impostazioni di visualizzazione"), ("Ratio", "Rapporto"), @@ -337,58 +337,58 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Account", "Account"), ("Theme", "Tema"), ("Dark Theme", "Tema Scuro"), - ("Dark", ""), - ("Light", ""), - ("Follow System", ""), - ("Enable hardware codec", ""), - ("Unlock Security Settings", ""), - ("Enable Audio", ""), - ("Temporary Password Length", ""), - ("Unlock Network Settings", ""), + ("Dark", "Scuro"), + ("Light", "Chiaro"), + ("Follow System", "Segui il sistema"), + ("Enable hardware codec", "Abilita codec hardware"), + ("Unlock Security Settings", "Sblocca impostazioni di sicurezza"), + ("Enable Audio", "Abilita audio"), + ("Temporary Password Length", "Lunghezza password temporanea"), + ("Unlock Network Settings", "Sblocca impostazioni di rete"), ("Server", ""), - ("Direct IP Access", ""), + ("Direct IP Access", "Accesso IP diretto"), ("Proxy", ""), - ("Port", ""), - ("Apply", ""), - ("Disconnect all devices?", ""), - ("Clear", ""), - ("Audio Input Device", ""), - ("Deny remote access", ""), - ("Use IP Whitelisting", ""), - ("Network", ""), - ("Enable RDP", ""), + ("Port", "Porta"), + ("Apply", "Applica"), + ("Disconnect all devices?", "Disconnettere tutti i dispositivi?"), + ("Clear", "Ripulisci"), + ("Audio Input Device", "Dispositivo di inpit audio"), + ("Deny remote access", "Nega accesso remoto"), + ("Use IP Whitelisting", "Utilizza la whitelist di IP"), + ("Network", "Rete"), + ("Enable RDP", "Abilita RDP"), ("Pin menubar", "Blocca la barra dei menu"), ("Unpin menubar", "Sblocca la barra dei menu"), - ("Recording", ""), - ("Directory", ""), - ("Automatically record incoming sessions", ""), - ("Change", ""), - ("Start session recording", ""), - ("Stop session recording", ""), - ("Enable Recording Session", ""), - ("Allow recording session", ""), - ("Enable LAN Discovery", ""), - ("Deny LAN Discovery", ""), - ("Write a message", ""), + ("Recording", "Registrazione"), + ("Directory", "Cartella"), + ("Automatically record incoming sessions", "Registra automaticamente le sessioni in entrata"), + ("Change", "Cambia"), + ("Start session recording", "Inizia registrazione della sessione"), + ("Stop session recording", "Ferma registrazione della sessione"), + ("Enable Recording Session", "Abilita registrazione della sessione"), + ("Allow recording session", "Permetti di registrare la sessione"), + ("Enable LAN Discovery", "Abilita il rilevamento della LAN"), + ("Deny LAN Discovery", "Nega il rilevamento della LAN"), + ("Write a message", "Scrivi un messaggio"), ("Prompt", ""), - ("Please wait for confirmation of UAC...", ""), + ("Please wait for confirmation of UAC...", "Attendi la conferma dell'UAC..."), ("elevated_foreground_window_tip", ""), - ("Disconnected", ""), - ("Other", ""), - ("Confirm before closing multiple tabs", ""), - ("Keyboard Settings", ""), - ("Custom", ""), - ("Full Access", ""), - ("Screen Share", ""), - ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland richiede Ubuntu 21.04 o versione successiva."), + ("Disconnected", "Disconnesso"), + ("Other", "Altro"), + ("Confirm before closing multiple tabs", "Conferma prima di chiudere più schede"), + ("Keyboard Settings", "Impostazioni tastiera"), + ("Custom", "Personalizzato"), + ("Full Access", "Accesso completo"), + ("Screen Share", "Condivisione dello schermo"), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland richiede Ubuntu 21.04 o successiva."), ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland richiede una versione superiore della distribuzione Linux. Prova X11 desktop o cambia il tuo sistema operativo."), ("JumpLink", "View"), ("Please Select the screen to be shared(Operate on the peer side).", "Seleziona lo schermo da condividere (opera sul lato peer)."), - ("Show RustDesk", ""), - ("This PC", ""), - ("or", ""), - ("Continue with", ""), - ("Elevate", ""), - ("Zoom cursor", ""), + ("Show RustDesk", "Mostra RustDesk"), + ("This PC", "Questo PC"), + ("or", "O"), + ("Continue with", "Continua con"), + ("Elevate", "Eleva"), + ("Zoom cursor", "Cursore zoom"), ].iter().cloned().collect(); } From 3adeba65d871fe8740466e603e4a64826e2295a8 Mon Sep 17 00:00:00 2001 From: fufesou Date: Fri, 18 Nov 2022 22:36:51 +0800 Subject: [PATCH 076/116] fix blurry screen when scale original Signed-off-by: fufesou --- flutter/lib/desktop/pages/remote_page.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index 1aca198c2..84ea36d78 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -565,9 +565,11 @@ class ImagePainter extends CustomPainter { // https://github.com/flutter/flutter/issues/76187#issuecomment-784628161 // https://api.flutter-io.cn/flutter/dart-ui/FilterQuality.html var paint = Paint(); - paint.filterQuality = FilterQuality.medium; - if (scale > 10.00000) { - paint.filterQuality = FilterQuality.high; + if ((scale - 1.0).abs() > 0.001) { + paint.filterQuality = FilterQuality.medium; + if (scale > 10.00000) { + paint.filterQuality = FilterQuality.high; + } } canvas.drawImage(image!, Offset(x, y), paint); } From 042a2bff904a82d812011a39ab6b48fe29240d40 Mon Sep 17 00:00:00 2001 From: fufesou Date: Fri, 18 Nov 2022 23:00:15 +0800 Subject: [PATCH 077/116] trivial changes Signed-off-by: fufesou --- flutter/lib/desktop/pages/remote_page.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index 84ea36d78..c1837cb21 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -561,11 +561,11 @@ class ImagePainter extends CustomPainter { void paint(Canvas canvas, Size size) { if (image == null) return; if (x.isNaN || y.isNaN) return; - canvas.scale(scale, scale); // https://github.com/flutter/flutter/issues/76187#issuecomment-784628161 // https://api.flutter-io.cn/flutter/dart-ui/FilterQuality.html var paint = Paint(); if ((scale - 1.0).abs() > 0.001) { + canvas.scale(scale, scale); paint.filterQuality = FilterQuality.medium; if (scale > 10.00000) { paint.filterQuality = FilterQuality.high; From 44e45082ba94812cdb22aef3038a16ba4e9464af Mon Sep 17 00:00:00 2001 From: RustDesk <71636191+rustdesk@users.noreply.github.com> Date: Fri, 18 Nov 2022 23:13:14 +0800 Subject: [PATCH 078/116] Revert "trivial changes" --- flutter/lib/desktop/pages/remote_page.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index c1837cb21..84ea36d78 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -561,11 +561,11 @@ class ImagePainter extends CustomPainter { void paint(Canvas canvas, Size size) { if (image == null) return; if (x.isNaN || y.isNaN) return; + canvas.scale(scale, scale); // https://github.com/flutter/flutter/issues/76187#issuecomment-784628161 // https://api.flutter-io.cn/flutter/dart-ui/FilterQuality.html var paint = Paint(); if ((scale - 1.0).abs() > 0.001) { - canvas.scale(scale, scale); paint.filterQuality = FilterQuality.medium; if (scale > 10.00000) { paint.filterQuality = FilterQuality.high; From eb673c8c78738f0091ffe9ff65ceec056efb1064 Mon Sep 17 00:00:00 2001 From: 21pages Date: Sat, 19 Nov 2022 10:57:17 +0800 Subject: [PATCH 079/116] portable-service: enable quick_support by rename as xxxqs.exe Signed-off-by: 21pages --- .github/workflows/flutter-nightly.yml | 9 +++--- Cargo.toml | 1 - build.py | 7 ----- .../lib/desktop/pages/connection_page.dart | 9 ++++-- libs/portable/src/main.rs | 5 +++- src/core_main.rs | 16 +++++++++-- src/flutter_ffi.rs | 1 + src/server/portable_service.rs | 28 +++++++++++++------ src/ui.rs | 19 +------------ 9 files changed, 49 insertions(+), 46 deletions(-) diff --git a/.github/workflows/flutter-nightly.yml b/.github/workflows/flutter-nightly.yml index 074eafe08..f2391e77e 100644 --- a/.github/workflows/flutter-nightly.yml +++ b/.github/workflows/flutter-nightly.yml @@ -15,7 +15,7 @@ env: jobs: build-for-windows: - name: ${{ matrix.job.target }} (${{ matrix.job.os }}) ${{ matrix.job.suffix }} + name: ${{ matrix.job.target }} (${{ matrix.job.os }}) runs-on: ${{ matrix.job.os }} strategy: fail-fast: false @@ -23,8 +23,7 @@ jobs: job: # - { target: i686-pc-windows-msvc , os: windows-2019 } # - { target: x86_64-pc-windows-gnu , os: windows-2019 } - - { target: x86_64-pc-windows-msvc , os: windows-2019, suffix: "" , extra-build-args: "" } - - { target: x86_64-pc-windows-msvc , os: windows-2019, suffix: "-qs", extra-build-args: "--quick_start" } + - { target: x86_64-pc-windows-msvc , os: windows-2019 } steps: - name: Checkout source code uses: actions/checkout@v3 @@ -84,13 +83,13 @@ jobs: shell: bash - name: Build rustdesk - run: python3 .\build.py --portable --hwcodec --flutter ${{ matrix.job.extra-build-args }} + run: python3 .\build.py --portable --hwcodec --flutter - name: Rename rustdesk shell: bash run: | for name in rustdesk*??-install.exe; do - mv "$name" "${name%%-install.exe}-${{ matrix.job.target }}${{ matrix.job.suffix }}.exe" + mv "$name" "${name%%-install.exe}-${{ matrix.job.target }}.exe" done - name: Publish Release diff --git a/Cargo.toml b/Cargo.toml index 44df74952..836bd07d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,6 @@ flutter = ["flutter_rust_bridge"] default = ["use_dasp"] hwcodec = ["scrap/hwcodec"] mediacodec = ["scrap/mediacodec"] -quick_start = [] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/build.py b/build.py index a887ff070..c907334ce 100755 --- a/build.py +++ b/build.py @@ -81,11 +81,6 @@ def make_parser(): action='store_true', help='Build windows portable' ) - parser.add_argument( - '--quick_start', - action='store_true', - help='Windows quick start portable' - ) parser.add_argument( '--flatpak', action='store_true', @@ -194,8 +189,6 @@ def get_features(args): features = ['inline'] if windows: features.extend(get_rc_features(args)) - if args.quick_start: - features.append('quick_start') if args.hwcodec: features.append('hwcodec') if args.flutter: diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index f73c6b0da..671335bfd 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -90,12 +90,15 @@ class _ConnectionPageState extends State Get.forceAppUpdate(); } isWindowMinisized = false; - } else if (eventName == 'close') { - // called more then one time - bind.mainOnMainWindowClose(); } } + @override + void onWindowClose() { + super.onWindowClose(); + bind.mainOnMainWindowClose(); + } + @override Widget build(BuildContext context) { return Column( diff --git a/libs/portable/src/main.rs b/libs/portable/src/main.rs index ad05e7376..edcbdd1fd 100644 --- a/libs/portable/src/main.rs +++ b/libs/portable/src/main.rs @@ -64,6 +64,7 @@ fn main() { i += 1; } let click_setup = args.is_empty() && arg_exe.to_lowercase().ends_with("install.exe"); + let quick_support = args.is_empty() && arg_exe.to_lowercase().ends_with("qs.exe"); let reader = BinaryReader::default(); if let Some(exe) = setup( @@ -72,7 +73,9 @@ fn main() { click_setup || args.contains(&"--silent-install".to_owned()), ) { if click_setup { - args = vec!["--install".to_owned()] + args = vec!["--install".to_owned()]; + } else if quick_support { + args = vec!["--quick_support".to_owned()]; } execute(exe, args); } diff --git a/src/core_main.rs b/src/core_main.rs index bd9680ffb..95331a184 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -14,6 +14,7 @@ pub fn core_main() -> Option> { let mut i = 0; let mut _is_elevate = false; let mut _is_run_as_system = false; + let mut _is_quick_support = false; let mut _is_flutter_connect = false; let mut arg_exe = Default::default(); for arg in std::env::args() { @@ -29,6 +30,8 @@ pub fn core_main() -> Option> { _is_elevate = true; } else if arg == "--run-as-system" { _is_run_as_system = true; + } else if arg == "--quick_support" { + _is_quick_support = true; } else { args.push(arg); } @@ -40,6 +43,11 @@ pub fn core_main() -> Option> { return core_main_invoke_new_connection(std::env::args()); } let click_setup = cfg!(windows) && args.is_empty() && crate::common::is_setup(&arg_exe); + #[cfg(not(feature = "flutter"))] + { + _is_quick_support = + cfg!(windows) && args.is_empty() && arg_exe.to_lowercase().ends_with("qs.exe"); + } if click_setup { args.push("--install".to_owned()); flutter_args.push("--install".to_string()); @@ -81,8 +89,12 @@ pub fn core_main() -> Option> { } } #[cfg(windows)] - #[cfg(feature = "quick_start")] - if !crate::platform::is_installed() && args.is_empty() && !_is_elevate && !_is_run_as_system { + if !crate::platform::is_installed() + && args.is_empty() + && _is_quick_support + && !_is_elevate + && !_is_run_as_system + { if let Err(e) = crate::portable_service::client::start_portable_service() { log::error!("Failed to start portable service:{:?}", e); } diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index b947fad47..36e38f86e 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -1178,6 +1178,7 @@ pub fn main_account_auth_result() -> String { } pub fn main_on_main_window_close() { + // may called more than one times #[cfg(windows)] crate::portable_service::client::drop_portable_service_shared_memory(); } diff --git a/src/server/portable_service.rs b/src/server/portable_service.rs index 861b04b3d..ace70e1bd 100644 --- a/src/server/portable_service.rs +++ b/src/server/portable_service.rs @@ -237,11 +237,10 @@ pub mod server { fn run_exit_check() { loop { if EXIT.lock().unwrap().clone() { - std::thread::sleep(Duration::from_secs(1)); - log::info!("exit from seperate check thread"); + std::thread::sleep(Duration::from_millis(50)); std::process::exit(0); } - std::thread::sleep(Duration::from_secs(1)); + std::thread::sleep(Duration::from_millis(50)); } } @@ -406,9 +405,8 @@ pub mod server { Pong => { nack = 0; } - ConnCount(Some(_n)) => { - #[cfg(not(feature = "quick_start"))] - if _n == 0 { + ConnCount(Some(n)) => { + if n == 0 { log::info!("Connnection count equals 0, exit"); stream.send(&Data::DataPortableService(WillClose)).await.ok(); break; @@ -436,7 +434,6 @@ pub mod server { break; } stream.send(&Data::DataPortableService(Ping)).await.ok(); - #[cfg(not(feature = "quick_start"))] stream.send(&Data::DataPortableService(ConnCount(None))).await.ok(); } } @@ -626,6 +623,17 @@ pub mod client { use DataPortableService::*; let rx = Arc::new(tokio::sync::Mutex::new(rx)); let postfix = IPC_PROFIX; + #[cfg(feature = "flutter")] + let quick_support = { + let args: Vec<_> = std::env::args().collect(); + args.contains(&"--quick_support".to_string()) + }; + #[cfg(not(feature = "flutter"))] + let quick_support = std::env::current_exe() + .unwrap_or("".into()) + .to_string_lossy() + .to_lowercase() + .ends_with("qs.exe"); match new_listener(postfix).await { Ok(mut incoming) => loop { @@ -663,8 +671,10 @@ pub mod client { *PORTABLE_SERVICE_RUNNING.lock().unwrap() = true; }, ConnCount(None) => { - let cnt = crate::server::CONN_COUNT.lock().unwrap().clone(); - stream.send(&Data::DataPortableService(ConnCount(Some(cnt)))).await.ok(); + if !quick_support { + let cnt = crate::server::CONN_COUNT.lock().unwrap().clone(); + stream.send(&Data::DataPortableService(ConnCount(Some(cnt)))).await.ok(); + } }, WillClose => { log::info!("portable service will close"); diff --git a/src/ui.rs b/src/ui.rs index 2d7f8d70a..991832627 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -15,7 +15,7 @@ use hbb_common::{ protobuf::Message as _, rendezvous_proto::*, tcp::FramedStream, - tokio::{self, sync::mpsc}, + tokio, }; use crate::common::get_app_name; @@ -44,23 +44,6 @@ lazy_static::lazy_static! { struct UIHostHandler; -// to-do: dead code? -fn check_connect_status( - reconnect: bool, -) -> ( - Arc>, - Arc>>, - mpsc::UnboundedSender, - Arc>, -) { - let status = Arc::new(Mutex::new((0, false, 0, "".to_owned()))); - let options = Arc::new(Mutex::new(Config::get_options())); - let (tx, rx) = mpsc::unbounded_channel::(); - let password = Arc::new(Mutex::new(String::default())); - std::thread::spawn(move || crate::ui_interface::check_connect_status_(reconnect, rx)); - (status, options, tx, password) -} - pub fn start(args: &mut [String]) { #[cfg(target_os = "macos")] if args.len() == 1 && args[0] == "--server" { From 9a9d0117e25018ef23e8041fc6666d053eb5e75a Mon Sep 17 00:00:00 2001 From: Kingtous Date: Sat, 19 Nov 2022 16:14:56 +0800 Subject: [PATCH 080/116] opt: reduce white screen flickering on sub window --- flutter/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index e76855f62..a05898468 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -63,7 +63,7 @@ dependencies: desktop_multi_window: git: url: https://github.com/Kingtous/rustdesk_desktop_multi_window - ref: 9b4c5ac1aec2c4d1bdabb4dd29e4bc3b75c76a79 + ref: 8ee8eb59cabf6ac83a13fe002de7d4a231263a58 freezed_annotation: ^2.0.3 tray_manager: git: From 2ccf9726da426ca6b3464f81fd01299b119eea32 Mon Sep 17 00:00:00 2001 From: neoGalaxy88 Date: Sat, 19 Nov 2022 11:23:34 +0100 Subject: [PATCH 081/116] Update it.rs --- 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 469a9c5ae..61f289ad6 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -352,7 +352,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Apply", "Applica"), ("Disconnect all devices?", "Disconnettere tutti i dispositivi?"), ("Clear", "Ripulisci"), - ("Audio Input Device", "Dispositivo di inpit audio"), + ("Audio Input Device", "Dispositivo di input audio"), ("Deny remote access", "Nega accesso remoto"), ("Use IP Whitelisting", "Utilizza la whitelist di IP"), ("Network", "Rete"), From 6d0039b104c3e35c52839500200d326a9dd9d9dc Mon Sep 17 00:00:00 2001 From: Kingtous Date: Sat, 19 Nov 2022 20:06:17 +0800 Subject: [PATCH 082/116] opt: stop show tray icon in root mode --- src/core_main.rs | 10 ++++++++-- src/tray.rs | 7 +++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/core_main.rs b/src/core_main.rs index 1f13172dd..13a2ef91c 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -188,8 +188,14 @@ pub fn core_main() -> Option> { #[cfg(target_os = "linux")] { let handler = std::thread::spawn(move || crate::start_server(true)); - crate::tray::start_tray(); - // revent server exit when encountering errors from tray + // Show the tray in linux only when current user is a normal user + // [Note] + // As for GNOME, the tray cannot be shown in user's status bar. + // As for KDE, the tray can be shown without user's theme. + if !crate::platform::is_root() { + crate::tray::start_tray(); + } + // prevent server exit when encountering errors from tray hbb_common::allow_err!(handler.join()); } } else if args[0] == "--import-config" { diff --git a/src/tray.rs b/src/tray.rs index 5064d96dc..3658739a4 100644 --- a/src/tray.rs +++ b/src/tray.rs @@ -150,6 +150,13 @@ fn get_default_app_indicator() -> Option { match std::fs::File::create(icon_path.clone()) { Ok(mut f) => { f.write_all(icon).unwrap(); + // set .png icon file to be writable + // this ensures successful file rewrite when switching between x11 and wayland. + let mut perm = f.metadata().unwrap().permissions(); + if perm.readonly() { + perm.set_readonly(false); + f.set_permissions(perm).unwrap(); + } } Err(err) => { error!("Error when writing icon to {:?}: {}", icon_path, err); From 05c549a5fea36ba7786e530872b1fe059b2eb3ec Mon Sep 17 00:00:00 2001 From: 21pages Date: Sun, 20 Nov 2022 15:53:08 +0800 Subject: [PATCH 083/116] approve mode, cm sync option Signed-off-by: 21pages --- .../desktop/pages/desktop_setting_page.dart | 70 ++++++++++++++----- .../lib/desktop/pages/remote_tab_page.dart | 1 - flutter/lib/desktop/pages/server_page.dart | 21 ++++-- flutter/lib/models/model.dart | 3 + flutter/lib/models/server_model.dart | 27 +++++-- src/client.rs | 15 ++-- src/core_main.rs | 1 + src/flutter_ffi.rs | 2 +- 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/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/pl.rs | 4 ++ src/lang/pt_PT.rs | 4 ++ src/lang/ptbr.rs | 4 ++ src/lang/ru.rs | 4 ++ src/lang/sk.rs | 4 ++ src/lang/template.rs | 4 ++ src/lang/tr.rs | 4 ++ src/lang/tw.rs | 4 ++ src/lang/ua.rs | 4 ++ src/lang/vn.rs | 4 ++ src/server/connection.rs | 8 +++ src/ui/cm.rs | 5 ++ src/ui/cm.tis | 21 +++++- src/ui/common.tis | 7 ++ src/ui/index.tis | 64 +++++++++++++---- src/ui_interface.rs | 9 ++- 39 files changed, 298 insertions(+), 56 deletions(-) diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index c03371a64..64ebc712e 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -580,20 +580,21 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { return ChangeNotifierProvider.value( value: gFFI.serverModel, child: Consumer(builder: ((context, model, child) { - List keys = [ + List passwordKeys = [ kUseTemporaryPassword, kUsePermanentPassword, kUseBothPasswords, ]; - List values = [ + List passwordValues = [ translate('Use temporary password'), translate('Use permanent password'), translate('Use both passwords'), ]; bool tmpEnabled = model.verificationMethod != kUsePermanentPassword; bool permEnabled = model.verificationMethod != kUseTemporaryPassword; - String currentValue = values[keys.indexOf(model.verificationMethod)]; - List radios = values + String currentValue = + passwordValues[passwordKeys.indexOf(model.verificationMethod)]; + List radios = passwordValues .map((value) => _Radio( context, value: value, @@ -601,8 +602,8 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { label: value, onChanged: ((value) { () async { - await model - .setVerificationMethod(keys[values.indexOf(value)]); + await model.setVerificationMethod( + passwordKeys[passwordValues.indexOf(value)]); await model.updatePasswordModel(); }(); }), @@ -640,20 +641,51 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { )) .toList(); + final modeKeys = ['password', 'click', '']; + final modeValues = [ + translate('Accept sessions via password'), + translate('Accept sessions via click'), + translate('Accept sessions via both'), + ]; + var modeInitialKey = model.approveMode; + if (!modeKeys.contains(modeInitialKey)) modeInitialKey = ''; + final usePassword = model.approveMode != 'click'; + return _Card(title: 'Password', children: [ - radios[0], - _SubLabeledWidget( - 'Temporary Password Length', - Row( - children: [ - ...lengthRadios, - ], - ), - enabled: tmpEnabled && !locked), - radios[1], - _SubButton('Set permanent password', setPasswordDialog, - permEnabled && !locked), - radios[2], + _ComboBox( + keys: modeKeys, + values: modeValues, + initialKey: modeInitialKey, + onChanged: (key) => model.setApproveMode(key), + ).marginOnly(left: _kContentHMargin), + Offstage( + offstage: !usePassword, + child: radios[0], + ), + Offstage( + offstage: !usePassword, + child: _SubLabeledWidget( + 'Temporary Password Length', + Row( + children: [ + ...lengthRadios, + ], + ), + enabled: tmpEnabled && !locked), + ), + Offstage( + offstage: !usePassword, + child: radios[1], + ), + Offstage( + offstage: !usePassword, + child: _SubButton('Set permanent password', setPasswordDialog, + permEnabled && !locked), + ), + Offstage( + offstage: !usePassword, + child: radios[2], + ), ]); }))); } diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index df8256496..1e942272c 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -84,7 +84,6 @@ class _ConnectionTabPageState extends State { if (call.method == "new_remote_desktop") { final args = jsonDecode(call.arguments); final id = args['id']; - ConnectionTypeState.init(id); window_on_top(windowId()); ConnectionTypeState.init(id); tabController.add(TabInfo( diff --git a/flutter/lib/desktop/pages/server_page.dart b/flutter/lib/desktop/pages/server_page.dart index 16abe0b64..ae69497bc 100644 --- a/flutter/lib/desktop/pages/server_page.dart +++ b/flutter/lib/desktop/pages/server_page.dart @@ -555,11 +555,12 @@ class _CmControlPanel extends StatelessWidget { final bool canElevate = bind.cmCanElevate(); final model = Provider.of(context); final showElevation = canElevate && model.showElevation; + final showAccept = model.approveMode != 'password'; return Column( mainAxisAlignment: MainAxisAlignment.end, children: [ Offstage( - offstage: !showElevation, + offstage: !showElevation || !showAccept, child: buildButton(context, color: Colors.green[700], onClick: () { handleAccept(context); handleElevate(context); @@ -575,11 +576,17 @@ class _CmControlPanel extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Expanded( - child: buildButton(context, color: MyTheme.accent, onClick: () { - handleAccept(context); - windowManager.minimize(); - }, text: 'Accept', textColor: Colors.white)), + if (showAccept) + Expanded( + child: Column( + children: [ + buildButton(context, color: MyTheme.accent, onClick: () { + handleAccept(context); + windowManager.minimize(); + }, text: 'Accept', textColor: Colors.white), + ], + ), + ), Expanded( child: buildButton(context, color: Colors.transparent, @@ -621,7 +628,7 @@ class _CmControlPanel extends StatelessWidget { ); } return Container( - height: 35, + height: 30, decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular(4), border: border), child: InkWell( diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index cae4485cb..a7cd7a11c 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -255,6 +255,9 @@ class FfiModel with ChangeNotifier { } else if (type == 'restarting') { showMsgBox(id, type, title, text, link, false, dialogManager, hasCancel: false); + } else if (type == 'wait-remote-accept-nook') { + msgBoxCommon(dialogManager, title, Text(translate(text)), + [msgBoxButton("Cancel", closeConnection)]); } else { var hasRetry = evt['hasRetry'] == 'true'; showMsgBox(id, type, title, text, link, hasRetry, dialogManager); diff --git a/flutter/lib/models/server_model.dart b/flutter/lib/models/server_model.dart index 1c0d1cbdd..a00630b22 100644 --- a/flutter/lib/models/server_model.dart +++ b/flutter/lib/models/server_model.dart @@ -31,6 +31,7 @@ class ServerModel with ChangeNotifier { int _connectStatus = 0; // Rendezvous Server status String _verificationMethod = ""; String _temporaryPasswordLength = ""; + String _approveMode = ""; late String _emptyIdShow; late final IDTextEditingController _serverId; @@ -68,6 +69,8 @@ class ServerModel with ChangeNotifier { return _verificationMethod; } + String get approveMode => _approveMode; + setVerificationMethod(String method) async { await bind.mainSetOption(key: "verification-method", value: method); } @@ -84,6 +87,10 @@ class ServerModel with ChangeNotifier { await bind.mainSetOption(key: "temporary-password-length", value: length); } + setApproveMode(String mode) async { + await bind.mainSetOption(key: 'approve-mode', value: mode); + } + TextEditingController get serverId => _serverId; TextEditingController get serverPasswd => _serverPasswd; @@ -98,8 +105,7 @@ class ServerModel with ChangeNotifier { _emptyIdShow = translate("Generating ..."); _serverId = IDTextEditingController(text: _emptyIdShow); - Timer.periodic(Duration(seconds: 1), (timer) async { - if (isTest) return timer.cancel(); + timerCallback() async { var status = await bind.mainGetOnlineStatue(); if (status > 0) { status = 1; @@ -115,7 +121,14 @@ class ServerModel with ChangeNotifier { } updatePasswordModel(); - }); + } + + if (!isTest) { + Future.delayed(Duration.zero, timerCallback); + Timer.periodic(Duration(milliseconds: 500), (timer) async { + await timerCallback(); + }); + } } /// 1. check android permission @@ -151,11 +164,17 @@ class ServerModel with ChangeNotifier { await bind.mainGetOption(key: "verification-method"); final temporaryPasswordLength = await bind.mainGetOption(key: "temporary-password-length"); + final approveMode = await bind.mainGetOption(key: 'approve-mode'); + if (_approveMode != approveMode) { + _approveMode = approveMode; + update = true; + } final oldPwdText = _serverPasswd.text; if (_serverPasswd.text != temporaryPassword) { _serverPasswd.text = temporaryPassword; } - if (verificationMethod == kUsePermanentPassword) { + if (verificationMethod == kUsePermanentPassword || + _approveMode == 'click') { _serverPasswd.text = '-'; } if (oldPwdText != _serverPasswd.text) { diff --git a/src/client.rs b/src/client.rs index c98561967..672a35693 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1337,6 +1337,15 @@ impl LoginConfigHandler { self.password = Default::default(); interface.msgbox("re-input-password", err, "Do you want to enter again?", ""); true + } else if err == "No Password Access" { + self.password = Default::default(); + interface.msgbox( + "wait-remote-accept-nook", + "Prompt", + "Please wait for the remote side to accept your session request...", + "", + ); + true } else { if err.contains(SCRAP_X11_REQUIRED) { interface.msgbox("error", "Login Error", err, SCRAP_X11_REF_URL); @@ -1434,11 +1443,7 @@ impl LoginConfigHandler { username: self.id.clone(), password: password.into(), my_id, - my_name: if cfg!(windows) { - crate::platform::get_active_username() - } else { - crate::username() - }, + my_name: crate::username(), option: self.get_option_message(true).into(), session_id: self.session_id, version: crate::VERSION.to_string(), diff --git a/src/core_main.rs b/src/core_main.rs index 13a2ef91c..f890a9525 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -226,6 +226,7 @@ pub fn core_main() -> Option> { // meanwhile, return true to call flutter window to show control panel #[cfg(feature = "flutter")] crate::flutter::connection_manager::start_listen_ipc_thread(); + crate::ui_interface::start_option_status_sync(); } } //_async_logger_holder.map(|x| x.flush()); diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 36e38f86e..928bca26b 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -562,7 +562,7 @@ pub fn main_get_connect_status() -> String { pub fn main_check_connect_status() { #[cfg(not(any(target_os = "android", target_os = "ios")))] - check_mouse_time(); // avoid multi calls + start_option_status_sync(); // avoid multi calls } pub fn main_is_using_public_server() -> bool { diff --git a/src/lang/ca.rs b/src/lang/ca.rs index 1958b5b94..a70fce1c9 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -389,5 +389,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", "Aquest PC"), ("or", "o"), ("Continue with", "Continuar amb"), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 16bbdb590..4588a148f 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", "使用"), ("Elevate", "提权"), ("Zoom cursor", "缩放鼠标"), + ("Accept sessions via password", "只允许密码访问"), + ("Accept sessions via click", "只允许点击访问"), + ("Accept sessions via both", "允许密码或点击访问"), + ("Please wait for the remote side to accept your session request...", "请等待对方接受你的连接..."), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 0f262cd25..46817bbc4 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index c7362e26f..6678e734a 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index acc22a461..28d220933 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 206229859..2fc63ecc2 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index ca866641a..4e04fa2a0 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", "Continuar con"), ("Elevate", "Elevar"), ("Zoom cursor", "Ampliar cursor"), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index b602bd404..040dcf204 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -389,5 +389,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", "یا"), ("Continue with", "ادامه با"), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index f4ff46cdf..926ad26fc 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", "Continuer avec"), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index aaad2e9f9..2cdb56b9b 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", "Folytatás a következővel"), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 96e7d38f4..65d447021 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 61f289ad6..58d493785 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", "Continua con"), ("Elevate", "Eleva"), ("Zoom cursor", "Cursore zoom"), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 1ff301bba..c0e6b667d 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index aa6c01e3d..3f0e10645 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 05055d1a3..a2d6a6dce 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index c62007778..d440b06f1 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", "Kontynuuj z"), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index ca0fcead9..71d3ffb53 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index 41459404b..8a213d51c 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", "Continuar com"), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 4920c2826..db0209fa8 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", "Продолжить с"), ("Elevate", "Повысить"), ("Zoom cursor", "Масштабировать курсор"), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 0844c8442..6d4a9d382 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index 9f1779119..22bf2ac23 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index 6f3c9ba92..bd439676e 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", "bununla devam et"), ("Elevate", "Yükseltme"), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index 900f25ccd..ff544c1d8 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", "提權"), ("Zoom cursor", ""), + ("Accept sessions via password", "只允許密碼訪問"), + ("Accept sessions via click", "只允許點擊訪問"), + ("Accept sessions via both", "允許密碼或點擊訪問"), + ("Please wait for the remote side to accept your session request...", "請等待對方接受你的連接..."), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index b336b1e36..d7efe411b 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index c21fe8aa8..96ff195b9 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/server/connection.rs b/src/server/connection.rs index cb2ddc2c6..f49e293a2 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -1046,6 +1046,14 @@ impl Connection { } if !crate::is_ip(&lr.username) && lr.username != Config::get_id() { self.send_login_error("Offline").await; + } else if Config::get_option("approve-mode") == "click" { + self.try_start_cm(lr.my_id, lr.my_name, false); + if hbb_common::get_version_number(&lr.version) + >= hbb_common::get_version_number("1.2.0") + { + self.send_login_error("No Password Access").await; + } + return true; } else if self.is_of_recent_session() { self.try_start_cm(lr.my_id, lr.my_name, true); self.send_logon_response().await; diff --git a/src/ui/cm.rs b/src/ui/cm.rs index 7c0e3fe24..2bd8824db 100644 --- a/src/ui/cm.rs +++ b/src/ui/cm.rs @@ -135,6 +135,10 @@ impl SciterConnectionManager { fn elevate_portable(&self, id: i32) { crate::ui_cm_interface::elevate_portable(id); } + + fn get_option(&self, key: String) -> String { + crate::ui_interface::get_option(key) + } } impl sciter::EventHandler for SciterConnectionManager { @@ -155,5 +159,6 @@ impl sciter::EventHandler for SciterConnectionManager { fn send_msg(i32, String); fn can_elevate(); fn elevate_portable(i32); + fn get_option(String); } } diff --git a/src/ui/cm.tis b/src/ui/cm.tis index 035b58650..4ecbe706c 100644 --- a/src/ui/cm.tis +++ b/src/ui/cm.tis @@ -30,6 +30,7 @@ class Body: Reactor.Component var right_style = show_chat ? "" : "display: none"; var disconnected = c.disconnected; var show_elevation_btn = handler.can_elevate() && show_elevation; + var show_accept_btn = handler.get_option('approve-mode') != 'password'; // below size:* is work around for Linux, it alreayd set in css, but not work, shit sciter return

@@ -58,16 +59,15 @@ class Body: Reactor.Component {c.port_forward ?
Port Forwarding: {c.port_forward}
: ""}
- {!auth && !disconnected && show_elevation_btn ? : "" } + {!auth && !disconnected && show_elevation_btn && show_accept_btn ? : "" } {auth && !disconnected && show_elevation_btn ? : "" }
- {!auth ? : "" } + {!auth && show_accept_btn ? : "" } {!auth ? : "" }
{auth && !disconnected ? : "" } {auth && disconnected ? : "" }
-
{c.is_file_transfer || c.port_forward ? "" :
{svg_chat}
}
@@ -453,6 +453,21 @@ function getElaspsed(time, now) { return out; } +var ui_status_cache = [""]; +function check_update_ui() { + self.timer(1s, function() { + var approve_mode = handler.get_option('approve-mode'); + var changed = false; + if (ui_status_cache[0] != approve_mode) { + ui_status_cache[0] = approve_mode; + changed = true; + } + if (changed) update(); + check_update_ui(); + }); +} +check_update_ui(); + function updateTime() { self.timer(1s, function() { var now = new Date(); diff --git a/src/ui/common.tis b/src/ui/common.tis index 7507d4895..b6723b131 100644 --- a/src/ui/common.tis +++ b/src/ui/common.tis @@ -264,6 +264,13 @@ function msgbox(type, title, content, link="", callback=null, height=180, width= }; } else if (type.indexOf("custom") < 0 && !is_port_forward && !callback) { callback = function() { view.close(); } + } else if (type == 'wait-remote-accept-nook') { + callback = function (res) { + if (!res) { + view.close(); + return; + } + }; } last_msgbox_tag = type + "-" + title + "-" + content + "-" + link; $(#msgbox).content(); diff --git a/src/ui/index.tis b/src/ui/index.tis index 31781c35e..840198896 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -824,7 +824,8 @@ function watch_screen_recording() { class PasswordEyeArea : Reactor.Component { render() { var method = handler.get_option('verification-method'); - var value = method != 'use-permanent-password' ? password_cache[0] : "-"; + var mode= handler.get_option('approve-mode'); + var value = mode == 'click' || method == 'use-permanent-password' ? "-" : password_cache[0]; return
@@ -901,27 +902,46 @@ class PasswordArea: Reactor.Component { function renderPop() { var method = handler.get_option('verification-method'); + var approve_mode= handler.get_option('approve-mode'); + var show_password = approve_mode != 'click'; return -
  • {svg_checkmark}{translate('Use temporary password')}
  • -
  • {svg_checkmark}{translate('Use permanent password')}
  • -
  • {svg_checkmark}{translate('Use both passwords')}
  • -
    -
  • {translate('Set permanent password')}
  • - +
  • {svg_checkmark}{translate('Accept sessions via password')}
  • +
  • {svg_checkmark}{translate('Accept sessions via click')}
  • +
  • {svg_checkmark}{translate('Accept sessions via both')}
  • + { !show_password ? '' :
    } + { !show_password ? '' :
  • {svg_checkmark}{translate('Use temporary password')}
  • } + { !show_password ? '' :
  • {svg_checkmark}{translate('Use permanent password')}
  • } + { !show_password ? '' :
  • {svg_checkmark}{translate('Use both passwords')}
  • } + { !show_password ? '' :
    } + { !show_password ? '' :
  • {translate('Set permanent password')}
  • } + { !show_password ? '' : } ; } function toggleMenuState() { - var id = handler.get_option('verification-method'); - if (id != 'use-temporary-password' && id != 'use-permanent-password') - id = 'use-both-passwords'; - for (var el in [this.$(li#use-temporary-password), this.$(li#use-permanent-password), this.$(li#use-both-passwords)]) { - el.attributes.toggleClass("selected", el.id == id); + var mode= handler.get_option('approve-mode'); + var mode_id; + if (mode == 'password') + mode_id = 'approve-mode-password'; + else if (mode == 'click') + mode_id = 'approve-mode-click'; + else + mode_id = 'approve-mode-both'; + var pwd_id = handler.get_option('verification-method'); + if (pwd_id != 'use-temporary-password' && pwd_id != 'use-permanent-password') + pwd_id = 'use-both-passwords'; + for (var el in this.$$(menu#edit-password-context>li)) { + if (el.id.indexOf("approve-mode-") == 0) + el.attributes.toggleClass("selected", el.id == mode_id); + if (el.id.indexOf("use-") == 0) + el.attributes.toggleClass("selected", el.id == pwd_id); } } event click $(svg#edit) (_, me) { - temporaryPasswordLengthMenu.update({show: true }); + var approve_mode= handler.get_option('approve-mode'); + var show_password = approve_mode != 'click'; + if(show_password && temporaryPasswordLengthMenu) temporaryPasswordLengthMenu.update({show: true }); var menu = $(menu#edit-password-context); me.popup(menu); } @@ -954,16 +974,28 @@ class PasswordArea: Reactor.Component { handler.set_option('verification-method', me.id); this.toggleMenuState(); passwordArea.update(); + } else if (me.id.indexOf('approve-mode') == 0) { + var approve_mode; + if (me.id == 'approve-mode-password') + approve_mode = 'password'; + else if (me.id == 'approve-mode-click') + approve_mode = 'click'; + else + approve_mode = ''; + handler.set_option('approve-mode', approve_mode); + this.toggleMenuState(); + passwordArea.update(); } } } -var password_cache = ["","",""]; +var password_cache = ["","","",""]; function updatePasswordArea() { self.timer(1s, function() { var temporary_password = handler.temporary_password(); var verification_method = handler.get_option('verification-method'); var temporary_password_length = handler.get_option('temporary-password-length'); + var approve_mode = handler.get_option('approve-mode'); var update = false; if (password_cache[0] != temporary_password) { password_cache[0] = temporary_password; @@ -977,6 +1009,10 @@ function updatePasswordArea() { password_cache[2] = temporary_password_length; update = true; } + if (password_cache[3] != approve_mode) { + password_cache[3] = approve_mode; + update = true; + } if (update) passwordArea.update(); updatePasswordArea(); }); diff --git a/src/ui_interface.rs b/src/ui_interface.rs index 0e443ad61..e1dc3005e 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -874,7 +874,12 @@ pub fn check_zombie(children: Children) { } } -pub(crate) fn check_connect_status(reconnect: bool) -> mpsc::UnboundedSender { +pub fn start_option_status_sync() { + let _sender = SENDER.lock().unwrap(); +} + +// not call directly +fn check_connect_status(reconnect: bool) -> mpsc::UnboundedSender { let (tx, rx) = mpsc::unbounded_channel::(); std::thread::spawn(move || check_connect_status_(reconnect, rx)); tx @@ -898,7 +903,7 @@ pub fn account_auth_result() -> String { // notice: avoiding create ipc connecton repeatly, // because windows named pipe has serious memory leak issue. #[tokio::main(flavor = "current_thread")] -pub(crate) async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver) { +async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver) { let mut key_confirmed = false; let mut rx = rx; let mut mouse_time = 0; From 2952f151a006c51bf7120f7769c80b8813ead1ed Mon Sep 17 00:00:00 2001 From: rustdesk Date: Sun, 20 Nov 2022 21:10:40 +0800 Subject: [PATCH 084/116] modify copyright in mac --- flutter/macos/Runner/Configs/AppInfo.xcconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/macos/Runner/Configs/AppInfo.xcconfig b/flutter/macos/Runner/Configs/AppInfo.xcconfig index bf05a4caa..389ae0a70 100644 --- a/flutter/macos/Runner/Configs/AppInfo.xcconfig +++ b/flutter/macos/Runner/Configs/AppInfo.xcconfig @@ -11,4 +11,4 @@ PRODUCT_NAME = rustdesk PRODUCT_BUNDLE_IDENTIFIER = com.carriez.flutterHbb // The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2022 com.carriez. All rights reserved. +PRODUCT_COPYRIGHT = Copyright © 2022 Purslane Ltd. All rights reserved. From 13fd55557be8a0f68dcdd0ed2f31d009ae4e7fb0 Mon Sep 17 00:00:00 2001 From: xxrl <837951112@qq.com> Date: Sun, 20 Nov 2022 22:46:27 +0800 Subject: [PATCH 085/116] feat: support track pad scroll on flutter --- flutter/lib/common/widgets/remote_input.dart | 3 ++ flutter/lib/models/input_model.dart | 57 ++++++++++++++++++++ src/client.rs | 11 ++-- src/flutter_ffi.rs | 2 + src/server/input_service.rs | 2 +- 5 files changed, 71 insertions(+), 4 deletions(-) diff --git a/flutter/lib/common/widgets/remote_input.dart b/flutter/lib/common/widgets/remote_input.dart index ad50d4839..89443e14f 100644 --- a/flutter/lib/common/widgets/remote_input.dart +++ b/flutter/lib/common/widgets/remote_input.dart @@ -51,6 +51,9 @@ class RawPointerMouseRegion extends StatelessWidget { onPointerUp: inputModel.onPointUpImage, onPointerMove: inputModel.onPointMoveImage, onPointerSignal: inputModel.onPointerSignalImage, + onPointerPanZoomStart: inputModel.onPointerPanZoomStart, + onPointerPanZoomUpdate: inputModel.onPointerPanZoomUpdate, + onPointerPanZoomEnd: inputModel.onPointerPanZoomEnd, child: MouseRegion( cursor: cursor ?? MouseCursor.defer, onEnter: onEnter, diff --git a/flutter/lib/models/input_model.dart b/flutter/lib/models/input_model.dart index 83171514d..eb1b4a3ff 100644 --- a/flutter/lib/models/input_model.dart +++ b/flutter/lib/models/input_model.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:convert'; import 'dart:math'; import 'dart:ui' as ui; @@ -39,6 +40,10 @@ class InputModel { var alt = false; var command = false; + // trackpad + var trackpadScrollDistance = Offset.zero; + Timer? _flingTimer; + // mouse final isPhysicalMouse = false.obs; int _lastMouseDownButtons = 0; @@ -236,6 +241,7 @@ class InputModel { if (!enter) { resetModifiers(); } + _flingTimer?.cancel(); bind.sessionEnterOrLeave(id: id, enter: enter); } @@ -258,6 +264,57 @@ class InputModel { } } + int _signOrZero(num x) { + if (x == 0) { + return 0; + } else { + return x > 0 ? 1 : -1; + } + } + + void onPointerPanZoomStart(PointerPanZoomStartEvent e) {} + + // https://docs.flutter.dev/release/breaking-changes/trackpad-gestures + // TODO(support zoom in/out) + void onPointerPanZoomUpdate(PointerPanZoomUpdateEvent e) { + var delta = e.panDelta; + trackpadScrollDistance += delta; + bind.sessionSendMouse( + id: id, + msg: + '{"type": "trackpad", "x": "${delta.dx.toInt()}", "y": "${delta.dy.toInt()}"}'); + } + + // Simple simulation for fling. + void _scheduleFling(var x, y, dx, dy) { + if (dx <= 0 && dy <= 0) { + return; + } + _flingTimer = Timer(Duration(milliseconds: 10), () { + bind.sessionSendMouse( + id: id, msg: '{"type": "trackpad", "x": "$x", "y": "$y"}'); + dx--; + dy--; + if (dx == 0) { + x = 0; + } + if (dy == 0) { + y = 0; + } + _scheduleFling(x, y, dx, dy); + }); + } + + void onPointerPanZoomEnd(PointerPanZoomEndEvent e) { + var x = _signOrZero(trackpadScrollDistance.dx); + var y = _signOrZero(trackpadScrollDistance.dy); + var dx = trackpadScrollDistance.dx.abs() ~/ 40; + var dy = trackpadScrollDistance.dy.abs() ~/ 40; + _scheduleFling(x, y, dx, dy); + + trackpadScrollDistance = Offset.zero; + } + void onPointDownImage(PointerDownEvent e) { debugPrint("onPointDownImage"); if (e.kind != ui.PointerDeviceKind.mouse) { diff --git a/src/client.rs b/src/client.rs index 3f738a369..b3be51cb4 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1572,9 +1572,14 @@ pub async fn handle_test_delay(t: TestDelay, peer: &mut Stream) { } } +/// Whether is track pad scrolling. #[inline] -#[cfg(all(target_os = "macos", not(feature = "flutter")))] +#[cfg(all(target_os = "macos"))] fn check_scroll_on_mac(mask: i32, x: i32, y: i32) -> bool { + // flutter version we set mask type bit to 4 when track pad scrolling. + if mask & 7 == 4 { + return true; + } if mask & 3 != 3 { return false; } @@ -1597,7 +1602,7 @@ fn check_scroll_on_mac(mask: i32, x: i32, y: i32) -> bool { /// /// * `mask` - Mouse event. /// * mask = buttons << 3 | type -/// * type, 1: down, 2: up, 3: wheel +/// * type, 1: down, 2: up, 3: wheel, 4: trackpad /// * buttons, 1: left, 2: right, 4: middle /// * `x` - X coordinate. /// * `y` - Y coordinate. @@ -1636,7 +1641,7 @@ pub fn send_mouse( if command { mouse_event.modifiers.push(ControlKey::Meta.into()); } - #[cfg(all(target_os = "macos", not(feature = "flutter")))] + #[cfg(all(target_os = "macos"))] if check_scroll_on_mac(mask, x, y) { mouse_event.modifiers.push(ControlKey::Scroll.into()); } diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 36e38f86e..bfee92f88 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -156,6 +156,7 @@ pub fn session_reconnect(id: String) { pub fn session_toggle_option(id: String, value: String) { if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { + log::warn!("toggle option {}", value); session.toggle_option(value); } } @@ -907,6 +908,7 @@ pub fn session_send_mouse(id: String, msg: String) { "down" => 1, "up" => 2, "wheel" => 3, + "trackpad" => 4, _ => 0, }; } diff --git a/src/server/input_service.rs b/src/server/input_service.rs index 005c828bc..ca63fed94 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -513,7 +513,7 @@ pub fn handle_mouse_(evt: &MouseEvent) { } _ => {} }, - 3 => { + 3 | 4 => { #[allow(unused_mut)] let mut x = evt.x; #[allow(unused_mut)] From 6f390759f301d39549cd800f44291a305700e193 Mon Sep 17 00:00:00 2001 From: 21pages Date: Mon, 21 Nov 2022 14:06:32 +0800 Subject: [PATCH 086/116] rename temporary password to one-time password Signed-off-by: 21pages --- flutter/lib/desktop/pages/desktop_home_page.dart | 6 ++++-- flutter/lib/desktop/pages/desktop_setting_page.dart | 4 ++-- flutter/lib/models/server_model.dart | 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/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/pl.rs | 6 +++--- src/lang/pt_PT.rs | 6 +++--- src/lang/ptbr.rs | 6 +++--- src/lang/ru.rs | 6 +++--- src/lang/sk.rs | 6 +++--- src/lang/template.rs | 6 +++--- src/lang/tr.rs | 6 +++--- src/lang/tw.rs | 6 +++--- src/lang/ua.rs | 6 +++--- src/lang/vn.rs | 6 +++--- src/ui/index.tis | 6 +++--- 29 files changed, 88 insertions(+), 84 deletions(-) diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart index e7d6f50e8..244d315ce 100644 --- a/flutter/lib/desktop/pages/desktop_home_page.dart +++ b/flutter/lib/desktop/pages/desktop_home_page.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:io'; import 'dart:convert'; +import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart' hide MenuItem; import 'package:flutter/services.dart'; import 'package:flutter_hbb/common.dart'; @@ -202,10 +203,11 @@ class _DesktopHomePageState extends State child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - translate("Password"), + AutoSizeText( + translate("One-time Password"), style: TextStyle( fontSize: 14, color: textColor?.withOpacity(0.5)), + maxLines: 1, ), Row( children: [ diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index 64ebc712e..b5aeaa7c3 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -586,7 +586,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { kUseBothPasswords, ]; List passwordValues = [ - translate('Use temporary password'), + translate('Use one-time password'), translate('Use permanent password'), translate('Use both passwords'), ]; @@ -665,7 +665,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { Offstage( offstage: !usePassword, child: _SubLabeledWidget( - 'Temporary Password Length', + 'One-time password length', Row( children: [ ...lengthRadios, diff --git a/flutter/lib/models/server_model.dart b/flutter/lib/models/server_model.dart index a00630b22..be3f02b5d 100644 --- a/flutter/lib/models/server_model.dart +++ b/flutter/lib/models/server_model.dart @@ -35,7 +35,8 @@ class ServerModel with ChangeNotifier { late String _emptyIdShow; late final IDTextEditingController _serverId; - final _serverPasswd = TextEditingController(text: ""); + final _serverPasswd = + TextEditingController(text: translate("Generating ...")); final tabController = DesktopTabController(tabType: DesktopTabType.cm); @@ -170,7 +171,8 @@ class ServerModel with ChangeNotifier { update = true; } final oldPwdText = _serverPasswd.text; - if (_serverPasswd.text != temporaryPassword) { + if (_serverPasswd.text != temporaryPassword && + temporaryPassword.isNotEmpty) { _serverPasswd.text = temporaryPassword; } if (verificationMethod == kUsePermanentPassword || diff --git a/src/lang/ca.rs b/src/lang/ca.rs index a70fce1c9..99150acd0 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", "Mode heretat"), ("Map mode", "Mode mapa"), ("Translate mode", "Mode traduit"), - ("Use temporary password", "Utilitzar contrasenya temporal"), ("Use permanent password", "Utilitzar contrasenya permament"), ("Use both passwords", "Utilitzar ambdues contrasenyas"), ("Set permanent password", "Establir contrasenya permament"), - ("Set temporary password length", "Establir llargada de la contrasenya temporal"), ("Enable Remote Restart", "Activar reinici remot"), ("Allow remote restart", "Permetre reinici remot"), ("Restart Remote Device", "Reiniciar dispositiu"), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", "Habilitar còdec per hardware"), ("Unlock Security Settings", "Desbloquejar ajustaments de seguritat"), ("Enable Audio", "Habilitar àudio"), - ("Temporary Password Length", "Longitut de Contrasenya Temporal"), ("Unlock Network Settings", "Desbloquejar Ajustaments de Xarxa"), ("Server", "Servidor"), ("Direct IP Access", "Accés IP Directe"), @@ -393,5 +390,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 4588a148f..5e38c3d27 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", "传统模式"), ("Map mode", "1:1传输"), ("Translate mode", "翻译模式"), - ("Use temporary password", "使用临时密码"), ("Use permanent password", "使用固定密码"), ("Use both passwords", "同时使用两种密码"), ("Set permanent password", "设置固定密码"), - ("Set temporary password length", "设置临时密码长度"), ("Enable Remote Restart", "允许远程重启"), ("Allow remote restart", "允许远程重启"), ("Restart Remote Device", "重启远程电脑"), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", "使用硬件编解码"), ("Unlock Security Settings", "解锁安全设置"), ("Enable Audio", "允许传输音频"), - ("Temporary Password Length", "临时密码长度"), ("Unlock Network Settings", "解锁网络设置"), ("Server", "服务器"), ("Direct IP Access", "IP直接访问"), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", "只允许点击访问"), ("Accept sessions via both", "允许密码或点击访问"), ("Please wait for the remote side to accept your session request...", "请等待对方接受你的连接..."), + ("One-time Password", "一次性密码"), + ("Use one-time password", "使用一次性密码"), + ("One-time password length", "一次性密码长度"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 46817bbc4..6081e4212 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", ""), ("Map mode", ""), ("Translate mode", ""), - ("Use temporary password", ""), ("Use permanent password", ""), ("Use both passwords", ""), ("Set permanent password", ""), - ("Set temporary password length", ""), ("Enable Remote Restart", ""), ("Allow remote restart", ""), ("Restart Remote Device", ""), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", ""), ("Unlock Security Settings", ""), ("Enable Audio", ""), - ("Temporary Password Length", ""), ("Unlock Network Settings", ""), ("Server", ""), ("Direct IP Access", ""), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index 6678e734a..ab1dbff38 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", "Bagudkompatibilitetstilstand"), ("Map mode", ""), ("Translate mode", ""), - ("Use temporary password", "Brug midlertidig adgangskode"), ("Use permanent password", "Brug permanent adgangskode"), ("Use both passwords", "Bug begge adgangskoder"), ("Set permanent password", "Sæt permanent adgangskode"), - ("Set temporary password length", "Sæt midlertidig adgangskode"), ("Enable Remote Restart", "Aktiver fjerngenstart"), ("Allow remote restart", "Tillad fjerngenstart"), ("Restart Remote Device", "Genstart fjernenhed"), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", "Aktiver hardware-codec"), ("Unlock Security Settings", "Lås op for sikkerhedsinstillinger"), ("Enable Audio", "Aktiver Lyd"), - ("Temporary Password Length", "Midlertidig Adgangskode Længde"), ("Unlock Network Settings", "Lås op for Netværksinstillinger"), ("Server", "Server"), ("Direct IP Access", "Direkte IP Adgang"), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index 28d220933..328c5128b 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", "Kompatibilitätsmodus"), ("Map mode", ""), ("Translate mode", "Übersetzungsmodus"), - ("Use temporary password", "Temporäres Passwort verwenden"), ("Use permanent password", "Dauerhaftes Passwort verwenden"), ("Use both passwords", "Beide Passwörter verwenden"), ("Set permanent password", "Dauerhaftes Passwort setzen"), - ("Set temporary password length", "Länge des temporären Passworts setzen"), ("Enable Remote Restart", "Entfernten Neustart aktivieren"), ("Allow remote restart", "Entfernten Neustart erlauben"), ("Restart Remote Device", "Entferntes Gerät neu starten"), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", "Hardware-Codec aktivieren"), ("Unlock Security Settings", "Sicherheitseinstellungen entsperren"), ("Enable Audio", "Audio aktivieren"), - ("Temporary Password Length", "Länge des temporären Passworts"), ("Unlock Network Settings", "Netzwerkeinstellungen entsperren"), ("Server", "Server"), ("Direct IP Access", "Direkter IP-Zugriff"), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 2fc63ecc2..9cd6eacd1 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", ""), ("Map mode", ""), ("Translate mode", ""), - ("Use temporary password", ""), ("Use permanent password", ""), ("Use both passwords", ""), ("Set permanent password", ""), - ("Set temporary password length", ""), ("Enable Remote Restart", ""), ("Allow remote restart", ""), ("Restart Remote Device", ""), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", ""), ("Unlock Security Settings", ""), ("Enable Audio", ""), - ("Temporary Password Length", ""), ("Unlock Network Settings", ""), ("Server", ""), ("Direct IP Access", ""), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index 4e04fa2a0..210dc4352 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", "Modo heredado"), ("Map mode", "Modo mapa"), ("Translate mode", "Modo traducido"), - ("Use temporary password", "Usar contraseña temporal"), ("Use permanent password", "Usar contraseña permamente"), ("Use both passwords", "Usar ambas contraseñas"), ("Set permanent password", "Establecer contraseña permamente"), - ("Set temporary password length", "Establecer largo de contraseña temporal"), ("Enable Remote Restart", "Activar reinicio remoto"), ("Allow remote restart", "Permitir reinicio remoto"), ("Restart Remote Device", "Reiniciar dispositivo"), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", "Habilitar códec por hardware"), ("Unlock Security Settings", "Desbloquear ajustes de seguridad"), ("Enable Audio", "Habilitar Audio"), - ("Temporary Password Length", "Longitud de Contraseña Temporal"), ("Unlock Network Settings", "Desbloquear Ajustes de Red"), ("Server", "Servidor"), ("Direct IP Access", "Acceso IP Directo"), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index 040dcf204..c6b5f60a6 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", "پشتیبانی موارد قدیمی"), ("Map mode", "حالت نقشه"), ("Translate mode", "حالت ترجمه"), - ("Use temporary password", "از رمز عبور موقت استفاده کنید"), ("Use permanent password", "از رمز عبور دائمی استفاده کنید"), ("Use both passwords", "از هر دو رمز عبور استفاده کنید"), ("Set permanent password", "یک رمز عبور دائمی تنظیم کنید"), - ("Set temporary password length", "تنظیم طول رمز عبور موقت"), ("Enable Remote Restart", "فعال کردن راه‌اندازی مجدد از راه دور"), ("Allow remote restart", "اجازه راه اندازی مجدد از راه دور"), ("Restart Remote Device", "راه‌اندازی مجدد دستگاه از راه دور"), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", "از کدک سخت افزاری استفاده کنید"), ("Unlock Security Settings", "تنظیمات امنیتی را باز کنید"), ("Enable Audio", "صدا را روشن کنید"), - ("Temporary Password Length", "طول رمز عبور موقت"), ("Unlock Network Settings", "باز کردن قفل تنظیمات شبکه"), ("Server", "سرور"), ("Direct IP Access", "دسترسی مستقیم به IP"), @@ -393,5 +390,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index 926ad26fc..b24fb71da 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", "Mode hérité"), ("Map mode", ""), ("Translate mode", ""), - ("Use temporary password", "Utiliser un mot de passe temporaire"), ("Use permanent password", "Utiliser un mot de passe permanent"), ("Use both passwords", "Utiliser les mots de passe temporaire et permanent"), ("Set permanent password", "Définir le mot de passe permanent"), - ("Set temporary password length", "Définir la longueur du mot de passe temporaire"), ("Enable Remote Restart", "Activer le redémarrage à distance"), ("Allow remote restart", "Autoriser le redémarrage à distance"), ("Restart Remote Device", "Redémarrer l'appareil à distance"), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", "Activer le transcodage matériel"), ("Unlock Security Settings", "Déverrouiller les configurations de sécurité"), ("Enable Audio", "Activer l'audio"), - ("Temporary Password Length", "Longueur mot de passe temporaire"), ("Unlock Network Settings", "Déverrouiller les configurations réseau"), ("Server", "Serveur"), ("Direct IP Access", "Accès IP direct"), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index 2cdb56b9b..b65ff2579 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", ""), ("Map mode", ""), ("Translate mode", "Fordító mód"), - ("Use temporary password", "Ideiglenes jelszó használata"), ("Use permanent password", "Állandó jelszó használata"), ("Use both passwords", "Mindkét jelszó használata"), ("Set permanent password", "Állandó jelszó beállítása"), - ("Set temporary password length", "Ideiglenes jelszó hosszának beállítása"), ("Enable Remote Restart", "Távoli újraindítás engedélyezése"), ("Allow remote restart", "Távoli újraindítás engedélyezése"), ("Restart Remote Device", "Távoli eszköz újraindítása"), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", "Hardveres kodek engedélyezése"), ("Unlock Security Settings", "Biztonsági beállítások feloldása"), ("Enable Audio", "Hang engedélyezése"), - ("Temporary Password Length", "Ideiglenes jelszó hossza"), ("Unlock Network Settings", "Hálózati beállítások feloldása"), ("Server", "Szerver"), ("Direct IP Access", "Közvetlen IP hozzáférés"), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 65d447021..0fb623606 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", "Mode lama"), ("Map mode", "Mode peta"), ("Translate mode", "Mode terjemahan"), - ("Use temporary password", "Gunakan kata sandi sementara"), ("Use permanent password", "Gunakan kata sandi permanaen"), ("Use both passwords", "Gunakan kedua kata sandi "), ("Set permanent password", "Setel kata sandi permanen"), - ("Set temporary password length", "Setel panjang kata sandi sementara"), ("Enable Remote Restart", "Aktifkan Restart Jarak Jauh"), ("Allow remote restart", "Ijinkan Restart Jarak Jauh"), ("Restart Remote Device", "Restart Perangkat Jarak Jauh"), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", "Aktifkan codec perangkat keras"), ("Unlock Security Settings", "Buka Kunci Pengaturan Keamanan"), ("Enable Audio", "Aktifkan Audio"), - ("Temporary Password Length", "Panjang Kata Sandi Sementara"), ("Unlock Network Settings", "Buka Kunci Pengaturan Jaringan"), ("Server", "Server"), ("Direct IP Access", "Direct IP Access"), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 58d493785..47c186fe5 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", "Modalità legacy"), ("Map mode", "Modalità mappa"), ("Translate mode", "Modalità di traduzione"), - ("Use temporary password", "Usa password temporanea"), ("Use permanent password", "Usa password permanente"), ("Use both passwords", "Usa entrambe le password"), ("Set permanent password", "Imposta password permanente"), - ("Set temporary password length", "Imposta lunghezza passwod temporanea"), ("Enable Remote Restart", "Abilita riavvio da remoto"), ("Allow remote restart", "Consenti riavvio da remoto"), ("Restart Remote Device", "Riavvia dispositivo remoto"), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", "Abilita codec hardware"), ("Unlock Security Settings", "Sblocca impostazioni di sicurezza"), ("Enable Audio", "Abilita audio"), - ("Temporary Password Length", "Lunghezza password temporanea"), ("Unlock Network Settings", "Sblocca impostazioni di rete"), ("Server", ""), ("Direct IP Access", "Accesso IP diretto"), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index c0e6b667d..fcd579c9f 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", ""), ("Map mode", ""), ("Translate mode", ""), - ("Use temporary password", "使い捨てのパスワードを使用"), ("Use permanent password", "固定のパスワードを使用"), ("Use both passwords", "どちらのパスワードも使用"), ("Set permanent password", "固定のパスワードを設定"), - ("Set temporary password length", "使い捨てのパスワードの長さを設定"), ("Enable Remote Restart", "リモートからの再起動を有効化"), ("Allow remote restart", "リモートからの再起動を許可"), ("Restart Remote Device", "リモートの端末を再起動"), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", ""), ("Unlock Security Settings", ""), ("Enable Audio", ""), - ("Temporary Password Length", ""), ("Unlock Network Settings", ""), ("Server", ""), ("Direct IP Access", ""), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index 3f0e10645..ee28e05eb 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", ""), ("Map mode", ""), ("Translate mode", ""), - ("Use temporary password", "임시 비밀번호 사용"), ("Use permanent password", "영구 비밀번호 사용"), ("Use both passwords", "두 비밀번호 (임시/영구) 사용"), ("Set permanent password", "영구 비밀번호 설정"), - ("Set temporary password length", "임시 비밀번호 길이 설정"), ("Enable Remote Restart", "원격지 재시작 활성화"), ("Allow remote restart", "원격지 재시작 허용"), ("Restart Remote Device", "원격 기기 재시작"), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", ""), ("Unlock Security Settings", ""), ("Enable Audio", ""), - ("Temporary Password Length", ""), ("Unlock Network Settings", ""), ("Server", ""), ("Direct IP Access", ""), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index a2d6a6dce..768e735b8 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", ""), ("Map mode", ""), ("Translate mode", ""), - ("Use temporary password", "Уақытша құпия сөзді қолдану"), ("Use permanent password", "Тұрақты құпия сөзді қолдану"), ("Use both passwords", "Қос құпия сөзді қолдану"), ("Set permanent password", "Тұрақты құпия сөзді орнату"), - ("Set temporary password length", "Уақытша құпия сөздің ұзындығын орнату"), ("Enable Remote Restart", "Қашықтан қайта-қосуды іске қосу"), ("Allow remote restart", "Қашықтан қайта-қосуды рұқсат ету"), ("Restart Remote Device", "Қашықтағы құрылғыны қайта-қосу"), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", ""), ("Unlock Security Settings", ""), ("Enable Audio", ""), - ("Temporary Password Length", ""), ("Unlock Network Settings", ""), ("Server", ""), ("Direct IP Access", ""), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index d440b06f1..c6ba009d3 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", "Tryb kompatybilności wstecznej (legacy)"), ("Map mode", "Tryb mapowania"), ("Translate mode", "Tryb translacji"), - ("Use temporary password", "Użyj tymczasowego hasła"), ("Use permanent password", "Użyj hasła permanentnego"), ("Use both passwords", "Użyj obu haseł"), ("Set permanent password", "Ustaw hasło permanentne"), - ("Set temporary password length", "Ustaw długość hasła tymczasowego"), ("Enable Remote Restart", "Włącz Zdalne Restartowanie"), ("Allow remote restart", "Zezwól na zdalne restartowanie"), ("Restart Remote Device", "Zrestartuj Zdalne Urządzenie"), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", "Włącz wsparcie sprzętowe dla kodeków"), ("Unlock Security Settings", "Odblokuj Ustawienia Zabezpieczeń"), ("Enable Audio", "Włącz Dźwięk"), - ("Temporary Password Length", "Długość hasła tymaczowego"), ("Unlock Network Settings", "Odblokuj ustawienia Sieciowe"), ("Server", "Serwer"), ("Direct IP Access", "Bezpośredni Adres IP"), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 71d3ffb53..97800a8f7 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", ""), ("Map mode", ""), ("Translate mode", ""), - ("Use temporary password", "Utilizar palavra-chave temporária"), ("Use permanent password", "Utilizar palavra-chave permanente"), ("Use both passwords", "Utilizar ambas as palavras-chave"), ("Set permanent password", "Definir palavra-chave permanente"), - ("Set temporary password length", "Definir tamanho de palavra-chave temporária"), ("Enable Remote Restart", "Activar reiniciar remoto"), ("Allow remote restart", "Permitir reiniciar remoto"), ("Restart Remote Device", "Reiniciar Dispositivo Remoto"), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", ""), ("Unlock Security Settings", ""), ("Enable Audio", ""), - ("Temporary Password Length", ""), ("Unlock Network Settings", ""), ("Server", ""), ("Direct IP Access", ""), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index 8a213d51c..f773a0a93 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", "Modo legado"), ("Map mode", "Modo mapa"), ("Translate mode", "Modo traduzido"), - ("Use temporary password", "Utilizar senha temporária"), ("Use permanent password", "Utilizar senha permanente"), ("Use both passwords", "Utilizar ambas as senhas"), ("Set permanent password", "Configurar senha permanente"), - ("Set temporary password length", "Configurar extensão da senha temporária"), ("Enable Remote Restart", "Habilitar reinicialização remota"), ("Allow remote restart", "Permitir reinicialização remota"), ("Restart Remote Device", "Reiniciar dispositivo remoto"), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", "Habilitar codec de hardware"), ("Unlock Security Settings", "Desabilitar configurações de segurança"), ("Enable Audio", "Habilitar áudio"), - ("Temporary Password Length", "Extensão da senha temporária"), ("Unlock Network Settings", "Desbloquear configurações de rede"), ("Server", "Servidor"), ("Direct IP Access", "Acesso direto por IP"), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index db0209fa8..fdee117c5 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", "Устаревший режим"), ("Map mode", "Режим сопоставления"), ("Translate mode", "Режим перевода"), - ("Use temporary password", "Использовать временный пароль"), ("Use permanent password", "Использовать постоянный пароль"), ("Use both passwords", "Использовать оба пароля"), ("Set permanent password", "Установить постоянный пароль"), - ("Set temporary password length", "Длина временного пароля"), ("Enable Remote Restart", "Включить удалённый перезапуск"), ("Allow remote restart", "Разрешить удалённый перезапуск"), ("Restart Remote Device", "Перезапустить удалённое устройство"), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", "Использовать аппаратный кодек"), ("Unlock Security Settings", "Разблокировать настройки безопасности"), ("Enable Audio", "Включить звук"), - ("Temporary Password Length", "Длинна временного пароля"), ("Unlock Network Settings", "Разблокировать настройки соединения"), ("Server", "Сервер"), ("Direct IP Access", "Прямой IP-доступ"), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 6d4a9d382..4013a95c0 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", ""), ("Map mode", ""), ("Translate mode", ""), - ("Use temporary password", ""), ("Use permanent password", ""), ("Use both passwords", ""), ("Set permanent password", ""), - ("Set temporary password length", ""), ("Enable Remote Restart", ""), ("Allow remote restart", ""), ("Restart Remote Device", ""), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", ""), ("Unlock Security Settings", ""), ("Enable Audio", ""), - ("Temporary Password Length", ""), ("Unlock Network Settings", ""), ("Server", ""), ("Direct IP Access", ""), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index 22bf2ac23..bd0f87519 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", ""), ("Map mode", ""), ("Translate mode", ""), - ("Use temporary password", ""), ("Use permanent password", ""), ("Use both passwords", ""), ("Set permanent password", ""), - ("Set temporary password length", ""), ("Enable Remote Restart", ""), ("Allow remote restart", ""), ("Restart Remote Device", ""), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", ""), ("Unlock Security Settings", ""), ("Enable Audio", ""), - ("Temporary Password Length", ""), ("Unlock Network Settings", ""), ("Server", ""), ("Direct IP Access", ""), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index bd439676e..5aef77c22 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", "Eski mod"), ("Map mode", "Haritalama modu"), ("Translate mode", "Çeviri modu"), - ("Use temporary password", "Geçici şifre kullan"), ("Use permanent password", "Kalıcı şifre kullan"), ("Use both passwords", "İki şifreyide kullan"), ("Set permanent password", "Kalıcı şifre oluştur"), - ("Set temporary password length", "Geçici şifre oluştur"), ("Enable Remote Restart", "Uzaktan yeniden başlatmayı aktif et"), ("Allow remote restart", "Uzaktan yeniden başlatmaya izin ver"), ("Restart Remote Device", "Uzaktaki cihazı yeniden başlat"), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", "Donanımsal codec aktif et"), ("Unlock Security Settings", "Güvenlik Ayarlarını Aç"), ("Enable Audio", "Sesi Aktif Et"), - ("Temporary Password Length", "Geçici Şifre Uzunluğu"), ("Unlock Network Settings", "Ağ Ayarlarını Aç"), ("Server", "Sunucu"), ("Direct IP Access", "Direk IP Erişimi"), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index ff544c1d8..7e3c451f7 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", "傳統模式"), ("Map mode", "1:1傳輸"), ("Translate mode", "翻譯模式"), - ("Use temporary password", "使用臨時密碼"), ("Use permanent password", "使用固定密碼"), ("Use both passwords", "同時使用兩種密碼"), ("Set permanent password", "設定固定密碼"), - ("Set temporary password length", "設定臨時密碼長度"), ("Enable Remote Restart", "允許遠程重啓"), ("Allow remote restart", "允許遠程重啓"), ("Restart Remote Device", "重啓遠程電腦"), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", "使用硬件編解碼"), ("Unlock Security Settings", "解鎖安全設置"), ("Enable Audio", "允許傳輸音頻"), - ("Temporary Password Length", "臨時密碼長度"), ("Unlock Network Settings", "解鎖網絡設置"), ("Server", "服務器"), ("Direct IP Access", "IP直接訪問"), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", "只允許點擊訪問"), ("Accept sessions via both", "允許密碼或點擊訪問"), ("Please wait for the remote side to accept your session request...", "請等待對方接受你的連接..."), + ("One-time Password", "一次性密碼"), + ("Use one-time password", "使用一次性密碼"), + ("One-time password length", "一次性密碼長度"), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index d7efe411b..656d7665b 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", ""), ("Map mode", ""), ("Translate mode", ""), - ("Use temporary password", "Використовувати тимчасовий пароль"), ("Use permanent password", "Використовувати постійний пароль"), ("Use both passwords", "Використовувати обидва паролі"), ("Set permanent password", "Встановити постійний пароль"), - ("Set temporary password length", "Довжина тимчасового пароля"), ("Enable Remote Restart", "Увімкнути віддалений перезапуск"), ("Allow remote restart", "Дозволити віддалений перезапуск"), ("Restart Remote Device", "Перезапустити віддалений пристрій"), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", "Увімкнути апаратний кодек"), ("Unlock Security Settings", "Розблокувати налаштування безпеки"), ("Enable Audio", "Вімкнути аудіо"), - ("Temporary Password Length", "Довжина тимчасового пароля"), ("Unlock Network Settings", "Розблокувати мережеві налаштування"), ("Server", "Сервер"), ("Direct IP Access", "Прямий IP доступ"), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index 96ff195b9..a5dc66db8 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -303,11 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Legacy mode", ""), ("Map mode", ""), ("Translate mode", ""), - ("Use temporary password", "Sử dụng mật khẩu tạm thời"), ("Use permanent password", "Sử dụng mật khẩu vĩnh viễn"), ("Use both passwords", "Sử dụng cả hai mật khẩu"), ("Set permanent password", "Đặt mật khẩu vĩnh viễn"), - ("Set temporary password length", "Đặt chiều dài của mật khẩu tạm thời"), ("Enable Remote Restart", "Bật khởi động lại từ xa"), ("Allow remote restart", "Cho phép khởi động lại từ xa"), ("Restart Remote Device", "Khởi động lại thiết bị từ xa"), @@ -343,7 +341,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable hardware codec", ""), ("Unlock Security Settings", ""), ("Enable Audio", ""), - ("Temporary Password Length", ""), ("Unlock Network Settings", ""), ("Server", ""), ("Direct IP Access", ""), @@ -394,5 +391,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via click", ""), ("Accept sessions via both", ""), ("Please wait for the remote side to accept your session request...", ""), + ("One-time Password", ""), + ("Use one-time password", ""), + ("One-time password length", ""), ].iter().cloned().collect(); } diff --git a/src/ui/index.tis b/src/ui/index.tis index 840198896..81cb588bc 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -850,7 +850,7 @@ class TemporaryPasswordLengthMenu: Reactor.Component { var me = this; var method = handler.get_option('verification-method'); self.timer(1ms, function() { me.toggleMenuState() }); - return
  • {translate("Set temporary password length")} + return
  • {translate("One-time password length")}
  • {svg_checkmark}6
  • {svg_checkmark}8
  • @@ -891,7 +891,7 @@ class PasswordArea: Reactor.Component { self.timer(1ms, function() { me.toggleMenuState() }); return
    -
    {translate('Password')}
    +
    {translate('One-time Password')}
    {this.renderPop()} @@ -909,7 +909,7 @@ class PasswordArea: Reactor.Component {
  • {svg_checkmark}{translate('Accept sessions via click')}
  • {svg_checkmark}{translate('Accept sessions via both')}
  • { !show_password ? '' :
    } - { !show_password ? '' :
  • {svg_checkmark}{translate('Use temporary password')}
  • } + { !show_password ? '' :
  • {svg_checkmark}{translate('Use one-time password')}
  • } { !show_password ? '' :
  • {svg_checkmark}{translate('Use permanent password')}
  • } { !show_password ? '' :
  • {svg_checkmark}{translate('Use both passwords')}
  • } { !show_password ? '' :
    } From 617e64d01f010d65f84b24a5999c3ac0b6dfcaf2 Mon Sep 17 00:00:00 2001 From: 21pages Date: Mon, 21 Nov 2022 15:29:00 +0800 Subject: [PATCH 087/116] fix approve mode judgement Signed-off-by: 21pages --- libs/hbb_common/src/password_security.rs | 18 ++++++++++++++++++ src/server/connection.rs | 16 ++++++++++------ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/libs/hbb_common/src/password_security.rs b/libs/hbb_common/src/password_security.rs index 55a6825fa..adaafebb3 100644 --- a/libs/hbb_common/src/password_security.rs +++ b/libs/hbb_common/src/password_security.rs @@ -13,6 +13,13 @@ enum VerificationMethod { UseBothPasswords, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ApproveMode { + Both, + Password, + Click, +} + // Should only be called in server pub fn update_temporary_password() { *TEMPORARY_PASSWORD.write().unwrap() = Config::get_auto_password(temporary_password_length()); @@ -58,6 +65,17 @@ pub fn has_valid_password() -> bool { || permanent_enabled() && !Config::get_permanent_password().is_empty() } +pub fn approve_mode() -> ApproveMode { + let mode = Config::get_option("approve-mode"); + if mode == "password" { + ApproveMode::Password + } else if mode == "click" { + ApproveMode::Click + } else { + ApproveMode::Both + } +} + const VERSION_LEN: usize = 2; pub fn encrypt_str_or_original(s: &str, version: &str) -> String { diff --git a/src/server/connection.rs b/src/server/connection.rs index f49e293a2..11960be8a 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -14,7 +14,8 @@ use hbb_common::{ futures::{SinkExt, StreamExt}, get_time, get_version_number, message_proto::{option_message::BoolOption, permission_info::Permission}, - password_security as password, sleep, timeout, + password_security::{self as password, ApproveMode}, + sleep, timeout, tokio::{ net::TcpStream, sync::mpsc, @@ -1046,7 +1047,9 @@ impl Connection { } if !crate::is_ip(&lr.username) && lr.username != Config::get_id() { self.send_login_error("Offline").await; - } else if Config::get_option("approve-mode") == "click" { + } else if password::approve_mode() == ApproveMode::Click + || password::approve_mode() == ApproveMode::Both && !password::has_valid_password() + { self.try_start_cm(lr.my_id, lr.my_name, false); if hbb_common::get_version_number(&lr.version) >= hbb_common::get_version_number("1.2.0") @@ -1054,6 +1057,11 @@ impl Connection { self.send_login_error("No Password Access").await; } return true; + } else if password::approve_mode() == ApproveMode::Password + && !password::has_valid_password() + { + self.send_login_error("Connection not allowed").await; + return false; } else if self.is_of_recent_session() { self.try_start_cm(lr.my_id, lr.my_name, true); self.send_logon_response().await; @@ -1063,10 +1071,6 @@ impl Connection { } else if lr.password.is_empty() { self.try_start_cm(lr.my_id, lr.my_name, false); } else { - if !password::has_valid_password() { - self.send_login_error("Connection not allowed").await; - return false; - } let mut failure = LOGIN_FAILURES .lock() .unwrap() From be9d04ff246a4a6bbe75029fb42871c4124c8620 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Mon, 21 Nov 2022 16:29:29 +0800 Subject: [PATCH 088/116] remove trackpad support in 3.0.5, will revert once upgrade to 3.3 --- flutter/lib/common/widgets/remote_input.dart | 2 ++ flutter/lib/models/input_model.dart | 2 ++ 2 files changed, 4 insertions(+) diff --git a/flutter/lib/common/widgets/remote_input.dart b/flutter/lib/common/widgets/remote_input.dart index 89443e14f..3a79d24fb 100644 --- a/flutter/lib/common/widgets/remote_input.dart +++ b/flutter/lib/common/widgets/remote_input.dart @@ -51,9 +51,11 @@ class RawPointerMouseRegion extends StatelessWidget { onPointerUp: inputModel.onPointUpImage, onPointerMove: inputModel.onPointMoveImage, onPointerSignal: inputModel.onPointerSignalImage, + /* onPointerPanZoomStart: inputModel.onPointerPanZoomStart, onPointerPanZoomUpdate: inputModel.onPointerPanZoomUpdate, onPointerPanZoomEnd: inputModel.onPointerPanZoomEnd, + */ child: MouseRegion( cursor: cursor ?? MouseCursor.defer, onEnter: onEnter, diff --git a/flutter/lib/models/input_model.dart b/flutter/lib/models/input_model.dart index eb1b4a3ff..bd1131c7a 100644 --- a/flutter/lib/models/input_model.dart +++ b/flutter/lib/models/input_model.dart @@ -264,6 +264,7 @@ class InputModel { } } +/* int _signOrZero(num x) { if (x == 0) { return 0; @@ -314,6 +315,7 @@ class InputModel { trackpadScrollDistance = Offset.zero; } +*/ void onPointDownImage(PointerDownEvent e) { debugPrint("onPointDownImage"); From 1f3042007148ab847da650c5ec41ec0be2ae68c2 Mon Sep 17 00:00:00 2001 From: mehdi-song Date: Mon, 21 Nov 2022 12:24:04 +0330 Subject: [PATCH 089/116] Update fa.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update fa.rs ("Accept sessions via password", "قبول درخواست با رمز عبور"), ("Accept sessions via click", "قبول درخواست با کلیک موس"), ("Accept sessions via both", "قبول درخواست با هر دو"), ("Please wait for the remote side to accept your session request...", "لطفا صبر کنید تا میزبان درخواست شما را قبول کند..."), ("One-time Password", "رمز عبور یکبار مصرف"), ("Use one-time password", "استفاده از رمز عبور یکبار مصرف"), ("One-time password length", "طول رمز عبور یکبار مصرف"), --- src/lang/fa.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lang/fa.rs b/src/lang/fa.rs index c6b5f60a6..7432dd8a1 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -385,13 +385,13 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", "This PC"), ("or", "یا"), ("Continue with", "ادامه با"), - ("Zoom cursor", ""), - ("Accept sessions via password", ""), - ("Accept sessions via click", ""), - ("Accept sessions via both", ""), - ("Please wait for the remote side to accept your session request...", ""), - ("One-time Password", ""), - ("Use one-time password", ""), - ("One-time password length", ""), + ("Zoom cursor", "نشانگر بزرگنمایی"), + ("Accept sessions via password", "قبول درخواست با رمز عبور"), + ("Accept sessions via click", "قبول درخواست با کلیک موس"), + ("Accept sessions via both", "قبول درخواست با هر دو"), + ("Please wait for the remote side to accept your session request...", "لطفا صبر کنید تا میزبان درخواست شما را قبول کند..."), + ("One-time Password", "رمز عبور یکبار مصرف"), + ("Use one-time password", "استفاده از رمز عبور یکبار مصرف"), + ("One-time password length", "طول رمز عبور یکبار مصرف"), ].iter().cloned().collect(); } From 2d528dde6fc2976808f540ff29a339172c53299b Mon Sep 17 00:00:00 2001 From: NicKoehler <53040044+NicKoehler@users.noreply.github.com> Date: Mon, 21 Nov 2022 11:43:20 +0100 Subject: [PATCH 090/116] Update it.rs --- src/lang/it.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lang/it.rs b/src/lang/it.rs index 47c186fe5..af49382c0 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -298,7 +298,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Language", "Linguaggio"), ("Keep RustDesk background service", "Mantieni il servizio di RustDesk in background"), ("Ignore Battery Optimizations", "Ignora le ottimizzazioni della batteria"), - ("android_open_battery_optimizations_tip", ""), + ("android_open_battery_optimizations_tip", "Se si desidera disabilitare questa funzione, andare nelle impostazioni dell'applicazione RustDesk, aprire la sezione [Batteria] e deselezionare [Senza restrizioni]."), ("Connection not allowed", "Connessione non consentita"), ("Legacy mode", "Modalità legacy"), ("Map mode", "Modalità mappa"), @@ -369,7 +369,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Write a message", "Scrivi un messaggio"), ("Prompt", ""), ("Please wait for confirmation of UAC...", "Attendi la conferma dell'UAC..."), - ("elevated_foreground_window_tip", ""), + ("elevated_foreground_window_tip", "La finestra corrente del desktop remoto richiede privilegi più elevati per funzionare, quindi non è in grado di utilizzare temporaneamente il mouse e la tastiera. È possibile chiedere all'utente remoto di ridurre a icona la finestra corrente o di fare clic sul pulsante di elevazione nella finestra di gestione della connessione. Per evitare questo problema, si consiglia di installare il software sul dispositivo remoto."), ("Disconnected", "Disconnesso"), ("Other", "Altro"), ("Confirm before closing multiple tabs", "Conferma prima di chiudere più schede"), @@ -387,12 +387,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", "Continua con"), ("Elevate", "Eleva"), ("Zoom cursor", "Cursore zoom"), - ("Accept sessions via password", ""), - ("Accept sessions via click", ""), - ("Accept sessions via both", ""), - ("Please wait for the remote side to accept your session request...", ""), - ("One-time Password", ""), - ("Use one-time password", ""), - ("One-time password length", ""), + ("Accept sessions via password", "Accetta sessioni via password"), + ("Accept sessions via click", "Accetta sessioni via click"), + ("Accept sessions via both", "Accetta sessioni con entrambi"), + ("Please wait for the remote side to accept your session request...", "Attendere che il lato remoto accetti la richiesta di sessione..."), + ("One-time Password", "Password monouso"), + ("Use one-time password", "Usa password monouso"), + ("One-time password length", "Lunghezza password monouso"), ].iter().cloned().collect(); } From 16165dae27cc85f7fd738d95c46b1f0d87ea68ae Mon Sep 17 00:00:00 2001 From: 21pages Date: Mon, 21 Nov 2022 16:37:15 +0800 Subject: [PATCH 091/116] allow set empty permanent password to delete it Signed-off-by: 21pages --- flutter/lib/desktop/pages/desktop_home_page.dart | 2 +- src/ui/index.tis | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart index 244d315ce..f7b07cf3a 100644 --- a/flutter/lib/desktop/pages/desktop_home_page.dart +++ b/flutter/lib/desktop/pages/desktop_home_page.dart @@ -486,7 +486,7 @@ void setPasswordDialog() async { errMsg1 = ""; }); final pass = p0.text.trim(); - if (pass.length < 6) { + if (pass.length < 6 && pass.isNotEmpty) { setState(() { errMsg0 = translate("Too short, at least 6 characters."); }); diff --git a/src/ui/index.tis b/src/ui/index.tis index 81cb588bc..8e2238b2d 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -958,7 +958,7 @@ class PasswordArea: Reactor.Component { if (!res) return; var p0 = (res.password || "").trim(); var p1 = (res.confirmation || "").trim(); - if (p0.length < 6) { + if (p0.length < 6 && p0.length != 0) { return translate("Too short, at least 6 characters."); } if (p0 != p1) { From 048fcf4016238979fa7bd4e5bf1de386406ead26 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 21 Nov 2022 18:56:27 +0800 Subject: [PATCH 092/116] fix win cursor color Signed-off-by: fufesou --- flutter/lib/models/model.dart | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index a7cd7a11c..7a08fc671 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -975,7 +975,7 @@ class CursorModel with ChangeNotifier { final image = await img.decodeImageFromPixels( rgba, width, height, ui.PixelFormat.rgba8888); _image = image; - if (await _updateCache(image, id, width, height)) { + if (await _updateCache(rgba, image, id, width, height)) { _images[id] = Tuple3(image, _hotx, _hoty); } else { _hotx = 0; @@ -989,22 +989,25 @@ class CursorModel with ChangeNotifier { } } - Future _updateCache(ui.Image image, int id, int w, int h) async { - ui.ImageByteFormat imgFormat = ui.ImageByteFormat.png; + Future _updateCache( + Uint8List rgba, ui.Image image, int id, int w, int h) async { + Uint8List? data; + img2.Image? imgOrigin; if (Platform.isWindows) { - imgFormat = ui.ImageByteFormat.rawRgba; + imgOrigin = img2.Image.fromBytes(w, h, rgba, format: img2.Format.rgba); + data = imgOrigin.getBytes(format: img2.Format.bgra); + } else { + ByteData? imgBytes = + await image.toByteData(format: ui.ImageByteFormat.png); + if (imgBytes == null) { + return false; + } + data = imgBytes.buffer.asUint8List(); } - - ByteData? imgBytes = await image.toByteData(format: imgFormat); - if (imgBytes == null) { - return false; - } - - Uint8List? data = imgBytes.buffer.asUint8List(); _cache = CursorData( peerId: this.id, id: id, - image: Platform.isWindows ? img2.Image.fromBytes(w, h, data) : null, + image: imgOrigin, scale: 1.0, data: data, hotxOrigin: _hotx, From a9773035c927222e5a1eeee905292ccd24adb8af Mon Sep 17 00:00:00 2001 From: 21pages Date: Mon, 21 Nov 2022 18:45:36 +0800 Subject: [PATCH 093/116] cm show requesting rather than connected when not authorized Signed-off-by: 21pages --- flutter/lib/desktop/pages/server_page.dart | 17 +++++++++++------ 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/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/pl.rs | 1 + src/lang/pt_PT.rs | 1 + src/lang/ptbr.rs | 1 + src/lang/ru.rs | 1 + src/lang/sk.rs | 1 + src/lang/template.rs | 1 + src/lang/tr.rs | 1 + src/lang/tw.rs | 1 + src/lang/ua.rs | 1 + src/lang/vn.rs | 1 + src/ui/cm.tis | 8 ++++++-- 27 files changed, 42 insertions(+), 8 deletions(-) diff --git a/flutter/lib/desktop/pages/server_page.dart b/flutter/lib/desktop/pages/server_page.dart index ae69497bc..aae6da8fc 100644 --- a/flutter/lib/desktop/pages/server_page.dart +++ b/flutter/lib/desktop/pages/server_page.dart @@ -304,7 +304,9 @@ class _CmHeaderState extends State<_CmHeader> void initState() { super.initState(); _timer = Timer.periodic(Duration(seconds: 1), (_) { - if (!client.disconnected) _time.value = _time.value + 1; + if (client.authorized && !client.disconnected) { + _time.value = _time.value + 1; + } }); } @@ -358,12 +360,15 @@ class _CmHeaderState extends State<_CmHeader> FittedBox( child: Row( children: [ - Text(client.disconnected - ? translate("Disconnected") - : translate("Connected")) + Text(client.authorized + ? client.disconnected + ? translate("Disconnected") + : translate("Connected") + : "${translate("Request access to your device")}...") .marginOnly(right: 8.0), - Obx(() => Text( - formatDurationToTime(Duration(seconds: _time.value)))) + if (client.authorized) + Obx(() => Text( + formatDurationToTime(Duration(seconds: _time.value)))) ], )) ], diff --git a/src/lang/ca.rs b/src/lang/ca.rs index 99150acd0..f5684b4c4 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -393,5 +393,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 5e38c3d27..7256c5d1f 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", "一次性密码"), ("Use one-time password", "使用一次性密码"), ("One-time password length", "一次性密码长度"), + ("Request access to your device", "请求访问你的设备"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 6081e4212..63fac7288 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index ab1dbff38..4278cdc20 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index 328c5128b..5d82f84d1 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 9cd6eacd1..3c7ac806a 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index 210dc4352..5dd471a4b 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index 7432dd8a1..0ea1f6f55 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -393,5 +393,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", "رمز عبور یکبار مصرف"), ("Use one-time password", "استفاده از رمز عبور یکبار مصرف"), ("One-time password length", "طول رمز عبور یکبار مصرف"), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index b24fb71da..4b8d0d83e 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index b65ff2579..9802ddb6f 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 0fb623606..002789066 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 47c186fe5..46602dfd4 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index fcd579c9f..b032fbe7e 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index ee28e05eb..338fc7ffe 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 768e735b8..3a343da21 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index c6ba009d3..b4f760a35 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 97800a8f7..dbb5fbbe9 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index f773a0a93..7d9c0b270 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index fdee117c5..ded00af23 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 4013a95c0..8da18e035 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index bd0f87519..bc9bc95e3 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index 5aef77c22..86283557f 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index 7e3c451f7..cc8f65e1c 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", "一次性密碼"), ("Use one-time password", "使用一次性密碼"), ("One-time password length", "一次性密碼長度"), + ("Request access to your device", "請求訪問你的設備"), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index 656d7665b..7d14ee7e0 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index a5dc66db8..3ddacdf8d 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -394,5 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", ""), ("Use one-time password", ""), ("One-time password length", ""), + ("Request access to your device", ""), ].iter().cloned().collect(); } diff --git a/src/ui/cm.tis b/src/ui/cm.tis index 4ecbe706c..2cfc14bf1 100644 --- a/src/ui/cm.tis +++ b/src/ui/cm.tis @@ -41,7 +41,10 @@ class Body: Reactor.Component
    {c.name}
    ({c.peer_id})
    -
    {disconnected ? translate('Disconnected') : translate('Connected')} {" "} {getElaspsed(c.time, c.now)}
    +
    {auth + ? {disconnected ? translate('Disconnected') : translate('Connected')}{" "}{getElaspsed(c.time, c.now)} + : {translate('Request access to your device')}{"..."}} +
    @@ -472,12 +475,13 @@ function updateTime() { self.timer(1s, function() { var now = new Date(); connections.map(function(c) { + if (!c.authorized) c.time = now; if (!c.disconnected) c.now = now; }); var el = $(#time); if (el) { var c = connections[body.cur]; - if (c && !c.disconnected) { + if (c && c.authorized && !c.disconnected) { el.text = getElaspsed(c.time, c.now); } } From 90ea283746b9b1cfb7c2fe2d6024c6cf37cfd4ed Mon Sep 17 00:00:00 2001 From: KrystianGraba Date: Mon, 21 Nov 2022 18:32:53 +0100 Subject: [PATCH 094/116] Update pl.rs --- src/lang/pl.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/lang/pl.rs b/src/lang/pl.rs index b4f760a35..ecc09ce2a 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -385,15 +385,15 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", "Ten komputer"), ("or", "albo"), ("Continue with", "Kontynuuj z"), - ("Elevate", ""), - ("Zoom cursor", ""), - ("Accept sessions via password", ""), - ("Accept sessions via click", ""), - ("Accept sessions via both", ""), - ("Please wait for the remote side to accept your session request...", ""), - ("One-time Password", ""), - ("Use one-time password", ""), - ("One-time password length", ""), - ("Request access to your device", ""), + ("Elevate", "Podwyższ"), + ("Zoom cursor", "Zoom kursora"), + ("Accept sessions via password", "Akceptuj sesje używając hasła"), + ("Accept sessions via click", "Akceptuj sesję klikając"), + ("Accept sessions via both", "Akceptuj sesjęna dwa sposoby"), + ("Please wait for the remote side to accept your session request...", "Proszę czekać aż zdalny host zaakceptuje Twoją prośbę..."), + ("One-time Password", "Hasło jednorazowe"), + ("Use one-time password", "Użyj hasła jednorazowego"), + ("One-time password length", "Długość hasła jednorazowego"), + ("Request access to your device", "Żądanie dostępu do Twojego urządzenia"), ].iter().cloned().collect(); } From 6dfe68be9be26f70447e6f886a7fa4b7f469e88d Mon Sep 17 00:00:00 2001 From: "Miguel F. G" <116861809+flusheDData@users.noreply.github.com> Date: Mon, 21 Nov 2022 20:14:23 +0100 Subject: [PATCH 095/116] Update es.rs New terms translated. --- src/lang/es.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lang/es.rs b/src/lang/es.rs index 5dd471a4b..cdebf7c59 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -387,13 +387,13 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", "Continuar con"), ("Elevate", "Elevar"), ("Zoom cursor", "Ampliar cursor"), - ("Accept sessions via password", ""), - ("Accept sessions via click", ""), - ("Accept sessions via both", ""), - ("Please wait for the remote side to accept your session request...", ""), - ("One-time Password", ""), - ("Use one-time password", ""), - ("One-time password length", ""), - ("Request access to your device", ""), + ("Accept sessions via password", "Aceptar sesiones a través de contraseña"), + ("Accept sessions via click", "Aceptar sesiones a través de clic"), + ("Accept sessions via both", "Aceptar sesiones a través de ambos"), + ("Please wait for the remote side to accept your session request...", "Por favor, esperar a que el lado remoto acepte la solicitud de sesión"), + ("One-time Password", "Constaseña de un solo uso"), + ("Use one-time password", "Usar contraseña de un solo uso"), + ("One-time password length", "Longitud de la contraseña de un solo uso"), + ("Request access to your device", "Solicitud de acceso a al dispositivo"), ].iter().cloned().collect(); } From 25286408e1d580c2129cd12821ae6e01926cc9b5 Mon Sep 17 00:00:00 2001 From: "Miguel F. G" <116861809+flusheDData@users.noreply.github.com> Date: Mon, 21 Nov 2022 20:16:47 +0100 Subject: [PATCH 096/116] Update es.rs --- src/lang/es.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lang/es.rs b/src/lang/es.rs index cdebf7c59..a59437581 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -390,10 +390,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Accept sessions via password", "Aceptar sesiones a través de contraseña"), ("Accept sessions via click", "Aceptar sesiones a través de clic"), ("Accept sessions via both", "Aceptar sesiones a través de ambos"), - ("Please wait for the remote side to accept your session request...", "Por favor, esperar a que el lado remoto acepte la solicitud de sesión"), + ("Please wait for the remote side to accept your session request...", "Por favor, espere a que el lado remoto acepte su solicitud de sesión"), ("One-time Password", "Constaseña de un solo uso"), ("Use one-time password", "Usar contraseña de un solo uso"), ("One-time password length", "Longitud de la contraseña de un solo uso"), - ("Request access to your device", "Solicitud de acceso a al dispositivo"), + ("Request access to your device", "Solicitud de acceso a su dispositivo"), ].iter().cloned().collect(); } From 32af62cccd924498f4d1251b72c3c8e0e48cd7c1 Mon Sep 17 00:00:00 2001 From: neoGalaxy88 Date: Tue, 22 Nov 2022 09:48:07 +0100 Subject: [PATCH 097/116] Update it.rs --- 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 61f9cad5e..76e034450 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -394,6 +394,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("One-time Password", "Password monouso"), ("Use one-time password", "Usa password monouso"), ("One-time password length", "Lunghezza password monouso"), - ("Request access to your device", ""), + ("Request access to your device", "Richiedi l'accesso al tuo dispositivo"), ].iter().cloned().collect(); } From edab4fd62d23be7695573e2ccd825a1987968958 Mon Sep 17 00:00:00 2001 From: fufesou Date: Tue, 22 Nov 2022 21:34:53 +0800 Subject: [PATCH 098/116] fix predefined win forbidden cursor Signed-off-by: fufesou --- flutter/lib/desktop/pages/remote_page.dart | 41 +++---- flutter/lib/mobile/pages/remote_page.dart | 8 +- flutter/lib/models/model.dart | 123 ++++++++++++--------- 3 files changed, 88 insertions(+), 84 deletions(-) diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index 84ea36d78..9e775f86f 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -356,9 +356,8 @@ class _ImagePaintState extends State { } } - MouseCursor _buildCustomCursor(BuildContext context, double scale) { - final cursor = Provider.of(context); - final cache = cursor.cache ?? cursor.defaultCache; + MouseCursor _buildCursorOfCache( + CursorModel cursor, double scale, CursorData? cache) { if (cache == null) { return MouseCursor.defer; } else { @@ -375,26 +374,16 @@ class _ImagePaintState extends State { } } + MouseCursor _buildCustomCursor(BuildContext context, double scale) { + final cursor = Provider.of(context); + final cache = cursor.cache ?? preDefaultCursor.cache; + return _buildCursorOfCache(cursor, scale, cache); + } + MouseCursor _buildDisabledCursor(BuildContext context, double scale) { final cursor = Provider.of(context); - final cache = cursor.cache; - if (cache == null) { - return MouseCursor.defer; - } else { - if (cursor.cachedForbidmemoryCursorData == null) { - cursor.updateForbiddenCursorBuffer(); - } - final key = 'disabled_cursor_key'; - cursor.addKey(key); - return FlutterCustomMemoryImageCursor( - pixbuf: cursor.cachedForbidmemoryCursorData, - key: key, - hotx: 0, - hoty: 0, - imageWidth: 32, - imageHeight: 32, - ); - } + final cache = preForbiddenCursor.cache; + return _buildCursorOfCache(cursor, scale, cache); } Widget _buildCrossScrollbarFromLayout( @@ -521,22 +510,22 @@ class CursorPaint extends StatelessWidget { double hotx = m.hotx; double hoty = m.hoty; if (m.image == null) { - if (m.defaultCache != null) { - hotx = m.defaultImage!.width / 2; - hoty = m.defaultImage!.height / 2; + if (preDefaultCursor.image != null) { + hotx = preDefaultCursor.image!.width / 2; + hoty = preDefaultCursor.image!.height / 2; } } return zoomCursor.isTrue ? CustomPaint( painter: ImagePainter( - image: m.image ?? m.defaultImage, + image: m.image ?? preDefaultCursor.image, x: m.x - hotx + c.x / c.scale, y: m.y - hoty + c.y / c.scale, scale: c.scale), ) : CustomPaint( painter: ImagePainter( - image: m.image ?? m.defaultImage, + image: m.image ?? preDefaultCursor.image, x: (m.x - hotx) * c.scale + c.x, y: (m.y - hoty) * c.scale + c.y, scale: 1.0), diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index b48e9960a..b17f0ef54 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -865,14 +865,14 @@ class CursorPaint extends StatelessWidget { double hotx = m.hotx; double hoty = m.hoty; if (m.image == null) { - if (m.defaultCache != null) { - hotx = m.defaultImage!.width / 2; - hoty = m.defaultImage!.height / 2; + if (preDefaultCursor.image != null) { + hotx = preDefaultCursor.image!.width / 2; + hoty = preDefaultCursor.image!.height / 2; } } return CustomPaint( painter: ImagePainter( - image: m.image ?? m.defaultImage, + image: m.image ?? preDefaultCursor.image, x: m.x * s - hotx * s + c.x, y: m.y * s - hoty * s + c.y - adjust, scale: 1), diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 7a08fc671..b7d72f878 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -763,13 +763,78 @@ class CursorData { } } +const _forbiddenCursorPng = + 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAkZQTFRFAAAA2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4GWAwCAAAAAAAA2B4GAAAAMTExAAAAAAAA2B4G2B4G2B4GAAAAmZmZkZGRAQEBAAAA2B4G2B4G2B4G////oKCgAwMDag8D2B4G2B4G2B4Gra2tBgYGbg8D2B4G2B4Gubm5CQkJTwsCVgwC2B4GxcXFDg4OAAAAAAAA2B4G2B4Gz8/PFBQUAAAAAAAA2B4G2B4G2B4G2B4G2B4G2B4G2B4GDgIA2NjYGxsbAAAAAAAA2B4GFwMB4eHhIyMjAAAAAAAA2B4G6OjoLCwsAAAAAAAA2B4G2B4G2B4G2B4G2B4GCQEA4ODgv7+/iYmJY2NjAgICAAAA9PT0Ojo6AAAAAAAAAAAA+/v7SkpKhYWFr6+vAAAAAAAA8/PzOTk5ERER9fX1KCgoAAAAgYGBKioqAAAAAAAApqamlpaWAAAAAAAAAAAAAAAAAAAAAAAALi4u/v7+GRkZAAAAAAAAAAAAAAAAAAAAfn5+AAAAAAAAV1dXkJCQAAAAAAAAAQEBAAAAAAAAAAAA7Hz6BAAAAMJ0Uk5TAAIWEwEynNz6//fVkCAatP2fDUHs6cDD8d0mPfT5fiEskiIR584A0gejr3AZ+P4plfALf5ZiTL85a4ziD6697fzN3UYE4v/4TwrNHuT///tdRKZh///+1U/ZBv///yjb///eAVL//50Cocv//6oFBbPvpGZCbfT//7cIhv///8INM///zBEcWYSZmO7//////1P////ts/////8vBv//////gv//R/z///QQz9sevP///2waXhNO/+fc//8mev/5gAe2r90MAAAByUlEQVR4nGNggANGJmYWBpyAlY2dg5OTi5uHF6s0H78AJxRwCAphyguLgKRExcQlQLSkFLq8tAwnp6ycPNABjAqKQKNElVDllVU4OVVhVquJA81Q10BRoAkUUYbJa4Edoo0sr6PLqaePLG/AyWlohKTAmJPTBFnelAFoixmSAnNOTgsUeQZLTk4rJAXWnJw2EHlbiDyDPCenHZICe04HFrh+RydnBgYWPU5uJAWinJwucPNd3dw9GDw5Ob2QFHBzcnrD7ffx9fMPCOTkDEINhmC4+3x8Q0LDwlEDIoKTMzIKKg9SEBIdE8sZh6SAJZ6Tkx0qD1YQkpCYlIwclCng0AXLQxSEpKalZyCryATKZwkhKQjJzsnNQ1KQXwBUUVhUXBJYWgZREFJeUVmFpMKlWg+anmqgCkJq6+obkG1pLEBTENLU3NKKrIKhrb2js8u4G6Kgpze0r3/CRAZMAHbkpJDJU6ZMmTqtFbuC6TNmhsyaMnsOFlmwgrnzpsxfELJwEXZ5Bp/FS3yWLlsesmLlKuwKVk9Ys5Zh3foN0zduwq5g85atDAzbpqSGbN9RhV0FGOzctWH3lD14FOzdt3H/gQw8Cg4u2gQPAwBYDXXdIH+wqAAAAABJRU5ErkJggg=='; +const _defaultCursorPng = + 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARzQklUCAgICHwIZIgAAAFmSURBVFiF7dWxSlxREMbx34QFDRowYBchZSxSCWlMCOwD5FGEFHap06UI7KPsAyyEEIQFqxRaCqYTsqCJFsKkuAeRXb17wrqV918dztw55zszc2fo6Oh47MR/e3zO1/iAHWmznHKGQwx9ip/LEbCfazbsoY8j/JLOhcC6sCW9wsjEwJf483AC9nPNc1+lFRwI13d+l3rYFS799rFGxJMqARv2pBXh+72XQ7gWvklPS7TmMl9Ak/M+DqrENvxAv/guKKApuKPWl0/TROK4+LbSqzhuB+OZ3fRSeFPWY+Fkyn56Y29hfgTSpnQ+s98cvorVey66uPlNFxKwZOYLCGfCs5n9NMYVrsp6mvXSoFqpqYFDvMBkStgJJe93dZOwVXxbqUnBENulydSReqUrDhcX0PT2EXarBYS3GNXMhboinBgIl9K71kg0L3+PvyYGdVpruT2MwrF0iotiXfIwus0Dj+OOjo6Of+e7ab74RkpgAAAAAElFTkSuQmCC'; + +final preForbiddenCursor = PredefinedCursor( + png: _forbiddenCursorPng, + id: -2, +); +final preDefaultCursor = PredefinedCursor( + png: _defaultCursorPng, + id: -1, + hotxGetter: (double w) => w / 2, + hotyGetter: (double h) => h / 2, +); + +class PredefinedCursor { + ui.Image? _image; + img2.Image? _image2; + CursorData? _cache; + String png; + int id; + double Function(double)? hotxGetter; + double Function(double)? hotyGetter; + + PredefinedCursor( + {required this.png, required this.id, this.hotxGetter, this.hotyGetter}) { + init(); + } + + ui.Image? get image => _image; + CursorData? get cache => _cache; + + init() { + _image2 = img2.decodePng(base64Decode(png)); + if (_image2 != null) { + () async { + final defaultImg = _image2!; + // This function is called only one time, no need to care about the performance. + Uint8List data = defaultImg.getBytes(format: img2.Format.rgba); + _image = await img.decodeImageFromPixels( + data, defaultImg.width, defaultImg.height, ui.PixelFormat.rgba8888); + + double scale = 1.0; + if (Platform.isWindows) { + data = _image2!.getBytes(format: img2.Format.bgra); + } else { + data = Uint8List.fromList(img2.encodePng(_image2!)); + } + + _cache = CursorData( + peerId: '', + id: id, + image: _image2?.clone(), + scale: scale, + data: data, + hotxOrigin: + hotxGetter != null ? hotxGetter!(_image2!.width.toDouble()) : 0, + hotyOrigin: + hotyGetter != null ? hotyGetter!(_image2!.height.toDouble()) : 0, + width: _image2!.width, + height: _image2!.height, + ); + }(); + } + } +} + class CursorModel with ChangeNotifier { ui.Image? _image; - ui.Image? _defaultImage; final _images = >{}; CursorData? _cache; - final _defaultCacheId = -1; - CursorData? _defaultCache; final _cacheMap = {}; final _cacheKeys = {}; double _x = -10000; @@ -785,9 +850,7 @@ class CursorModel with ChangeNotifier { WeakReference parent; ui.Image? get image => _image; - ui.Image? get defaultImage => _defaultImage; CursorData? get cache => _cache; - CursorData? get defaultCache => _getDefaultCache(); double get x => _x - _displayOriginX; double get y => _y - _displayOriginY; @@ -801,50 +864,11 @@ class CursorModel with ChangeNotifier { DateTime.now().difference(_lastPeerMouse).inMilliseconds < kMouseControlTimeoutMSec; - CursorModel(this.parent) { - _getDefaultImage(); - _getDefaultCache(); - } + CursorModel(this.parent); Set get cachedKeys => _cacheKeys; addKey(String key) => _cacheKeys.add(key); - Future _getDefaultImage() async { - if (_defaultImage == null) { - final defaultImg = defaultCursorImage!; - // This function is called only one time, no need to care about the performance. - Uint8List data = defaultImg.getBytes(format: img2.Format.rgba); - _defaultImage = await img.decodeImageFromPixels( - data, defaultImg.width, defaultImg.height, ui.PixelFormat.rgba8888); - } - return _defaultImage; - } - - CursorData? _getDefaultCache() { - if (_defaultCache == null) { - Uint8List data; - double scale = 1.0; - if (Platform.isWindows) { - data = defaultCursorImage!.getBytes(format: img2.Format.bgra); - } else { - data = Uint8List.fromList(img2.encodePng(defaultCursorImage!)); - } - - _defaultCache = CursorData( - peerId: id, - id: _defaultCacheId, - image: defaultCursorImage?.clone(), - scale: scale, - data: data, - hotxOrigin: defaultCursorImage!.width / 2, - hotyOrigin: defaultCursorImage!.height / 2, - width: defaultCursorImage!.width, - height: defaultCursorImage!.height, - ); - } - return _defaultCache; - } - // remote physical display coordinate Rect getVisibleRect() { final size = MediaQueryData.fromWindow(ui.window).size; @@ -1085,15 +1109,6 @@ class CursorModel with ChangeNotifier { customCursorController.freeCache(k); } } - - Uint8List? cachedForbidmemoryCursorData; - void updateForbiddenCursorBuffer() { - cachedForbidmemoryCursorData ??= base64Decode( - 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAkZQTFRFAAAA2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4GWAwCAAAAAAAA2B4GAAAAMTExAAAAAAAA2B4G2B4G2B4GAAAAmZmZkZGRAQEBAAAA2B4G2B4G2B4G////oKCgAwMDag8D2B4G2B4G2B4Gra2tBgYGbg8D2B4G2B4Gubm5CQkJTwsCVgwC2B4GxcXFDg4OAAAAAAAA2B4G2B4Gz8/PFBQUAAAAAAAA2B4G2B4G2B4G2B4G2B4G2B4G2B4GDgIA2NjYGxsbAAAAAAAA2B4GFwMB4eHhIyMjAAAAAAAA2B4G6OjoLCwsAAAAAAAA2B4G2B4G2B4G2B4G2B4GCQEA4ODgv7+/iYmJY2NjAgICAAAA9PT0Ojo6AAAAAAAAAAAA+/v7SkpKhYWFr6+vAAAAAAAA8/PzOTk5ERER9fX1KCgoAAAAgYGBKioqAAAAAAAApqamlpaWAAAAAAAAAAAAAAAAAAAAAAAALi4u/v7+GRkZAAAAAAAAAAAAAAAAAAAAfn5+AAAAAAAAV1dXkJCQAAAAAAAAAQEBAAAAAAAAAAAA7Hz6BAAAAMJ0Uk5TAAIWEwEynNz6//fVkCAatP2fDUHs6cDD8d0mPfT5fiEskiIR584A0gejr3AZ+P4plfALf5ZiTL85a4ziD6697fzN3UYE4v/4TwrNHuT///tdRKZh///+1U/ZBv///yjb///eAVL//50Cocv//6oFBbPvpGZCbfT//7cIhv///8INM///zBEcWYSZmO7//////1P////ts/////8vBv//////gv//R/z///QQz9sevP///2waXhNO/+fc//8mev/5gAe2r90MAAAByUlEQVR4nGNggANGJmYWBpyAlY2dg5OTi5uHF6s0H78AJxRwCAphyguLgKRExcQlQLSkFLq8tAwnp6ycPNABjAqKQKNElVDllVU4OVVhVquJA81Q10BRoAkUUYbJa4Edoo0sr6PLqaePLG/AyWlohKTAmJPTBFnelAFoixmSAnNOTgsUeQZLTk4rJAXWnJw2EHlbiDyDPCenHZICe04HFrh+RydnBgYWPU5uJAWinJwucPNd3dw9GDw5Ob2QFHBzcnrD7ffx9fMPCOTkDEINhmC4+3x8Q0LDwlEDIoKTMzIKKg9SEBIdE8sZh6SAJZ6Tkx0qD1YQkpCYlIwclCng0AXLQxSEpKalZyCryATKZwkhKQjJzsnNQ1KQXwBUUVhUXBJYWgZREFJeUVmFpMKlWg+anmqgCkJq6+obkG1pLEBTENLU3NKKrIKhrb2js8u4G6Kgpze0r3/CRAZMAHbkpJDJU6ZMmTqtFbuC6TNmhsyaMnsOFlmwgrnzpsxfELJwEXZ5Bp/FS3yWLlsesmLlKuwKVk9Ys5Zh3foN0zduwq5g85atDAzbpqSGbN9RhV0FGOzctWH3lD14FOzdt3H/gQw8Cg4u2gQPAwBYDXXdIH+wqAAAAABJRU5ErkJggg=='); - } - - img2.Image? defaultCursorImage = img2.decodePng(base64Decode( - 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARzQklUCAgICHwIZIgAAAFmSURBVFiF7dWxSlxREMbx34QFDRowYBchZSxSCWlMCOwD5FGEFHap06UI7KPsAyyEEIQFqxRaCqYTsqCJFsKkuAeRXb17wrqV918dztw55zszc2fo6Oh47MR/e3zO1/iAHWmznHKGQwx9ip/LEbCfazbsoY8j/JLOhcC6sCW9wsjEwJf483AC9nPNc1+lFRwI13d+l3rYFS799rFGxJMqARv2pBXh+72XQ7gWvklPS7TmMl9Ak/M+DqrENvxAv/guKKApuKPWl0/TROK4+LbSqzhuB+OZ3fRSeFPWY+Fkyn56Y29hfgTSpnQ+s98cvorVey66uPlNFxKwZOYLCGfCs5n9NMYVrsp6mvXSoFqpqYFDvMBkStgJJe93dZOwVXxbqUnBENulydSReqUrDhcX0PT2EXarBYS3GNXMhboinBgIl9K71kg0L3+PvyYGdVpruT2MwrF0iotiXfIwus0Dj+OOjo6Of+e7ab74RkpgAAAAAElFTkSuQmCC')); } class QualityMonitorData { From db18f4ab26c2cdf5a403a7277b8c9534414d5bda Mon Sep 17 00:00:00 2001 From: fufesou Date: Tue, 22 Nov 2022 22:12:10 +0800 Subject: [PATCH 099/116] fix session option zoom cursor 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 9e775f86f..c0a05c6d5 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -70,8 +70,7 @@ class _RemotePageState extends State ShowRemoteCursorState.init(id); RemoteCursorMovedState.init(id); final optZoomCursor = 'zoom-cursor'; - PeerBoolOption.init(id, optZoomCursor, - () => bind.sessionGetToggleOptionSync(id: id, arg: optZoomCursor)); + PeerBoolOption.init(id, optZoomCursor, () => false); _zoomCursor = PeerBoolOption.find(id, optZoomCursor); _showRemoteCursor = ShowRemoteCursorState.find(id); _keyboardEnabled = KeyboardEnabledState.find(id); @@ -91,9 +90,7 @@ class _RemotePageState extends State void initState() { super.initState(); _initStates(widget.id); - _ffi = FFI(); - Get.put(_ffi, tag: widget.id); _ffi.start(widget.id); WidgetsBinding.instance.addPostFrameCallback((_) { @@ -107,8 +104,11 @@ class _RemotePageState extends State _rawKeyFocusNode.requestFocus(); _ffi.ffiModel.updateEventListener(widget.id); _ffi.qualityMonitorModel.checkShowQualityMonitor(widget.id); + // Session option should be set after models.dart/FFI.start _showRemoteCursor.value = bind.sessionGetToggleOptionSync( id: widget.id, arg: 'show-remote-cursor'); + _zoomCursor.value = + bind.sessionGetToggleOptionSync(id: widget.id, arg: 'zoom-cursor'); if (!_isCustomCursorInited) { customCursorController.registerNeedUpdateCursorCallback( (String? lastKey, String? currentKey) async { From cea402ffcc379e294cf24454dcb1cca403cb22ad Mon Sep 17 00:00:00 2001 From: Kingtous Date: Sun, 20 Nov 2022 16:40:59 +0800 Subject: [PATCH 100/116] feat: initial macos ci --- .github/workflows/flutter-nightly.yml | 80 +++++++++++++++++++++++++++ build.py | 10 +++- 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/.github/workflows/flutter-nightly.yml b/.github/workflows/flutter-nightly.yml index f2391e77e..246c717f4 100644 --- a/.github/workflows/flutter-nightly.yml +++ b/.github/workflows/flutter-nightly.yml @@ -100,6 +100,86 @@ jobs: files: | rustdesk-*.exe + builf-for-macOS: + name: ${{ matrix.job.target }} (${{ matrix.job.os }},${{ matrix.job.extra-build-args }}) + runs-on: ${{ matrix.job.os }} + strategy: + fail-fast: false + matrix: + job: + - { target: x86_64-apple-darwin , os: macos-10.15, extra-build-args: ""} + steps: + - name: Checkout source code + uses: actions/checkout@v3 + + - name: Get build target triple + uses: jungwinter/split@v2 + id: build-target-triple + with: + separator: '-' + msg: ${{ matrix.job.target }} + + - name: Install build runtime + run: | + brew install llvm create-dmg + + - name: Install flutter + uses: subosito/flutter-action@v2 + with: + channel: 'stable' + flutter-version: ${{ env.FLUTTER_VERSION }} + + - name: Install Rust toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + target: ${{ matrix.job.target }} + override: true + profile: minimal # minimal component installation (ie, no documentation) + + - uses: Swatinem/rust-cache@v2 + with: + prefix-key: ${{ matrix.job.os }} + + - name: Install flutter rust bridge deps + shell: bash + run: | + dart pub global activate ffigen --version 5.0.1 + # flutter_rust_bridge + pushd /tmp && git clone https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge --depth=1 && popd + pushd /tmp/flutter_rust_bridge/frb_codegen && cargo install --path . && popd + pushd flutter && flutter pub get && popd + ~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart + + - name: Restore from cache and install vcpkg + uses: lukka/run-vcpkg@v7 + with: + setupOnly: true + vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }} + + - name: Install vcpkg dependencies + run: | + $VCPKG_ROOT/vcpkg install libvpx libyuv opus + shell: bash + + - name: Install cargo bundle tools + run: | + cargo install cargo-bundle + + - name: Show version information (Rust, cargo, Clang) + shell: bash + run: | + clang --version || true + rustup -V + rustup toolchain list + rustup default + cargo -V + rustc -V + + - name: Build rustdesk + run: ./build.py --flutter --hwcodec ${{ matrix.job.extra-build-args }} + + build-for-linux: name: ${{ matrix.job.target }} (${{ matrix.job.os }},${{ matrix.job.extra-build-args }}) runs-on: ${{ matrix.job.os }} diff --git a/build.py b/build.py index a95c64dc1..595c719d5 100755 --- a/build.py +++ b/build.py @@ -263,6 +263,14 @@ def build_flutter_deb(version, features): os.chdir("..") +def build_flutter_dmg(version, features): + os.system(f'cargo build --features {features} --lib --release') + ffi_bindgen_function_refactor() + os.chdir('flutter') + os.system('flutter build macos --release') + # TODO: pass + + def build_flutter_arch_manjaro(version, features): os.system(f'cargo build --features {features} --lib --release') ffi_bindgen_function_refactor() @@ -372,7 +380,7 @@ def main(): os.system('cargo bundle --release --features ' + features) if flutter: if osx: - # todo: OSX build + build_flutter_dmg(version, features) pass else: os.system( From 592a609fb6234b87aac5ca3012da8b5d707f9cd2 Mon Sep 17 00:00:00 2001 From: Kingtous Date: Sun, 20 Nov 2022 16:42:46 +0800 Subject: [PATCH 101/116] fix: ci --- .github/workflows/flutter-nightly.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/flutter-nightly.yml b/.github/workflows/flutter-nightly.yml index 246c717f4..b11bc4fcd 100644 --- a/.github/workflows/flutter-nightly.yml +++ b/.github/workflows/flutter-nightly.yml @@ -112,13 +112,6 @@ jobs: - name: Checkout source code uses: actions/checkout@v3 - - name: Get build target triple - uses: jungwinter/split@v2 - id: build-target-triple - with: - separator: '-' - msg: ${{ matrix.job.target }} - - name: Install build runtime run: | brew install llvm create-dmg From 8b15174ca68055c69ce933e7d4e7a5ce334f3621 Mon Sep 17 00:00:00 2001 From: Kingtous Date: Sun, 20 Nov 2022 16:54:54 +0800 Subject: [PATCH 102/116] update: deps wip: add arm,arm64 triplet opt: macos nightly ci --- .github/workflows/flutter-nightly.yml | 46 +- build.py | 55 +- flutter/lib/models/native_model.dart | 4 +- flutter/macos/Podfile.lock | 20 +- .../macos/Runner.xcodeproj/project.pbxproj | 138 ++--- .../xcshareddata/xcschemes/Runner.xcscheme | 8 +- flutter/macos/Runner/Info.plist | 20 +- .../macos/rustdesk.xcodeproj/project.pbxproj | 309 ----------- flutter/pubspec.lock | 486 ++++++++---------- 9 files changed, 358 insertions(+), 728 deletions(-) diff --git a/.github/workflows/flutter-nightly.yml b/.github/workflows/flutter-nightly.yml index b11bc4fcd..0b49b9893 100644 --- a/.github/workflows/flutter-nightly.yml +++ b/.github/workflows/flutter-nightly.yml @@ -114,7 +114,7 @@ jobs: - name: Install build runtime run: | - brew install llvm create-dmg + brew install llvm create-dmg nasm yasm cmake gcc wget ninja - name: Install flutter uses: subosito/flutter-action@v2 @@ -153,7 +153,6 @@ jobs: - name: Install vcpkg dependencies run: | $VCPKG_ROOT/vcpkg install libvpx libyuv opus - shell: bash - name: Install cargo bundle tools run: | @@ -170,8 +169,23 @@ jobs: rustc -V - name: Build rustdesk - run: ./build.py --flutter --hwcodec ${{ matrix.job.extra-build-args }} - + run: | + # --hwcodec not supported on macos yet + ./build.py --flutter ${{ matrix.job.extra-build-args }} + + - name: Rename rustdesk + run: | + for name in rustdesk*??.dmg; do + mv "$name" "${name%%.dmg}-untested-${{ matrix.job.target }}.dmg" + done + + - name: Publish DMG package + uses: softprops/action-gh-release@v1 + with: + prerelease: true + tag_name: ${{ env.TAG_NAME }} + files: | + rustdesk*-${{ matrix.job.target }}.dmg build-for-linux: name: ${{ matrix.job.target }} (${{ matrix.job.os }},${{ matrix.job.extra-build-args }}) @@ -180,12 +194,11 @@ jobs: fail-fast: false matrix: job: - # - { target: aarch64-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true } + # - { target: aarch64-unknown-linux-gnu , os: ubuntu-18.04, use-cross: true } # - { target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true } # - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true } # - { target: i686-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true } # - { target: i686-unknown-linux-musl , os: ubuntu-20.04, use-cross: true } - # - { target: x86_64-apple-darwin , os: macos-10.15 } - { target: x86_64-unknown-linux-gnu , os: ubuntu-18.04, extra-build-args: ""} - { target: x86_64-unknown-linux-gnu , os: ubuntu-18.04, extra-build-args: "--flatpak"} # - { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true } @@ -203,10 +216,12 @@ jobs: - name: Install prerequisites run: | case ${{ matrix.job.target }} in - x86_64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt install -y g++ gcc 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 libclang-dev llvm-dev libclang-10-dev llvm-10-dev;; - # arm-unknown-linux-*) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;; - # aarch64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt-get -y install gcc-aarch64-linux-gnu ;; + x86_64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt install -y g++ gcc;; + arm-unknown-linux-*) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;; + aarch64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt-get -y install gcc-aarch64-linux-gnu ;; esac + # common package + sudo apt 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 libclang-dev llvm-dev libclang-10-dev llvm-10-dev - name: Install flutter uses: subosito/flutter-action@v2 @@ -244,7 +259,11 @@ jobs: - name: Install vcpkg dependencies run: | - $VCPKG_ROOT/vcpkg install libvpx libyuv opus + case ${{ matrix.job.target }} in + x86_64-unknown-linux-gnu) $VCPKG_ROOT/vcpkg install libvpx libyuv opus;; + arm-unknown-linux-*) $VCPKG_ROOT/vcpkg install libvpx:arm-linux libyuv:arm-linux opus:arm-linux;; + aarch64-unknown-linux-gnu) $VCPKG_ROOT/vcpkg install libvpx:arm64-linux libyuv:arm64-linux opus:arm64-linux;; + esac shell: bash - name: Install cargo bundle tools @@ -286,6 +305,11 @@ jobs: name: rustdesk-${{ env.VERSION }}-${{ matrix.job.target }}-${{ matrix.job.os }}.deb path: rustdesk-${{ env.VERSION }}-${{ matrix.job.target }}-${{ matrix.job.os }}.deb + - name: Patch archlinux PKGBUILD + if: ${{ matrix.job.extra-build-args == '' }} + run: | + sed -i "s/arch=('x86_64')/arch=('${{ steps.build-target-triple.outputs._0 }}')/g" res/PKGBUILD + - name: Build archlinux package if: ${{ matrix.job.extra-build-args == '' }} uses: vufa/arch-makepkg-action@master @@ -358,7 +382,7 @@ jobs: fail-fast: false matrix: job: - # - { target: aarch64-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true } + - { target: aarch64-unknown-linux-gnu , os: ubuntu-18.04, use-cross: true } # - { target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true } # - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true } # - { target: i686-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true } diff --git a/build.py b/build.py index 595c719d5..445eb15bf 100755 --- a/build.py +++ b/build.py @@ -10,7 +10,8 @@ import hashlib import argparse windows = platform.platform().startswith('Windows') -osx = platform.platform().startswith('Darwin') or platform.platform().startswith("macOS") +osx = platform.platform().startswith( + 'Darwin') or platform.platform().startswith("macOS") hbb_name = 'rustdesk' + ('.exe' if windows else '') exe_path = 'target/release/' + hbb_name flutter_win_target_dir = 'flutter/build/windows/runner/Release/' @@ -124,6 +125,7 @@ def generate_build_script_for_docker(): os.system("chmod +x /tmp/build.sh") os.system("bash /tmp/build.sh") + def download_extract_features(features, res_dir): proxy = '' @@ -139,7 +141,8 @@ def download_extract_features(features, res_dir): for (feat, feat_info) in features.items(): print(f'{feat} download begin') download_filename = feat_info['zip_url'].split('/')[-1] - checksum_md5_response = urllib.request.urlopen(req(feat_info['checksum_url'])) + checksum_md5_response = urllib.request.urlopen( + req(feat_info['checksum_url'])) for line in checksum_md5_response.read().decode('utf-8').splitlines(): if line.split()[1] == download_filename: checksum_md5 = line.split()[0] @@ -186,7 +189,7 @@ def get_rc_features(args): def get_features(args): - features = ['inline'] + features = ['inline'] if not args.flutter else [] if windows: features.extend(get_rc_features(args)) if args.hwcodec: @@ -227,7 +230,6 @@ def build_flutter_deb(version, features): os.system(f'cargo build --features {features} --lib --release') ffi_bindgen_function_refactor() os.chdir('flutter') - os.system('dpkg-deb -R rustdesk.deb tmpdeb') os.system('flutter build linux --release') os.system('mkdir -p tmpdeb/usr/bin/') os.system('mkdir -p tmpdeb/usr/lib/rustdesk') @@ -265,10 +267,18 @@ def build_flutter_deb(version, features): def build_flutter_dmg(version, features): os.system(f'cargo build --features {features} --lib --release') - ffi_bindgen_function_refactor() + # copy dylib + os.system( + "cp target/release/liblibrustdesk.dylib target/release/librustdesk.dylib") + # ffi_bindgen_function_refactor() + # limitations from flutter rust bridge + os.system('sed -i "" "s/char \*\*rustdesk_core_main(int \*args_len);//" flutter/macos/Runner/bridge_generated.h') os.chdir('flutter') os.system('flutter build macos --release') - # TODO: pass + os.system( + "create-dmg rustdesk.dmg ./build/macos/Build/Products/Release/rustdesk.app") + os.rename("rustdesk.dmg", f"../rustdesk-{version}.dmg") + os.chdir("..") def build_flutter_arch_manjaro(version, features): @@ -289,19 +299,24 @@ def build_flutter_windows(version, features): os.chdir('flutter') os.system('flutter build windows --release') os.chdir('..') - shutil.copy2('target/release/deps/dylib_virtual_display.dll', flutter_win_target_dir) + shutil.copy2('target/release/deps/dylib_virtual_display.dll', + flutter_win_target_dir) os.chdir('libs/portable') os.system('pip3 install -r requirements.txt') os.system( f'python3 ./generate.py -f ../../{flutter_win_target_dir} -o . -e ../../{flutter_win_target_dir}/rustdesk.exe') os.chdir('../..') if os.path.exists('./rustdesk_portable.exe'): - os.replace('./target/release/rustdesk-portable-packer.exe', './rustdesk_portable.exe') + os.replace('./target/release/rustdesk-portable-packer.exe', + './rustdesk_portable.exe') else: - os.rename('./target/release/rustdesk-portable-packer.exe', './rustdesk_portable.exe') - print(f'output location: {os.path.abspath(os.curdir)}/rustdesk_portable.exe') + os.rename('./target/release/rustdesk-portable-packer.exe', + './rustdesk_portable.exe') + print( + f'output location: {os.path.abspath(os.curdir)}/rustdesk_portable.exe') os.rename('./rustdesk_portable.exe', f'./rustdesk-{version}-install.exe') - print(f'output location: {os.path.abspath(os.curdir)}/rustdesk-{version}-install.exe') + print( + f'output location: {os.path.abspath(os.curdir)}/rustdesk-{version}-install.exe') def main(): @@ -322,7 +337,8 @@ def main(): version = get_version() features = ','.join(get_features(args)) flutter = args.flutter - os.system('python3 res/inline-sciter.py') + if not flutter: + os.system('python3 res/inline-sciter.py') portable = args.portable if windows: # build virtual display dynamic library @@ -343,7 +359,8 @@ def main(): 'target\\release\\rustdesk.exe') else: print('Not signed') - os.system(f'cp -rf target/release/RustDesk.exe rustdesk-{version}-win7-install.exe') + os.system( + f'cp -rf target/release/RustDesk.exe rustdesk-{version}-win7-install.exe') elif os.path.isfile('/usr/bin/pacman'): # pacman -S -needed base-devel os.system("sed -i 's/pkgver=.*/pkgver=%s/g' res/PKGBUILD" % version) @@ -356,12 +373,13 @@ def main(): os.system('ln -s res/pacman_install && ln -s res/PKGBUILD') os.system('HBB=`pwd` makepkg -f') os.system('mv rustdesk-%s-0-x86_64.pkg.tar.zst rustdesk-%s-manjaro-arch.pkg.tar.zst' % ( - version, version)) + version, version)) # pacman -U ./rustdesk.pkg.tar.zst elif os.path.isfile('/usr/bin/yum'): os.system('cargo build --release --features ' + features) os.system('strip target/release/rustdesk') - os.system("sed -i 's/Version: .*/Version: %s/g' res/rpm.spec" % version) + os.system( + "sed -i 's/Version: .*/Version: %s/g' res/rpm.spec" % version) os.system('HBB=`pwd` rpmbuild -ba res/rpm.spec') os.system( 'mv $HOME/rpmbuild/RPMS/x86_64/rustdesk-%s-0.x86_64.rpm ./rustdesk-%s-fedora28-centos8.rpm' % ( @@ -370,14 +388,14 @@ def main(): elif os.path.isfile('/usr/bin/zypper'): os.system('cargo build --release --features ' + features) os.system('strip target/release/rustdesk') - os.system("sed -i 's/Version: .*/Version: %s/g' res/rpm-suse.spec" % version) + os.system( + "sed -i 's/Version: .*/Version: %s/g' res/rpm-suse.spec" % version) os.system('HBB=`pwd` rpmbuild -ba res/rpm-suse.spec') os.system( 'mv $HOME/rpmbuild/RPMS/x86_64/rustdesk-%s-0.x86_64.rpm ./rustdesk-%s-suse.rpm' % ( - version, version)) + version, version)) # yum localinstall rustdesk.rpm else: - os.system('cargo bundle --release --features ' + features) if flutter: if osx: build_flutter_dmg(version, features) @@ -387,6 +405,7 @@ def main(): 'mv target/release/bundle/deb/rustdesk*.deb ./flutter/rustdesk.deb') build_flutter_deb(version, features) else: + os.system('cargo bundle --release --features ' + features) if osx: os.system( 'strip target/release/bundle/osx/RustDesk.app/Contents/MacOS/rustdesk') diff --git a/flutter/lib/models/native_model.dart b/flutter/lib/models/native_model.dart index 3af6f4fd7..e8aad8638 100644 --- a/flutter/lib/models/native_model.dart +++ b/flutter/lib/models/native_model.dart @@ -96,9 +96,7 @@ class PlatformFFI { ? DynamicLibrary.open('librustdesk.so') : Platform.isWindows ? DynamicLibrary.open('librustdesk.dll') - : Platform.isMacOS - ? DynamicLibrary.open('librustdesk.dylib') - : DynamicLibrary.process(); + : DynamicLibrary.process(); debugPrint('initializing FFI $_appType'); try { _translate = dylib.lookupFunction('translate'); diff --git a/flutter/macos/Podfile.lock b/flutter/macos/Podfile.lock index 812fbf8b3..952996e5f 100644 --- a/flutter/macos/Podfile.lock +++ b/flutter/macos/Podfile.lock @@ -17,19 +17,21 @@ PODS: - FlutterMacOS - screen_retriever (0.0.1): - FlutterMacOS - - shared_preferences_macos (0.0.1): - - FlutterMacOS - sqflite (0.0.2): - FlutterMacOS - FMDB (>= 2.7.5) - tray_manager (0.0.1): - FlutterMacOS + - uni_links_desktop (0.0.1): + - FlutterMacOS - url_launcher_macos (0.0.1): - FlutterMacOS - wakelock_macos (0.0.1): - FlutterMacOS - window_manager (0.2.0): - FlutterMacOS + - window_size (0.0.2): + - FlutterMacOS DEPENDENCIES: - desktop_drop (from `Flutter/ephemeral/.symlinks/plugins/desktop_drop/macos`) @@ -40,12 +42,13 @@ DEPENDENCIES: - package_info_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus_macos/macos`) - path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`) - screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`) - - shared_preferences_macos (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos`) - sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`) - tray_manager (from `Flutter/ephemeral/.symlinks/plugins/tray_manager/macos`) + - uni_links_desktop (from `Flutter/ephemeral/.symlinks/plugins/uni_links_desktop/macos`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) - wakelock_macos (from `Flutter/ephemeral/.symlinks/plugins/wakelock_macos/macos`) - window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`) + - window_size (from `Flutter/ephemeral/.symlinks/plugins/window_size/macos`) SPEC REPOS: trunk: @@ -68,35 +71,38 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos screen_retriever: :path: Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos - shared_preferences_macos: - :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos sqflite: :path: Flutter/ephemeral/.symlinks/plugins/sqflite/macos tray_manager: :path: Flutter/ephemeral/.symlinks/plugins/tray_manager/macos + uni_links_desktop: + :path: Flutter/ephemeral/.symlinks/plugins/uni_links_desktop/macos url_launcher_macos: :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos wakelock_macos: :path: Flutter/ephemeral/.symlinks/plugins/wakelock_macos/macos window_manager: :path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos + window_size: + :path: Flutter/ephemeral/.symlinks/plugins/window_size/macos SPEC CHECKSUMS: desktop_drop: 69eeff437544aa619c8db7f4481b3a65f7696898 desktop_multi_window: 566489c048b501134f9d7fb6a2354c60a9126486 device_info_plus_macos: 1ad388a1ef433505c4038e7dd9605aadd1e2e9c7 flutter_custom_cursor: 629957115075c672287bd0fa979d863ccf6024f7 - FlutterMacOS: ae6af50a8ea7d6103d888583d46bd8328a7e9811 + FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424 FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a package_info_plus_macos: f010621b07802a241d96d01876d6705f15e77c1c path_provider_macos: 3c0c3b4b0d4a76d2bf989a913c2de869c5641a19 screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38 - shared_preferences_macos: a64dc611287ed6cbe28fd1297898db1336975727 sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea tray_manager: 9064e219c56d75c476e46b9a21182087930baf90 + uni_links_desktop: 45900fb319df48fcdea2df0756e9c2626696b026 url_launcher_macos: 597e05b8e514239626bcf4a850fcf9ef5c856ec3 wakelock_macos: bc3f2a9bd8d2e6c89fee1e1822e7ddac3bd004a9 window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8 + window_size: 339dafa0b27a95a62a843042038fa6c3c48de195 PODFILE CHECKSUM: c7161fcf45d4fd9025dc0f48a76d6e64e52f8176 diff --git a/flutter/macos/Runner.xcodeproj/project.pbxproj b/flutter/macos/Runner.xcodeproj/project.pbxproj index 23549954b..8a44007a9 100644 --- a/flutter/macos/Runner.xcodeproj/project.pbxproj +++ b/flutter/macos/Runner.xcodeproj/project.pbxproj @@ -26,9 +26,8 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 84010B42292B58A400152837 /* liblibrustdesk.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 84010B41292B585400152837 /* liblibrustdesk.a */; }; C5E54335B73C89F72DB1B606 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26C84465887F29AE938039CB /* Pods_Runner.framework */; }; - CC13D44B2847D53E00EF8B54 /* librustdesk.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = CC13D4362847C8C200EF8B54 /* librustdesk.dylib */; }; - CC13D4502847D5E800EF8B54 /* librustdesk.dylib in Bundle Framework */ = {isa = PBXBuildFile; fileRef = CC13D4362847C8C200EF8B54 /* librustdesk.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -39,53 +38,17 @@ remoteGlobalIDString = 33CC111A2044C6BA0003C045; remoteInfo = FLX; }; - CC13D4352847C8C200EF8B54 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CC13D42E2847C8C200EF8B54 /* rustdesk.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = CA6071B5A0F5A7A3EF2297AA; - remoteInfo = "librustdesk-cdylib"; - }; - CC13D4372847C8C200EF8B54 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CC13D42E2847C8C200EF8B54 /* rustdesk.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = CA604C7415FB2A3731F5016A; - remoteInfo = "librustdesk-staticlib"; - }; - CC13D4392847C8C200EF8B54 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CC13D42E2847C8C200EF8B54 /* rustdesk.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = CA60D3BC5386D3D7DBD96893; - remoteInfo = "naming-bin"; - }; - CC13D43B2847C8C200EF8B54 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CC13D42E2847C8C200EF8B54 /* rustdesk.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = CA60D3BC5386B357B2AB834F; - remoteInfo = "rustdesk-bin"; - }; - CC13D43D2847C8CB00EF8B54 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CC13D42E2847C8C200EF8B54 /* rustdesk.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = CA6071B5A0F5D6691E4C3FF1; - remoteInfo = "librustdesk-cdylib"; - }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ - 33CC110E2044A8840003C045 /* Bundle Framework */ = { + 840109CF292B240500152837 /* Embed Libraries */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( - CC13D4502847D5E800EF8B54 /* librustdesk.dylib in Bundle Framework */, ); - name = "Bundle Framework"; + name = "Embed Libraries"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ @@ -95,7 +58,7 @@ 295AD07E63F13855C270A0E0 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* flutter_hbb.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = flutter_hbb.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10ED2044A3C60003C045 /* rustdesk.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = rustdesk.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; @@ -109,9 +72,9 @@ 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; 7436B85D94E8F7B5A9324869 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 84010B41292B585400152837 /* liblibrustdesk.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = liblibrustdesk.a; path = ../../target/release/liblibrustdesk.a; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; C3BB669FF6190AE1B11BCAEA /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - CC13D42E2847C8C200EF8B54 /* rustdesk.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = rustdesk.xcodeproj; sourceTree = SOURCE_ROOT; }; CCB6FE9A2848A6B800E58D48 /* bridge_generated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bridge_generated.h; path = Runner/bridge_generated.h; sourceTree = ""; }; /* End PBXFileReference section */ @@ -120,8 +83,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - CC13D44B2847D53E00EF8B54 /* librustdesk.dylib in Frameworks */, C5E54335B73C89F72DB1B606 /* Pods_Runner.framework in Frameworks */, + 84010B42292B58A400152837 /* liblibrustdesk.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -154,7 +117,7 @@ 33CC10EE2044A3C60003C045 /* Products */ = { isa = PBXGroup; children = ( - 33CC10ED2044A3C60003C045 /* flutter_hbb.app */, + 33CC10ED2044A3C60003C045 /* rustdesk.app */, ); name = Products; sourceTree = ""; @@ -184,7 +147,6 @@ 33FAB671232836740065AC1E /* Runner */ = { isa = PBXGroup; children = ( - CC13D42E2847C8C200EF8B54 /* rustdesk.xcodeproj */, 33CC10F02044A3C60003C045 /* AppDelegate.swift */, 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, 33E51913231747F40026EE4D /* DebugProfile.entitlements */, @@ -205,20 +167,10 @@ path = Pods; sourceTree = ""; }; - CC13D42F2847C8C200EF8B54 /* Products */ = { - isa = PBXGroup; - children = ( - CC13D4362847C8C200EF8B54 /* librustdesk.dylib */, - CC13D4382847C8C200EF8B54 /* liblibrustdesk_static.a */, - CC13D43A2847C8C200EF8B54 /* naming */, - CC13D43C2847C8C200EF8B54 /* rustdesk */, - ); - name = Products; - sourceTree = ""; - }; D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( + 84010B41292B585400152837 /* liblibrustdesk.a */, 26C84465887F29AE938039CB /* Pods_Runner.framework */, ); name = Frameworks; @@ -235,19 +187,18 @@ 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, - 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, + 840109CF292B240500152837 /* Embed Libraries */, 4688A20DD8E4F3E900927B2C /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( - CC13D43E2847C8CB00EF8B54 /* PBXTargetDependency */, 33CC11202044C79F0003C045 /* PBXTargetDependency */, ); name = Runner; productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* flutter_hbb.app */; + productReference = 33CC10ED2044A3C60003C045 /* rustdesk.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -287,12 +238,6 @@ mainGroup = 33CC10E42044A3C60003C045; productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; projectDirPath = ""; - projectReferences = ( - { - ProductGroup = CC13D42F2847C8C200EF8B54 /* Products */; - ProjectRef = CC13D42E2847C8C200EF8B54 /* rustdesk.xcodeproj */; - }, - ); projectRoot = ""; targets = ( 33CC10EC2044A3C60003C045 /* Runner */, @@ -301,37 +246,6 @@ }; /* End PBXProject section */ -/* Begin PBXReferenceProxy section */ - CC13D4362847C8C200EF8B54 /* librustdesk.dylib */ = { - isa = PBXReferenceProxy; - fileType = "compiled.mach-o.dylib"; - path = librustdesk.dylib; - remoteRef = CC13D4352847C8C200EF8B54 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - CC13D4382847C8C200EF8B54 /* liblibrustdesk_static.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = liblibrustdesk_static.a; - remoteRef = CC13D4372847C8C200EF8B54 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - CC13D43A2847C8C200EF8B54 /* naming */ = { - isa = PBXReferenceProxy; - fileType = "compiled.mach-o.executable"; - path = naming; - remoteRef = CC13D4392847C8C200EF8B54 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - CC13D43C2847C8C200EF8B54 /* rustdesk */ = { - isa = PBXReferenceProxy; - fileType = "compiled.mach-o.executable"; - path = rustdesk; - remoteRef = CC13D43B2847C8C200EF8B54 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; -/* End PBXReferenceProxy section */ - /* Begin PBXResourcesBuildPhase section */ 33CC10EB2044A3C60003C045 /* Resources */ = { isa = PBXResourcesBuildPhase; @@ -442,11 +356,6 @@ target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; }; - CC13D43E2847C8CB00EF8B54 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = "librustdesk-cdylib"; - targetProxy = CC13D43D2847C8CB00EF8B54 /* PBXContainerItemProxy */; - }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -467,6 +376,7 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = x86_64; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -502,6 +412,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; + ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; @@ -522,6 +433,12 @@ "$(inherited)", "@executable_path/../Frameworks", ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + ../../target/profile, + ); + MACOSX_DEPLOYMENT_TARGET = 10.15; + PRODUCT_BUNDLE_IDENTIFIER = com.carriez.rustdesk; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; @@ -540,6 +457,7 @@ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = x86_64; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -579,7 +497,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -593,6 +511,7 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = x86_64; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -626,8 +545,9 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; + ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; @@ -648,6 +568,12 @@ "$(inherited)", "@executable_path/../Frameworks", ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + ../../target/debug, + ); + MACOSX_DEPLOYMENT_TARGET = 10.15; + PRODUCT_BUNDLE_IDENTIFIER = com.carriez.rustdesk; PROVISIONING_PROFILE_SPECIFIER = ""; "SWIFT_OBJC_BRIDGING_HEADER[arch=*]" = Runner/bridge_generated.h; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -669,6 +595,12 @@ "$(inherited)", "@executable_path/../Frameworks", ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + ../../target/release, + ); + MACOSX_DEPLOYMENT_TARGET = 10.15; + PRODUCT_BUNDLE_IDENTIFIER = com.carriez.rustdesk; PROVISIONING_PROFILE_SPECIFIER = ""; "SWIFT_OBJC_BRIDGING_HEADER[arch=*]" = Runner/bridge_generated.h; SWIFT_VERSION = 5.0; diff --git a/flutter/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/flutter/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 85831efcf..898fbe4e7 100644 --- a/flutter/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/flutter/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -15,7 +15,7 @@ @@ -31,7 +31,7 @@ @@ -54,7 +54,7 @@ @@ -71,7 +71,7 @@ diff --git a/flutter/macos/Runner/Info.plist b/flutter/macos/Runner/Info.plist index 8245f21a0..7b985c870 100644 --- a/flutter/macos/Runner/Info.plist +++ b/flutter/macos/Runner/Info.plist @@ -18,16 +18,6 @@ APPL CFBundleShortVersionString $(FLUTTER_BUILD_NAME) - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - $(PRODUCT_COPYRIGHT) - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication CFBundleURLTypes @@ -41,5 +31,15 @@ + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication diff --git a/flutter/macos/rustdesk.xcodeproj/project.pbxproj b/flutter/macos/rustdesk.xcodeproj/project.pbxproj index 7aacb5f05..e334f0ac5 100644 --- a/flutter/macos/rustdesk.xcodeproj/project.pbxproj +++ b/flutter/macos/rustdesk.xcodeproj/project.pbxproj @@ -6,37 +6,8 @@ objectVersion = 53; objects = { -/* Begin PBXBuildFile section */ - CA6061C6409F12977AAB839F /* Cargo.toml in Sources */ = {isa = PBXBuildFile; fileRef = CA603C4309E13EF4668187A5 /* Cargo.toml */; settings = {COMPILER_FLAGS = "--lib"; }; }; - CA6061C6409FC858B7409EE3 /* Cargo.toml in Sources */ = {isa = PBXBuildFile; fileRef = CA603C4309E13EF4668187A5 /* Cargo.toml */; settings = {COMPILER_FLAGS = "--bin naming"; }; }; - CA6061C6409FC9FA710A2219 /* Cargo.toml in Sources */ = {isa = PBXBuildFile; fileRef = CA603C4309E13EF4668187A5 /* Cargo.toml */; settings = {COMPILER_FLAGS = "--bin rustdesk"; }; }; - CA6061C6409FD6691E4C3FF1 /* Cargo.toml in Sources */ = {isa = PBXBuildFile; fileRef = CA603C4309E13EF4668187A5 /* Cargo.toml */; settings = {COMPILER_FLAGS = "--lib"; }; }; -/* End PBXBuildFile section */ - -/* Begin PBXBuildRule section */ - CA603C4309E1AC6C1400ACA8 /* PBXBuildRule */ = { - isa = PBXBuildRule; - compilerSpec = com.apple.compilers.proxy.script; - dependencyFile = "$(DERIVED_FILE_DIR)/$(CARGO_XCODE_TARGET_ARCH)-$(EXECUTABLE_NAME).d"; - filePatterns = "*/Cargo.toml"; - fileType = pattern.proxy; - inputFiles = ( - ); - isEditable = 0; - name = "Cargo project build"; - outputFiles = ( - "$(OBJECT_FILE_DIR)/$(CARGO_XCODE_TARGET_ARCH)-$(EXECUTABLE_NAME)", - ); - script = "# generated with cargo-xcode 1.4.1\n\nset -eu; export PATH=$PATH:~/.cargo/bin:/usr/local/bin;\nif [ \"${IS_MACCATALYST-NO}\" = YES ]; then\n CARGO_XCODE_TARGET_TRIPLE=\"${CARGO_XCODE_TARGET_ARCH}-apple-ios-macabi\"\nelse\n CARGO_XCODE_TARGET_TRIPLE=\"${CARGO_XCODE_TARGET_ARCH}-apple-${CARGO_XCODE_TARGET_OS}\"\nfi\nif [ \"$CARGO_XCODE_TARGET_OS\" != \"darwin\" ]; then\n PATH=\"${PATH/\\/Contents\\/Developer\\/Toolchains\\/XcodeDefault.xctoolchain\\/usr\\/bin:/xcode-provided-ld-cant-link-lSystem-for-the-host-build-script:}\"\nfi\nPATH=\"$PATH:/opt/homebrew/bin\" # Rust projects often depend on extra tools like nasm, which Xcode lacks\nif [ \"$CARGO_XCODE_BUILD_MODE\" == release ]; then\n OTHER_INPUT_FILE_FLAGS=\"${OTHER_INPUT_FILE_FLAGS} --release\"\nfi\nif command -v rustup &> /dev/null; then\n if ! rustup target list --installed | egrep -q \"${CARGO_XCODE_TARGET_TRIPLE}\"; then\n echo \"warning: this build requires rustup toolchain for $CARGO_XCODE_TARGET_TRIPLE, but it isn't installed\"\n rustup target add \"${CARGO_XCODE_TARGET_TRIPLE}\" || echo >&2 \"warning: can't install $CARGO_XCODE_TARGET_TRIPLE\"\n fi\nfi\nif [ \"$ACTION\" = clean ]; then\n ( set -x; cargo clean --manifest-path=\"$SCRIPT_INPUT_FILE\" ${OTHER_INPUT_FILE_FLAGS} --target=\"${CARGO_XCODE_TARGET_TRIPLE}\"; );\nelse\n ( set -x; cargo build --manifest-path=\"$SCRIPT_INPUT_FILE\" --features=\"${CARGO_XCODE_FEATURES:-}\" ${OTHER_INPUT_FILE_FLAGS} --target=\"${CARGO_XCODE_TARGET_TRIPLE}\"; );\nfi\n# it's too hard to explain Cargo's actual exe path to Xcode build graph, so hardlink to a known-good path instead\nBUILT_SRC=\"${CARGO_TARGET_DIR}/${CARGO_XCODE_TARGET_TRIPLE}/${CARGO_XCODE_BUILD_MODE}/${CARGO_XCODE_CARGO_FILE_NAME}\"\nln -f -- \"$BUILT_SRC\" \"$SCRIPT_OUTPUT_FILE_0\"\n\n# xcode generates dep file, but for its own path, so append our rename to it\nDEP_FILE_SRC=\"${CARGO_TARGET_DIR}/${CARGO_XCODE_TARGET_TRIPLE}/${CARGO_XCODE_BUILD_MODE}/${CARGO_XCODE_CARGO_DEP_FILE_NAME}\"\nif [ -f \"$DEP_FILE_SRC\" ]; then\n DEP_FILE_DST=\"${DERIVED_FILE_DIR}/${CARGO_XCODE_TARGET_ARCH}-${EXECUTABLE_NAME}.d\"\n cp -f \"$DEP_FILE_SRC\" \"$DEP_FILE_DST\"\n echo >> \"$DEP_FILE_DST\" \"$SCRIPT_OUTPUT_FILE_0: $BUILT_SRC\"\nfi\n\n# lipo script needs to know all the platform-specific files that have been built\n# archs is in the file name, so that paths don't stay around after archs change\n# must match input for LipoScript\nFILE_LIST=\"${DERIVED_FILE_DIR}/${ARCHS}-${EXECUTABLE_NAME}.xcfilelist\"\ntouch \"$FILE_LIST\"\nif ! egrep -q \"$SCRIPT_OUTPUT_FILE_0\" \"$FILE_LIST\" ; then\n echo >> \"$FILE_LIST\" \"$SCRIPT_OUTPUT_FILE_0\"\nfi\n"; - }; -/* End PBXBuildRule section */ - /* Begin PBXFileReference section */ ADDEDBA66A6E1 /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; }; - CA604C7415FB2A3731F5016A /* liblibrustdesk_static.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = liblibrustdesk_static.a; sourceTree = BUILT_PRODUCTS_DIR; }; - CA6071B5A0F5A7A3EF2297AA /* librustdesk.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = librustdesk.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; - CA60D3BC5386B357B2AB834F /* rustdesk */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = rustdesk; sourceTree = BUILT_PRODUCTS_DIR; }; - CA60D3BC5386D3D7DBD96893 /* naming */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = naming; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXGroup section */ @@ -51,10 +22,6 @@ CA603C4309E122869D176AE5 /* Products */ = { isa = PBXGroup; children = ( - CA6071B5A0F5A7A3EF2297AA /* librustdesk.dylib */, - CA604C7415FB2A3731F5016A /* liblibrustdesk_static.a */, - CA60D3BC5386D3D7DBD96893 /* naming */, - CA60D3BC5386B357B2AB834F /* rustdesk */, ); name = Products; sourceTree = ""; @@ -70,7 +37,6 @@ CA603C4309E1D65BC3C892A8 = { isa = PBXGroup; children = ( - CA603C4309E13EF4668187A5 /* Cargo.toml */, CA603C4309E122869D176AE5 /* Products */, CA603C4309E198AF0B5890DB /* Frameworks */, ); @@ -78,100 +44,11 @@ }; /* End PBXGroup section */ -/* Begin PBXNativeTarget section */ - CA604C7415FB12977AAB839F /* librustdesk-staticlib */ = { - isa = PBXNativeTarget; - buildConfigurationList = CA6028B9540B12977AAB839F /* Build configuration list for PBXNativeTarget "librustdesk-staticlib" */; - buildPhases = ( - CA6033723F8212977AAB839F /* Sources */, - CA603C4309E1AF6EBB7F357C /* Universal Binary lipo */, - ); - buildRules = ( - CA603C4309E1AC6C1400ACA8 /* PBXBuildRule */, - ); - dependencies = ( - ); - name = "librustdesk-staticlib"; - productName = liblibrustdesk_static.a; - productReference = CA604C7415FB2A3731F5016A /* liblibrustdesk_static.a */; - productType = "com.apple.product-type.library.static"; - }; - CA6071B5A0F5D6691E4C3FF1 /* librustdesk-cdylib */ = { - isa = PBXNativeTarget; - buildConfigurationList = CA6028B9540BD6691E4C3FF1 /* Build configuration list for PBXNativeTarget "librustdesk-cdylib" */; - buildPhases = ( - CA6033723F82D6691E4C3FF1 /* Sources */, - CA603C4309E1AF6EBB7F357C /* Universal Binary lipo */, - ); - buildRules = ( - CA603C4309E1AC6C1400ACA8 /* PBXBuildRule */, - ); - dependencies = ( - ); - name = "librustdesk-cdylib"; - productName = librustdesk.dylib; - productReference = CA6071B5A0F5A7A3EF2297AA /* librustdesk.dylib */; - productType = "com.apple.product-type.library.dynamic"; - }; - CA60D3BC5386C858B7409EE3 /* naming-bin */ = { - isa = PBXNativeTarget; - buildConfigurationList = CA6028B9540BC858B7409EE3 /* Build configuration list for PBXNativeTarget "naming-bin" */; - buildPhases = ( - CA6033723F82C858B7409EE3 /* Sources */, - CA603C4309E1AF6EBB7F357C /* Universal Binary lipo */, - ); - buildRules = ( - CA603C4309E1AC6C1400ACA8 /* PBXBuildRule */, - ); - dependencies = ( - ); - name = "naming-bin"; - productName = naming; - productReference = CA60D3BC5386D3D7DBD96893 /* naming */; - productType = "com.apple.product-type.tool"; - }; - CA60D3BC5386C9FA710A2219 /* rustdesk-bin */ = { - isa = PBXNativeTarget; - buildConfigurationList = CA6028B9540BC9FA710A2219 /* Build configuration list for PBXNativeTarget "rustdesk-bin" */; - buildPhases = ( - CA6033723F82C9FA710A2219 /* Sources */, - CA603C4309E1AF6EBB7F357C /* Universal Binary lipo */, - ); - buildRules = ( - CA603C4309E1AC6C1400ACA8 /* PBXBuildRule */, - ); - dependencies = ( - ); - name = "rustdesk-bin"; - productName = rustdesk; - productReference = CA60D3BC5386B357B2AB834F /* rustdesk */; - productType = "com.apple.product-type.tool"; - }; -/* End PBXNativeTarget section */ - /* Begin PBXProject section */ CA603C4309E1E04653AD465F /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 1300; - TargetAttributes = { - CA604C7415FB12977AAB839F = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Automatic; - }; - CA6071B5A0F5D6691E4C3FF1 = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Automatic; - }; - CA60D3BC5386C858B7409EE3 = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Automatic; - }; - CA60D3BC5386C9FA710A2219 = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Automatic; - }; - }; }; buildConfigurationList = CA603C4309E180E02D6C7F57 /* Build configuration list for PBXProject "rustdesk" */; compatibilityVersion = "Xcode 11.4"; @@ -186,161 +63,11 @@ projectDirPath = ""; projectRoot = ""; targets = ( - CA6071B5A0F5D6691E4C3FF1 /* librustdesk-cdylib */, - CA604C7415FB12977AAB839F /* librustdesk-staticlib */, - CA60D3BC5386C858B7409EE3 /* naming-bin */, - CA60D3BC5386C9FA710A2219 /* rustdesk-bin */, ); }; /* End PBXProject section */ -/* Begin PBXShellScriptBuildPhase section */ - CA603C4309E1AF6EBB7F357C /* Universal Binary lipo */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "$(DERIVED_FILE_DIR)/$(ARCHS)-$(EXECUTABLE_NAME).xcfilelist", - ); - name = "Universal Binary lipo"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(TARGET_BUILD_DIR)/$(EXECUTABLE_PATH)", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "# generated with cargo-xcode 1.4.1\nset -eux; cat \"$DERIVED_FILE_DIR/$ARCHS-$EXECUTABLE_NAME.xcfilelist\" | tr '\\n' '\\0' | xargs -0 lipo -create -output \"$TARGET_BUILD_DIR/$EXECUTABLE_PATH\""; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - CA6033723F8212977AAB839F /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - CA6061C6409F12977AAB839F /* Cargo.toml in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CA6033723F82C858B7409EE3 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - CA6061C6409FC858B7409EE3 /* Cargo.toml in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CA6033723F82C9FA710A2219 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - CA6061C6409FC9FA710A2219 /* Cargo.toml in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CA6033723F82D6691E4C3FF1 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - CA6061C6409FD6691E4C3FF1 /* Cargo.toml in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - /* Begin XCBuildConfiguration section */ - CA604B55B26012977AAB839F /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CARGO_XCODE_CARGO_DEP_FILE_NAME = liblibrustdesk.d; - CARGO_XCODE_CARGO_FILE_NAME = liblibrustdesk.a; - INSTALL_GROUP = ""; - INSTALL_MODE_FLAG = ""; - INSTALL_OWNER = ""; - PRODUCT_NAME = librustdesk_static; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos"; - }; - name = Debug; - }; - CA604B55B260C858B7409EE3 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CARGO_XCODE_CARGO_DEP_FILE_NAME = naming.d; - CARGO_XCODE_CARGO_FILE_NAME = naming; - PRODUCT_NAME = naming; - SUPPORTED_PLATFORMS = macosx; - }; - name = Debug; - }; - CA604B55B260C9FA710A2219 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CARGO_XCODE_CARGO_DEP_FILE_NAME = rustdesk.d; - CARGO_XCODE_CARGO_FILE_NAME = rustdesk; - PRODUCT_NAME = rustdesk; - SUPPORTED_PLATFORMS = macosx; - }; - name = Debug; - }; - CA604B55B260D6691E4C3FF1 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CARGO_XCODE_CARGO_DEP_FILE_NAME = liblibrustdesk.d; - CARGO_XCODE_CARGO_FILE_NAME = liblibrustdesk.dylib; - PRODUCT_NAME = librustdesk; - SUPPORTED_PLATFORMS = macosx; - }; - name = Debug; - }; - CA60583BB9CE12977AAB839F /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CARGO_XCODE_CARGO_DEP_FILE_NAME = liblibrustdesk.d; - CARGO_XCODE_CARGO_FILE_NAME = liblibrustdesk.a; - INSTALL_GROUP = ""; - INSTALL_MODE_FLAG = ""; - INSTALL_OWNER = ""; - PRODUCT_NAME = librustdesk_static; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos"; - }; - name = Release; - }; - CA60583BB9CEC858B7409EE3 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CARGO_XCODE_CARGO_DEP_FILE_NAME = naming.d; - CARGO_XCODE_CARGO_FILE_NAME = naming; - PRODUCT_NAME = naming; - SUPPORTED_PLATFORMS = macosx; - }; - name = Release; - }; - CA60583BB9CEC9FA710A2219 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CARGO_XCODE_CARGO_DEP_FILE_NAME = rustdesk.d; - CARGO_XCODE_CARGO_FILE_NAME = rustdesk; - PRODUCT_NAME = rustdesk; - SUPPORTED_PLATFORMS = macosx; - }; - name = Release; - }; - CA60583BB9CED6691E4C3FF1 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CARGO_XCODE_CARGO_DEP_FILE_NAME = liblibrustdesk.d; - CARGO_XCODE_CARGO_FILE_NAME = liblibrustdesk.dylib; - PRODUCT_NAME = librustdesk; - SUPPORTED_PLATFORMS = macosx; - }; - name = Release; - }; CA608F3F78EE228BE02872F8 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -387,42 +114,6 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - CA6028B9540B12977AAB839F /* Build configuration list for PBXNativeTarget "librustdesk-staticlib" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - CA60583BB9CE12977AAB839F /* Release */, - CA604B55B26012977AAB839F /* Debug */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - CA6028B9540BC858B7409EE3 /* Build configuration list for PBXNativeTarget "naming-bin" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - CA60583BB9CEC858B7409EE3 /* Release */, - CA604B55B260C858B7409EE3 /* Debug */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - CA6028B9540BC9FA710A2219 /* Build configuration list for PBXNativeTarget "rustdesk-bin" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - CA60583BB9CEC9FA710A2219 /* Release */, - CA604B55B260C9FA710A2219 /* Debug */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - CA6028B9540BD6691E4C3FF1 /* Build configuration list for PBXNativeTarget "librustdesk-cdylib" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - CA60583BB9CED6691E4C3FF1 /* Release */, - CA604B55B260D6691E4C3FF1 /* Debug */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; CA603C4309E180E02D6C7F57 /* Build configuration list for PBXProject "rustdesk" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/flutter/pubspec.lock b/flutter/pubspec.lock index 432b15b15..738567b22 100644 --- a/flutter/pubspec.lock +++ b/flutter/pubspec.lock @@ -5,253 +5,260 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "49.0.0" + version: "50.0.0" after_layout: dependency: transitive description: name: after_layout - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.0" analyzer: dependency: transitive description: name: analyzer - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "5.1.0" + version: "5.2.0" animations: dependency: transitive description: name: animations - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.7" archive: dependency: transitive description: name: archive - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.3.1" + version: "3.3.4" args: dependency: transitive description: name: args - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.1" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.9.0" auto_size_text: dependency: "direct main" description: name: auto_size_text - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.0" back_button_interceptor: dependency: "direct main" description: name: back_button_interceptor - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "6.0.1" + version: "6.0.2" + bot_toast: + dependency: "direct main" + description: + name: bot_toast + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.0.3" build: dependency: transitive description: name: build - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.1" build_config: dependency: transitive description: name: build_config - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.0" + version: "1.1.1" build_daemon: dependency: transitive description: name: build_daemon - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.0" build_resolvers: dependency: transitive description: name: build_resolvers - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.10" build_runner: dependency: "direct dev" description: name: build_runner - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.2.1" + version: "2.3.2" build_runner_core: dependency: transitive description: name: build_runner_core - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "7.2.4" + version: "7.2.7" built_collection: dependency: transitive description: name: built_collection - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "5.1.1" built_value: dependency: transitive description: name: built_value - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "8.4.1" + version: "8.4.2" cached_network_image: dependency: transitive description: name: cached_network_image - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.2.1" cached_network_image_platform_interface: dependency: transitive description: name: cached_network_image_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.0" cached_network_image_web: dependency: transitive description: name: cached_network_image_web - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.0" charcode: dependency: transitive description: name: charcode - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.1" checked_yaml: dependency: transitive description: name: checked_yaml - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.1" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" code_builder: dependency: transitive description: name: code_builder - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "4.3.0" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.16.0" contextmenu: dependency: "direct main" description: name: contextmenu - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.0" convert: dependency: transitive description: name: convert - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.2" + version: "3.1.0" cross_file: dependency: transitive description: name: cross_file - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.3.3+2" crypto: dependency: transitive description: name: crypto - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.2" csslib: dependency: transitive description: name: csslib - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.17.2" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.5" dart_style: dependency: transitive description: name: dart_style - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.4" dash_chat_2: dependency: "direct main" description: name: dash_chat_2 - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.0.15" desktop_drop: dependency: "direct main" description: name: desktop_drop - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.3.3" desktop_multi_window: dependency: "direct main" description: path: "." - ref: bf278fc8a8ff787e46fa3ab97674373bfaa20f23 - resolved-ref: bf278fc8a8ff787e46fa3ab97674373bfaa20f23 + ref: "8ee8eb59cabf6ac83a13fe002de7d4a231263a58" + resolved-ref: "8ee8eb59cabf6ac83a13fe002de7d4a231263a58" url: "https://github.com/Kingtous/rustdesk_desktop_multi_window" source: git version: "0.1.0" @@ -259,91 +266,91 @@ packages: dependency: "direct main" description: name: device_info_plus - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "4.1.3" device_info_plus_linux: dependency: transitive description: name: device_info_plus_linux - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.0" device_info_plus_macos: dependency: transitive description: name: device_info_plus_macos - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.0" device_info_plus_platform_interface: dependency: transitive description: name: device_info_plus_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.0" device_info_plus_web: dependency: transitive description: name: device_info_plus_web - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.0" device_info_plus_windows: dependency: transitive description: name: device_info_plus_windows - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "4.1.0" draggable_float_widget: dependency: "direct main" description: name: draggable_float_widget - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.0.2" event_bus: dependency: transitive description: name: event_bus - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.0" external_path: dependency: "direct main" description: name: external_path - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.3" ffi: dependency: "direct main" description: name: ffi - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.1" file: dependency: transitive description: name: file - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "6.1.4" file_picker: dependency: "direct main" description: name: file_picker - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "5.2.1" + version: "5.2.2" fixnum: dependency: transitive description: name: fixnum - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" flutter: @@ -355,29 +362,29 @@ packages: dependency: transitive description: name: flutter_blurhash - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.7.0" flutter_breadcrumb: dependency: "direct main" description: name: flutter_breadcrumb - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" flutter_cache_manager: dependency: transitive description: name: flutter_cache_manager - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.3.0" flutter_custom_cursor: dependency: "direct main" description: path: "." - ref: dec2166e881c47d922e1edc484d10d2cd5c2103b - resolved-ref: dec2166e881c47d922e1edc484d10d2cd5c2103b + ref: bfb19c84a8244771488bc05cc5f9c9b5e0324cfd + resolved-ref: bfb19c84a8244771488bc05cc5f9c9b5e0324cfd url: "https://github.com/Kingtous/rustdesk_flutter_custom_cursor" source: git version: "0.0.1" @@ -385,14 +392,14 @@ packages: dependency: "direct main" description: name: flutter_improved_scrolling - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.0.3" flutter_lints: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.1" flutter_localizations: @@ -404,14 +411,14 @@ packages: dependency: transitive description: name: flutter_parsed_text - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.1" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.7" flutter_rust_bridge: @@ -427,9 +434,9 @@ packages: dependency: "direct main" description: name: flutter_svg - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.5" + version: "1.1.6" flutter_web_plugins: dependency: transitive description: flutter @@ -439,408 +446,415 @@ packages: dependency: "direct dev" description: name: freezed - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.1" + version: "2.2.1" freezed_annotation: dependency: "direct main" description: name: freezed_annotation - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.0" + version: "2.2.0" frontend_server_client: dependency: transitive description: name: frontend_server_client - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.3" + version: "3.1.0" get: dependency: "direct main" description: name: get - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "4.6.5" glob: dependency: transitive description: name: glob - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.0" + version: "2.1.1" graphs: dependency: transitive description: name: graphs - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.0" + version: "2.2.0" html: dependency: transitive description: name: html - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.15.0" + version: "0.15.1" http: dependency: "direct main" description: name: http - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.13.5" http_multi_server: dependency: transitive description: name: http_multi_server - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.2.1" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "4.0.1" + version: "4.0.2" icons_launcher: dependency: "direct dev" description: name: icons_launcher - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.4" image: dependency: "direct main" description: name: image - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.2.0" + version: "3.2.2" image_picker: dependency: "direct main" description: name: image_picker - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.8.6" image_picker_android: dependency: transitive description: name: image_picker_android - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.8.5+3" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.10" image_picker_ios: dependency: transitive description: name: image_picker_ios - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.8.6+1" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.6.2" intl: dependency: transitive description: name: intl - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.17.0" io: dependency: transitive description: name: io - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.3" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.6.4" json_annotation: dependency: transitive description: name: json_annotation - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "4.7.0" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.0" + version: "2.0.1" logging: dependency: transitive description: name: logging - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.12.12" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.1.4" menu_base: dependency: transitive description: name: menu_base - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.1.1" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.7.0" mime: dependency: transitive description: name: mime - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.2" nested: dependency: transitive description: name: nested - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.0" octo_image: dependency: transitive description: name: octo_image - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.2" package_config: dependency: transitive description: name: package_config - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" package_info_plus: dependency: "direct main" description: name: package_info_plus - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.4.3+1" package_info_plus_linux: dependency: transitive description: name: package_info_plus_linux - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.5" package_info_plus_macos: dependency: transitive description: name: package_info_plus_macos - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.0" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.2" package_info_plus_web: dependency: transitive description: name: package_info_plus_web - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.6" package_info_plus_windows: dependency: transitive description: name: package_info_plus_windows - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" path: dependency: "direct main" description: name: path - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.8.1" path_drawing: dependency: transitive description: name: path_drawing - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" path_parsing: dependency: transitive description: name: path_parsing - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" path_provider: dependency: "direct main" description: name: path_provider - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.11" path_provider_android: dependency: transitive description: name: path_provider_android - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.20" + version: "2.0.21" path_provider_ios: dependency: transitive description: name: path_provider_ios - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.11" path_provider_linux: dependency: transitive description: name: path_provider_linux - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.7" path_provider_macos: dependency: transitive description: name: path_provider_macos - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.6" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.5" path_provider_windows: dependency: transitive description: name: path_provider_windows - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.3" pedantic: dependency: transitive description: name: pedantic - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.11.1" petitparser: dependency: transitive description: name: petitparser - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "5.0.0" platform: dependency: transitive description: name: platform - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.3" + pointycastle: + dependency: transitive + description: + name: pointycastle + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.6.2" pool: dependency: transitive description: name: pool - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.5.1" process: dependency: transitive description: name: process - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "4.2.4" provider: dependency: "direct main" description: name: provider - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "6.0.3" + version: "6.0.4" pub_semver: dependency: transitive description: name: pub_semver - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.1" + version: "2.1.3" pubspec_parse: dependency: transitive description: name: pubspec_parse - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.1" qr_code_scanner: dependency: "direct main" description: name: qr_code_scanner - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" rxdart: dependency: "direct main" description: name: rxdart - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.27.5" + version: "0.27.7" screen_retriever: dependency: transitive description: @@ -854,91 +868,35 @@ packages: dependency: "direct main" description: name: scroll_pos - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.3.0" settings_ui: dependency: "direct main" description: name: settings_ui - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.2" - shared_preferences: - dependency: "direct main" - description: - name: shared_preferences - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.15" - shared_preferences_android: - dependency: transitive - description: - name: shared_preferences_android - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.13" - shared_preferences_ios: - dependency: transitive - description: - name: shared_preferences_ios - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - shared_preferences_linux: - dependency: transitive - description: - name: shared_preferences_linux - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - shared_preferences_macos: - dependency: transitive - description: - name: shared_preferences_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.4" - shared_preferences_platform_interface: - dependency: transitive - description: - name: shared_preferences_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - shared_preferences_web: - dependency: transitive - description: - name: shared_preferences_web - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.4" - shared_preferences_windows: - dependency: transitive - description: - name: shared_preferences_windows - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" shelf: dependency: transitive description: name: shelf - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.4.0" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.2" + version: "1.0.3" shortid: dependency: transitive description: name: shortid - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.1.2" sky_engine: @@ -950,84 +908,84 @@ packages: dependency: transitive description: name: source_gen - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.2.5" + version: "1.2.6" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.9.1" sqflite: dependency: transitive description: name: sqflite - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.3+1" sqflite_common: dependency: transitive description: name: sqflite_common - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.3.0" + version: "2.4.0" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.1" stream_transform: dependency: transitive description: name: stream_transform - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.1" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.1" synchronized: dependency: transitive description: name: synchronized - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.0+3" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.1" timing: dependency: transitive description: name: timing - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.0" toggle_switch: dependency: "direct main" description: name: toggle_switch - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.4.0" tray_manager: @@ -1043,232 +1001,234 @@ packages: dependency: "direct main" description: name: tuple - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.1" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.1" uni_links: dependency: "direct main" description: name: uni_links - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.5.1" uni_links_desktop: dependency: "direct main" description: - name: uni_links_desktop - url: "https://pub.dartlang.org" - source: hosted + path: "." + ref: "5be5113d59c753989dbf1106241379e3fd4c9b18" + resolved-ref: "5be5113d59c753989dbf1106241379e3fd4c9b18" + url: "https://github.com/fufesou/uni_links_desktop.git" + source: git version: "0.1.3" uni_links_platform_interface: dependency: transitive description: name: uni_links_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.0" uni_links_web: dependency: transitive description: name: uni_links_web - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.1.0" universal_io: dependency: transitive description: name: universal_io - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.4" url_launcher: dependency: "direct main" description: name: url_launcher - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "6.1.6" url_launcher_android: dependency: transitive description: name: url_launcher_android - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "6.0.19" + version: "6.0.21" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "6.0.17" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.1" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.1" url_launcher_web: dependency: transitive description: name: url_launcher_web - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.13" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.1" uuid: dependency: transitive description: name: uuid - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.6" + version: "3.0.7" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.2" video_player: dependency: transitive description: name: video_player - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.4.7" video_player_android: dependency: transitive description: name: video_player_android - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.9" video_player_avfoundation: dependency: transitive description: name: video_player_avfoundation - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.7" video_player_platform_interface: dependency: transitive description: name: video_player_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "5.1.4" video_player_web: dependency: transitive description: name: video_player_web - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.12" visibility_detector: dependency: "direct main" description: name: visibility_detector - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.3.3" wakelock: dependency: "direct main" description: name: wakelock - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.6.2" wakelock_macos: dependency: transitive description: name: wakelock_macos - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.4.0" wakelock_platform_interface: dependency: transitive description: name: wakelock_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.3.0" wakelock_web: dependency: transitive description: name: wakelock_web - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.4.0" wakelock_windows: dependency: transitive description: name: wakelock_windows - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.1" watcher: dependency: transitive description: name: watcher - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.1" + version: "1.0.2" web_socket_channel: dependency: transitive description: name: web_socket_channel - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.0" win32: dependency: transitive description: name: win32 - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.0" + version: "3.1.1" win32_registry: dependency: transitive description: name: win32_registry - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.2" window_manager: dependency: "direct main" description: path: "." - ref: "88487257cbafc501599ab4f82ec343b46acec020" - resolved-ref: "88487257cbafc501599ab4f82ec343b46acec020" + ref: "32b24c66151b72bba033ef8b954486aa9351d97b" + resolved-ref: "32b24c66151b72bba033ef8b954486aa9351d97b" url: "https://github.com/Kingtous/rustdesk_window_manager" source: git version: "0.2.7" @@ -1285,28 +1245,28 @@ packages: dependency: transitive description: name: xdg_directories - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.0+2" xml: dependency: transitive description: name: xml - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "6.1.0" yaml: dependency: transitive description: name: yaml - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.1" zxing2: dependency: "direct main" description: name: zxing2 - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.1.0" sdks: From 1491dea9d81473cb66070e280226e1470da6228c Mon Sep 17 00:00:00 2001 From: Kingtous Date: Mon, 21 Nov 2022 17:10:38 +0800 Subject: [PATCH 103/116] fix: nightly build --- .github/workflows/flutter-nightly.yml | 372 ++++++++++++++++++++------ build.py | 35 ++- 2 files changed, 309 insertions(+), 98 deletions(-) diff --git a/.github/workflows/flutter-nightly.yml b/.github/workflows/flutter-nightly.yml index 0b49b9893..76b82044d 100644 --- a/.github/workflows/flutter-nightly.yml +++ b/.github/workflows/flutter-nightly.yml @@ -10,7 +10,9 @@ env: LLVM_VERSION: "10.0" FLUTTER_VERSION: "3.0.5" TAG_NAME: "nightly" - VCPKG_COMMIT_ID: '6ca56aeb457f033d344a7106cb3f9f1abf8f4e98' + # vcpkg version: 2022.05.10 + # for multiarch gcc compatibility + VCPKG_COMMIT_ID: "14e7bb4ae24616ec54ff6b2f6ef4e8659434ea44" VERSION: "1.2.0" jobs: @@ -23,7 +25,7 @@ jobs: job: # - { target: i686-pc-windows-msvc , os: windows-2019 } # - { target: x86_64-pc-windows-gnu , os: windows-2019 } - - { target: x86_64-pc-windows-msvc , os: windows-2019 } + - { target: x86_64-pc-windows-msvc, os: windows-2019 } steps: - name: Checkout source code uses: actions/checkout@v3 @@ -36,9 +38,9 @@ jobs: - name: Install flutter uses: subosito/flutter-action@v2 with: - channel: 'stable' + channel: "stable" flutter-version: ${{ env.FLUTTER_VERSION }} - + - name: Replace engine with rustdesk custom flutter engine run: | flutter doctor -v @@ -100,18 +102,22 @@ jobs: files: | rustdesk-*.exe - builf-for-macOS: + build-for-macOS: name: ${{ matrix.job.target }} (${{ matrix.job.os }},${{ matrix.job.extra-build-args }}) runs-on: ${{ matrix.job.os }} strategy: fail-fast: false matrix: job: - - { target: x86_64-apple-darwin , os: macos-10.15, extra-build-args: ""} + - { + target: x86_64-apple-darwin, + os: macos-10.15, + extra-build-args: "", + } steps: - name: Checkout source code uses: actions/checkout@v3 - + - name: Install build runtime run: | brew install llvm create-dmg nasm yasm cmake gcc wget ninja @@ -119,7 +125,7 @@ jobs: - name: Install flutter uses: subosito/flutter-action@v2 with: - channel: 'stable' + channel: "stable" flutter-version: ${{ env.FLUTTER_VERSION }} - name: Install Rust toolchain @@ -143,7 +149,7 @@ jobs: pushd /tmp/flutter_rust_bridge/frb_codegen && cargo install --path . && popd pushd flutter && flutter pub get && popd ~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart - + - name: Restore from cache and install vcpkg uses: lukka/run-vcpkg@v7 with: @@ -187,47 +193,85 @@ jobs: files: | rustdesk*-${{ matrix.job.target }}.dmg - build-for-linux: - name: ${{ matrix.job.target }} (${{ matrix.job.os }},${{ matrix.job.extra-build-args }}) + build-vcpkg-deps-linux: runs-on: ${{ matrix.job.os }} strategy: fail-fast: false matrix: job: - # - { target: aarch64-unknown-linux-gnu , os: ubuntu-18.04, use-cross: true } - # - { target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true } - # - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true } - # - { target: i686-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true } - # - { target: i686-unknown-linux-musl , os: ubuntu-20.04, use-cross: true } - - { target: x86_64-unknown-linux-gnu , os: ubuntu-18.04, extra-build-args: ""} - - { target: x86_64-unknown-linux-gnu , os: ubuntu-18.04, extra-build-args: "--flatpak"} - # - { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true } + # - { arch: armv7 , os: ubuntu-18.04} + - { arch: x86_64, os: ubuntu-18.04 } + # - { arch: aarch64 , os: ubuntu-18.04} + steps: + - name: Create vcpkg artifacts folder + run: mkdir -p /opt/artifacts + + - name: Cache Vcpkg + id: cache-vcpkg + uses: actions/cache@v3 + with: + path: /opt/artifacts + key: vcpkg-${{ matrix.job.arch }} + + - uses: Kingtous/run-on-arch-action@amd64-support + name: Run vcpkg install on ${{ matrix.job.arch }} + id: vcpkg + with: + arch: ${{ matrix.job.arch }} + distro: ubuntu18.04 + githubToken: ${{ github.token }} + setup: | + ls -l "/opt/artifacts" + dockerRunArgs: | + --volume "/opt/artifacts:/artifacts" + shell: /bin/bash + install: | + apt update -y + # CMake 3.15+ + apt install -y gpg wget ca-certificates + echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ bionic main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null + wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null + apt update -y + apt install -y curl zip unzip tar git cmake g++ gcc build-essential pkg-config wget nasm yasm ninja-build + cmake --version + gcc -v + run: | + export VCPKG_FORCE_SYSTEM_BINARIES=1 + pushd /artifacts + git clone https://github.com/microsoft/vcpkg.git || true + git config --global --add safe.directory /artifacts/vcpkg || true + pushd vcpkg + git reset --hard ${{ env.VCPKG_COMMIT_ID }} + ./bootstrap-vcpkg.sh + ./vcpkg install libvpx libyuv opus + + - name: Upload artifacts + uses: actions/upload-artifact@master + with: + name: vcpkg-artifact-${{ matrix.job.arch }} + path: | + /opt/artifacts/vcpkg/installed + + generate-bridge-linux: + name: generate bridge + runs-on: ${{ matrix.job.os }} + strategy: + fail-fast: false + matrix: + job: + - { + target: x86_64-unknown-linux-gnu, + os: ubuntu-18.04, + extra-build-args: "", + } steps: - name: Checkout source code uses: actions/checkout@v3 - - name: Get build target triple - uses: jungwinter/split@v2 - id: build-target-triple - with: - separator: '-' - msg: ${{ matrix.job.target }} - - name: Install prerequisites run: | - case ${{ matrix.job.target }} in - x86_64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt install -y g++ gcc;; - arm-unknown-linux-*) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;; - aarch64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt-get -y install gcc-aarch64-linux-gnu ;; - esac - # common package - sudo apt 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 libclang-dev llvm-dev libclang-10-dev llvm-10-dev - - - name: Install flutter - uses: subosito/flutter-action@v2 - with: - channel: 'stable' - flutter-version: ${{ env.FLUTTER_VERSION }} + sudo apt update -y + sudo apt install -y g++ gcc 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 libclang-dev llvm-dev libclang-10-dev llvm-10-dev pkg-config - name: Install Rust toolchain uses: actions-rs/toolchain@v1 @@ -239,49 +283,210 @@ jobs: - uses: Swatinem/rust-cache@v2 with: - prefix-key: ${{ matrix.job.os }} + prefix-key: bridge-${{ matrix.job.os }} + + - name: Cache Bridge + id: cache-bridge + uses: actions/cache@v3 + with: + path: /tmp/flutter_rust_bridge + key: vcpkg-${{ matrix.job.arch }} + + - name: Install flutter + uses: subosito/flutter-action@v2 + with: + channel: "stable" + flutter-version: ${{ env.FLUTTER_VERSION }} + + - name: Install ffigen + run: | + dart pub global activate ffigen --version 5.0.1 - name: Install flutter rust bridge deps shell: bash run: | - dart pub global activate ffigen --version 5.0.1 - # flutter_rust_bridge - pushd /tmp && git clone https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge --depth=1 && popd + pushd /tmp && git clone https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge --depth=1 || true && popd pushd /tmp/flutter_rust_bridge/frb_codegen && cargo install --path . && popd pushd flutter && flutter pub get && popd + + - name: Run flutter rust bridge + run: | ~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart - - name: Restore from cache and install vcpkg - uses: lukka/run-vcpkg@v7 + - name: Upload Artifcat + uses: actions/upload-artifact@master with: - setupOnly: true - vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }} + name: bridge-artifact + path: | + ./src/bridge_generated.rs + ./flutter/lib/generated_bridge.dart + ./flutter/lib/generated_bridge.freezed.dart - - name: Install vcpkg dependencies + build-rustdesk-lib-linux: + needs: [generate-bridge-linux, build-vcpkg-deps-linux] + name: build-rust-lib ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-features }}] + runs-on: ${{ matrix.job.os }} + strategy: + fail-fast: false + matrix: + job: + # - { arch: aarch64, target: aarch64-unknown-linux-gnu , os: ubuntu-18.04, use-cross: true, extra-build-features: "" } + # - { arch: aarch64, target: aarch64-unknown-linux-gnu , os: ubuntu-18.04, use-cross: true, extra-build-features: "flatpak" } + # - { arch: armv7, target: arm-unknown-linux-gnueabihf , os: ubuntu-18.04, use-cross: true, extra-build-features: "" } + # - { arch: armv7, target: arm-unknown-linux-gnueabihf , os: ubuntu-18.04, use-cross: true, extra-build-features: "flatpak" } + # - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true } + # - { target: i686-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true } + # - { target: i686-unknown-linux-musl , os: ubuntu-20.04, use-cross: true } + - { + arch: x86_64, + target: x86_64-unknown-linux-gnu, + os: ubuntu-18.04, + extra-build-features: "", + } + - { + arch: x86_64, + target: x86_64-unknown-linux-gnu, + os: ubuntu-18.04, + extra-build-features: "flatpak", + } + # - { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true } + steps: + - name: Checkout source code + uses: actions/checkout@v3 + + - name: Install Rust toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + target: ${{ matrix.job.target }} + override: true + profile: minimal # minimal component installation (ie, no documentation) + + - uses: Swatinem/rust-cache@v2 + with: + prefix-key: bridge-${{ matrix.job.os }} + + - name: Disable rust bridge build run: | + sed -i "s/gen_flutter_rust_bridge();/\/\//g" build.rs + + - name: Restore bridge files + uses: actions/download-artifact@master + with: + name: bridge-artifact + path: ./ + + - name: Restore vcpkg files + uses: actions/download-artifact@master + with: + name: vcpkg-artifact-${{ matrix.job.arch }} + path: /opt/artifacts/vcpkg/installed + + - name: Output devs + run: | + ls -l ./ + tree -L 3 /opt/artifacts/vcpkg/installed + + - name: Install prerequisites + run: | + sudo apt update -y case ${{ matrix.job.target }} in - x86_64-unknown-linux-gnu) $VCPKG_ROOT/vcpkg install libvpx libyuv opus;; - arm-unknown-linux-*) $VCPKG_ROOT/vcpkg install libvpx:arm-linux libyuv:arm-linux opus:arm-linux;; - aarch64-unknown-linux-gnu) $VCPKG_ROOT/vcpkg install libvpx:arm64-linux libyuv:arm64-linux opus:arm64-linux;; + x86_64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt install -y g++ gcc;; + arm-unknown-linux-*) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;; + aarch64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt-get -y install gcc-aarch64-linux-gnu ;; esac - shell: bash + # common package + sudo apt 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 libclang-dev llvm-dev libclang-10-dev llvm-10-dev pkg-config tree - - name: Install cargo bundle tools + - name: Build rustdesk lib run: | - cargo install cargo-bundle + export VCPKG_ROOT=/opt/artifacts/vcpkg + cargo build --lib --features hwcodec,flutter,${{ matrix.job.extra-build-features }} --release - - name: Show version information (Rust, cargo, GCC) - shell: bash + - name: Upload Artifacts + uses: actions/upload-artifact@master + with: + name: librustdesk-${{ matrix.job.arch }}-${{ matrix.job.extra-build-features }}.so + path: target/release/liblibrustdesk.so + + build-rustdesk-linux: + needs: [build-rustdesk-lib-linux] + name: build-rustdesk ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-args }}] + runs-on: ${{ matrix.job.os }} + strategy: + fail-fast: false + matrix: + job: + # - { arch: aarch64, target: aarch64-unknown-linux-gnu , os: ubuntu-18.04, use-cross: true, extra-build-features: "" } + # - { arch: aarch64, target: aarch64-unknown-linux-gnu , os: ubuntu-18.04, use-cross: true, extra-build-features: "flatpak" } + # - { arch: armv7, target: arm-unknown-linux-gnueabihf , os: ubuntu-18.04, use-cross: true, extra-build-features: "" } + # - { arch: armv7, target: arm-unknown-linux-gnueabihf , os: ubuntu-18.04, use-cross: true, extra-build-features: "flatpak" } + # - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true } + # - { target: i686-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true } + # - { target: i686-unknown-linux-musl , os: ubuntu-20.04, use-cross: true } + - { + arch: x86_64, + target: x86_64-unknown-linux-gnu, + os: ubuntu-18.04, + extra-build-features: "", + } + - { + arch: x86_64, + target: x86_64-unknown-linux-gnu, + os: ubuntu-18.04, + extra-build-features: "flatpak", + } + # - { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true } + steps: + - name: Checkout source code + uses: actions/checkout@v3 + + - name: Restore bridge files + uses: actions/download-artifact@master + with: + name: bridge-artifact + path: ./ + + - name: Prepare env run: | - gcc --version || true - rustup -V - rustup toolchain list - rustup default - cargo -V - rustc -V + sudo apt update -y + sudo apt install -y git curl wget nasm yasm libgtk-3-dev + mkdir -p ./target/release/ - - name: Build rustdesk - run: ./build.py --flutter --hwcodec ${{ matrix.job.extra-build-args }} + - name: Restore rust lib files + uses: actions/download-artifact@master + with: + name: librustdesk-${{ matrix.job.arch }}-${{ matrix.job.extra-build-features }}.so + path: ./target/release/liblibrustdesk.so + + - uses: Kingtous/run-on-arch-action@amd64-support + name: Run vcpkg install on ${{ matrix.job.arch }} + id: vcpkg + with: + arch: ${{ matrix.job.arch }} + distro: ubuntu18.04 + githubToken: ${{ github.token }} + setup: | + ls -l "${PWD}" + dockerRunArgs: | + --volume "${PWD}:/workspace" + --volume "/opt/artifacts:/opt/artifacts" + shell: /bin/bash + install: | + apt update -y + apt 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 + run: | + # disable git safe.directory + git config --global --add safe.directory "*" + # Setup Flutter + pushd /opt + wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_${{ env.FLUTTER_VERSION }}-stable.tar.xz + tar xf flutter_linux_${{ env.FLUTTER_VERSION }}-stable.tar.xz + ls -l . + export PATH=/opt/flutter/bin:$PATH + flutter doctor -v + pushd /workspace + python3 ./build.py --flutter --hwcodec --skip-cargo - name: Rename rustdesk shell: bash @@ -297,21 +502,21 @@ jobs: tag_name: ${{ env.TAG_NAME }} files: | rustdesk-${{ env.VERSION }}-${{ matrix.job.target }}-${{ matrix.job.os }}.deb - + - name: Upload Artifcat uses: actions/upload-artifact@master - if: ${{ contains(matrix.job.extra-build-args, 'flatpak') }} + if: ${{ contains(matrix.job.extra-build-features, 'flatpak') }} with: name: rustdesk-${{ env.VERSION }}-${{ matrix.job.target }}-${{ matrix.job.os }}.deb path: rustdesk-${{ env.VERSION }}-${{ matrix.job.target }}-${{ matrix.job.os }}.deb - name: Patch archlinux PKGBUILD - if: ${{ matrix.job.extra-build-args == '' }} + if: ${{ matrix.job.extra-build-features == '' }} run: | - sed -i "s/arch=('x86_64')/arch=('${{ steps.build-target-triple.outputs._0 }}')/g" res/PKGBUILD + sed -i "s/arch=('x86_64')/arch=('${{ matrix.job.arch }}')/g" res/PKGBUILD - name: Build archlinux package - if: ${{ matrix.job.extra-build-args == '' }} + if: ${{ matrix.job.extra-build-features == '' }} uses: vufa/arch-makepkg-action@master with: packages: > @@ -346,7 +551,7 @@ jobs: cd res && HBB=`pwd`/.. FLUTTER=1 makepkg -f - name: Publish archlinux package - if: ${{ matrix.job.extra-build-args == '' }} + if: ${{ matrix.job.extra-build-features == '' }} uses: softprops/action-gh-release@v1 with: prerelease: true @@ -356,40 +561,34 @@ jobs: - name: Make RPM package shell: bash - if: ${{ matrix.job.extra-build-args == '' }} + if: ${{ matrix.job.extra-build-features == '' }} run: | sudo apt install -y rpm HBB=`pwd` rpmbuild ./res/rpm-flutter.spec -bb - pushd ~/rpmbuild/RPMS/${{ steps.build-target-triple.outputs._0 }} + pushd ~/rpmbuild/RPMS/${{ matrix.job.arch }} for name in rustdesk*??.rpm; do mv "$name" "${name%%.rpm}-fedora28-centos8.rpm" done - name: Publish fedora28/centos8 package - if: ${{ matrix.job.extra-build-args == '' }} + if: ${{ matrix.job.extra-build-features == '' }} uses: softprops/action-gh-release@v1 with: prerelease: true tag_name: ${{ env.TAG_NAME }} files: | - /home/runner/rpmbuild/RPMS/${{ steps.build-target-triple.outputs._0 }}/*.rpm + /home/runner/rpmbuild/RPMS/${{ matrix.job.arch }}/*.rpm build-flatpak: name: Build Flatpak - needs: [build-for-linux] + needs: [build-rustdesk-linux] runs-on: ${{ matrix.job.os }} strategy: fail-fast: false matrix: job: - - { target: aarch64-unknown-linux-gnu , os: ubuntu-18.04, use-cross: true } - # - { target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true } - # - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true } - # - { target: i686-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true } - # - { target: i686-unknown-linux-musl , os: ubuntu-20.04, use-cross: true } - # - { target: x86_64-apple-darwin , os: macos-10.15 } - - { target: x86_64-unknown-linux-gnu , os: ubuntu-18.04, arch: x86_64} - # - { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true } + # - { target: aarch64-unknown-linux-gnu , os: ubuntu-18.04, use-cross: true, arch: arm64 } + - { target: x86_64-unknown-linux-gnu, os: ubuntu-18.04, arch: x86_64 } steps: - name: Checkout source code uses: actions/checkout@v3 @@ -404,11 +603,11 @@ jobs: with: name: rustdesk-${{ env.VERSION }}-${{ matrix.job.target }}-${{ matrix.job.os }}.deb path: . - - - name: Rename Binary + + - name: Rename Binary run: | mv rustdesk-${{ env.VERSION }}-${{ matrix.job.target }}-${{ matrix.job.os }}.deb rustdesk-${{ env.VERSION }}.deb - + - name: Install Flatpak deps run: | flatpak --user remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo @@ -429,4 +628,3 @@ jobs: tag_name: ${{ env.TAG_NAME }} files: | flatpak/rustdesk-${{ env.VERSION }}-${{ matrix.job.target }}.flatpak - diff --git a/build.py b/build.py index 445eb15bf..aa98ec17e 100755 --- a/build.py +++ b/build.py @@ -15,6 +15,7 @@ osx = platform.platform().startswith( hbb_name = 'rustdesk' + ('.exe' if windows else '') exe_path = 'target/release/' + hbb_name flutter_win_target_dir = 'flutter/build/windows/runner/Release/' +skip_cargo = False def get_version(): @@ -87,6 +88,11 @@ def make_parser(): action='store_true', help='Build rustdesk libs with the flatpak feature enabled' ) + parser.add_argument( + '--skip-cargo', + action='store_true', + help='Skip cargo build process, only flutter version + Linux supported currently' + ) return parser @@ -227,8 +233,9 @@ def ffi_bindgen_function_refactor(): def build_flutter_deb(version, features): - os.system(f'cargo build --features {features} --lib --release') - ffi_bindgen_function_refactor() + if not skip_cargo: + os.system(f'cargo build --features {features} --lib --release') + ffi_bindgen_function_refactor() os.chdir('flutter') os.system('flutter build linux --release') os.system('mkdir -p tmpdeb/usr/bin/') @@ -236,7 +243,6 @@ def build_flutter_deb(version, features): os.system('mkdir -p tmpdeb/usr/share/rustdesk/files/systemd/') os.system('mkdir -p tmpdeb/usr/share/applications/') os.system('mkdir -p tmpdeb/usr/share/polkit-1/actions') - os.system('rm tmpdeb/usr/bin/rustdesk') os.system( 'cp -r build/linux/x64/release/bundle/* tmpdeb/usr/lib/rustdesk/') @@ -266,7 +272,8 @@ def build_flutter_deb(version, features): def build_flutter_dmg(version, features): - os.system(f'cargo build --features {features} --lib --release') + if not skip_cargo: + os.system(f'cargo build --features {features} --lib --release') # copy dylib os.system( "cp target/release/liblibrustdesk.dylib target/release/librustdesk.dylib") @@ -282,7 +289,8 @@ def build_flutter_dmg(version, features): def build_flutter_arch_manjaro(version, features): - os.system(f'cargo build --features {features} --lib --release') + if not skip_cargo: + os.system(f'cargo build --features {features} --lib --release') ffi_bindgen_function_refactor() os.chdir('flutter') os.system('flutter build linux --release') @@ -292,10 +300,11 @@ def build_flutter_arch_manjaro(version, features): def build_flutter_windows(version, features): - os.system(f'cargo build --features {features} --lib --release') - if not os.path.exists("target/release/librustdesk.dll"): - print("cargo build failed, please check rust source code.") - exit(-1) + if not skip_cargo: + os.system(f'cargo build --features {features} --lib --release') + if not os.path.exists("target/release/librustdesk.dll"): + print("cargo build failed, please check rust source code.") + exit(-1) os.chdir('flutter') os.system('flutter build windows --release') os.chdir('..') @@ -320,6 +329,7 @@ def build_flutter_windows(version, features): def main(): + global skip_cargo parser = make_parser() args = parser.parse_args() @@ -339,6 +349,9 @@ def main(): flutter = args.flutter if not flutter: os.system('python3 res/inline-sciter.py') + print(args.skip_cargo) + if args.skip_cargo: + skip_cargo = True portable = args.portable if windows: # build virtual display dynamic library @@ -401,8 +414,8 @@ def main(): build_flutter_dmg(version, features) pass else: - os.system( - 'mv target/release/bundle/deb/rustdesk*.deb ./flutter/rustdesk.deb') + # os.system( + # 'mv target/release/bundle/deb/rustdesk*.deb ./flutter/rustdesk.deb') build_flutter_deb(version, features) else: os.system('cargo bundle --release --features ' + features) From 649543dfea24b859af56c70528737d1db1cbe642 Mon Sep 17 00:00:00 2001 From: Kingtous Date: Tue, 22 Nov 2022 19:48:26 +0800 Subject: [PATCH 104/116] opt: ci step name --- .github/workflows/flutter-nightly.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/flutter-nightly.yml b/.github/workflows/flutter-nightly.yml index 76b82044d..57d6ae504 100644 --- a/.github/workflows/flutter-nightly.yml +++ b/.github/workflows/flutter-nightly.yml @@ -103,7 +103,7 @@ jobs: rustdesk-*.exe build-for-macOS: - name: ${{ matrix.job.target }} (${{ matrix.job.os }},${{ matrix.job.extra-build-args }}) + name: ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-args }}] runs-on: ${{ matrix.job.os }} strategy: fail-fast: false @@ -460,7 +460,7 @@ jobs: path: ./target/release/liblibrustdesk.so - uses: Kingtous/run-on-arch-action@amd64-support - name: Run vcpkg install on ${{ matrix.job.arch }} + name: Build rustdesk binary for ${{ matrix.job.arch }} id: vcpkg with: arch: ${{ matrix.job.arch }} From 0862057b855f7fba69d0492a70c94731ddd1a441 Mon Sep 17 00:00:00 2001 From: Kingtous Date: Tue, 22 Nov 2022 20:27:20 +0800 Subject: [PATCH 105/116] fix: so rename --- .github/workflows/flutter-nightly.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/flutter-nightly.yml b/.github/workflows/flutter-nightly.yml index 57d6ae504..251d5b52c 100644 --- a/.github/workflows/flutter-nightly.yml +++ b/.github/workflows/flutter-nightly.yml @@ -453,11 +453,17 @@ jobs: sudo apt install -y git curl wget nasm yasm libgtk-3-dev mkdir -p ./target/release/ - - name: Restore rust lib files + - name: Restore the rustdesk lib file uses: actions/download-artifact@master with: name: librustdesk-${{ matrix.job.arch }}-${{ matrix.job.extra-build-features }}.so - path: ./target/release/liblibrustdesk.so + path: ./target/release/ + + - name: Rename the rustdesk lib file + shell: bash + run: | + pushd ./target/release + mv librustdesk-${{ matrix.job.arch }}-${{ matrix.job.extra-build-features }}.so librustdesk.so - uses: Kingtous/run-on-arch-action@amd64-support name: Build rustdesk binary for ${{ matrix.job.arch }} From 4a3dd3a5afbc9ca600f6579fb2563b3ce8ece3e1 Mon Sep 17 00:00:00 2001 From: kingtous Date: Tue, 22 Nov 2022 20:30:22 +0800 Subject: [PATCH 106/116] opt: relative macos dylib --- Cargo.toml | 1 + flutter/lib/models/native_model.dart | 4 +++- flutter/macos/Runner.xcodeproj/project.pbxproj | 10 ++++++---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6375bce26..c7b0c51b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -161,3 +161,4 @@ codegen-units = 1 panic = 'abort' strip = true #opt-level = 'z' # only have smaller size after strip +rpath = true \ No newline at end of file diff --git a/flutter/lib/models/native_model.dart b/flutter/lib/models/native_model.dart index e8aad8638..d29e0fd2c 100644 --- a/flutter/lib/models/native_model.dart +++ b/flutter/lib/models/native_model.dart @@ -96,7 +96,9 @@ class PlatformFFI { ? DynamicLibrary.open('librustdesk.so') : Platform.isWindows ? DynamicLibrary.open('librustdesk.dll') - : DynamicLibrary.process(); + : Platform.isMacOS + ? DynamicLibrary.open("liblibrustdesk.dylib") + : DynamicLibrary.process(); debugPrint('initializing FFI $_appType'); try { _translate = dylib.lookupFunction('translate'); diff --git a/flutter/macos/Runner.xcodeproj/project.pbxproj b/flutter/macos/Runner.xcodeproj/project.pbxproj index 8a44007a9..5f369ea9e 100644 --- a/flutter/macos/Runner.xcodeproj/project.pbxproj +++ b/flutter/macos/Runner.xcodeproj/project.pbxproj @@ -26,7 +26,8 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; - 84010B42292B58A400152837 /* liblibrustdesk.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 84010B41292B585400152837 /* liblibrustdesk.a */; }; + 84010BA8292CF66600152837 /* liblibrustdesk.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 84010BA7292CF66600152837 /* liblibrustdesk.dylib */; settings = {ATTRIBUTES = (Weak, ); }; }; + 84010BA9292CF68300152837 /* liblibrustdesk.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 84010BA7292CF66600152837 /* liblibrustdesk.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; C5E54335B73C89F72DB1B606 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26C84465887F29AE938039CB /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ @@ -47,6 +48,7 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( + 84010BA9292CF68300152837 /* liblibrustdesk.dylib in Embed Libraries */, ); name = "Embed Libraries"; runOnlyForDeploymentPostprocessing = 0; @@ -72,7 +74,7 @@ 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; 7436B85D94E8F7B5A9324869 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; - 84010B41292B585400152837 /* liblibrustdesk.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = liblibrustdesk.a; path = ../../target/release/liblibrustdesk.a; sourceTree = ""; }; + 84010BA7292CF66600152837 /* liblibrustdesk.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = liblibrustdesk.dylib; path = ../../target/release/liblibrustdesk.dylib; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; C3BB669FF6190AE1B11BCAEA /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; CCB6FE9A2848A6B800E58D48 /* bridge_generated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bridge_generated.h; path = Runner/bridge_generated.h; sourceTree = ""; }; @@ -84,7 +86,7 @@ buildActionMask = 2147483647; files = ( C5E54335B73C89F72DB1B606 /* Pods_Runner.framework in Frameworks */, - 84010B42292B58A400152837 /* liblibrustdesk.a in Frameworks */, + 84010BA8292CF66600152837 /* liblibrustdesk.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -170,7 +172,7 @@ D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( - 84010B41292B585400152837 /* liblibrustdesk.a */, + 84010BA7292CF66600152837 /* liblibrustdesk.dylib */, 26C84465887F29AE938039CB /* Pods_Runner.framework */, ); name = Frameworks; From 9bbe2919a1bf423feef9770681197defcc4e53f6 Mon Sep 17 00:00:00 2001 From: Kingtous Date: Tue, 22 Nov 2022 20:52:50 +0800 Subject: [PATCH 107/116] fix: linux ci --- .github/workflows/flutter-nightly.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/flutter-nightly.yml b/.github/workflows/flutter-nightly.yml index 251d5b52c..499a5f996 100644 --- a/.github/workflows/flutter-nightly.yml +++ b/.github/workflows/flutter-nightly.yml @@ -459,12 +459,6 @@ jobs: name: librustdesk-${{ matrix.job.arch }}-${{ matrix.job.extra-build-features }}.so path: ./target/release/ - - name: Rename the rustdesk lib file - shell: bash - run: | - pushd ./target/release - mv librustdesk-${{ matrix.job.arch }}-${{ matrix.job.extra-build-features }}.so librustdesk.so - - uses: Kingtous/run-on-arch-action@amd64-support name: Build rustdesk binary for ${{ matrix.job.arch }} id: vcpkg From 064322715435d73c332aac9597167a3e60e98f84 Mon Sep 17 00:00:00 2001 From: kingtous Date: Tue, 22 Nov 2022 23:01:42 +0800 Subject: [PATCH 108/116] fix: macos titlebar --- flutter/lib/main.dart | 11 ++++--- flutter/macos/Runner/MainFlutterWindow.swift | 31 ++++++++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index 989ba12f5..e83c4b323 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -42,7 +42,9 @@ Future main(List args) async { if (args.isNotEmpty && args.first == 'multi_window') { windowId = int.parse(args[1]); stateGlobal.setWindowId(windowId!); - WindowController.fromWindowId(windowId!).showTitleBar(false); + if (!Platform.isMacOS) { + WindowController.fromWindowId(windowId!).showTitleBar(false); + } final argument = args[2].isEmpty ? {} : jsonDecode(args[2]) as Map; @@ -168,13 +170,14 @@ void runMultiWindow( ); switch (appType) { case kAppTypeDesktopRemote: - await restoreWindowPosition(WindowType.RemoteDesktop, windowId: windowId!); + await restoreWindowPosition(WindowType.RemoteDesktop, + windowId: windowId!); break; case kAppTypeDesktopFileTransfer: - await restoreWindowPosition(WindowType.FileTransfer, windowId: windowId!); + await restoreWindowPosition(WindowType.FileTransfer, windowId: windowId!); break; case kAppTypeDesktopPortForward: - await restoreWindowPosition(WindowType.PortForward, windowId: windowId!); + await restoreWindowPosition(WindowType.PortForward, windowId: windowId!); break; default: // no such appType diff --git a/flutter/macos/Runner/MainFlutterWindow.swift b/flutter/macos/Runner/MainFlutterWindow.swift index 688292371..2ebdf7fc0 100644 --- a/flutter/macos/Runner/MainFlutterWindow.swift +++ b/flutter/macos/Runner/MainFlutterWindow.swift @@ -1,7 +1,22 @@ import Cocoa import FlutterMacOS +import desktop_multi_window // import bitsdojo_window_macos +import desktop_drop +import device_info_plus_macos +import flutter_custom_cursor +import package_info_plus_macos +import path_provider_macos +import screen_retriever +import sqflite +import tray_manager +import uni_links_desktop +import url_launcher_macos +import wakelock_macos +import window_manager +import window_size + class MainFlutterWindow: NSWindow { override func awakeFromNib() { if (!rustdesk_core_main()){ @@ -14,6 +29,22 @@ class MainFlutterWindow: NSWindow { self.setFrame(windowFrame, display: true) RegisterGeneratedPlugins(registry: flutterViewController) + + FlutterMultiWindowPlugin.setOnWindowCreatedCallback { controller in + // Register the plugin which you want access from other isolate. + // DesktopLifecyclePlugin.register(with: controller.registrar(forPlugin: "DesktopLifecyclePlugin")) + DesktopDropPlugin.register(with: controller.registrar(forPlugin: "DesktopDropPlugin")) + DeviceInfoPlusMacosPlugin.register(with: controller.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) + FlutterCustomCursorPlugin.register(with: controller.registrar(forPlugin: "FlutterCustomCursorPlugin")) + FLTPackageInfoPlusPlugin.register(with: controller.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) + PathProviderPlugin.register(with: controller.registrar(forPlugin: "PathProviderPlugin")) + SqflitePlugin.register(with: controller.registrar(forPlugin: "SqflitePlugin")) + TrayManagerPlugin.register(with: controller.registrar(forPlugin: "TrayManagerPlugin")) + UniLinksDesktopPlugin.register(with: controller.registrar(forPlugin: "UniLinksDesktopPlugin")) + UrlLauncherPlugin.register(with: controller.registrar(forPlugin: "UrlLauncherPlugin")) + WakelockMacosPlugin.register(with: controller.registrar(forPlugin: "WakelockMacosPlugin")) + WindowSizePlugin.register(with: controller.registrar(forPlugin: "WindowSizePlugin")) + } super.awakeFromNib() } From ce9427c65c21e4bf1d71e515b5b0193dc6e2af31 Mon Sep 17 00:00:00 2001 From: "Miguel F. G" <116861809+flusheDData@users.noreply.github.com> Date: Tue, 22 Nov 2022 17:46:28 +0100 Subject: [PATCH 109/116] Update es.rs A small change for consistency (Enable/Habilitar instead of Activate/Activar --- 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 a59437581..ef7d8e0fc 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -306,7 +306,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use permanent password", "Usar contraseña permamente"), ("Use both passwords", "Usar ambas contraseñas"), ("Set permanent password", "Establecer contraseña permamente"), - ("Enable Remote Restart", "Activar reinicio remoto"), + ("Enable Remote Restart", "Habilitar reinicio remoto"), ("Allow remote restart", "Permitir reinicio remoto"), ("Restart Remote Device", "Reiniciar dispositivo"), ("Are you sure you want to restart", "Esta Seguro que desea reiniciar?"), From 2211a36e0f38c53f10a8f7737d59ce92dca770a3 Mon Sep 17 00:00:00 2001 From: Agent-JY Date: Tue, 22 Nov 2022 18:50:32 +0100 Subject: [PATCH 110/116] Update de.rs Added missing translations --- src/lang/de.rs | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/lang/de.rs b/src/lang/de.rs index 5d82f84d1..3ba0ae0cb 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -368,32 +368,32 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Deny LAN Discovery", "LAN-Erkennung verbieten"), ("Write a message", "Nachricht schreiben"), ("Prompt", ""), - ("Please wait for confirmation of UAC...", ""), + ("Please wait for confirmation of UAC...", "Bitte auf die Bestätigung des Nutzers warten..."), ("elevated_foreground_window_tip", ""), - ("Disconnected", ""), + ("Disconnected", "Verbindung abgebrochen"), ("Other", ""), - ("Confirm before closing multiple tabs", ""), - ("Keyboard Settings", ""), - ("Custom", ""), - ("Full Access", ""), - ("Screen Share", ""), + ("Confirm before closing multiple tabs", "Bitte vor dem Schließen mehrerer Tabs bestägigen"), + ("Keyboard Settings", "Tastatureinstellungen"), + ("Custom", "Individuell"), + ("Full Access", "Vollzugriff"), + ("Screen Share", "Bildschirmfreigabe"), ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland erfordert Ubuntu 21.04 oder eine höhere Version."), ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland erfordert eine höhere Version der Linux-Distribution. Bitte versuchen Sie den X11-Desktop oder ändern Sie Ihr Betriebssystem."), ("JumpLink", "View"), ("Please Select the screen to be shared(Operate on the peer side).", "Bitte wählen Sie den Bildschirm aus, der freigegeben werden soll (auf der Peer-Seite arbeiten)."), - ("Show RustDesk", ""), - ("This PC", ""), - ("or", ""), - ("Continue with", ""), - ("Elevate", ""), - ("Zoom cursor", ""), - ("Accept sessions via password", ""), - ("Accept sessions via click", ""), - ("Accept sessions via both", ""), - ("Please wait for the remote side to accept your session request...", ""), - ("One-time Password", ""), - ("Use one-time password", ""), - ("One-time password length", ""), - ("Request access to your device", ""), + ("Show RustDesk", "RustDesk anzeigen"), + ("This PC", "Dieser PC"), + ("or", "oder"), + ("Continue with", "Fortfahren mit"), + ("Elevate", "Erheben"), + ("Zoom cursor", "Cursor zoomen"), + ("Accept sessions via password", "Sitzung mit Passwort bestätigen"), + ("Accept sessions via click", "Sitzung mit einem Klick bestätigen"), + ("Accept sessions via both", "Sitzung durch beides bestätigen"), + ("Please wait for the remote side to accept your session request...", "Bitte warten Sie auf die Gegenstelle, dass diese Ihre Sitzungsanfrage bestätigt..."), + ("One-time Password", "Einmalpasswort"), + ("Use one-time password", "Einmalpasswort verwenden"), + ("One-time password length", "Länge des Einmalpassworts"), + ("Request access to your device", "Zugriff zu Ihrem Gerät erbitten"), ].iter().cloned().collect(); } From cf721e9bb3009b9ceea1a656173bdbe26b40e228 Mon Sep 17 00:00:00 2001 From: Xerxes-2 Date: Wed, 23 Nov 2022 02:42:36 +1100 Subject: [PATCH 111/116] support CIDR for whitelist Signed-off-by: Xerxes-2 --- Cargo.lock | 31 ++++++++++++++++++++++++++ Cargo.toml | 1 + flutter/lib/common/widgets/dialog.dart | 2 +- src/server/connection.rs | 6 ++++- src/ui/index.tis | 2 +- 5 files changed, 39 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9eb270683..09485efa6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -633,6 +633,19 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "cidr-utils" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "355d5b5df67e58b523953d0c1a8d3d2c05f5af51f1332b0199b9c92263614ed0" +dependencies = [ + "debug-helper", + "num-bigint", + "num-traits 0.2.15", + "once_cell", + "regex", +] + [[package]] name = "clang-sys" version = "1.3.3" @@ -1244,6 +1257,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7046468a81e6a002061c01e6a7c83139daf91b11c30e66795b13217c2d885c8b" +[[package]] +name = "debug-helper" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f578e8e2c440e7297e008bb5486a3a8a194775224bbc23729b0dbdfaeebf162e" + [[package]] name = "default-net" version = "0.11.0" @@ -3291,6 +3310,17 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg 1.1.0", + "num-integer", + "num-traits 0.2.15", +] + [[package]] name = "num-complex" version = "0.4.2" @@ -4375,6 +4405,7 @@ dependencies = [ "cc", "cfg-if 1.0.0", "chrono", + "cidr-utils", "clap 3.2.17", "clipboard", "cocoa", diff --git a/Cargo.toml b/Cargo.toml index 6375bce26..cfe18f019 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,6 +68,7 @@ url = { version = "2.1", features = ["serde"] } reqwest = { version = "0.11", features = ["blocking", "json", "rustls-tls"], default-features=false } chrono = "0.4.23" +cidr-utils = "0.5.9" [target.'cfg(not(any(target_os = "android", target_os = "linux")))'.dependencies] cpal = "0.13.5" diff --git a/flutter/lib/common/widgets/dialog.dart b/flutter/lib/common/widgets/dialog.dart index 35a303c0b..8fab02a77 100644 --- a/flutter/lib/common/widgets/dialog.dart +++ b/flutter/lib/common/widgets/dialog.dart @@ -133,7 +133,7 @@ void changeWhiteList({Function()? callback}) async { final ips = newWhiteListField.trim().split(RegExp(r"[\s,;\n]+")); // test ip - final ipMatch = RegExp(r"^\d+\.\d+\.\d+\.\d+$"); + final ipMatch = RegExp(r"^\d+\.\d+\.\d+\.\d+(\/\d+)?$"); for (final ip in ips) { if (!ipMatch.hasMatch(ip)) { msg = "${translate("Invalid IP")} $ip"; diff --git a/src/server/connection.rs b/src/server/connection.rs index 11960be8a..50c91d057 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -7,6 +7,7 @@ use crate::video_service; #[cfg(any(target_os = "android", target_os = "ios"))] use crate::{common::DEVICE_NAME, flutter::connection_manager::start_channel}; use crate::{ipc, VERSION}; +use cidr_utils::cidr::IpCidr; use hbb_common::{ config::Config, fs, @@ -631,7 +632,10 @@ impl Connection { .is_none() && whitelist .iter() - .filter(|x| x.parse() == Ok(addr.ip())) + .filter(|x| match IpCidr::from_str(x) { + Ok(cidr) => cidr.contains(addr.ip()), + Err(_) => false, + }) .next() .is_none() { diff --git a/src/ui/index.tis b/src/ui/index.tis index 8e2238b2d..6b1d1b7c7 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -395,7 +395,7 @@ class MyIdMenu: Reactor.Component { if (value) { var values = value.split(/[\s,;\n]+/g); for (var ip in values) { - if (!ip.match(/^\d+\.\d+\.\d+\.\d+$/)) { + if (!ip.match(/^\d+\.\d+\.\d+\.\d+(\/\d+)?$/)) { return translate("Invalid IP") + ": " + ip; } } From de951ad70ac7ac287864f06cb47e37e2ca85680c Mon Sep 17 00:00:00 2001 From: Xerxes-2 Date: Wed, 23 Nov 2022 04:09:49 +1100 Subject: [PATCH 112/116] update IPv4 check and add IPv6 check in whitelist Signed-off-by: Xerxes-2 --- flutter/lib/common/widgets/dialog.dart | 7 +++++-- src/server/connection.rs | 5 +---- src/ui/index.tis | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/flutter/lib/common/widgets/dialog.dart b/flutter/lib/common/widgets/dialog.dart index 8fab02a77..a6de0384f 100644 --- a/flutter/lib/common/widgets/dialog.dart +++ b/flutter/lib/common/widgets/dialog.dart @@ -133,9 +133,12 @@ void changeWhiteList({Function()? callback}) async { final ips = newWhiteListField.trim().split(RegExp(r"[\s,;\n]+")); // test ip - final ipMatch = RegExp(r"^\d+\.\d+\.\d+\.\d+(\/\d+)?$"); + final ipMatch = RegExp( + r"^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)(\/([1-9]|[1-2][0-9]|3[0-2])){0,1}$"); + final ipv6Match = RegExp( + r"^(((?:[0-9A-Fa-f]{1,4}))*((?::[0-9A-Fa-f]{1,4}))*::((?:[0-9A-Fa-f]{1,4}))*((?::[0-9A-Fa-f]{1,4}))*|((?:[0-9A-Fa-f]{1,4}))((?::[0-9A-Fa-f]{1,4})){7})(\/([1-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])){0,1}$"); for (final ip in ips) { - if (!ipMatch.hasMatch(ip)) { + if (!ipMatch.hasMatch(ip) && !ipv6Match.hasMatch(ip)) { msg = "${translate("Invalid IP")} $ip"; setState(() { isInProgress = false; diff --git a/src/server/connection.rs b/src/server/connection.rs index 50c91d057..a337d6022 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -632,10 +632,7 @@ impl Connection { .is_none() && whitelist .iter() - .filter(|x| match IpCidr::from_str(x) { - Ok(cidr) => cidr.contains(addr.ip()), - Err(_) => false, - }) + .filter(|x| IpCidr::from_str(x).map_or(false, |y| y.contains(addr.ip()))) .next() .is_none() { diff --git a/src/ui/index.tis b/src/ui/index.tis index 6b1d1b7c7..9dcd4f4c4 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -395,7 +395,8 @@ class MyIdMenu: Reactor.Component { if (value) { var values = value.split(/[\s,;\n]+/g); for (var ip in values) { - if (!ip.match(/^\d+\.\d+\.\d+\.\d+(\/\d+)?$/)) { + if (!ip.match(/^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)(\/([1-9]|[1-2][0-9]|3[0-2])){0,1}$/) + && !ip.match(/^(((?:[0-9A-Fa-f]{1,4}))*((?::[0-9A-Fa-f]{1,4}))*::((?:[0-9A-Fa-f]{1,4}))*((?::[0-9A-Fa-f]{1,4}))*|((?:[0-9A-Fa-f]{1,4}))((?::[0-9A-Fa-f]{1,4})){7})(\/([1-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])){0,1}$/)) { return translate("Invalid IP") + ": " + ip; } } From ae7d94632a02ee66dcd36f688c628386c709a195 Mon Sep 17 00:00:00 2001 From: emporiobviver <106774307+emporiobviver@users.noreply.github.com> Date: Tue, 22 Nov 2022 16:52:05 -0300 Subject: [PATCH 113/116] Update ptbr.rs --- src/lang/ptbr.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index 7d9c0b270..42d28df71 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -385,15 +385,15 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", "Este PC"), ("or", "ou"), ("Continue with", "Continuar com"), - ("Elevate", ""), - ("Zoom cursor", ""), - ("Accept sessions via password", ""), - ("Accept sessions via click", ""), - ("Accept sessions via both", ""), - ("Please wait for the remote side to accept your session request...", ""), - ("One-time Password", ""), - ("Use one-time password", ""), - ("One-time password length", ""), - ("Request access to your device", ""), + ("Elevate", "Elevar"), + ("Zoom cursor", "Aumentar cursor"), + ("Accept sessions via password", "Aceitar sessões via senha"), + ("Accept sessions via click", "Aceitar sessões via clique"), + ("Accept sessions via both", "Aceitar sessões de ambos os modos"), + ("Please wait for the remote side to accept your session request...", "Por favor aguarde enquanto o cliente remoto aceita seu pedido de sessão..."), + ("One-time Password", "Senha de uso único"), + ("Use one-time password", "Usar senha de uso único"), + ("One-time password length", "Comprimento da senha de uso único"), + ("Request access to your device", "Solicitar acesso ao seu dispositivo"), ].iter().cloned().collect(); } From 8b4d50f3fb392ceeb549166f57935c8cded33b7c Mon Sep 17 00:00:00 2001 From: 21pages Date: Wed, 23 Nov 2022 09:41:05 +0800 Subject: [PATCH 114/116] flutter version allow hide cm Signed-off-by: 21pages --- .../lib/desktop/pages/connection_page.dart | 16 +++-- .../desktop/pages/desktop_setting_page.dart | 69 +++++++++++++------ flutter/lib/main.dart | 26 +++++-- flutter/lib/models/server_model.dart | 39 ++++++++++- libs/hbb_common/src/password_security.rs | 6 ++ src/flutter_ffi.rs | 4 ++ src/lang/ca.rs | 2 + src/lang/cn.rs | 2 + src/lang/cs.rs | 2 + src/lang/da.rs | 2 + src/lang/de.rs | 2 + src/lang/en.rs | 3 +- 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/pl.rs | 2 + src/lang/pt_PT.rs | 2 + src/lang/ptbr.rs | 2 + src/lang/ru.rs | 2 + src/lang/sk.rs | 2 + src/lang/template.rs | 2 + src/lang/tr.rs | 2 + src/lang/tw.rs | 2 + src/lang/ua.rs | 2 + src/lang/vn.rs | 2 + src/server/connection.rs | 11 ++- src/server/video_service.rs | 4 +- src/ui_cm_interface.rs | 4 +- src/ui_interface.rs | 9 ++- src/ui_session_interface.rs | 1 + 37 files changed, 198 insertions(+), 44 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 671335bfd..83e57dba8 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -4,6 +4,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hbb/common/widgets/address_book.dart'; import 'package:flutter_hbb/consts.dart'; @@ -177,12 +178,15 @@ class _ConnectionPageState extends State children: [ Row( children: [ - Text( - translate('Control Remote Desktop'), - style: Theme.of(context) - .textTheme - .titleLarge - ?.merge(TextStyle(height: 1)), + Expanded( + child: AutoSizeText( + translate('Control Remote Desktop'), + maxLines: 1, + style: Theme.of(context) + .textTheme + .titleLarge + ?.merge(TextStyle(height: 1)), + ), ), ], ).marginOnly(bottom: 15), diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index b5aeaa7c3..056b1028b 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -658,13 +658,9 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { initialKey: modeInitialKey, onChanged: (key) => model.setApproveMode(key), ).marginOnly(left: _kContentHMargin), - Offstage( - offstage: !usePassword, - child: radios[0], - ), - Offstage( - offstage: !usePassword, - child: _SubLabeledWidget( + if (usePassword) radios[0], + if (usePassword) + _SubLabeledWidget( 'One-time password length', Row( children: [ @@ -672,20 +668,13 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { ], ), enabled: tmpEnabled && !locked), - ), - Offstage( - offstage: !usePassword, - child: radios[1], - ), - Offstage( - offstage: !usePassword, - child: _SubButton('Set permanent password', setPasswordDialog, + if (usePassword) radios[1], + if (usePassword) + _SubButton('Set permanent password', setPasswordDialog, permEnabled && !locked), - ), - Offstage( - offstage: !usePassword, - child: radios[2], - ), + if (usePassword) + hide_cm(!locked).marginOnly(left: _kContentHSubMargin - 6), + if (usePassword) radios[2], ]); }))); } @@ -814,6 +803,46 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { ).marginOnly(left: _kCheckBoxLeftMargin); }); } + + Widget hide_cm(bool enabled) { + return ChangeNotifierProvider.value( + value: gFFI.serverModel, + child: Consumer(builder: (context, model, child) { + final enableHideCm = model.approveMode == 'password' && + model.verificationMethod == kUsePermanentPassword; + onHideCmChanged(bool? b) { + if (b != null) { + bind.mainSetOption( + key: 'allow-hide-cm', value: bool2option('allow-hide-cm', b)); + } + } + + return Tooltip( + message: enableHideCm ? "" : translate('hide_cm_tip'), + child: GestureDetector( + onTap: + enableHideCm ? () => onHideCmChanged(!model.hideCm) : null, + child: Row( + children: [ + Checkbox( + value: model.hideCm, + onChanged: enabled && enableHideCm + ? onHideCmChanged + : null) + .marginOnly(right: 5), + Expanded( + child: Text( + translate('Hide connection management window'), + style: TextStyle( + color: _disabledTextColor( + context, enabled && enableHideCm)), + ), + ), + ], + ), + )); + })); + } } class _Network extends StatefulWidget { diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index e83c4b323..44db1436e 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -85,7 +85,7 @@ Future main(List args) async { debugPrint("--cm started"); desktopType = DesktopType.cm; await windowManager.ensureInitialized(); - runConnectionManagerScreen(); + runConnectionManagerScreen(args.contains('--hide')); } else if (args.contains('--install')) { runInstallPage(); } else { @@ -185,16 +185,23 @@ void runMultiWindow( } } -void runConnectionManagerScreen() async { +void runConnectionManagerScreen(bool hide) async { await initEnv(kAppTypeMain); - // initialize window - WindowOptions windowOptions = - getHiddenTitleBarWindowOptions(size: kConnectionManagerWindowSize); _runApp( '', const DesktopServerPage(), MyTheme.currentThemeMode(), ); + if (hide) { + hideCmWindow(); + } else { + showCmWindow(); + } +} + +void showCmWindow() { + WindowOptions windowOptions = + getHiddenTitleBarWindowOptions(size: kConnectionManagerWindowSize); windowManager.waitUntilReadyToShow(windowOptions, () async { await windowManager.show(); await Future.wait([windowManager.focus(), windowManager.setOpacity(1)]); @@ -204,6 +211,15 @@ void runConnectionManagerScreen() async { }); } +void hideCmWindow() { + WindowOptions windowOptions = + getHiddenTitleBarWindowOptions(size: kConnectionManagerWindowSize); + windowManager.setOpacity(0); + windowManager.waitUntilReadyToShow(windowOptions, () async { + await windowManager.hide(); + }); +} + void _runApp( String title, Widget home, diff --git a/flutter/lib/models/server_model.dart b/flutter/lib/models/server_model.dart index be3f02b5d..456c3cdd2 100644 --- a/flutter/lib/models/server_model.dart +++ b/flutter/lib/models/server_model.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:flutter_hbb/main.dart'; import 'package:flutter_hbb/models/platform_model.dart'; import 'package:get/get.dart'; import 'package:wakelock/wakelock.dart'; @@ -28,6 +29,7 @@ class ServerModel with ChangeNotifier { bool _audioOk = false; bool _fileOk = false; bool _showElevation = true; + bool _hideCm = false; int _connectStatus = 0; // Rendezvous Server status String _verificationMethod = ""; String _temporaryPasswordLength = ""; @@ -56,6 +58,8 @@ class ServerModel with ChangeNotifier { bool get showElevation => _showElevation; + bool get hideCm => _hideCm; + int get connectStatus => _connectStatus; String get verificationMethod { @@ -74,6 +78,10 @@ class ServerModel with ChangeNotifier { setVerificationMethod(String method) async { await bind.mainSetOption(key: "verification-method", value: method); + if (method != kUsePermanentPassword) { + await bind.mainSetOption( + key: 'allow-hide-cm', value: bool2option('allow-hide-cm', false)); + } } String get temporaryPasswordLength { @@ -90,6 +98,10 @@ class ServerModel with ChangeNotifier { setApproveMode(String mode) async { await bind.mainSetOption(key: 'approve-mode', value: mode); + if (mode != 'password') { + await bind.mainSetOption( + key: 'allow-hide-cm', value: bool2option('allow-hide-cm', false)); + } } TextEditingController get serverId => _serverId; @@ -125,7 +137,11 @@ class ServerModel with ChangeNotifier { } if (!isTest) { - Future.delayed(Duration.zero, timerCallback); + Future.delayed(Duration.zero, () async { + if (await bind.optionSynced()) { + await timerCallback(); + } + }); Timer.periodic(Duration(milliseconds: 500), (timer) async { await timerCallback(); }); @@ -166,6 +182,12 @@ class ServerModel with ChangeNotifier { final temporaryPasswordLength = await bind.mainGetOption(key: "temporary-password-length"); final approveMode = await bind.mainGetOption(key: 'approve-mode'); + var hideCm = option2bool( + 'allow-hide-cm', await bind.mainGetOption(key: 'allow-hide-cm')); + if (!(approveMode == 'password' && + verificationMethod == kUsePermanentPassword)) { + hideCm = false; + } if (_approveMode != approveMode) { _approveMode = approveMode; update = true; @@ -190,6 +212,17 @@ class ServerModel with ChangeNotifier { _temporaryPasswordLength = temporaryPasswordLength; update = true; } + if (_hideCm != hideCm) { + _hideCm = hideCm; + if (desktopType == DesktopType.cm) { + if (hideCm) { + hideCmWindow(); + } else { + showCmWindow(); + } + } + update = true; + } if (update) { notifyListeners(); } @@ -436,11 +469,11 @@ class ServerModel with ChangeNotifier { }, page: desktop.buildConnectionCard(client))); Future.delayed(Duration.zero, () async { - window_on_top(null); + if (!hideCm) window_on_top(null); }); if (client.authorized) { cmHiddenTimer = Timer(const Duration(seconds: 3), () { - windowManager.minimize(); + if (!hideCm) windowManager.minimize(); cmHiddenTimer = null; }); } diff --git a/libs/hbb_common/src/password_security.rs b/libs/hbb_common/src/password_security.rs index adaafebb3..602906990 100644 --- a/libs/hbb_common/src/password_security.rs +++ b/libs/hbb_common/src/password_security.rs @@ -76,6 +76,12 @@ pub fn approve_mode() -> ApproveMode { } } +pub fn hide_cm() -> bool { + approve_mode() == ApproveMode::Password + && verification_method() == VerificationMethod::OnlyUsePermanentPassword + && !Config::get_option("allow-hide-cm").is_empty() +} + const VERSION_LEN: usize = 2; pub fn encrypt_str_or_original(s: &str, version: &str) -> String { diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index ea33290fe..00f9b51e6 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -1098,6 +1098,10 @@ pub fn version_to_number(v: String) -> i64 { hbb_common::get_version_number(&v) } +pub fn option_synced() -> bool { + crate::ui_interface::option_synced() +} + pub fn main_is_installed() -> SyncReturn { SyncReturn(is_installed()) } diff --git a/src/lang/ca.rs b/src/lang/ca.rs index f5684b4c4..0dd21e168 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -394,5 +394,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", ""), ("One-time password length", ""), ("Request access to your device", ""), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 7256c5d1f..a3b3b47c8 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", "使用一次性密码"), ("One-time password length", "一次性密码长度"), ("Request access to your device", "请求访问你的设备"), + ("Hide connection management window", "隐藏连接管理窗口"), + ("hide_cm_tip", "在只允许密码连接并且只用固定密码的情况下才允许隐藏"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 63fac7288..450f3971a 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", ""), ("One-time password length", ""), ("Request access to your device", ""), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index 4278cdc20..ea7263ac8 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", ""), ("One-time password length", ""), ("Request access to your device", ""), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index 3ba0ae0cb..66514fa0f 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", "Einmalpasswort verwenden"), ("One-time password length", "Länge des Einmalpassworts"), ("Request access to your device", "Zugriff zu Ihrem Gerät erbitten"), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/en.rs b/src/lang/en.rs index ee68d4431..2550135a1 100644 --- a/src/lang/en.rs +++ b/src/lang/en.rs @@ -33,7 +33,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_foreground_window_tip", "The current window of the remote desktop requires higher privilege to operate, so it's unable to use the mouse and keyboard temporarily. You can request the remote user to minimize the current window, or click elevation button on the connection management window. To avoid this problem, it is recommended to install the software on the remote device."), ("JumpLink", "View"), ("Stop service", "Stop Service"), - ("or", ""), - ("Continue with", ""), + ("hide_cm_tip", "Allow hiding only if accepting sessions via password and using pernament password"), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 3c7ac806a..797eb2bb6 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", ""), ("One-time password length", ""), ("Request access to your device", ""), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index ef7d8e0fc..ca67a68be 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", "Usar contraseña de un solo uso"), ("One-time password length", "Longitud de la contraseña de un solo uso"), ("Request access to your device", "Solicitud de acceso a su dispositivo"), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index 0ea1f6f55..4dfb22621 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -394,5 +394,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", "استفاده از رمز عبور یکبار مصرف"), ("One-time password length", "طول رمز عبور یکبار مصرف"), ("Request access to your device", ""), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index 4b8d0d83e..6c9cb6a3f 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", ""), ("One-time password length", ""), ("Request access to your device", ""), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index 9802ddb6f..417c83f45 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", ""), ("One-time password length", ""), ("Request access to your device", ""), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 002789066..b76bb687d 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", ""), ("One-time password length", ""), ("Request access to your device", ""), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 76e034450..83741d47d 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", "Usa password monouso"), ("One-time password length", "Lunghezza password monouso"), ("Request access to your device", "Richiedi l'accesso al tuo dispositivo"), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index b032fbe7e..8d806416d 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", ""), ("One-time password length", ""), ("Request access to your device", ""), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index 338fc7ffe..9f8027be7 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", ""), ("One-time password length", ""), ("Request access to your device", ""), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 3a343da21..3a8c27cf3 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", ""), ("One-time password length", ""), ("Request access to your device", ""), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index ecc09ce2a..dae77ed88 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", "Użyj hasła jednorazowego"), ("One-time password length", "Długość hasła jednorazowego"), ("Request access to your device", "Żądanie dostępu do Twojego urządzenia"), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index dbb5fbbe9..bc5fbbdfd 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", ""), ("One-time password length", ""), ("Request access to your device", ""), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index 42d28df71..0d77eb905 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", "Usar senha de uso único"), ("One-time password length", "Comprimento da senha de uso único"), ("Request access to your device", "Solicitar acesso ao seu dispositivo"), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index ded00af23..e318b7cda 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", ""), ("One-time password length", ""), ("Request access to your device", ""), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 8da18e035..33f2be7ab 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", ""), ("One-time password length", ""), ("Request access to your device", ""), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index bc9bc95e3..8f855d96a 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", ""), ("One-time password length", ""), ("Request access to your device", ""), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index 86283557f..a97f832ba 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", ""), ("One-time password length", ""), ("Request access to your device", ""), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index cc8f65e1c..4945fd511 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", "使用一次性密碼"), ("One-time password length", "一次性密碼長度"), ("Request access to your device", "請求訪問你的設備"), + ("Hide connection management window", "隱藏連接管理窗口"), + ("hide_cm_tip", "在只允許密碼連接並且只用固定密碼的情況下才允許隱藏"), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index 7d14ee7e0..3861f0598 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", ""), ("One-time password length", ""), ("Request access to your device", ""), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index 3ddacdf8d..8ddeadfca 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -395,5 +395,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Use one-time password", ""), ("One-time password length", ""), ("Request access to your device", ""), + ("Hide connection management window", ""), + ("hide_cm_tip", ""), ].iter().cloned().collect(); } diff --git a/src/server/connection.rs b/src/server/connection.rs index a337d6022..249dadc5e 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -1571,17 +1571,18 @@ async fn start_ipc( if let Ok(s) = crate::ipc::connect(1000, "_cm").await { stream = Some(s); } else { + let extra_args = if password::hide_cm() { "--hide" } else { "" }; let run_done; if crate::platform::is_root() { let mut res = Ok(None); for _ in 0..10 { #[cfg(not(target_os = "linux"))] { - res = crate::platform::run_as_user("--cm"); + res = crate::platform::run_as_user(&format!("--cm {}", extra_args)); } #[cfg(target_os = "linux")] { - res = crate::platform::run_as_user("--cm", None); + res = crate::platform::run_as_user(&format!("--cm {}", extra_args), None); } if res.is_ok() { break; @@ -1596,10 +1597,14 @@ async fn start_ipc( run_done = false; } if !run_done { + let mut args = vec!["--cm"]; + if !extra_args.is_empty() { + args.push(&extra_args); + } super::CHILD_PROCESS .lock() .unwrap() - .push(crate::run_me(vec!["--cm"])?); + .push(crate::run_me(args)?); } for _ in 0..10 { sleep(0.3).await; diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 3ccc3af39..db419fc65 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -192,7 +192,7 @@ fn create_capturer( privacy_mode_id: i32, display: Display, use_yuv: bool, - current: usize, + _current: usize, _portable_service_running: bool, ) -> ResultType> { #[cfg(not(windows))] @@ -256,7 +256,7 @@ fn create_capturer( log::debug!("Create capturer dxgi|gdi"); #[cfg(windows)] return crate::portable_service::client::create_capturer( - current, + _current, display, use_yuv, _portable_service_running, diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 5edf53507..26e5e4077 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -784,11 +784,11 @@ pub fn can_elevate() -> bool { return false; } -pub fn elevate_portable(id: i32) { +pub fn elevate_portable(_id: i32) { #[cfg(windows)] { let lock = CLIENTS.read().unwrap(); - if let Some(s) = lock.get(&id) { + if let Some(s) = lock.get(&_id) { allow_err!(s.tx.send(ipc::Data::DataPortableService( ipc::DataPortableService::RequestStart ))); diff --git a/src/ui_interface.rs b/src/ui_interface.rs index e1dc3005e..28ce897bc 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -39,6 +39,7 @@ lazy_static::lazy_static! { static ref OPTIONS : Arc>> = Arc::new(Mutex::new(Config::get_options())); static ref ASYNC_JOB_STATUS : Arc> = Default::default(); static ref TEMPORARY_PASSWD : Arc> = Arc::new(Mutex::new("".to_owned())); + pub static ref OPTION_SYNCED : Arc> = Default::default(); } #[cfg(not(any(target_os = "android", target_os = "ios")))] @@ -924,7 +925,8 @@ async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver { - *OPTIONS.lock().unwrap() = v + *OPTIONS.lock().unwrap() = v; + *OPTION_SYNCED.lock().unwrap() = true; } Ok(Some(ipc::Data::Config((name, Some(value))))) => { if name == "id" { @@ -967,6 +969,11 @@ async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver bool { + OPTION_SYNCED.lock().unwrap().clone() +} + #[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] #[tokio::main(flavor = "current_thread")] pub(crate) async fn send_to_cm(data: &ipc::Data) { diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index 9b00730e5..efc82cbc1 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -200,6 +200,7 @@ impl Session { h265 = h265 && encoding_265; return (h264, h265); } + #[allow(dead_code)] (false, false) } From 7c04855e15fcd5f1ff146ca753f8a18d831367fd Mon Sep 17 00:00:00 2001 From: fufesou Date: Wed, 23 Nov 2022 14:23:57 +0800 Subject: [PATCH 115/116] fix cm hidden timer null Signed-off-by: fufesou --- flutter/lib/desktop/pages/server_page.dart | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/flutter/lib/desktop/pages/server_page.dart b/flutter/lib/desktop/pages/server_page.dart index aae6da8fc..6c586994b 100644 --- a/flutter/lib/desktop/pages/server_page.dart +++ b/flutter/lib/desktop/pages/server_page.dart @@ -107,13 +107,14 @@ class ConnectionManagerState extends State { @override Widget build(BuildContext context) { final serverModel = Provider.of(context); - final pointerHandler = serverModel.cmHiddenTimer != null - ? (PointerEvent e) { - serverModel.cmHiddenTimer!.cancel(); - serverModel.cmHiddenTimer = null; - debugPrint("CM hidden timer has been canceled"); - } - : null; + pointerHandler(PointerEvent e) { + if (serverModel.cmHiddenTimer != null) { + serverModel.cmHiddenTimer!.cancel(); + serverModel.cmHiddenTimer = null; + debugPrint("CM hidden timer has been canceled"); + } + } + return serverModel.clients.isEmpty ? Column( children: [ From af65267555eb8006ca987dedc3c3ebcd23d429a0 Mon Sep 17 00:00:00 2001 From: Agent-JY Date: Wed, 23 Nov 2022 10:54:52 +0100 Subject: [PATCH 116/116] Update de.rs --- src/lang/de.rs | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/lang/de.rs b/src/lang/de.rs index 66514fa0f..318f2b645 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -3,7 +3,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = [ ("Status", "Status"), ("Your Desktop", "Ihr Desktop"), - ("desk_tip", "Mit dieser ID und diesem Passwort können Sie auf Ihren Desktop zugreifen."), + ("desk_tip", "Mit dieser ID und diesem Passwort kann auf Ihren Desktop zugegriffen werden."), ("Password", "Passwort"), ("Ready", "Bereit"), ("Established", "Verbunden"), @@ -12,7 +12,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Start Service", "Starte Vermittlungsdienst"), ("Service is running", "Vermittlungsdienst aktiv"), ("Service is not running", "Vermittlungsdienst deaktiviert"), - ("not_ready_status", "Nicht bereit. Bitte überprüfen Sie Ihre Verbindung"), + ("not_ready_status", "Nicht bereit. Bitte überprüfen Sie Ihre Netzwerkverbindung"), ("Control Remote Desktop", "Entfernten PC steuern"), ("Transfer File", "Datei übertragen"), ("Connect", "Verbinden"), @@ -30,9 +30,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("IP Whitelisting", "IP-Whitelist"), ("ID/Relay Server", "ID/Vermittlungsserver"), ("Import Server Config", "Serverkonfiguration importieren"), - ("Export Server Config", ""), + ("Export Server Config", "Serverkonfiguration exportieren"), ("Import server configuration successfully", "Serverkonfiguration erfolgreich importiert"), - ("Export server configuration successfully", ""), + ("Export server configuration successfully", "Serverkonfiguration erfolgreich exportiert"), ("Invalid server configuration", "Ungültige Serverkonfiguration"), ("Clipboard is empty", "Zwischenablage ist leer"), ("Stop service", "Vermittlungsdienst deaktivieren"), @@ -67,12 +67,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Connection Error", "Verbindungsfehler"), ("Error", "Fehler"), ("Reset by the peer", "Verbindung wurde von der Gegenstelle zurückgesetzt"), - ("Connecting...", "Verbinden..."), + ("Connecting...", "Verbindung wird hergestellt..."), ("Connection in progress. Please wait.", "Die Verbindung wird hergestellt. Bitte warten..."), ("Please try 1 minute later", "Bitte versuchen Sie es später erneut"), ("Login Error", "Anmeldefehler"), ("Successful", "Erfolgreich"), - ("Connected, waiting for image...", "Verbunden, warte auf Bild..."), + ("Connected, waiting for image...", "Verbindung hergestellt. Warten auf Bild..."), ("Name", "Name"), ("Type", "Typ"), ("Modified", "Geändert"), @@ -89,15 +89,15 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Delete", "Löschen"), ("Properties", "Eigenschaften"), ("Multi Select", "Mehrfachauswahl"), - ("Select All", ""), - ("Unselect All", ""), + ("Select All", "Alles auswählen"), + ("Unselect All", "Alles abwählen"), ("Empty Directory", "Leerer Ordner"), ("Not an empty directory", "Ordner ist nicht leer"), ("Are you sure you want to delete this file?", "Sind Sie sicher, dass Sie diese Datei löschen wollen?"), ("Are you sure you want to delete this empty directory?", "Sind Sie sicher, dass Sie diesen leeren Ordner löschen möchten?"), ("Are you sure you want to delete the file of this directory?", "Sind Sie sicher, dass Sie die Datei dieses Ordners löschen möchten?"), ("Do this for all conflicts", "Für alle Konflikte merken"), - ("This is irreversible!", "Dies ist irreversibel!"), + ("This is irreversible!", "Dies kann nicht rückgängig gemacht werden!"), ("Deleting", "Löschen"), ("files", "Dateien"), ("Waiting", "Warten"), @@ -113,14 +113,14 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Stretch", "Strecken"), ("Scrollbar", "Scrollleiste"), ("ScrollAuto", "Automatisch scrollen"), - ("Good image quality", "Qualität"), + ("Good image quality", "Hohe Bildqualität"), ("Balanced", "Ausgeglichen"), ("Optimize reaction time", "Geschwindigkeit"), - ("Custom", ""), + ("Custom", "Individuell"), ("Show remote cursor", "Entfernten Cursor anzeigen"), ("Show quality monitor", "Qualitätsüberwachung anzeigen"), ("Disable clipboard", "Zwischenablage deaktivieren"), - ("Lock after session end", "Sperren nach Sitzungsende"), + ("Lock after session end", "Nach Sitzungsende sperren"), ("Insert", "Einfügen"), ("Insert Lock", "Win+L (Sperren) senden"), ("Refresh", "Aktualisieren"), @@ -136,7 +136,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Failed to make direct connection to remote desktop", "Direkte Verbindung zum entfernten PC fehlgeschlagen"), ("Set Password", "Passwort festlegen"), ("OS Password", "Betriebssystem-Passwort"), - ("install_tip", "Aufgrund der UAC kann RustDesk in manchen Fällen nicht ordnungsgemäß funktionieren. Um UAC zu vermeiden, klicken Sie bitte auf die Schaltfläche unten, um RustDesk auf dem System zu installieren"), + ("install_tip", "Aufgrund der Benutzerkontensteuerung (UAC) kann RustDesk in manchen Fällen nicht ordnungsgemäß funktionieren. Um die Benutzerkontensteuerung zu umgehen, klicken Sie bitte auf die Schaltfläche unten, um RustDesk auf dem System zu installieren"), ("Click to upgrade", "Zum Aktualisieren anklicken"), ("Click to download", "Zum Herunterladen klicken"), ("Click to update", "Zum Aktualisieren klicken"), @@ -161,11 +161,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Action", "Aktion"), ("Add", "Hinzufügen"), ("Local Port", "Lokaler Port"), - ("Local Address", "Lokale ddresse"), + ("Local Address", "Lokale Addresse"), ("Change Local Port", "Lokalen Port ändern"), ("setup_server_tip", "Für eine schnellere Verbindung richten Sie bitte Ihren eigenen Verbindungsserver ein"), ("Too short, at least 6 characters.", "Zu kurz, mindestens 6 Zeichen."), - ("The confirmation is not identical.", "Die Passwörter sind nicht identisch."), + ("The confirmation is not identical.", "Die Passwörter stimmen nicht überein."), ("Permissions", "Berechtigungen"), ("Accept", "Akzeptieren"), ("Dismiss", "Ablehnen"), @@ -181,7 +181,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Relayed and unencrypted connection", "Vermittelte und unverschlüsselte Verbindung"), ("Enter Remote ID", "Remote-ID eingeben"), ("Enter your password", "Geben Sie Ihr Passwort ein"), - ("Logging in...", "Anmeldung..."), + ("Logging in...", "Anmelden..."), ("Enable RDP session sharing", "RDP-Sitzungsfreigabe aktivieren"), ("Auto Login", "Automatisch anmelden (nur gültig, wenn Sie \"Sperren nach Sitzungsende\" aktiviert haben)"), ("Enable Direct IP Access", "Direkten IP-Zugang aktivieren"), @@ -209,7 +209,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("whitelist_tip", "Nur IPs auf der Whitelist können zugreifen"), ("Login", "Anmelden"), ("Logout", "Abmelden"), - ("Tags", "Stichworte"), + ("Tags", "Schlagworte"), ("Search ID", "Suche ID"), ("Current Wayland display server is not supported", "Der aktuelle Wayland-Anzeigeserver wird nicht unterstützt"), ("whitelist_sep", "Getrennt durch Komma, Semikolon, Leerzeichen oder Zeilenumbruch"), @@ -220,15 +220,15 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Username missed", "Benutzername vergessen"), ("Password missed", "Passwort vergessen"), ("Wrong credentials", "Falsche Anmeldedaten"), - ("Edit Tag", "Stichwort bearbeiten"), + ("Edit Tag", "Schlagwort bearbeiten"), ("Unremember Password", "Passwort vergessen"), ("Favorites", "Favoriten"), ("Add to Favorites", "Zu Favoriten hinzufügen"), ("Remove from Favorites", "Aus Favoriten entfernen"), - ("Empty", "Leer"), + ("Empty", "Keine Einträge"), ("Invalid folder name", "Ungültiger Ordnername"), ("Socks5 Proxy", "Socks5 Proxy"), - ("Hostname", "Rechnername"), + ("Hostname", "Hostname"), ("Discovered", "Gefunden"), ("install_daemon_tip", "Um mit System zu starten, muss der Systemdienst installiert sein"), ("Remote ID", "Entfernte ID"), @@ -278,7 +278,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("android_stop_service_tip", "Durch das Deaktivieren des Dienstes werden automatisch alle hergestellten Verbindungen getrennt."), ("android_version_audio_tip", "Ihre Android-Version unterstützt keine Audioaufnahme, bitte aktualisieren Sie auf Android 10 oder höher, falls möglich."), ("android_start_service_tip", "Tippen Sie auf [Dienst aktivieren] oder aktivieren Sie die Berechtigung [Bildschirmzugr.], um den Bildschirmfreigabedienst zu starten."), - ("Account", "Account"), + ("Account", "Konto"), ("Overwrite", "Überschreiben"), ("This file exists, skip or overwrite this file?", "Diese Datei existiert; überspringen oder überschreiben?"), ("Quit", "Beenden"), @@ -298,7 +298,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Language", "Sprache"), ("Keep RustDesk background service", "RustDesk im Hintergrund ausführen"), ("Ignore Battery Optimizations", "Batterieoptimierung ignorieren"), - ("android_open_battery_optimizations_tip", "Möchten Sie die Batterieopimierungs-Einstellungen öffnen?"), + ("android_open_battery_optimizations_tip", "Möchten Sie die Einstellungen zur Batterieopimierung öffnen?"), ("Connection not allowed", "Verbindung abgelehnt"), ("Legacy mode", "Kompatibilitätsmodus"), ("Map mode", ""), @@ -332,7 +332,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Scale adaptive", "Adaptiv skalieren"), ("General", "Allgemein"), ("Security", "Sicherheit"), - ("Account", "Account"), + ("Account", "KOnto"), ("Theme", "Farbgebung"), ("Dark Theme", "dunkle Farbgebung"), ("Dark", "Dunkel"),