From ca97826b80e09979f29f2c96993e6125d42e0e36 Mon Sep 17 00:00:00 2001 From: fufesou Date: Fri, 3 Feb 2023 19:17:59 +0800 Subject: [PATCH 1/2] update cursor position when menu is dismissed Signed-off-by: fufesou --- flutter/lib/desktop/widgets/popup_menu.dart | 55 ++++++++++++++++--- .../lib/desktop/widgets/remote_menubar.dart | 45 ++++++++++++++- 2 files changed, 90 insertions(+), 10 deletions(-) diff --git a/flutter/lib/desktop/widgets/popup_menu.dart b/flutter/lib/desktop/widgets/popup_menu.dart index 0cbdad929..9833dcbca 100644 --- a/flutter/lib/desktop/widgets/popup_menu.dart +++ b/flutter/lib/desktop/widgets/popup_menu.dart @@ -109,13 +109,17 @@ class MenuConfig { this.boxWidth}); } +typedef DismissCallback = Function(); + abstract class MenuEntryBase { bool dismissOnClicked; + DismissCallback? dismissCallback; RxBool? enabled; MenuEntryBase({ this.dismissOnClicked = false, this.enabled, + this.dismissCallback, }); List> build(BuildContext context, MenuConfig conf); @@ -146,12 +150,14 @@ class MenuEntryRadioOption { String value; bool dismissOnClicked; RxBool? enabled; + DismissCallback? dismissCallback; MenuEntryRadioOption({ required this.text, required this.value, this.dismissOnClicked = false, this.enabled, + this.dismissCallback, }); } @@ -177,8 +183,13 @@ class MenuEntryRadios extends MenuEntryBase { required this.optionSetter, this.padding, dismissOnClicked = false, + dismissCallback, RxBool? enabled, - }) : super(dismissOnClicked: dismissOnClicked, enabled: enabled) { + }) : super( + dismissOnClicked: dismissOnClicked, + enabled: enabled, + dismissCallback: dismissCallback, + ) { () async { _curOption.value = await curOptionGetter(); }(); @@ -249,6 +260,9 @@ class MenuEntryRadios extends MenuEntryBase { onPressed() { if (opt.dismissOnClicked && Navigator.canPop(context)) { Navigator.pop(context); + if (opt.dismissCallback != null) { + opt.dismissCallback!(); + } } setOption(opt.value); } @@ -360,6 +374,9 @@ class MenuEntrySubRadios extends MenuEntryBase { onPressed: () { if (opt.dismissOnClicked && Navigator.canPop(context)) { Navigator.pop(context); + if (opt.dismissCallback != null) { + opt.dismissCallback!(); + } } setOption(opt.value); }, @@ -421,7 +438,12 @@ abstract class MenuEntrySwitchBase extends MenuEntryBase { this.textStyle, this.padding, RxBool? enabled, - }) : super(dismissOnClicked: dismissOnClicked, enabled: enabled); + dismissCallback, + }) : super( + dismissOnClicked: dismissOnClicked, + enabled: enabled, + dismissCallback: dismissCallback, + ); RxBool get curOption; Future setOption(bool? option); @@ -463,6 +485,9 @@ abstract class MenuEntrySwitchBase extends MenuEntryBase { if (super.dismissOnClicked && Navigator.canPop(context)) { Navigator.pop(context); + if (super.dismissCallback != null) { + super.dismissCallback!(); + } } setOption(v); }, @@ -474,6 +499,9 @@ abstract class MenuEntrySwitchBase extends MenuEntryBase { if (super.dismissOnClicked && Navigator.canPop(context)) { Navigator.pop(context); + if (super.dismissCallback != null) { + super.dismissCallback!(); + } } setOption(v); }, @@ -485,6 +513,9 @@ abstract class MenuEntrySwitchBase extends MenuEntryBase { onPressed: () { if (super.dismissOnClicked && Navigator.canPop(context)) { Navigator.pop(context); + if (super.dismissCallback != null) { + super.dismissCallback!(); + } } setOption(!curOption.value); }, @@ -508,6 +539,7 @@ class MenuEntrySwitch extends MenuEntrySwitchBase { EdgeInsets? padding, dismissOnClicked = false, RxBool? enabled, + dismissCallback, }) : super( switchType: switchType, text: text, @@ -515,6 +547,7 @@ class MenuEntrySwitch extends MenuEntrySwitchBase { padding: padding, dismissOnClicked: dismissOnClicked, enabled: enabled, + dismissCallback: dismissCallback, ) { () async { _curOption.value = await getter(); @@ -551,12 +584,15 @@ class MenuEntrySwitch2 extends MenuEntrySwitchBase { EdgeInsets? padding, dismissOnClicked = false, RxBool? enabled, + dismissCallback, }) : super( - switchType: switchType, - text: text, - textStyle: textStyle, - padding: padding, - dismissOnClicked: dismissOnClicked); + switchType: switchType, + text: text, + textStyle: textStyle, + padding: padding, + dismissOnClicked: dismissOnClicked, + dismissCallback: dismissCallback, + ); @override RxBool get curOption => getter(); @@ -627,9 +663,11 @@ class MenuEntryButton extends MenuEntryBase { this.padding, dismissOnClicked = false, RxBool? enabled, + dismissCallback, }) : super( dismissOnClicked: dismissOnClicked, enabled: enabled, + dismissCallback: dismissCallback, ); Widget _buildChild(BuildContext context, MenuConfig conf) { @@ -641,6 +679,9 @@ class MenuEntryButton extends MenuEntryBase { ? () { if (super.dismissOnClicked && Navigator.canPop(context)) { Navigator.pop(context); + if (super.dismissCallback != null) { + super.dismissCallback!(); + } } proc(); } diff --git a/flutter/lib/desktop/widgets/remote_menubar.dart b/flutter/lib/desktop/widgets/remote_menubar.dart index 2a84dcf14..5b418bcc4 100644 --- a/flutter/lib/desktop/widgets/remote_menubar.dart +++ b/flutter/lib/desktop/widgets/remote_menubar.dart @@ -231,6 +231,8 @@ class _RemoteMenubarState extends State { ); } + _menuDismissCallback() => widget.ffi.inputModel.refreshMousePos(); + Widget _buildMenubar(BuildContext context) { final List menubarItems = []; if (!isWebDesktop) { @@ -374,6 +376,7 @@ class _RemoteMenubarState extends State { onPressed: () { if (Navigator.canPop(context)) { Navigator.pop(context); + _menuDismissCallback(); } RxInt display = CurrentDisplayState.find(widget.id); if (display.value != i) { @@ -551,6 +554,7 @@ class _RemoteMenubarState extends State { onPressed: () { if (Navigator.canPop(context)) { Navigator.pop(context); + _menuDismissCallback(); } showSetOSPassword( widget.id, false, widget.ffi.dialogManager); @@ -563,6 +567,7 @@ class _RemoteMenubarState extends State { }, padding: padding, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, ), MenuEntryButton( childBuilder: (TextStyle? style) => Text( @@ -574,6 +579,7 @@ class _RemoteMenubarState extends State { }, padding: padding, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, ), MenuEntryButton( childBuilder: (TextStyle? style) => Text( @@ -585,6 +591,7 @@ class _RemoteMenubarState extends State { connect(context, widget.id, isTcpTunneling: true); }, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, ), ]); // {handler.get_audit_server() &&
  • {translate('Note')}
  • } @@ -602,6 +609,7 @@ class _RemoteMenubarState extends State { }, padding: padding, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, ), ); } @@ -618,6 +626,7 @@ class _RemoteMenubarState extends State { }, padding: padding, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, )); } } @@ -635,6 +644,7 @@ class _RemoteMenubarState extends State { }, padding: padding, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, )); } @@ -649,6 +659,7 @@ class _RemoteMenubarState extends State { }, padding: padding, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, )); if (pi.platform == kPeerPlatformWindows) { @@ -667,6 +678,7 @@ class _RemoteMenubarState extends State { }, padding: padding, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, )); } if (pi.platform != kPeerPlatformAndroid && @@ -681,6 +693,7 @@ class _RemoteMenubarState extends State { showConfirmSwitchSidesDialog(widget.id, widget.ffi.dialogManager), padding: padding, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, )); } } @@ -696,6 +709,7 @@ class _RemoteMenubarState extends State { }, padding: padding, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, )); } @@ -717,6 +731,7 @@ class _RemoteMenubarState extends State { // }, // padding: padding, // dismissOnClicked: true, + // dismissCallback: _menuDismissCallback, // )); // } } @@ -762,11 +777,13 @@ class _RemoteMenubarState extends State { text: translate('Scale original'), value: kRemoteViewStyleOriginal, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, ), MenuEntryRadioOption( text: translate('Scale adaptive'), value: kRemoteViewStyleAdaptive, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, ), ], curOptionGetter: () async { @@ -782,6 +799,7 @@ class _RemoteMenubarState extends State { }, padding: padding, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, ), MenuEntryDivider(), MenuEntryRadios( @@ -791,21 +809,26 @@ class _RemoteMenubarState extends State { text: translate('Good image quality'), value: kRemoteImageQualityBest, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, ), MenuEntryRadioOption( text: translate('Balanced'), value: kRemoteImageQualityBalanced, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, ), MenuEntryRadioOption( text: translate('Optimize reaction time'), value: kRemoteImageQualityLow, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, ), MenuEntryRadioOption( - text: translate('Custom'), - value: kRemoteImageQualityCustom, - dismissOnClicked: true), + text: translate('Custom'), + value: kRemoteImageQualityCustom, + dismissOnClicked: true, + dismissCallback: _menuDismissCallback, + ), ], curOptionGetter: () async => // null means peer id is not found, which there's no need to care about @@ -970,12 +993,14 @@ class _RemoteMenubarState extends State { text: translate('ScrollAuto'), value: kRemoteScrollStyleAuto, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, enabled: widget.ffi.canvasModel.imageOverflow, ), MenuEntryRadioOption( text: translate('Scrollbar'), value: kRemoteScrollStyleBar, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, enabled: widget.ffi.canvasModel.imageOverflow, ), ], @@ -988,6 +1013,7 @@ class _RemoteMenubarState extends State { }, padding: padding, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, )); displayMenu.insert(3, MenuEntryDivider()); @@ -1058,6 +1084,7 @@ class _RemoteMenubarState extends State { }, padding: padding, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, ), ); } @@ -1084,11 +1111,13 @@ class _RemoteMenubarState extends State { text: translate('Auto'), value: 'auto', dismissOnClicked: true, + dismissCallback: _menuDismissCallback, ), MenuEntryRadioOption( text: 'VP9', value: 'vp9', dismissOnClicked: true, + dismissCallback: _menuDismissCallback, ), ]; if (codecs[0]) { @@ -1096,6 +1125,7 @@ class _RemoteMenubarState extends State { text: 'H264', value: 'h264', dismissOnClicked: true, + dismissCallback: _menuDismissCallback, )); } if (codecs[1]) { @@ -1103,6 +1133,7 @@ class _RemoteMenubarState extends State { text: 'H265', value: 'h265', dismissOnClicked: true, + dismissCallback: _menuDismissCallback, )); } return list; @@ -1119,6 +1150,7 @@ class _RemoteMenubarState extends State { }, padding: padding, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, )); } } @@ -1141,6 +1173,7 @@ class _RemoteMenubarState extends State { }, padding: padding, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, ); }()); } @@ -1163,6 +1196,7 @@ class _RemoteMenubarState extends State { }, padding: padding, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, ); }()); } @@ -1182,6 +1216,7 @@ class _RemoteMenubarState extends State { }, padding: padding, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, )); final perms = widget.ffi.ffiModel.permissions; @@ -1219,6 +1254,7 @@ class _RemoteMenubarState extends State { }, padding: padding, dismissOnClicked: true, + dismissCallback: _menuDismissCallback, )); } } @@ -1290,6 +1326,7 @@ class _RemoteMenubarState extends State { onPressed: () { if (Navigator.canPop(context)) { Navigator.pop(context); + _menuDismissCallback(); } showKBLayoutTypeChooser( localPlatform, widget.ffi.dialogManager); @@ -1302,6 +1339,7 @@ class _RemoteMenubarState extends State { proc: () {}, padding: EdgeInsets.zero, dismissOnClicked: false, + dismissCallback: _menuDismissCallback, ), ); } @@ -1321,6 +1359,7 @@ class _RemoteMenubarState extends State { }, padding: padding, dismissOnClicked: dismissOnClicked, + dismissCallback: _menuDismissCallback, ); } } From 0940c93a481b90652af890e320ace5c4e00dde3e Mon Sep 17 00:00:00 2001 From: fufesou Date: Fri, 3 Feb 2023 20:27:05 +0800 Subject: [PATCH 2/2] show cursor on conn is established Signed-off-by: fufesou --- flutter/lib/models/model.dart | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 8a7a1005d..d032719e9 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -904,10 +904,10 @@ class CursorModel with ChangeNotifier { double _hoty = 0; double _displayOriginX = 0; double _displayOriginY = 0; - bool _firstUpdateMousePos = false; + DateTime? _firstUpdateMouseTime; bool gotMouseControl = true; DateTime _lastPeerMouse = DateTime.now() - .subtract(Duration(milliseconds: 2 * kMouseControlTimeoutMSec)); + .subtract(Duration(milliseconds: 3000 * kMouseControlTimeoutMSec)); String id = ''; WeakReference parent; @@ -926,6 +926,15 @@ class CursorModel with ChangeNotifier { DateTime.now().difference(_lastPeerMouse).inMilliseconds < kMouseControlTimeoutMSec; + bool isConnIn2Secs() { + if (_firstUpdateMouseTime == null) { + _firstUpdateMouseTime = DateTime.now(); + return true; + } else { + return DateTime.now().difference(_firstUpdateMouseTime!).inSeconds < 2; + } + } + CursorModel(this.parent); Set get cachedKeys => _cacheKeys; @@ -1122,12 +1131,10 @@ class CursorModel with ChangeNotifier { /// Update the cursor position. updateCursorPosition(Map evt, String id) async { - if (!_firstUpdateMousePos) { - _firstUpdateMousePos = true; - } else { + if (!isConnIn2Secs()) { gotMouseControl = false; + _lastPeerMouse = DateTime.now(); } - _lastPeerMouse = DateTime.now(); _x = double.parse(evt['x']); _y = double.parse(evt['y']); try {