mirror of
https://github.com/rustdesk/rustdesk.git
synced 2025-12-12 02:57:22 +00:00
refact: restore terminals (#12334)
Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
@@ -64,6 +64,7 @@ const String kWindowEventNewFileTransfer = "new_file_transfer";
|
||||
const String kWindowEventNewViewCamera = "new_view_camera";
|
||||
const String kWindowEventNewPortForward = "new_port_forward";
|
||||
const String kWindowEventNewTerminal = "new_terminal";
|
||||
const String kWindowEventRestoreTerminalSessions = "restore_terminal_sessions";
|
||||
const String kWindowEventActiveSession = "active_session";
|
||||
const String kWindowEventActiveDisplaySession = "active_display_session";
|
||||
const String kWindowEventGetRemoteList = "get_remote_list";
|
||||
|
||||
@@ -171,6 +171,8 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
|
||||
forceRelay: args['forceRelay'],
|
||||
connToken: args['connToken'],
|
||||
));
|
||||
} else if (call.method == kWindowEventRestoreTerminalSessions) {
|
||||
_restoreSessions(call.arguments);
|
||||
} else if (call.method == "onDestroy") {
|
||||
tabController.clear();
|
||||
} else if (call.method == kWindowActionRebuild) {
|
||||
@@ -188,6 +190,32 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _restoreSessions(String arguments) async {
|
||||
Map<String, dynamic>? args;
|
||||
try {
|
||||
args = jsonDecode(arguments) as Map<String, dynamic>;
|
||||
} catch (e) {
|
||||
debugPrint("Error parsing JSON arguments in _restoreSessions: $e");
|
||||
return;
|
||||
}
|
||||
final persistentSessions =
|
||||
args['persistent_sessions'] as List<dynamic>? ?? [];
|
||||
final sortedSessions = persistentSessions.whereType<int>().toList()..sort();
|
||||
for (final terminalId in sortedSessions) {
|
||||
_addNewTerminalForCurrentPeer(terminalId: terminalId);
|
||||
// A delay is required to ensure the UI has sufficient time to update
|
||||
// before adding the next terminal. Without this delay, `_TerminalPageState::dispose()`
|
||||
// may be called prematurely while the tab widget is still in the tab controller.
|
||||
// This behavior is likely due to a race condition between the UI rendering lifecycle
|
||||
// and the addition of new tabs. Attempts to use `_TerminalPageState::addPostFrameCallback()`
|
||||
// to wait for the previous page to be ready were unsuccessful, as the observed call sequence is:
|
||||
// `initState() 2 -> dispose() 2 -> postFrameCallback() 2`, followed by `initState() 3`.
|
||||
// The `Future.delayed` approach mitigates this issue by introducing a buffer period,
|
||||
// allowing the UI to stabilize before proceeding.
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
}
|
||||
}
|
||||
|
||||
bool _handleKeyEvent(KeyEvent event) {
|
||||
if (event is KeyDownEvent) {
|
||||
// Use Cmd+T on macOS, Ctrl+Shift+T on other platforms
|
||||
@@ -276,17 +304,20 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
|
||||
return false;
|
||||
}
|
||||
|
||||
void _addNewTerminal(String peerId) {
|
||||
void _addNewTerminal(String peerId, {int? terminalId}) {
|
||||
// Find first tab for this peer to get connection parameters
|
||||
final firstTab = tabController.state.value.tabs.firstWhere(
|
||||
(tab) => tab.key.startsWith('$peerId\_'),
|
||||
);
|
||||
if (firstTab.page is TerminalPage) {
|
||||
final page = firstTab.page as TerminalPage;
|
||||
final terminalId = _nextTerminalId++;
|
||||
final newTerminalId = terminalId ?? _nextTerminalId++;
|
||||
if (terminalId != null && terminalId >= _nextTerminalId) {
|
||||
_nextTerminalId = terminalId + 1;
|
||||
}
|
||||
tabController.add(_createTerminalTab(
|
||||
peerId: peerId,
|
||||
terminalId: terminalId,
|
||||
terminalId: newTerminalId,
|
||||
password: page.password,
|
||||
isSharedPassword: page.isSharedPassword,
|
||||
forceRelay: page.forceRelay,
|
||||
@@ -295,12 +326,12 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
|
||||
}
|
||||
}
|
||||
|
||||
void _addNewTerminalForCurrentPeer() {
|
||||
void _addNewTerminalForCurrentPeer({int? terminalId}) {
|
||||
final currentTab = tabController.state.value.selectedTabInfo;
|
||||
final parts = currentTab.key.split('_');
|
||||
if (parts.isNotEmpty) {
|
||||
final peerId = parts[0];
|
||||
_addNewTerminal(peerId);
|
||||
_addNewTerminal(peerId, terminalId: terminalId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'package:desktop_multi_window/desktop_multi_window.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hbb/consts.dart';
|
||||
import 'package:flutter_hbb/main.dart';
|
||||
import 'package:xterm/xterm.dart';
|
||||
|
||||
import 'model.dart';
|
||||
@@ -195,6 +198,17 @@ class TerminalModel with ChangeNotifier {
|
||||
debugPrint('[TerminalModel] Error processing buffered input: $e');
|
||||
notifyListeners();
|
||||
});
|
||||
|
||||
final persistentSessions =
|
||||
evt['persistent_sessions'] as List<dynamic>? ?? [];
|
||||
if (kWindowId != null && persistentSessions.isNotEmpty) {
|
||||
DesktopMultiWindow.invokeMethod(
|
||||
kWindowId!,
|
||||
kWindowEventRestoreTerminalSessions,
|
||||
jsonEncode({
|
||||
'persistent_sessions': persistentSessions,
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
terminal.write('Failed to open terminal: $message\r\n');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user