| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | import 'dart:convert'; | 
					
						
							| 
									
										
										
										
											2023-01-28 09:33:57 +08:00
										 |  |  | import 'dart:io'; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import 'package:desktop_multi_window/desktop_multi_window.dart'; | 
					
						
							| 
									
										
										
										
											2023-01-06 20:40:29 -08:00
										 |  |  | import 'package:flutter/foundation.dart'; | 
					
						
							| 
									
										
										
										
											2022-08-09 13:39:30 +08:00
										 |  |  | import 'package:flutter/material.dart'; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | import 'package:flutter/services.dart'; | 
					
						
							| 
									
										
										
										
											2022-10-14 19:48:41 +09:00
										 |  |  | import 'package:flutter_hbb/common.dart'; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /// must keep the order
 | 
					
						
							|  |  |  | enum WindowType { Main, RemoteDesktop, FileTransfer, PortForward, Unknown } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extension Index on int { | 
					
						
							|  |  |  |   WindowType get windowType { | 
					
						
							|  |  |  |     switch (this) { | 
					
						
							|  |  |  |       case 0: | 
					
						
							|  |  |  |         return WindowType.Main; | 
					
						
							|  |  |  |       case 1: | 
					
						
							|  |  |  |         return WindowType.RemoteDesktop; | 
					
						
							|  |  |  |       case 2: | 
					
						
							|  |  |  |         return WindowType.FileTransfer; | 
					
						
							|  |  |  |       case 3: | 
					
						
							|  |  |  |         return WindowType.PortForward; | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |         return WindowType.Unknown; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /// Window Manager
 | 
					
						
							|  |  |  | /// mainly use it in `Main Window`
 | 
					
						
							|  |  |  | /// use it in sub window is not recommended
 | 
					
						
							|  |  |  | class RustDeskMultiWindowManager { | 
					
						
							|  |  |  |   RustDeskMultiWindowManager._(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   static final instance = RustDeskMultiWindowManager._(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-05 23:41:22 +08:00
										 |  |  |   final List<int> _activeWindows = List.empty(growable: true); | 
					
						
							| 
									
										
										
										
											2023-01-06 20:40:29 -08:00
										 |  |  |   final List<AsyncCallback> _windowActiveCallbacks = List.empty(growable: true); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   int? _remoteDesktopWindowId; | 
					
						
							| 
									
										
										
										
											2022-06-17 22:57:41 +08:00
										 |  |  |   int? _fileTransferWindowId; | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |   int? _portForwardWindowId; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-13 16:40:24 +08:00
										 |  |  |   Future<dynamic> newRemoteDesktop( | 
					
						
							|  |  |  |     String remoteId, { | 
					
						
							| 
									
										
										
										
											2023-03-20 00:16:06 +08:00
										 |  |  |     String? password, | 
					
						
							| 
									
										
										
										
											2023-02-13 16:40:24 +08:00
										 |  |  |     String? switch_uuid, | 
					
						
							|  |  |  |     bool? forceRelay, | 
					
						
							|  |  |  |   }) async { | 
					
						
							| 
									
										
										
										
											2023-02-01 19:49:41 +08:00
										 |  |  |     var params = { | 
					
						
							| 
									
										
										
										
											2023-01-17 13:28:33 +08:00
										 |  |  |       "type": WindowType.RemoteDesktop.index, | 
					
						
							|  |  |  |       "id": remoteId, | 
					
						
							| 
									
										
										
										
											2023-03-20 00:16:06 +08:00
										 |  |  |       "password": password, | 
					
						
							| 
									
										
										
										
											2023-02-13 16:40:24 +08:00
										 |  |  |       "forceRelay": forceRelay | 
					
						
							| 
									
										
										
										
											2023-02-01 19:49:41 +08:00
										 |  |  |     }; | 
					
						
							|  |  |  |     if (switch_uuid != null) { | 
					
						
							|  |  |  |       params['switch_uuid'] = switch_uuid; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     final msg = jsonEncode(params); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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 | 
					
						
							|  |  |  |         ..setFrame(const Offset(0, 0) & const Size(1280, 720)) | 
					
						
							|  |  |  |         ..center() | 
					
						
							| 
									
										
										
										
											2023-01-23 22:07:50 +08:00
										 |  |  |         ..setTitle(getWindowNameWithId(remoteId, | 
					
						
							| 
									
										
										
										
											2023-01-28 09:41:05 +08:00
										 |  |  |             overrideType: WindowType.RemoteDesktop)); | 
					
						
							| 
									
										
										
										
											2023-01-28 09:33:57 +08:00
										 |  |  |       if (Platform.isMacOS) { | 
					
						
							|  |  |  |         Future.microtask(() => remoteDesktopController.show()); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-11-05 23:41:22 +08:00
										 |  |  |       registerActiveWindow(remoteDesktopController.windowId); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |       _remoteDesktopWindowId = remoteDesktopController.windowId; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return call(WindowType.RemoteDesktop, "new_remote_desktop", msg); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-07 12:22:39 +08:00
										 |  |  |   Future<dynamic> newFileTransfer(String remoteId, | 
					
						
							|  |  |  |       {String? password, bool? forceRelay}) async { | 
					
						
							| 
									
										
										
										
											2023-02-13 16:40:24 +08:00
										 |  |  |     var msg = jsonEncode({ | 
					
						
							|  |  |  |       "type": WindowType.FileTransfer.index, | 
					
						
							|  |  |  |       "id": remoteId, | 
					
						
							| 
									
										
										
										
											2023-07-07 12:22:39 +08:00
										 |  |  |       "password": password, | 
					
						
							| 
									
										
										
										
											2023-02-13 16:40:24 +08:00
										 |  |  |       "forceRelay": forceRelay, | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2022-06-17 22:57:41 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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() | 
					
						
							| 
									
										
										
										
											2023-01-23 22:07:50 +08:00
										 |  |  |         ..setTitle(getWindowNameWithId(remoteId, | 
					
						
							| 
									
										
										
										
											2023-01-28 09:41:05 +08:00
										 |  |  |             overrideType: WindowType.FileTransfer)); | 
					
						
							| 
									
										
										
										
											2023-01-28 09:33:57 +08:00
										 |  |  |       if (Platform.isMacOS) { | 
					
						
							|  |  |  |         Future.microtask(() => fileTransferController.show()); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-11-05 23:41:22 +08:00
										 |  |  |       registerActiveWindow(fileTransferController.windowId); | 
					
						
							| 
									
										
										
										
											2022-06-17 22:57:41 +08:00
										 |  |  |       _fileTransferWindowId = fileTransferController.windowId; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return call(WindowType.FileTransfer, "new_file_transfer", msg); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-13 16:40:24 +08:00
										 |  |  |   Future<dynamic> newPortForward(String remoteId, bool isRDP, | 
					
						
							| 
									
										
										
										
											2023-07-07 12:22:39 +08:00
										 |  |  |       {String? password, bool? forceRelay}) async { | 
					
						
							| 
									
										
										
										
											2023-02-13 16:40:24 +08:00
										 |  |  |     final msg = jsonEncode({ | 
					
						
							|  |  |  |       "type": WindowType.PortForward.index, | 
					
						
							|  |  |  |       "id": remoteId, | 
					
						
							|  |  |  |       "isRDP": isRDP, | 
					
						
							| 
									
										
										
										
											2023-07-07 12:22:39 +08:00
										 |  |  |       "password": password, | 
					
						
							| 
									
										
										
										
											2023-02-13 16:40:24 +08:00
										 |  |  |       "forceRelay": forceRelay, | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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() | 
					
						
							| 
									
										
										
										
											2023-01-28 09:41:05 +08:00
										 |  |  |         ..setTitle(getWindowNameWithId(remoteId, | 
					
						
							|  |  |  |             overrideType: WindowType.PortForward)); | 
					
						
							| 
									
										
										
										
											2023-01-28 09:33:57 +08:00
										 |  |  |       if (Platform.isMacOS) { | 
					
						
							|  |  |  |         Future.microtask(() => portForwardController.show()); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-11-05 23:41:22 +08:00
										 |  |  |       registerActiveWindow(portForwardController.windowId); | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |       _portForwardWindowId = portForwardController.windowId; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return call(WindowType.PortForward, "new_port_forward", msg); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   Future<dynamic> call(WindowType type, String methodName, dynamic args) async { | 
					
						
							|  |  |  |     int? windowId = findWindowByType(type); | 
					
						
							|  |  |  |     if (windowId == null) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return await DesktopMultiWindow.invokeMethod(windowId, methodName, args); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int? findWindowByType(WindowType type) { | 
					
						
							|  |  |  |     switch (type) { | 
					
						
							|  |  |  |       case WindowType.Main: | 
					
						
							| 
									
										
										
										
											2022-08-09 09:01:06 +08:00
										 |  |  |         return 0; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |       case WindowType.RemoteDesktop: | 
					
						
							|  |  |  |         return _remoteDesktopWindowId; | 
					
						
							|  |  |  |       case WindowType.FileTransfer: | 
					
						
							| 
									
										
										
										
											2022-06-27 16:44:34 +08:00
										 |  |  |         return _fileTransferWindowId; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |       case WindowType.PortForward: | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |         return _portForwardWindowId; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |       case WindowType.Unknown: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return null; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-03 17:08:40 +08:00
										 |  |  |   void clearWindowType(WindowType type) { | 
					
						
							|  |  |  |     switch (type) { | 
					
						
							|  |  |  |       case WindowType.Main: | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       case WindowType.RemoteDesktop: | 
					
						
							|  |  |  |         _remoteDesktopWindowId = null; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case WindowType.FileTransfer: | 
					
						
							|  |  |  |         _fileTransferWindowId = null; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case WindowType.PortForward: | 
					
						
							|  |  |  |         _portForwardWindowId = null; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case WindowType.Unknown: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   void setMethodHandler( | 
					
						
							|  |  |  |       Future<dynamic> Function(MethodCall call, int fromWindowId)? handler) { | 
					
						
							|  |  |  |     DesktopMultiWindow.setMethodHandler(handler); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-08-09 13:39:30 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Future<void> closeAllSubWindows() async { | 
					
						
							|  |  |  |     await Future.wait(WindowType.values.map((e) => closeWindows(e))); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |   Future<void> closeWindows(WindowType type) async { | 
					
						
							| 
									
										
										
										
											2022-08-09 13:39:30 +08:00
										 |  |  |     if (type == WindowType.Main) { | 
					
						
							|  |  |  |       // skip main window, use window manager instead
 | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     int? wId = findWindowByType(type); | 
					
						
							|  |  |  |     if (wId != null) { | 
					
						
							|  |  |  |       debugPrint("closing multi window: ${type.toString()}"); | 
					
						
							| 
									
										
										
										
											2022-10-27 18:40:45 +08:00
										 |  |  |       await saveWindowPosition(type, windowId: wId); | 
					
						
							| 
									
										
										
										
											2022-08-09 13:39:30 +08:00
										 |  |  |       try { | 
					
						
							|  |  |  |         final ids = await DesktopMultiWindow.getAllSubWindowIds(); | 
					
						
							|  |  |  |         if (!ids.contains(wId)) { | 
					
						
							|  |  |  |           // no such window already
 | 
					
						
							|  |  |  |           return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-11-06 17:39:19 +08:00
										 |  |  |         await WindowController.fromWindowId(wId).setPreventClose(false); | 
					
						
							| 
									
										
										
										
											2022-08-30 20:48:03 +08:00
										 |  |  |         await WindowController.fromWindowId(wId).close(); | 
					
						
							| 
									
										
										
										
											2023-05-02 23:48:49 +08:00
										 |  |  |         // unregister the sub window in the main window.
 | 
					
						
							|  |  |  |         unregisterActiveWindow(wId); | 
					
						
							| 
									
										
										
										
											2023-02-03 17:08:40 +08:00
										 |  |  |       } catch (e) { | 
					
						
							|  |  |  |         debugPrint("$e"); | 
					
						
							| 
									
										
										
										
											2022-08-09 13:39:30 +08:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2023-02-03 17:08:40 +08:00
										 |  |  |       } finally { | 
					
						
							|  |  |  |         clearWindowType(type); | 
					
						
							| 
									
										
										
										
											2022-08-09 13:39:30 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-11-05 23:41:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Future<List<int>> getAllSubWindowIds() async { | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       final windows = await DesktopMultiWindow.getAllSubWindowIds(); | 
					
						
							|  |  |  |       return windows; | 
					
						
							|  |  |  |     } catch (err) { | 
					
						
							|  |  |  |       if (err is AssertionError) { | 
					
						
							|  |  |  |         return []; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         rethrow; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   List<int> getActiveWindows() { | 
					
						
							|  |  |  |     return _activeWindows; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-06 20:40:29 -08:00
										 |  |  |   Future<void> _notifyActiveWindow() async { | 
					
						
							| 
									
										
										
										
											2022-11-05 23:41:22 +08:00
										 |  |  |     for (final callback in _windowActiveCallbacks) { | 
					
						
							| 
									
										
										
										
											2023-01-06 20:40:29 -08:00
										 |  |  |       await callback.call(); | 
					
						
							| 
									
										
										
										
											2022-11-05 23:41:22 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-06 20:40:29 -08:00
										 |  |  |   Future<void> registerActiveWindow(int windowId) async { | 
					
						
							| 
									
										
										
										
											2022-11-05 23:41:22 +08:00
										 |  |  |     if (_activeWindows.contains(windowId)) { | 
					
						
							|  |  |  |       // ignore
 | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       _activeWindows.add(windowId); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-01-06 20:40:29 -08:00
										 |  |  |     await _notifyActiveWindow(); | 
					
						
							| 
									
										
										
										
											2022-11-05 23:41:22 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-06 17:39:19 +08:00
										 |  |  |   /// Remove active window which has [`windowId`]
 | 
					
						
							| 
									
										
										
										
											2023-01-17 13:28:33 +08:00
										 |  |  |   ///
 | 
					
						
							| 
									
										
										
										
											2022-12-25 20:21:13 +03:00
										 |  |  |   /// [Availability]
 | 
					
						
							| 
									
										
										
										
											2022-11-06 17:39:19 +08:00
										 |  |  |   /// This function should only be called from main window.
 | 
					
						
							|  |  |  |   /// For other windows, please post a unregister(hide) event to main window handler:
 | 
					
						
							|  |  |  |   /// `rustDeskWinManager.call(WindowType.Main, kWindowEventHide, {"id": windowId!});`
 | 
					
						
							| 
									
										
										
										
											2023-01-06 20:40:29 -08:00
										 |  |  |   Future<void> unregisterActiveWindow(int windowId) async { | 
					
						
							| 
									
										
										
										
											2022-11-05 23:41:22 +08:00
										 |  |  |     if (!_activeWindows.contains(windowId)) { | 
					
						
							|  |  |  |       // ignore
 | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       _activeWindows.remove(windowId); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-01-06 20:40:29 -08:00
										 |  |  |     await _notifyActiveWindow(); | 
					
						
							| 
									
										
										
										
											2022-11-05 23:41:22 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-06 20:40:29 -08:00
										 |  |  |   void registerActiveWindowListener(AsyncCallback callback) { | 
					
						
							| 
									
										
										
										
											2022-11-05 23:41:22 +08:00
										 |  |  |     _windowActiveCallbacks.add(callback); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-06 20:40:29 -08:00
										 |  |  |   void unregisterActiveWindowListener(AsyncCallback callback) { | 
					
						
							| 
									
										
										
										
											2022-11-05 23:41:22 +08:00
										 |  |  |     _windowActiveCallbacks.remove(callback); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | final rustDeskWinManager = RustDeskMultiWindowManager.instance; |