mirror of
https://github.com/rustdesk/rustdesk.git
synced 2025-12-14 03:56:27 +00:00
feat, multi_flutter_ui_sessions
Signed-off-by: dignow <linlong1265@gmail.com>
This commit is contained in:
@@ -2,6 +2,7 @@ import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:desktop_multi_window/desktop_multi_window.dart';
|
||||
@@ -86,7 +87,7 @@ class CachedPeerData {
|
||||
class FfiModel with ChangeNotifier {
|
||||
CachedPeerData cachedPeerData = CachedPeerData();
|
||||
PeerInfo _pi = PeerInfo();
|
||||
Display _display = Display();
|
||||
Rect? _rect;
|
||||
|
||||
var _inputBlocked = false;
|
||||
final _permissions = <String, bool>{};
|
||||
@@ -103,9 +104,15 @@ class FfiModel with ChangeNotifier {
|
||||
Timer? waitForImageTimer;
|
||||
RxBool waitForFirstImage = true.obs;
|
||||
|
||||
Map<String, bool> get permissions => _permissions;
|
||||
Rect? get rect => _rect;
|
||||
bool get isOriginalResolutionSet =>
|
||||
_pi.tryGetDisplayIfNotAllDisplay()?.isOriginalResolutionSet ?? false;
|
||||
bool get isVirtualDisplayResolution =>
|
||||
_pi.tryGetDisplayIfNotAllDisplay()?.isVirtualDisplayResolution ?? false;
|
||||
bool get isOriginalResolution =>
|
||||
_pi.tryGetDisplayIfNotAllDisplay()?.isOriginalResolution ?? false;
|
||||
|
||||
Display get display => _display;
|
||||
Map<String, bool> get permissions => _permissions;
|
||||
|
||||
bool? get secure => _secure;
|
||||
|
||||
@@ -130,6 +137,24 @@ class FfiModel with ChangeNotifier {
|
||||
sessionId = parent.target!.sessionId;
|
||||
}
|
||||
|
||||
Rect? displaysRect() {
|
||||
final displays = _pi.getCurDisplays();
|
||||
if (displays.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
double l = displays[0].x;
|
||||
double t = displays[0].y;
|
||||
double r = displays[0].x + displays[0].width;
|
||||
double b = displays[0].y + displays[0].height;
|
||||
for (var display in displays.sublist(1)) {
|
||||
l = min(l, display.x);
|
||||
t = min(t, display.y);
|
||||
r = max(r, display.x + display.width);
|
||||
b = max(b, display.y + display.height);
|
||||
}
|
||||
return Rect.fromLTRB(l, t, r, b);
|
||||
}
|
||||
|
||||
toggleTouchMode() {
|
||||
if (!isPeerAndroid) {
|
||||
_touchMode = !_touchMode;
|
||||
@@ -154,7 +179,6 @@ class FfiModel with ChangeNotifier {
|
||||
|
||||
clear() {
|
||||
_pi = PeerInfo();
|
||||
_display = Display();
|
||||
_secure = null;
|
||||
_direct = null;
|
||||
_inputBlocked = false;
|
||||
@@ -207,8 +231,10 @@ class FfiModel with ChangeNotifier {
|
||||
updateLastCursorId(element);
|
||||
await handleCursorData(element);
|
||||
}
|
||||
updateLastCursorId(data.lastCursorId);
|
||||
handleCursorId(data.lastCursorId);
|
||||
if (data.lastCursorId.isNotEmpty) {
|
||||
updateLastCursorId(data.lastCursorId);
|
||||
handleCursorId(data.lastCursorId);
|
||||
}
|
||||
}
|
||||
|
||||
// todo: why called by two position
|
||||
@@ -220,11 +246,12 @@ class FfiModel with ChangeNotifier {
|
||||
} else if (name == 'peer_info') {
|
||||
handlePeerInfo(evt, peerId);
|
||||
} else if (name == 'sync_peer_info') {
|
||||
handleSyncPeerInfo(evt, sessionId);
|
||||
handleSyncPeerInfo(evt, sessionId, peerId);
|
||||
} else if (name == 'connection_ready') {
|
||||
setConnectionType(
|
||||
peerId, evt['secure'] == 'true', evt['direct'] == 'true');
|
||||
} else if (name == 'switch_display') {
|
||||
// switch display is kept for backward compatibility
|
||||
handleSwitchDisplay(evt, sessionId, peerId);
|
||||
} else if (name == 'cursor_data') {
|
||||
updateLastCursorId(evt);
|
||||
@@ -279,7 +306,7 @@ class FfiModel with ChangeNotifier {
|
||||
await bind.sessionSwitchSides(sessionId: sessionId);
|
||||
closeConnection(id: peer_id);
|
||||
} else if (name == 'portable_service_running') {
|
||||
parent.target?.elevationModel.onPortableServiceRunning(evt);
|
||||
_handlePortableServiceRunning(peerId, evt);
|
||||
} else if (name == 'on_url_scheme_received') {
|
||||
// currently comes from "_url" ipc of mac and dbus of linux
|
||||
onUrlSchemeReceived(evt);
|
||||
@@ -354,20 +381,65 @@ class FfiModel with ChangeNotifier {
|
||||
platformFFI.setEventCallback(startEventListener(sessionId, peerId));
|
||||
}
|
||||
|
||||
_updateCurDisplay(SessionID sessionId, Display newDisplay) {
|
||||
if (newDisplay != _display) {
|
||||
if (newDisplay.x != _display.x || newDisplay.y != _display.y) {
|
||||
parent.target?.cursorModel
|
||||
.updateDisplayOrigin(newDisplay.x, newDisplay.y);
|
||||
_handlePortableServiceRunning(String peerId, Map<String, dynamic> evt) {
|
||||
final running = evt['running'] == 'true';
|
||||
parent.target?.elevationModel.onPortableServiceRunning(running);
|
||||
if (running) {
|
||||
if (pi.primaryDisplay != kInvalidDisplayIndex) {
|
||||
if (pi.currentDisplay != pi.primaryDisplay) {
|
||||
// Notify to switch display
|
||||
msgBox(sessionId, 'custom-nook-nocancel-hasclose-info', 'Prompt',
|
||||
'elevated_switch_display_msg', '', parent.target!.dialogManager);
|
||||
bind.sessionSwitchDisplay(
|
||||
sessionId: sessionId,
|
||||
value: Int32List.fromList([pi.primaryDisplay]));
|
||||
}
|
||||
}
|
||||
_display = newDisplay;
|
||||
}
|
||||
}
|
||||
|
||||
handleAliasChanged(Map<String, dynamic> evt) {
|
||||
if (!isDesktop) return;
|
||||
final String peerId = evt['id'];
|
||||
final String alias = evt['alias'];
|
||||
String label = getDesktopTabLabel(peerId, alias);
|
||||
final rxTabLabel = PeerStringOption.find(evt['id'], 'tabLabel');
|
||||
if (rxTabLabel.value != label) {
|
||||
rxTabLabel.value = label;
|
||||
}
|
||||
}
|
||||
|
||||
updateCurDisplay(SessionID sessionId) {
|
||||
final newRect = displaysRect();
|
||||
if (newRect == null) {
|
||||
return;
|
||||
}
|
||||
if (newRect != _rect) {
|
||||
_rect = newRect;
|
||||
if (newRect.left != _rect?.left || newRect.top != _rect?.top) {
|
||||
parent.target?.cursorModel
|
||||
.updateDisplayOrigin(newRect.left, newRect.top);
|
||||
}
|
||||
parent.target?.canvasModel.updateViewStyle();
|
||||
_updateSessionWidthHeight(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
handleSwitchDisplay(
|
||||
Map<String, dynamic> evt, SessionID sessionId, String peerId) {
|
||||
_pi.currentDisplay = int.parse(evt['display']);
|
||||
final curDisplay = int.parse(evt['display']);
|
||||
|
||||
// The message should be handled by the another UI session.
|
||||
if (_pi.isSupportMultiDisplay) {
|
||||
if (curDisplay != _pi.currentDisplay) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_pi.currentDisplay != kAllDisplayValue) {
|
||||
_pi.currentDisplay = curDisplay;
|
||||
}
|
||||
|
||||
var newDisplay = Display();
|
||||
newDisplay.x = double.tryParse(evt['x']) ?? newDisplay.x;
|
||||
newDisplay.y = double.tryParse(evt['y']) ?? newDisplay.y;
|
||||
@@ -378,11 +450,11 @@ class FfiModel with ChangeNotifier {
|
||||
int.tryParse(evt['original_width']) ?? kInvalidResolutionValue;
|
||||
newDisplay.originalHeight =
|
||||
int.tryParse(evt['original_height']) ?? kInvalidResolutionValue;
|
||||
_pi.displays[curDisplay] = newDisplay;
|
||||
|
||||
_updateCurDisplay(sessionId, newDisplay);
|
||||
|
||||
updateCurDisplay(sessionId);
|
||||
try {
|
||||
CurrentDisplayState.find(peerId).value = _pi.currentDisplay;
|
||||
CurrentDisplayState.find(peerId).value = curDisplay;
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
@@ -522,13 +594,30 @@ class FfiModel with ChangeNotifier {
|
||||
}
|
||||
|
||||
_updateSessionWidthHeight(SessionID sessionId) {
|
||||
parent.target?.canvasModel.updateViewStyle();
|
||||
if (display.width <= 0 || display.height <= 0) {
|
||||
if (_rect == null) return;
|
||||
if (_rect!.width <= 0 || _rect!.height <= 0) {
|
||||
debugPrintStack(
|
||||
label: 'invalid display size (${display.width},${display.height})');
|
||||
label: 'invalid display size (${_rect!.width},${_rect!.height})');
|
||||
} else {
|
||||
bind.sessionSetSize(
|
||||
sessionId: sessionId, width: display.width, height: display.height);
|
||||
final displays = _pi.getCurDisplays();
|
||||
if (displays.length == 1) {
|
||||
bind.sessionSetSize(
|
||||
sessionId: sessionId,
|
||||
display:
|
||||
pi.currentDisplay == kAllDisplayValue ? 0 : pi.currentDisplay,
|
||||
width: _rect!.width.toInt(),
|
||||
height: _rect!.height.toInt(),
|
||||
);
|
||||
} else {
|
||||
for (int i = 0; i < displays.length; ++i) {
|
||||
bind.sessionSetSize(
|
||||
sessionId: sessionId,
|
||||
display: i,
|
||||
width: displays[i].width.toInt(),
|
||||
height: displays[i].height.toInt(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -541,11 +630,20 @@ class FfiModel with ChangeNotifier {
|
||||
|
||||
parent.target?.dialogManager.dismissAll();
|
||||
_pi.version = evt['version'];
|
||||
_pi.isSupportMultiUiSession =
|
||||
bind.isSupportMultiUiSession(version: _pi.version);
|
||||
_pi.username = evt['username'];
|
||||
_pi.hostname = evt['hostname'];
|
||||
_pi.platform = evt['platform'];
|
||||
_pi.sasEnabled = evt['sas_enabled'] == 'true';
|
||||
_pi.currentDisplay = int.parse(evt['current_display']);
|
||||
final currentDisplay = int.parse(evt['current_display']);
|
||||
if (_pi.primaryDisplay == kInvalidDisplayIndex) {
|
||||
_pi.primaryDisplay = currentDisplay;
|
||||
}
|
||||
|
||||
if (bind.peerGetDefaultSessionsCount(id: peerId) <= 1) {
|
||||
_pi.currentDisplay = currentDisplay;
|
||||
}
|
||||
|
||||
try {
|
||||
CurrentDisplayState.find(peerId).value = _pi.currentDisplay;
|
||||
@@ -569,10 +667,10 @@ class FfiModel with ChangeNotifier {
|
||||
for (int i = 0; i < displays.length; ++i) {
|
||||
_pi.displays.add(evtToDisplay(displays[i]));
|
||||
}
|
||||
stateGlobal.displaysCount.value = _pi.displays.length;
|
||||
_pi.displaysCount.value = _pi.displays.length;
|
||||
if (_pi.currentDisplay < _pi.displays.length) {
|
||||
_display = _pi.displays[_pi.currentDisplay];
|
||||
_updateSessionWidthHeight(sessionId);
|
||||
// now replaced to _updateCurDisplay
|
||||
updateCurDisplay(sessionId);
|
||||
}
|
||||
if (displays.isNotEmpty) {
|
||||
_reconnects = 1;
|
||||
@@ -590,12 +688,12 @@ class FfiModel with ChangeNotifier {
|
||||
sessionId: sessionId, arg: 'view-only'));
|
||||
}
|
||||
if (connType == ConnType.defaultConn) {
|
||||
final platform_additions = evt['platform_additions'];
|
||||
if (platform_additions != null && platform_additions != '') {
|
||||
final platformDdditions = evt['platform_additions'];
|
||||
if (platformDdditions != null && platformDdditions != '') {
|
||||
try {
|
||||
_pi.platform_additions = json.decode(platform_additions);
|
||||
_pi.platformDdditions = json.decode(platformDdditions);
|
||||
} catch (e) {
|
||||
debugPrint('Failed to decode platform_additions $e');
|
||||
debugPrint('Failed to decode platformDdditions $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -670,7 +768,8 @@ class FfiModel with ChangeNotifier {
|
||||
}
|
||||
|
||||
/// Handle the peer info synchronization event based on [evt].
|
||||
handleSyncPeerInfo(Map<String, dynamic> evt, SessionID sessionId) async {
|
||||
handleSyncPeerInfo(
|
||||
Map<String, dynamic> evt, SessionID sessionId, String peerId) async {
|
||||
if (evt['displays'] != null) {
|
||||
cachedPeerData.peerInfo['displays'] = evt['displays'];
|
||||
List<dynamic> displays = json.decode(evt['displays']);
|
||||
@@ -679,14 +778,54 @@ class FfiModel with ChangeNotifier {
|
||||
newDisplays.add(evtToDisplay(displays[i]));
|
||||
}
|
||||
_pi.displays = newDisplays;
|
||||
stateGlobal.displaysCount.value = _pi.displays.length;
|
||||
if (_pi.currentDisplay >= 0 && _pi.currentDisplay < _pi.displays.length) {
|
||||
_updateCurDisplay(sessionId, _pi.displays[_pi.currentDisplay]);
|
||||
_pi.displaysCount.value = _pi.displays.length;
|
||||
if (_pi.currentDisplay == kAllDisplayValue) {
|
||||
updateCurDisplay(sessionId);
|
||||
// to-do: What if the displays are changed?
|
||||
} else {
|
||||
if (_pi.currentDisplay >= 0 &&
|
||||
_pi.currentDisplay < _pi.displays.length) {
|
||||
updateCurDisplay(sessionId);
|
||||
} else {
|
||||
if (_pi.displays.isNotEmpty) {
|
||||
// Notify to switch display
|
||||
msgBox(sessionId, 'custom-nook-nocancel-hasclose-info', 'Prompt',
|
||||
'display_is_plugged_out_msg', '', parent.target!.dialogManager);
|
||||
final newDisplay = pi.primaryDisplay == kInvalidDisplayIndex
|
||||
? 0
|
||||
: pi.primaryDisplay;
|
||||
final displays = newDisplay;
|
||||
bind.sessionSwitchDisplay(
|
||||
sessionId: sessionId, value: Int32List.fromList([displays]));
|
||||
|
||||
if (_pi.isSupportMultiUiSession) {
|
||||
// If the peer supports multi-ui-session, no switch display message will be send back.
|
||||
// We need to update the display manually.
|
||||
switchToNewDisplay(newDisplay, sessionId, peerId);
|
||||
}
|
||||
} else {
|
||||
msgBox(sessionId, 'nocancel-error', 'Prompt', 'No Displays', '',
|
||||
parent.target!.dialogManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Directly switch to the new display without waiting for the response.
|
||||
switchToNewDisplay(int display, SessionID sessionId, String peerId) {
|
||||
// no need to wait for the response
|
||||
pi.currentDisplay = display;
|
||||
updateCurDisplay(sessionId);
|
||||
try {
|
||||
CurrentDisplayState.find(peerId).value = display;
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
parent.target?.recordingModel.onSwitchDisplay();
|
||||
}
|
||||
|
||||
updateBlockInputState(Map<String, dynamic> evt, String peerId) {
|
||||
_inputBlocked = evt['input_state'] == 'on';
|
||||
notifyListeners();
|
||||
@@ -709,7 +848,7 @@ class FfiModel with ChangeNotifier {
|
||||
}
|
||||
|
||||
void setViewOnly(String id, bool value) {
|
||||
if (version_cmp(_pi.version, '1.2.0') < 0) return;
|
||||
if (versionCmp(_pi.version, '1.2.0') < 0) return;
|
||||
// tmp fix for https://github.com/rustdesk/rustdesk/pull/3706#issuecomment-1481242389
|
||||
// because below rx not used in mobile version, so not initialized, below code will cause crash
|
||||
// current our flutter code quality is fucking shit now. !!!!!!!!!!!!!!!!
|
||||
@@ -749,16 +888,16 @@ class ImageModel with ChangeNotifier {
|
||||
|
||||
addCallbackOnFirstImage(Function(String) cb) => callbacksOnFirstImage.add(cb);
|
||||
|
||||
onRgba(Uint8List rgba) {
|
||||
onRgba(int display, Uint8List rgba) {
|
||||
final pid = parent.target?.id;
|
||||
img.decodeImageFromPixels(
|
||||
rgba,
|
||||
parent.target?.ffiModel.display.width ?? 0,
|
||||
parent.target?.ffiModel.display.height ?? 0,
|
||||
parent.target?.ffiModel.rect?.width.toInt() ?? 0,
|
||||
parent.target?.ffiModel.rect?.height.toInt() ?? 0,
|
||||
isWeb ? ui.PixelFormat.rgba8888 : ui.PixelFormat.bgra8888,
|
||||
onPixelsCopied: () {
|
||||
// Unlock the rgba memory from rust codes.
|
||||
platformFFI.nextRgba(sessionId);
|
||||
platformFFI.nextRgba(sessionId, display);
|
||||
}).then((image) {
|
||||
if (parent.target?.id != pid) return;
|
||||
try {
|
||||
@@ -1017,20 +1156,20 @@ class CanvasModel with ChangeNotifier {
|
||||
}
|
||||
|
||||
bool get cursorEmbedded =>
|
||||
parent.target?.ffiModel.display.cursorEmbedded ?? false;
|
||||
parent.target?.ffiModel._pi.cursorEmbedded ?? false;
|
||||
|
||||
int getDisplayWidth() {
|
||||
final defaultWidth = (isDesktop || isWebDesktop)
|
||||
? kDesktopDefaultDisplayWidth
|
||||
: kMobileDefaultDisplayWidth;
|
||||
return parent.target?.ffiModel.display.width ?? defaultWidth;
|
||||
return parent.target?.ffiModel.rect?.width.toInt() ?? defaultWidth;
|
||||
}
|
||||
|
||||
int getDisplayHeight() {
|
||||
final defaultHeight = (isDesktop || isWebDesktop)
|
||||
? kDesktopDefaultDisplayHeight
|
||||
: kMobileDefaultDisplayHeight;
|
||||
return parent.target?.ffiModel.display.height ?? defaultHeight;
|
||||
return parent.target?.ffiModel.rect?.height.toInt() ?? defaultHeight;
|
||||
}
|
||||
|
||||
static double get windowBorderWidth => stateGlobal.windowBorderWidth.value;
|
||||
@@ -1619,7 +1758,27 @@ class QualityMonitorModel with ChangeNotifier {
|
||||
updateQualityStatus(Map<String, dynamic> evt) {
|
||||
try {
|
||||
if ((evt['speed'] as String).isNotEmpty) _data.speed = evt['speed'];
|
||||
if ((evt['fps'] as String).isNotEmpty) _data.fps = evt['fps'];
|
||||
if ((evt['fps'] as String).isNotEmpty) {
|
||||
final fps = jsonDecode(evt['fps']) as Map<String, dynamic>;
|
||||
final pi = parent.target?.ffiModel.pi;
|
||||
if (pi != null) {
|
||||
final currentDisplay = pi.currentDisplay;
|
||||
if (currentDisplay != kAllDisplayValue) {
|
||||
final fps2 = fps[currentDisplay.toString()];
|
||||
if (fps2 != null) {
|
||||
_data.fps = fps2.toString();
|
||||
}
|
||||
} else if (fps.isNotEmpty) {
|
||||
final fpsList = [];
|
||||
for (var i = 0; i < pi.displays.length; i++) {
|
||||
fpsList.add((fps[i.toString()] ?? 0).toString());
|
||||
}
|
||||
_data.fps = fpsList.join(' ');
|
||||
}
|
||||
} else {
|
||||
_data.fps = null;
|
||||
}
|
||||
}
|
||||
if ((evt['delay'] as String).isNotEmpty) _data.delay = evt['delay'];
|
||||
if ((evt['target_bitrate'] as String).isNotEmpty) {
|
||||
_data.targetBitrate = evt['target_bitrate'];
|
||||
@@ -1646,8 +1805,15 @@ class RecordingModel with ChangeNotifier {
|
||||
int? width = parent.target?.canvasModel.getDisplayWidth();
|
||||
int? height = parent.target?.canvasModel.getDisplayHeight();
|
||||
if (sessionId == null || width == null || height == null) return;
|
||||
bind.sessionRecordScreen(
|
||||
sessionId: sessionId, start: true, width: width, height: height);
|
||||
final currentDisplay = parent.target?.ffiModel.pi.currentDisplay;
|
||||
if (currentDisplay != kAllDisplayValue) {
|
||||
bind.sessionRecordScreen(
|
||||
sessionId: sessionId,
|
||||
start: true,
|
||||
display: currentDisplay!,
|
||||
width: width,
|
||||
height: height);
|
||||
}
|
||||
}
|
||||
|
||||
toggle() async {
|
||||
@@ -1658,10 +1824,20 @@ class RecordingModel with ChangeNotifier {
|
||||
notifyListeners();
|
||||
await bind.sessionRecordStatus(sessionId: sessionId, status: _start);
|
||||
if (_start) {
|
||||
bind.sessionRefresh(sessionId: sessionId);
|
||||
final pi = parent.target?.ffiModel.pi;
|
||||
if (pi != null) {
|
||||
sessionRefreshVideo(sessionId, pi);
|
||||
}
|
||||
} else {
|
||||
bind.sessionRecordScreen(
|
||||
sessionId: sessionId, start: false, width: 0, height: 0);
|
||||
final currentDisplay = parent.target?.ffiModel.pi.currentDisplay;
|
||||
if (currentDisplay != kAllDisplayValue) {
|
||||
bind.sessionRecordScreen(
|
||||
sessionId: sessionId,
|
||||
start: false,
|
||||
display: currentDisplay!,
|
||||
width: 0,
|
||||
height: 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1670,8 +1846,15 @@ class RecordingModel with ChangeNotifier {
|
||||
final sessionId = parent.target?.sessionId;
|
||||
if (sessionId == null) return;
|
||||
_start = false;
|
||||
bind.sessionRecordScreen(
|
||||
sessionId: sessionId, start: false, width: 0, height: 0);
|
||||
final currentDisplay = parent.target?.ffiModel.pi.currentDisplay;
|
||||
if (currentDisplay != kAllDisplayValue) {
|
||||
bind.sessionRecordScreen(
|
||||
sessionId: sessionId,
|
||||
start: false,
|
||||
display: currentDisplay!,
|
||||
width: 0,
|
||||
height: 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1686,9 +1869,7 @@ class ElevationModel with ChangeNotifier {
|
||||
_running = false;
|
||||
}
|
||||
|
||||
onPortableServiceRunning(Map<String, dynamic> evt) {
|
||||
_running = evt['running'] == 'true';
|
||||
}
|
||||
onPortableServiceRunning(bool running) => _running = running;
|
||||
}
|
||||
|
||||
enum ConnType { defaultConn, fileTransfer, portForward, rdp }
|
||||
@@ -1751,14 +1932,18 @@ class FFI {
|
||||
}
|
||||
|
||||
/// Start with the given [id]. Only transfer file if [isFileTransfer], only port forward if [isPortForward].
|
||||
void start(String id,
|
||||
{bool isFileTransfer = false,
|
||||
bool isPortForward = false,
|
||||
bool isRdp = false,
|
||||
String? switchUuid,
|
||||
String? password,
|
||||
bool? forceRelay,
|
||||
int? tabWindowId}) {
|
||||
void start(
|
||||
String id, {
|
||||
bool isFileTransfer = false,
|
||||
bool isPortForward = false,
|
||||
bool isRdp = false,
|
||||
String? switchUuid,
|
||||
String? password,
|
||||
bool? forceRelay,
|
||||
int? tabWindowId,
|
||||
int? display,
|
||||
List<int>? displays,
|
||||
}) {
|
||||
closed = false;
|
||||
auditNote = '';
|
||||
if (isMobile) mobileReset();
|
||||
@@ -1788,11 +1973,34 @@ class FFI {
|
||||
forceRelay: forceRelay ?? false,
|
||||
password: password ?? '',
|
||||
);
|
||||
} else if (display != null) {
|
||||
if (displays == null) {
|
||||
debugPrint(
|
||||
'Unreachable, failed to add existed session to $id, the displays is null while display is $display');
|
||||
return;
|
||||
}
|
||||
final addRes = bind.sessionAddExistedSync(id: id, sessionId: sessionId);
|
||||
if (addRes != '') {
|
||||
debugPrint(
|
||||
'Unreachable, failed to add existed session to $id, $addRes');
|
||||
return;
|
||||
}
|
||||
bind.sessionTryAddDisplay(
|
||||
sessionId: sessionId, displays: Int32List.fromList(displays));
|
||||
ffiModel.pi.currentDisplay = display;
|
||||
}
|
||||
final stream = bind.sessionStart(sessionId: sessionId, id: id);
|
||||
final cb = ffiModel.startEventListener(sessionId, id);
|
||||
final useTextureRender = bind.mainUseTextureRender();
|
||||
|
||||
// Force refresh displays.
|
||||
// The controlled side may not refresh the image when the (peer,display) is already subscribed.
|
||||
if (displays != null) {
|
||||
for (final display in displays) {
|
||||
bind.sessionRefresh(sessionId: sessionId, display: display);
|
||||
}
|
||||
}
|
||||
|
||||
final SimpleWrapper<bool> isToNewWindowNotified = SimpleWrapper(false);
|
||||
// Preserved for the rgba data.
|
||||
stream.listen((message) {
|
||||
@@ -1801,8 +2009,9 @@ class FFI {
|
||||
// Session is read to be moved to a new window.
|
||||
// Get the cached data and handle the cached data.
|
||||
Future.delayed(Duration.zero, () async {
|
||||
final args = jsonEncode({'id': id, 'close': display == null});
|
||||
final cachedData = await DesktopMultiWindow.invokeMethod(
|
||||
tabWindowId, kWindowEventGetCachedSessionData, id);
|
||||
tabWindowId, kWindowEventGetCachedSessionData, args);
|
||||
if (cachedData == null) {
|
||||
// unreachable
|
||||
debugPrint('Unreachable, the cached data is empty.');
|
||||
@@ -1814,7 +2023,7 @@ class FFI {
|
||||
return;
|
||||
}
|
||||
await ffiModel.handleCachedPeerData(data, id);
|
||||
await bind.sessionRefresh(sessionId: sessionId);
|
||||
await sessionRefreshVideo(sessionId, ffiModel.pi);
|
||||
});
|
||||
isToNewWindowNotified.value = true;
|
||||
}
|
||||
@@ -1836,18 +2045,19 @@ class FFI {
|
||||
await cb(event);
|
||||
}
|
||||
} else if (message is EventToUI_Rgba) {
|
||||
final display = message.field0;
|
||||
if (useTextureRender) {
|
||||
onEvent2UIRgba();
|
||||
} else {
|
||||
// Fetch the image buffer from rust codes.
|
||||
final sz = platformFFI.getRgbaSize(sessionId);
|
||||
final sz = platformFFI.getRgbaSize(sessionId, display);
|
||||
if (sz == 0) {
|
||||
return;
|
||||
}
|
||||
final rgba = platformFFI.getRgba(sessionId, sz);
|
||||
final rgba = platformFFI.getRgba(sessionId, display, sz);
|
||||
if (rgba != null) {
|
||||
onEvent2UIRgba();
|
||||
imageModel.onRgba(rgba);
|
||||
imageModel.onRgba(display, rgba);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1979,22 +2189,73 @@ class Features {
|
||||
bool privacyMode = false;
|
||||
}
|
||||
|
||||
const kInvalidDisplayIndex = -1;
|
||||
|
||||
class PeerInfo with ChangeNotifier {
|
||||
String version = '';
|
||||
String username = '';
|
||||
String hostname = '';
|
||||
String platform = '';
|
||||
bool sasEnabled = false;
|
||||
bool isSupportMultiUiSession = false;
|
||||
int currentDisplay = 0;
|
||||
int primaryDisplay = kInvalidDisplayIndex;
|
||||
List<Display> displays = [];
|
||||
Features features = Features();
|
||||
List<Resolution> resolutions = [];
|
||||
Map<String, dynamic> platform_additions = {};
|
||||
Map<String, dynamic> platformDdditions = {};
|
||||
|
||||
RxInt displaysCount = 0.obs;
|
||||
RxBool isSet = false.obs;
|
||||
|
||||
bool get is_wayland => platform_additions['is_wayland'] == true;
|
||||
bool get is_headless => platform_additions['headless'] == true;
|
||||
bool get isWayland => platformDdditions['is_wayland'] == true;
|
||||
bool get isHeadless => platformDdditions['headless'] == true;
|
||||
|
||||
bool get isSupportMultiDisplay =>
|
||||
isDesktop && isSupportMultiUiSession && isChooseDisplayToOpen;
|
||||
|
||||
bool get cursorEmbedded => tryGetDisplay()?.cursorEmbedded ?? false;
|
||||
|
||||
Display? tryGetDisplay() {
|
||||
if (displays.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
if (currentDisplay == kAllDisplayValue) {
|
||||
return displays[0];
|
||||
} else {
|
||||
if (currentDisplay > 0 && currentDisplay < displays.length) {
|
||||
return displays[currentDisplay];
|
||||
} else {
|
||||
return displays[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Display? tryGetDisplayIfNotAllDisplay() {
|
||||
if (displays.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
if (currentDisplay == kAllDisplayValue) {
|
||||
return null;
|
||||
}
|
||||
if (currentDisplay > 0 && currentDisplay < displays.length) {
|
||||
return displays[currentDisplay];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
List<Display> getCurDisplays() {
|
||||
if (currentDisplay == kAllDisplayValue) {
|
||||
return displays;
|
||||
} else {
|
||||
if (currentDisplay >= 0 && currentDisplay < displays.length) {
|
||||
return [displays[currentDisplay]];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const canvasKey = 'canvas';
|
||||
@@ -2038,8 +2299,8 @@ Future<void> initializeCursorAndCanvas(FFI ffi) async {
|
||||
currentDisplay = p['currentDisplay'];
|
||||
}
|
||||
if (p == null || currentDisplay != ffi.ffiModel.pi.currentDisplay) {
|
||||
ffi.cursorModel
|
||||
.updateDisplayOrigin(ffi.ffiModel.display.x, ffi.ffiModel.display.y);
|
||||
ffi.cursorModel.updateDisplayOrigin(
|
||||
ffi.ffiModel.rect?.left ?? 0, ffi.ffiModel.rect?.top ?? 0);
|
||||
return;
|
||||
}
|
||||
double xCursor = p['xCursor'];
|
||||
@@ -2047,8 +2308,8 @@ Future<void> initializeCursorAndCanvas(FFI ffi) async {
|
||||
double xCanvas = p['xCanvas'];
|
||||
double yCanvas = p['yCanvas'];
|
||||
double scale = p['scale'];
|
||||
ffi.cursorModel.updateDisplayOriginWithCursor(
|
||||
ffi.ffiModel.display.x, ffi.ffiModel.display.y, xCursor, yCursor);
|
||||
ffi.cursorModel.updateDisplayOriginWithCursor(ffi.ffiModel.rect?.left ?? 0,
|
||||
ffi.ffiModel.rect?.top ?? 0, xCursor, yCursor);
|
||||
ffi.canvasModel.update(xCanvas, yCanvas, scale);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user