refact, separate remote window
Signed-off-by: dignow <linlong1265@gmail.com>
This commit is contained in:
parent
72c198a1e9
commit
f495bf105f
@ -19,7 +19,6 @@ import 'package:flutter_hbb/utils/multi_window_manager.dart';
|
||||
import 'package:flutter_hbb/utils/platform_channel.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:texture_rgba_renderer/texture_rgba_renderer.dart';
|
||||
import 'package:uni_links/uni_links.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
@ -47,11 +46,6 @@ var isMobile = isAndroid || isIOS;
|
||||
var version = "";
|
||||
int androidVersion = 0;
|
||||
|
||||
/// Incriment count for textureId.
|
||||
int _textureId = 0;
|
||||
int get newTextureId => _textureId++;
|
||||
final textureRenderer = TextureRgbaRenderer();
|
||||
|
||||
/// only available for Windows target
|
||||
int windowsBuildNumber = 0;
|
||||
DesktopType? desktopType;
|
||||
@ -1698,7 +1692,7 @@ bool handleUriLink({List<String>? cmdArgs, Uri? uri, String? uriString}) {
|
||||
Future.delayed(Duration.zero, () {
|
||||
rustDeskWinManager.newRemoteDesktop(id!,
|
||||
password: password,
|
||||
switch_uuid: switchUuid,
|
||||
switchUuid: switchUuid,
|
||||
forceRelay: forceRelay);
|
||||
});
|
||||
break;
|
||||
|
@ -22,6 +22,8 @@ const String kAppTypeDesktopRemote = "remote";
|
||||
const String kAppTypeDesktopFileTransfer = "file transfer";
|
||||
const String kAppTypeDesktopPortForward = "port forward";
|
||||
|
||||
const bool kCloseMultiWindowByHide = true;
|
||||
|
||||
const String kWindowMainWindowOnTop = "main_window_on_top";
|
||||
const String kWindowGetWindowInfo = "get_window_info";
|
||||
const String kWindowDisableGrabKeyboard = "disable_grab_keyboard";
|
||||
@ -30,6 +32,8 @@ const String kWindowEventHide = "hide";
|
||||
const String kWindowEventShow = "show";
|
||||
const String kWindowConnect = "connect";
|
||||
|
||||
const String kOptionSeparateRemoteWindow = "enable-separate-remote-window";
|
||||
|
||||
const String kUniLinksPrefix = "rustdesk://";
|
||||
const String kUrlActionClose = "close";
|
||||
|
||||
|
@ -554,7 +554,13 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
} else if (call.method == kWindowEventShow) {
|
||||
await rustDeskWinManager.registerActiveWindow(call.arguments["id"]);
|
||||
} else if (call.method == kWindowEventHide) {
|
||||
await rustDeskWinManager.unregisterActiveWindow(call.arguments["id"]);
|
||||
final wId = call.arguments['id'];
|
||||
final isSeparateWindowEnabled =
|
||||
mainGetBoolOptionSync(kOptionSeparateRemoteWindow);
|
||||
if (isSeparateWindowEnabled && !kCloseMultiWindowByHide) {
|
||||
await rustDeskWinManager.destroyWindow(wId);
|
||||
}
|
||||
await rustDeskWinManager.unregisterActiveWindow(wId);
|
||||
} else if (call.method == kWindowConnect) {
|
||||
await connectMainDesktop(
|
||||
call.arguments['id'],
|
||||
|
@ -316,7 +316,9 @@ class _GeneralState extends State<_General> {
|
||||
_OptionCheckBox(context, 'Confirm before closing multiple tabs',
|
||||
'enable-confirm-closing-tabs',
|
||||
isServer: false),
|
||||
_OptionCheckBox(context, 'Adaptive Bitrate', 'enable-abr')
|
||||
_OptionCheckBox(context, 'Adaptive Bitrate', 'enable-abr'),
|
||||
_OptionCheckBox(
|
||||
context, 'Separate remote window', kOptionSeparateRemoteWindow, isServer: false),
|
||||
];
|
||||
// though this is related to GUI, but opengl problem affects all users, so put in config rather than local
|
||||
children.add(Tooltip(
|
||||
|
@ -18,6 +18,7 @@ import '../../common/widgets/remote_input.dart';
|
||||
import '../../common.dart';
|
||||
import '../../common/widgets/dialog.dart';
|
||||
import '../../models/model.dart';
|
||||
import '../../models/desktop_render_texture.dart';
|
||||
import '../../models/platform_model.dart';
|
||||
import '../../common/shared_state.dart';
|
||||
import '../../utils/image.dart';
|
||||
@ -66,9 +67,7 @@ class _RemotePageState extends State<RemotePage>
|
||||
late RxBool _zoomCursor;
|
||||
late RxBool _remoteCursorMoved;
|
||||
late RxBool _keyboardEnabled;
|
||||
late RxInt _textureId;
|
||||
late int _textureKey;
|
||||
final useTextureRender = bind.mainUseTextureRender();
|
||||
late RenderTexture _renderTexture;
|
||||
|
||||
final _blockableOverlayState = BlockableOverlayState();
|
||||
|
||||
@ -86,8 +85,6 @@ class _RemotePageState extends State<RemotePage>
|
||||
_showRemoteCursor = ShowRemoteCursorState.find(id);
|
||||
_keyboardEnabled = KeyboardEnabledState.find(id);
|
||||
_remoteCursorMoved = RemoteCursorMovedState.find(id);
|
||||
_textureKey = newTextureId;
|
||||
_textureId = RxInt(-1);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -115,17 +112,13 @@ class _RemotePageState extends State<RemotePage>
|
||||
Wakelock.enable();
|
||||
}
|
||||
// Register texture.
|
||||
_textureId.value = -1;
|
||||
if (useTextureRender) {
|
||||
textureRenderer.createTexture(_textureKey).then((id) async {
|
||||
debugPrint("id: $id, texture_key: $_textureKey");
|
||||
if (id != -1) {
|
||||
final ptr = await textureRenderer.getTexturePtr(_textureKey);
|
||||
platformFFI.registerTexture(sessionId, ptr);
|
||||
_textureId.value = id;
|
||||
}
|
||||
});
|
||||
if (mainGetBoolOptionSync(kOptionSeparateRemoteWindow)) {
|
||||
_renderTexture = renderTexture;
|
||||
} else {
|
||||
_renderTexture = RenderTexture();
|
||||
}
|
||||
_renderTexture.create(sessionId);
|
||||
|
||||
_ffi.ffiModel.updateEventListener(sessionId, widget.id);
|
||||
bind.pluginSyncUi(syncTo: kAppTypeDesktopRemote);
|
||||
_ffi.qualityMonitorModel.checkShowQualityMonitor(sessionId);
|
||||
@ -208,13 +201,8 @@ class _RemotePageState extends State<RemotePage>
|
||||
Future<void> dispose() async {
|
||||
// https://github.com/flutter/flutter/issues/64935
|
||||
super.dispose();
|
||||
debugPrint("REMOTE PAGE dispose ${widget.id}");
|
||||
if (useTextureRender) {
|
||||
platformFFI.registerTexture(sessionId, 0);
|
||||
// sleep for a while to avoid the texture is used after it's unregistered.
|
||||
await Future.delayed(Duration(milliseconds: 100));
|
||||
await textureRenderer.closeTexture(_textureKey);
|
||||
}
|
||||
debugPrint("REMOTE PAGE dispose session $sessionId ${widget.id}");
|
||||
await _renderTexture.destroy();
|
||||
// ensure we leave this session, this is a double check
|
||||
bind.sessionEnterOrLeave(sessionId: sessionId, enter: false);
|
||||
DesktopMultiWindow.removeListener(this);
|
||||
@ -392,8 +380,8 @@ class _RemotePageState extends State<RemotePage>
|
||||
cursorOverImage: _cursorOverImage,
|
||||
keyboardEnabled: _keyboardEnabled,
|
||||
remoteCursorMoved: _remoteCursorMoved,
|
||||
textureId: _textureId,
|
||||
useTextureRender: useTextureRender,
|
||||
textureId: _renderTexture.textureId,
|
||||
useTextureRender: _renderTexture.useTextureRender,
|
||||
listenerBuilder: (child) =>
|
||||
_buildRawTouchAndPointerRegion(child, enterView, leaveView),
|
||||
);
|
||||
|
@ -13,6 +13,7 @@ import 'package:flutter_hbb/consts.dart';
|
||||
import 'package:flutter_hbb/main.dart';
|
||||
import 'package:flutter_hbb/models/platform_model.dart';
|
||||
import 'package:flutter_hbb/models/state_model.dart';
|
||||
import 'package:flutter_hbb/models/desktop_render_texture.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get/get_rx/src/rx_workers/utils/debouncer.dart';
|
||||
@ -574,6 +575,8 @@ class WindowActionPanelState extends State<WindowActionPanel>
|
||||
}
|
||||
await windowManager.hide();
|
||||
} else {
|
||||
renderTexture.destroy();
|
||||
|
||||
// it's safe to hide the subwindow
|
||||
final controller = WindowController.fromWindowId(kWindowId!);
|
||||
if (Platform.isMacOS && await controller.isFullScreen()) {
|
||||
|
46
flutter/lib/models/desktop_render_texture.dart
Normal file
46
flutter/lib/models/desktop_render_texture.dart
Normal file
@ -0,0 +1,46 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:texture_rgba_renderer/texture_rgba_renderer.dart';
|
||||
|
||||
import '../../common.dart';
|
||||
import './platform_model.dart';
|
||||
|
||||
class RenderTexture {
|
||||
final RxInt textureId = RxInt(-1);
|
||||
int _textureKey = -1;
|
||||
SessionID? _sessionId;
|
||||
final useTextureRender = bind.mainUseTextureRender();
|
||||
|
||||
final textureRenderer = TextureRgbaRenderer();
|
||||
|
||||
RenderTexture();
|
||||
|
||||
create(SessionID sessionId) {
|
||||
if (useTextureRender) {
|
||||
_textureKey = bind.getNextTextureKey();
|
||||
_sessionId = sessionId;
|
||||
|
||||
textureRenderer.createTexture(_textureKey).then((id) async {
|
||||
debugPrint("id: $id, texture_key: $_textureKey");
|
||||
if (id != -1) {
|
||||
final ptr = await textureRenderer.getTexturePtr(_textureKey);
|
||||
platformFFI.registerTexture(sessionId, ptr);
|
||||
textureId.value = id;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
destroy() async {
|
||||
if (useTextureRender && _textureKey != -1 && _sessionId != null) {
|
||||
platformFFI.registerTexture(_sessionId!, 0);
|
||||
await textureRenderer.closeTexture(_textureKey);
|
||||
_textureKey = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static final RenderTexture instance = RenderTexture();
|
||||
}
|
||||
|
||||
// Global instance for separate texture
|
||||
final renderTexture = RenderTexture.instance;
|
@ -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();
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ pub type FlutterRgbaRendererPluginOnRgba = unsafe extern "C" fn(
|
||||
#[derive(Clone)]
|
||||
struct VideoRenderer {
|
||||
// TextureRgba pointer in flutter native.
|
||||
ptr: usize,
|
||||
ptr: Arc<RwLock<usize>>,
|
||||
width: usize,
|
||||
height: usize,
|
||||
on_rgba_func: Option<Symbol<'static, FlutterRgbaRendererPluginOnRgba>>,
|
||||
@ -214,7 +214,7 @@ impl Default for VideoRenderer {
|
||||
}
|
||||
};
|
||||
Self {
|
||||
ptr: 0,
|
||||
ptr: Default::default(),
|
||||
width: 0,
|
||||
height: 0,
|
||||
on_rgba_func,
|
||||
@ -231,7 +231,8 @@ impl VideoRenderer {
|
||||
}
|
||||
|
||||
pub fn on_rgba(&self, rgba: &mut scrap::ImageRgb) {
|
||||
if self.ptr == usize::default() {
|
||||
let ptr = self.ptr.read().unwrap();
|
||||
if *ptr == usize::default() {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -243,7 +244,7 @@ impl VideoRenderer {
|
||||
if let Some(func) = &self.on_rgba_func {
|
||||
unsafe {
|
||||
func(
|
||||
self.ptr as _,
|
||||
*ptr as _,
|
||||
rgba.raw.as_ptr() as _,
|
||||
rgba.raw.len() as _,
|
||||
rgba.w as _,
|
||||
@ -328,7 +329,7 @@ impl FlutterHandler {
|
||||
#[inline]
|
||||
#[cfg(feature = "flutter_texture_render")]
|
||||
pub fn register_texture(&mut self, ptr: usize) {
|
||||
self.renderer.write().unwrap().ptr = ptr;
|
||||
*self.renderer.read().unwrap().ptr.write().unwrap() = ptr;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -15,7 +15,7 @@ use flutter_rust_bridge::{StreamSink, SyncReturn};
|
||||
use hbb_common::allow_err;
|
||||
use hbb_common::{
|
||||
config::{self, LocalConfig, PeerConfig, PeerInfoSerde},
|
||||
fs, log,
|
||||
fs, lazy_static, log,
|
||||
message_proto::KeyboardMode,
|
||||
ResultType,
|
||||
};
|
||||
@ -24,11 +24,19 @@ use std::{
|
||||
ffi::{CStr, CString},
|
||||
os::raw::c_char,
|
||||
str::FromStr,
|
||||
sync::{
|
||||
atomic::{AtomicI32, Ordering},
|
||||
Arc,
|
||||
},
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
pub type SessionID = uuid::Uuid;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref TEXTURE_RENDER_KEY: Arc<AtomicI32> = Arc::new(AtomicI32::new(0));
|
||||
}
|
||||
|
||||
fn initialize(app_dir: &str) {
|
||||
*config::APP_DIR.write().unwrap() = app_dir.to_owned();
|
||||
#[cfg(target_os = "android")]
|
||||
@ -197,6 +205,11 @@ pub fn session_set_flutter_config(session_id: SessionID, k: String, v: String) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_next_texture_key() -> SyncReturn<i32> {
|
||||
let k = TEXTURE_RENDER_KEY.fetch_add(1, Ordering::SeqCst) + 1;
|
||||
SyncReturn(k)
|
||||
}
|
||||
|
||||
pub fn get_local_flutter_config(k: String) -> SyncReturn<String> {
|
||||
SyncReturn(ui_interface::get_local_flutter_config(k))
|
||||
}
|
||||
|
69
src/ui.rs
69
src/ui.rs
@ -94,8 +94,7 @@ pub fn start(args: &mut [String]) {
|
||||
args[1] = id;
|
||||
}
|
||||
if args.is_empty() {
|
||||
let children: Children = Default::default();
|
||||
std::thread::spawn(move || check_zombie(children));
|
||||
std::thread::spawn(move || check_zombie());
|
||||
crate::common::check_software_update();
|
||||
frame.event_handler(UI {});
|
||||
frame.sciter_handler(UIHostHandler {});
|
||||
@ -693,28 +692,6 @@ impl sciter::host::HostHandler for UIHostHandler {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_zombie(children: Children) {
|
||||
let mut deads = Vec::new();
|
||||
loop {
|
||||
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() {
|
||||
deads.push(id.clone());
|
||||
n += 1;
|
||||
}
|
||||
}
|
||||
for ref id in deads.drain(..) {
|
||||
lock.1.remove(id);
|
||||
}
|
||||
if n > 0 {
|
||||
lock.0 = true;
|
||||
}
|
||||
drop(lock);
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
fn get_sound_inputs() -> Vec<String> {
|
||||
let mut out = Vec::new();
|
||||
@ -748,50 +725,6 @@ pub fn value_crash_workaround(values: &[Value]) -> Arc<Vec<Value>> {
|
||||
persist
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_remote(id: String, remote_type: String, force_relay: bool) {
|
||||
let mut lock = CHILDREN.lock().unwrap();
|
||||
let mut args = vec![format!("--{}", remote_type), id.clone()];
|
||||
if force_relay {
|
||||
args.push("".to_string()); // password
|
||||
args.push("--relay".to_string());
|
||||
}
|
||||
let key = (id.clone(), remote_type.clone());
|
||||
if let Some(c) = lock.1.get_mut(&key) {
|
||||
if let Ok(Some(_)) = c.try_wait() {
|
||||
lock.1.remove(&key);
|
||||
} else {
|
||||
if remote_type == "rdp" {
|
||||
allow_err!(c.kill());
|
||||
std::thread::sleep(std::time::Duration::from_millis(30));
|
||||
c.try_wait().ok();
|
||||
lock.1.remove(&key);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
match crate::run_me(args) {
|
||||
Ok(child) => {
|
||||
lock.1.insert(key, child);
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("Failed to spawn remote: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn recent_sessions_updated() -> bool {
|
||||
let mut children = CHILDREN.lock().unwrap();
|
||||
if children.0 {
|
||||
children.0 = false;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_icon() -> String {
|
||||
// 128x128
|
||||
#[cfg(target_os = "macos")]
|
||||
|
@ -65,6 +65,7 @@ lazy_static::lazy_static! {
|
||||
static ref OPTION_SYNCED: Arc<Mutex<bool>> = Default::default();
|
||||
static ref OPTIONS : Arc<Mutex<HashMap<String, String>>> = Arc::new(Mutex::new(Config::get_options()));
|
||||
pub static ref SENDER : Mutex<mpsc::UnboundedSender<ipc::Data>> = Mutex::new(check_connect_status(true));
|
||||
static ref CHILDREN : Children = Default::default();
|
||||
}
|
||||
|
||||
const INIT_ASYNC_JOB_STATUS: &str = " ";
|
||||
@ -827,11 +828,11 @@ pub fn check_super_user_permission() -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn check_zombie(children: Children) {
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios", feature = "flutter")))]
|
||||
pub fn check_zombie() {
|
||||
let mut deads = Vec::new();
|
||||
loop {
|
||||
let mut lock = children.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() {
|
||||
@ -850,6 +851,51 @@ pub fn check_zombie(children: Children) {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios", feature = "flutter")))]
|
||||
pub fn recent_sessions_updated() -> bool {
|
||||
let mut children = CHILDREN.lock().unwrap();
|
||||
if children.0 {
|
||||
children.0 = false;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios", feature = "flutter")))]
|
||||
pub fn new_remote(id: String, remote_type: String, force_relay: bool) {
|
||||
let mut lock = CHILDREN.lock().unwrap();
|
||||
let mut args = vec![format!("--{}", remote_type), id.clone()];
|
||||
if force_relay {
|
||||
args.push("".to_string()); // password
|
||||
args.push("--relay".to_string());
|
||||
}
|
||||
let key = (id.clone(), remote_type.clone());
|
||||
if let Some(c) = lock.1.get_mut(&key) {
|
||||
if let Ok(Some(_)) = c.try_wait() {
|
||||
lock.1.remove(&key);
|
||||
} else {
|
||||
if remote_type == "rdp" {
|
||||
allow_err!(c.kill());
|
||||
std::thread::sleep(std::time::Duration::from_millis(30));
|
||||
c.try_wait().ok();
|
||||
lock.1.remove(&key);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
match crate::run_me(args) {
|
||||
Ok(child) => {
|
||||
lock.1.insert(key, child);
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("Failed to spawn remote: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure `SENDER` is inited here.
|
||||
#[inline]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
|
Loading…
x
Reference in New Issue
Block a user