refact, separate remote window

Signed-off-by: dignow <linlong1265@gmail.com>
This commit is contained in:
dignow 2023-08-01 22:19:38 +08:00
parent 72c198a1e9
commit f495bf105f
12 changed files with 297 additions and 233 deletions

View file

@ -5,6 +5,7 @@ import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hbb/consts.dart';
import 'package:flutter_hbb/common.dart';
/// must keep the order
@ -35,146 +36,159 @@ class RustDeskMultiWindowManager {
static final instance = RustDeskMultiWindowManager._();
final List<int> _activeWindows = List.empty(growable: true);
final Set<int> _inactiveWindows = {};
final Set<int> _activeWindows = {};
final List<AsyncCallback> _windowActiveCallbacks = List.empty(growable: true);
int? _remoteDesktopWindowId;
int? _fileTransferWindowId;
int? _portForwardWindowId;
final Map<int, Set<String>> _remoteDesktopWindows = {};
final Map<int, Set<String>> _fileTransferWindows = {};
final Map<int, Set<String>> _portForwardWindows = {};
Future<dynamic> newRemoteDesktop(
String remoteId, {
Future<dynamic> newSession(
WindowType type,
String methodName,
String remoteId,
Map<int, Set<String>> windows, {
String? password,
String? switch_uuid,
bool? forceRelay,
String? switchUuid,
bool? isRDP,
}) async {
var params = {
"type": WindowType.RemoteDesktop.index,
"type": type.index,
"id": remoteId,
"password": password,
"forceRelay": forceRelay
};
if (switch_uuid != null) {
params['switch_uuid'] = switch_uuid;
if (switchUuid != null) {
params['switch_uuid'] = switchUuid;
}
if (isRDP != null) {
params['isRDP'] = isRDP;
}
final msg = jsonEncode(params);
try {
final ids = await DesktopMultiWindow.getAllSubWindowIds();
if (!ids.contains(_remoteDesktopWindowId)) {
_remoteDesktopWindowId = null;
}
} on Error {
_remoteDesktopWindowId = null;
}
if (_remoteDesktopWindowId == null) {
final remoteDesktopController =
await DesktopMultiWindow.createWindow(msg);
remoteDesktopController
newSessionWindow() async {
final windowController = await DesktopMultiWindow.createWindow(msg);
windowController
..setFrame(const Offset(0, 0) & const Size(1280, 720))
..center()
..setTitle(getWindowNameWithId(remoteId,
overrideType: WindowType.RemoteDesktop));
..setTitle(getWindowNameWithId(
remoteId,
overrideType: type,
));
if (Platform.isMacOS) {
Future.microtask(() => remoteDesktopController.show());
Future.microtask(() => windowController.show());
}
registerActiveWindow(remoteDesktopController.windowId);
_remoteDesktopWindowId = remoteDesktopController.windowId;
} else {
return call(WindowType.RemoteDesktop, "new_remote_desktop", msg);
registerActiveWindow(windowController.windowId);
windows[windowController.windowId] = {remoteId};
}
// separate window for file transfer is not supported
bool separateWindow = type != WindowType.FileTransfer &&
mainGetBoolOptionSync(kOptionSeparateRemoteWindow);
if (separateWindow) {
for (final item in windows.entries) {
if (_activeWindows.contains(item.key) &&
item.value.contains(remoteId)) {
// already has a window for this remote
final windowController = WindowController.fromWindowId(item.key);
windowController.show();
// to-do: macos?
// if (Platform.isMacOS) {
// Future.microtask(() => windowController.show());
// }
return;
}
}
if (kCloseMultiWindowByHide && _inactiveWindows.isNotEmpty) {
final windowId = _inactiveWindows.first;
final invokeRes =
await DesktopMultiWindow.invokeMethod(windowId, methodName, msg);
final windowController = WindowController.fromWindowId(windowId);
windowController.show();
registerActiveWindow(windowController.windowId);
windows[windowController.windowId] = {remoteId};
return invokeRes;
} else {
await newSessionWindow();
}
} else {
if (windows.isEmpty) {
await newSessionWindow();
} else {
return call(type, methodName, msg);
}
}
}
Future<dynamic> newRemoteDesktop(
String remoteId, {
String? password,
String? switchUuid,
bool? forceRelay,
}) async {
return await newSession(
WindowType.RemoteDesktop,
'new_remote_desktop',
remoteId,
_remoteDesktopWindows,
password: password,
forceRelay: forceRelay,
switchUuid: switchUuid,
);
}
Future<dynamic> newFileTransfer(String remoteId,
{String? password, bool? forceRelay}) async {
var msg = jsonEncode({
"type": WindowType.FileTransfer.index,
"id": remoteId,
"password": password,
"forceRelay": forceRelay,
});
try {
final ids = await DesktopMultiWindow.getAllSubWindowIds();
if (!ids.contains(_fileTransferWindowId)) {
_fileTransferWindowId = null;
}
} on Error {
_fileTransferWindowId = null;
}
if (_fileTransferWindowId == null) {
final fileTransferController = await DesktopMultiWindow.createWindow(msg);
fileTransferController
..setFrame(const Offset(0, 0) & const Size(1280, 720))
..center()
..setTitle(getWindowNameWithId(remoteId,
overrideType: WindowType.FileTransfer));
if (Platform.isMacOS) {
Future.microtask(() => fileTransferController.show());
}
registerActiveWindow(fileTransferController.windowId);
_fileTransferWindowId = fileTransferController.windowId;
} else {
return call(WindowType.FileTransfer, "new_file_transfer", msg);
}
return await newSession(
WindowType.FileTransfer,
'new_file_transfer',
remoteId,
_fileTransferWindows,
password: password,
forceRelay: forceRelay,
);
}
Future<dynamic> newPortForward(String remoteId, bool isRDP,
{String? password, bool? forceRelay}) async {
final msg = jsonEncode({
"type": WindowType.PortForward.index,
"id": remoteId,
"isRDP": isRDP,
"password": password,
"forceRelay": forceRelay,
});
try {
final ids = await DesktopMultiWindow.getAllSubWindowIds();
if (!ids.contains(_portForwardWindowId)) {
_portForwardWindowId = null;
}
} on Error {
_portForwardWindowId = null;
}
if (_portForwardWindowId == null) {
final portForwardController = await DesktopMultiWindow.createWindow(msg);
portForwardController
..setFrame(const Offset(0, 0) & const Size(1280, 720))
..center()
..setTitle(getWindowNameWithId(remoteId,
overrideType: WindowType.PortForward));
if (Platform.isMacOS) {
Future.microtask(() => portForwardController.show());
}
registerActiveWindow(portForwardController.windowId);
_portForwardWindowId = portForwardController.windowId;
} else {
return call(WindowType.PortForward, "new_port_forward", msg);
}
return await newSession(
WindowType.PortForward,
'new_port_forward',
remoteId,
_portForwardWindows,
password: password,
forceRelay: forceRelay,
isRDP: isRDP,
);
}
Future<dynamic> call(WindowType type, String methodName, dynamic args) async {
int? windowId = findWindowByType(type);
if (windowId == null) {
final wnds = _findWindowsByType(type);
if (wnds.isEmpty) {
return;
}
return await DesktopMultiWindow.invokeMethod(windowId, methodName, args);
return await DesktopMultiWindow.invokeMethod(
wnds.keys.toList()[0], methodName, args);
}
int? findWindowByType(WindowType type) {
Map<int, Set<String>> _findWindowsByType(WindowType type) {
switch (type) {
case WindowType.Main:
return 0;
return {
0: {''}
};
case WindowType.RemoteDesktop:
return _remoteDesktopWindowId;
return _remoteDesktopWindows;
case WindowType.FileTransfer:
return _fileTransferWindowId;
return _fileTransferWindows;
case WindowType.PortForward:
return _portForwardWindowId;
return _portForwardWindows;
case WindowType.Unknown:
break;
}
return null;
return {};
}
void clearWindowType(WindowType type) {
@ -182,13 +196,13 @@ class RustDeskMultiWindowManager {
case WindowType.Main:
return;
case WindowType.RemoteDesktop:
_remoteDesktopWindowId = null;
_remoteDesktopWindows.clear();
break;
case WindowType.FileTransfer:
_fileTransferWindowId = null;
_fileTransferWindows.clear();
break;
case WindowType.PortForward:
_portForwardWindowId = null;
_portForwardWindows.clear();
break;
case WindowType.Unknown:
break;
@ -209,27 +223,37 @@ class RustDeskMultiWindowManager {
// skip main window, use window manager instead
return;
}
int? wId = findWindowByType(type);
if (wId != null) {
List<int> windows = [];
try {
windows = await DesktopMultiWindow.getAllSubWindowIds();
} catch (e) {
debugPrint('Failed to getAllSubWindowIds of $type, $e');
return;
}
if (windows.isEmpty) {
return;
}
for (final wId in windows) {
debugPrint("closing multi window: ${type.toString()}");
await saveWindowPosition(type, windowId: wId);
try {
final ids = await DesktopMultiWindow.getAllSubWindowIds();
if (!ids.contains(wId)) {
// no such window already
return;
}
// final ids = await DesktopMultiWindow.getAllSubWindowIds();
// if (!ids.contains(wId)) {
// // no such window already
// return;
// }
await WindowController.fromWindowId(wId).setPreventClose(false);
await WindowController.fromWindowId(wId).close();
// unregister the sub window in the main window.
unregisterActiveWindow(wId);
_activeWindows.remove(wId);
} catch (e) {
debugPrint("$e");
return;
} finally {
clearWindowType(type);
}
}
await _notifyActiveWindow();
clearWindowType(type);
}
Future<List<int>> getAllSubWindowIds() async {
@ -245,7 +269,7 @@ class RustDeskMultiWindowManager {
}
}
List<int> getActiveWindows() {
Set<int> getActiveWindows() {
return _activeWindows;
}
@ -256,14 +280,19 @@ class RustDeskMultiWindowManager {
}
Future<void> registerActiveWindow(int windowId) async {
if (_activeWindows.contains(windowId)) {
// ignore
} else {
_activeWindows.add(windowId);
}
_activeWindows.add(windowId);
_inactiveWindows.remove(windowId);
await _notifyActiveWindow();
}
Future<void> destroyWindow(int windowId) async {
await WindowController.fromWindowId(windowId).setPreventClose(false);
await WindowController.fromWindowId(windowId).close();
_remoteDesktopWindows.remove(windowId);
_fileTransferWindows.remove(windowId);
_portForwardWindows.remove(windowId);
}
/// Remove active window which has [`windowId`]
///
/// [Availability]
@ -271,10 +300,9 @@ class RustDeskMultiWindowManager {
/// For other windows, please post a unregister(hide) event to main window handler:
/// `rustDeskWinManager.call(WindowType.Main, kWindowEventHide, {"id": windowId!});`
Future<void> unregisterActiveWindow(int windowId) async {
if (!_activeWindows.contains(windowId)) {
// ignore
} else {
_activeWindows.remove(windowId);
_activeWindows.remove(windowId);
if (windowId != kMainWindowId) {
_inactiveWindows.add(windowId);
}
await _notifyActiveWindow();
}