From 55fc0cb63bd2aae078397fda635c487dc6ebd1c9 Mon Sep 17 00:00:00 2001 From: dignow Date: Thu, 7 Sep 2023 13:39:20 +0800 Subject: [PATCH 1/4] feat, remember remote window fullscreen state Signed-off-by: dignow --- flutter/lib/common.dart | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 672adca75..8b20214df 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -1392,9 +1392,10 @@ class LastWindowPosition { double? offsetWidth; double? offsetHeight; bool? isMaximized; + bool? isFullscreen; LastWindowPosition(this.width, this.height, this.offsetWidth, - this.offsetHeight, this.isMaximized); + this.offsetHeight, this.isMaximized, this.isFullscreen); Map toJson() { return { @@ -1403,6 +1404,7 @@ class LastWindowPosition { "offsetWidth": offsetWidth, "offsetHeight": offsetHeight, "isMaximized": isMaximized, + "isFullscreen": isFullscreen, }; } @@ -1418,7 +1420,7 @@ class LastWindowPosition { try { final m = jsonDecode(content); return LastWindowPosition(m["width"], m["height"], m["offsetWidth"], - m["offsetHeight"], m["isMaximized"]); + m["offsetHeight"], m["isMaximized"], m["isFullscreen"]); } catch (e) { debugPrintStack( label: @@ -1484,20 +1486,21 @@ Future saveWindowPosition(WindowType type, {int? windowId}) async { } final pos = LastWindowPosition( - sz.width, sz.height, position.dx, position.dy, isMaximized); + sz.width, sz.height, position.dx, position.dy, isMaximized, stateGlobal.fullscreen); debugPrint( - "Saving frame: $windowId: ${pos.width}/${pos.height}, offset:${pos.offsetWidth}/${pos.offsetHeight}, isMaximized:${pos.isMaximized}"); + "Saving frame: $windowId: ${pos.width}/${pos.height}, offset:${pos.offsetWidth}/${pos.offsetHeight}, isMaximized:${pos.isMaximized}, isFullscreen:${pos.isFullscreen}"); await bind.setLocalFlutterOption( k: kWindowPrefix + type.name, v: pos.toString()); if (type == WindowType.RemoteDesktop && windowId != null) { - await _saveSessionWindowPosition(type, windowId, isMaximized, pos); + await _saveSessionWindowPosition( + type, windowId, isMaximized, stateGlobal.fullscreen, pos); } } Future _saveSessionWindowPosition(WindowType windowType, int windowId, - bool isMaximized, LastWindowPosition pos) async { + bool isMaximized, bool isFullscreen, LastWindowPosition pos) async { final remoteList = await DesktopMultiWindow.invokeMethod( windowId, kWindowEventGetRemoteList, null); getPeerPos(String peerId) { @@ -1510,7 +1513,8 @@ Future _saveSessionWindowPosition(WindowType windowType, int windowId, lpos?.height ?? pos.offsetHeight, lpos?.offsetWidth ?? pos.offsetWidth, lpos?.offsetHeight ?? pos.offsetHeight, - isMaximized) + isMaximized, + isFullscreen) .toString(); } else { return pos.toString(); @@ -1700,7 +1704,13 @@ Future restoreWindowPosition(WindowType type, await wc.setFrame(frame); } } - if (lpos.isMaximized == true) { + if (lpos.isFullscreen == true) { + await restoreFrame(); + // An duration is needed to avoid the window being restored after fullscreen. + Future.delayed(Duration(milliseconds: 300), () async { + stateGlobal.setFullscreen(true); + }); + } else if (lpos.isMaximized == true) { await restoreFrame(); // An duration is needed to avoid the window being restored after maximized. Future.delayed(Duration(milliseconds: 300), () async { From 17af5622eca67a7ccc209e8b8eb5b654da37c314 Mon Sep 17 00:00:00 2001 From: dignow Date: Thu, 7 Sep 2023 20:04:23 +0800 Subject: [PATCH 2/4] remember remote window fullscreen, set global state Signed-off-by: dignow --- .../lib/desktop/pages/remote_tab_page.dart | 1 + flutter/lib/models/state_model.dart | 32 ++++++++++--------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index 4467adad4..0490ce373 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -410,6 +410,7 @@ class _ConnectionTabPageState extends State { void onRemoveId(String id) async { if (tabController.state.value.tabs.isEmpty) { await WindowController.fromWindowId(windowId()).close(); + stateGlobal.setFullscreen(false, procWnd: false); } ConnectionTypeState.delete(id); _update_remote_count(); diff --git a/flutter/lib/models/state_model.dart b/flutter/lib/models/state_model.dart index d7784f652..a70d0f97d 100644 --- a/flutter/lib/models/state_model.dart +++ b/flutter/lib/models/state_model.dart @@ -64,7 +64,7 @@ class StateGlobal { setMinimized(bool v) => _isMinimized = v; - setFullscreen(bool v) { + setFullscreen(bool v, {bool procWnd = true}) { if (_fullscreen != v) { _fullscreen = v; _showTabBar.value = !_fullscreen; @@ -76,20 +76,22 @@ class StateGlobal { print( "fullscreen: $fullscreen, resizeEdgeSize: ${_resizeEdgeSize.value}"); _windowBorderWidth.value = fullscreen ? 0 : kWindowBorderWidth; - 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); - }); - } - }); + if (procWnd) { + 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 5293e3b2776167349dc9fa0b1d71938de3cb0a2e Mon Sep 17 00:00:00 2001 From: dignow Date: Thu, 7 Sep 2023 21:50:03 +0800 Subject: [PATCH 3/4] fix, macos, remote fullscreen mode Signed-off-by: dignow --- flutter/lib/common.dart | 6 +- .../lib/desktop/pages/remote_tab_page.dart | 9 +++ .../lib/desktop/widgets/tabbar_widget.dart | 57 +++++++++++++++---- flutter/lib/models/chat_model.dart | 1 - flutter/lib/models/state_model.dart | 2 + 5 files changed, 61 insertions(+), 14 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 8b20214df..33321c81a 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -1441,6 +1441,8 @@ Future saveWindowPosition(WindowType type, {int? windowId}) async { late Offset position; late Size sz; late bool isMaximized; + bool isFullscreen = stateGlobal.fullscreen || + (Platform.isMacOS && stateGlobal.closeOnFullscreen); setFrameIfMaximized() { if (isMaximized) { final pos = bind.getLocalFlutterOption(k: kWindowPrefix + type.name); @@ -1486,7 +1488,7 @@ Future saveWindowPosition(WindowType type, {int? windowId}) async { } final pos = LastWindowPosition( - sz.width, sz.height, position.dx, position.dy, isMaximized, stateGlobal.fullscreen); + sz.width, sz.height, position.dx, position.dy, isMaximized, isFullscreen); debugPrint( "Saving frame: $windowId: ${pos.width}/${pos.height}, offset:${pos.offsetWidth}/${pos.offsetHeight}, isMaximized:${pos.isMaximized}, isFullscreen:${pos.isFullscreen}"); @@ -1495,7 +1497,7 @@ Future saveWindowPosition(WindowType type, {int? windowId}) async { if (type == WindowType.RemoteDesktop && windowId != null) { await _saveSessionWindowPosition( - type, windowId, isMaximized, stateGlobal.fullscreen, pos); + type, windowId, isMaximized, isFullscreen, pos); } } diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index 0490ce373..cb9438465 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:async'; import 'dart:io'; import 'dart:ui' as ui; @@ -109,6 +110,14 @@ class _ConnectionTabPageState extends State { final sessionId = args['session_id']; final tabWindowId = args['tab_window_id']; windowOnTop(windowId()); + if (tabController.length == 0) { + if (Platform.isMacOS && stateGlobal.closeOnFullscreen) { + Timer( + Duration(milliseconds: 300), + () async => await WindowController.fromWindowId(windowId()) + .setFullscreen(true)); + } + } ConnectionTypeState.init(id); _toolbarState.setShow( bind.mainGetUserDefaultOption(key: 'collapse_toolbar') != 'Y'); diff --git a/flutter/lib/desktop/widgets/tabbar_widget.dart b/flutter/lib/desktop/widgets/tabbar_widget.dart index b27e8fafe..2dcd757a1 100644 --- a/flutter/lib/desktop/widgets/tabbar_widget.dart +++ b/flutter/lib/desktop/widgets/tabbar_widget.dart @@ -482,6 +482,8 @@ class WindowActionPanel extends StatefulWidget { class WindowActionPanelState extends State with MultiWindowListener, WindowListener { final _saveFrameDebounce = Debouncer(delay: Duration(seconds: 1)); + Timer? _macOSCheckRestoreTimer; + int _macOSCheckRestoreCounter = 0; @override void initState() { @@ -514,6 +516,7 @@ class WindowActionPanelState extends State void dispose() { DesktopMultiWindow.removeListener(this); windowManager.removeListener(this); + _macOSCheckRestoreTimer?.cancel(); super.dispose(); } @@ -566,6 +569,33 @@ class WindowActionPanelState extends State @override void onWindowClose() async { + mainWindowClose() async => await windowManager.hide(); + notMainWindowClose(WindowController controller) async { + await controller.hide(); + await Future.wait([ + rustDeskWinManager + .call(WindowType.Main, kWindowEventHide, {"id": kWindowId!}), + widget.onClose?.call() ?? Future.microtask(() => null) + ]); + } + + macOSWindowClose( + Future Function() restoreFunc, + Future Function() checkFullscreen, + Future Function() closeFunc) async { + await restoreFunc(); + _macOSCheckRestoreCounter = 0; + _macOSCheckRestoreTimer = + Timer.periodic(Duration(milliseconds: 30), (timer) async { + _macOSCheckRestoreCounter++; + if (!await checkFullscreen() || _macOSCheckRestoreCounter >= 30) { + _macOSCheckRestoreTimer?.cancel(); + _macOSCheckRestoreTimer = null; + Timer(Duration(milliseconds: 500), () async => await closeFunc()); + } + }); + } + // hide window on close if (widget.isMainWindow) { if (rustDeskWinManager.getActiveWindows().contains(kMainWindowId)) { @@ -573,23 +603,28 @@ class WindowActionPanelState extends State } // macOS specific workaround, the window is not hiding when in fullscreen. if (Platform.isMacOS && await windowManager.isFullScreen()) { - await windowManager.setFullScreen(false); - await Future.delayed(Duration(seconds: 1)); + stateGlobal.closeOnFullscreen = true; + await macOSWindowClose( + () async => await windowManager.setFullScreen(false), + () async => await windowManager.isFullScreen(), + mainWindowClose); + } else { + stateGlobal.closeOnFullscreen = false; + await mainWindowClose(); } - await windowManager.hide(); } else { // it's safe to hide the subwindow final controller = WindowController.fromWindowId(kWindowId!); if (Platform.isMacOS && await controller.isFullScreen()) { - await controller.setFullscreen(false); - await Future.delayed(Duration(seconds: 1)); + stateGlobal.closeOnFullscreen = true; + await macOSWindowClose( + () async => await controller.setFullscreen(false), + () async => await controller.isFullScreen(), + () async => await notMainWindowClose(controller)); + } else { + stateGlobal.closeOnFullscreen = false; + await notMainWindowClose(controller); } - await controller.hide(); - await Future.wait([ - rustDeskWinManager - .call(WindowType.Main, kWindowEventHide, {"id": kWindowId!}), - widget.onClose?.call() ?? Future.microtask(() => null) - ]); } super.onWindowClose(); } diff --git a/flutter/lib/models/chat_model.dart b/flutter/lib/models/chat_model.dart index 37766e54a..61d7682e1 100644 --- a/flutter/lib/models/chat_model.dart +++ b/flutter/lib/models/chat_model.dart @@ -10,7 +10,6 @@ import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart'; import 'package:flutter_hbb/mobile/pages/home_page.dart'; import 'package:flutter_hbb/models/platform_model.dart'; import 'package:flutter_hbb/models/state_model.dart'; -import 'package:get/get_rx/src/rx_types/rx_types.dart'; import 'package:get/get.dart'; import 'package:uuid/uuid.dart'; import 'package:window_manager/window_manager.dart'; diff --git a/flutter/lib/models/state_model.dart b/flutter/lib/models/state_model.dart index a70d0f97d..e36bef924 100644 --- a/flutter/lib/models/state_model.dart +++ b/flutter/lib/models/state_model.dart @@ -20,6 +20,8 @@ class StateGlobal { final RxBool showRemoteToolBar = false.obs; final RxInt displaysCount = 0.obs; final svcStatus = SvcStatus.notReady.obs; + // Only used for macOS + bool closeOnFullscreen = false; // Use for desktop -> remote toolbar -> resolution final Map> _lastResolutionGroupValues = {}; From 296ebd0341bd6a16cd66feeab99e1b61ba7fa0f1 Mon Sep 17 00:00:00 2001 From: dignow Date: Thu, 7 Sep 2023 22:26:32 +0800 Subject: [PATCH 4/4] fix, macos, remote fullscreen state, debug Signed-off-by: dignow --- flutter/lib/desktop/pages/remote_tab_page.dart | 5 +---- flutter/lib/desktop/widgets/tabbar_widget.dart | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index cb9438465..063fe49d8 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -112,10 +112,7 @@ class _ConnectionTabPageState extends State { windowOnTop(windowId()); if (tabController.length == 0) { if (Platform.isMacOS && stateGlobal.closeOnFullscreen) { - Timer( - Duration(milliseconds: 300), - () async => await WindowController.fromWindowId(windowId()) - .setFullscreen(true)); + stateGlobal.setFullscreen(true); } } ConnectionTypeState.init(id); diff --git a/flutter/lib/desktop/widgets/tabbar_widget.dart b/flutter/lib/desktop/widgets/tabbar_widget.dart index 2dcd757a1..be089559b 100644 --- a/flutter/lib/desktop/widgets/tabbar_widget.dart +++ b/flutter/lib/desktop/widgets/tabbar_widget.dart @@ -591,7 +591,7 @@ class WindowActionPanelState extends State if (!await checkFullscreen() || _macOSCheckRestoreCounter >= 30) { _macOSCheckRestoreTimer?.cancel(); _macOSCheckRestoreTimer = null; - Timer(Duration(milliseconds: 500), () async => await closeFunc()); + Timer(Duration(milliseconds: 700), () async => await closeFunc()); } }); }