refact: remove linux headless (#15866)

* refact: remove linux headless

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(linux): probe DRM availability asynchronously on login

Signed-off-by: fufesou <linlong1266@gmail.com>

* revert changes in drm_capturer.rs

Signed-off-by: fufesou <linlong1266@gmail.com>

* Update submodule hbb_common

Signed-off-by: fufesou <linlong1266@gmail.com>

* docs(linux): clarify DRM availability comments

Remove stale headless and unauthenticated-request
wording, and document the Available-only login-screen gate.

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(linux): remove unreachable session cleanup branch

Remove the obsolete empty-session path and
clarify the intended use of cached DRM availability.

Signed-off-by: fufesou <linlong1266@gmail.com>

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
fufesou
2026-08-18 15:02:50 +08:00
committed by GitHub
parent 0c00d576dd
commit b0008edcb5
99 changed files with 133 additions and 2944 deletions

View File

@@ -936,26 +936,19 @@ void enterPasswordDialog(
);
}
void enterUserLoginDialog(
SessionID sessionId,
OverlayDialogManager dialogManager,
String osAccountDescTip,
bool canRememberAccount) async {
void enterUserLoginDialog(SessionID sessionId,
OverlayDialogManager dialogManager, String osAccountDescTip) async {
await _connectDialog(
sessionId,
dialogManager,
osUsernameController: TextEditingController(),
osPasswordController: TextEditingController(),
osAccountDescTip: osAccountDescTip,
canRememberAccount: canRememberAccount,
);
}
void enterUserLoginAndPasswordDialog(
SessionID sessionId,
OverlayDialogManager dialogManager,
String osAccountDescTip,
bool canRememberAccount) async {
void enterUserLoginAndPasswordDialog(SessionID sessionId,
OverlayDialogManager dialogManager, String osAccountDescTip) async {
await _connectDialog(
sessionId,
dialogManager,
@@ -963,7 +956,6 @@ void enterUserLoginAndPasswordDialog(
osPasswordController: TextEditingController(),
passwordController: TextEditingController(),
osAccountDescTip: osAccountDescTip,
canRememberAccount: canRememberAccount,
);
}
@@ -974,7 +966,6 @@ _connectDialog(
TextEditingController? osPasswordController,
TextEditingController? passwordController,
String? osAccountDescTip,
bool canRememberAccount = true,
}) async {
final errUsername = ''.obs;
var rememberPassword = false;
@@ -982,11 +973,6 @@ _connectDialog(
rememberPassword =
await bind.sessionGetRemember(sessionId: sessionId) ?? false;
}
var rememberAccount = false;
if (canRememberAccount && osUsernameController != null) {
rememberAccount =
await bind.sessionGetRemember(sessionId: sessionId) ?? false;
}
if (osUsernameController != null) {
osUsernameController.addListener(() {
if (errUsername.value.isNotEmpty) {
@@ -1014,12 +1000,6 @@ _connectDialog(
final osPassword = osPasswordController?.text.trim() ?? '';
final password = passwordController?.text.trim() ?? '';
if (passwordController != null && password.isEmpty) return;
if (rememberAccount) {
bind.sessionPeerOption(
sessionId: sessionId, name: 'os-username', value: osUsername);
bind.sessionPeerOption(
sessionId: sessionId, name: 'os-password', value: osPassword);
}
gFFI.login(
osUsername,
osPassword,
@@ -1096,16 +1076,6 @@ _connectDialog(
controller: osPasswordController,
autoFocus: false,
),
if (canRememberAccount)
rememberWidget(
translate('remember_account_tip'),
rememberAccount,
(v) {
if (v != null) {
setState(() => rememberAccount = v);
}
},
),
],
);
}
@@ -1542,91 +1512,6 @@ showSetOSPassword(
});
}
showSetOSAccount(
SessionID sessionId,
OverlayDialogManager dialogManager,
) async {
final usernameController = TextEditingController();
final passwdController = TextEditingController();
var username =
await bind.sessionGetOption(sessionId: sessionId, arg: 'os-username') ??
'';
var password =
await bind.sessionGetOption(sessionId: sessionId, arg: 'os-password') ??
'';
usernameController.text = username;
passwdController.text = password;
dialogManager.show((setState, close, context) {
submit() {
final username = usernameController.text.trim();
final password = usernameController.text.trim();
bind.sessionPeerOption(
sessionId: sessionId, name: 'os-username', value: username);
bind.sessionPeerOption(
sessionId: sessionId, name: 'os-password', value: password);
close();
}
descWidget(String text) {
return Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(
text,
maxLines: 3,
softWrap: true,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 16),
),
),
Container(
height: 8,
),
],
);
}
return CustomAlertDialog(
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.password_rounded, color: MyTheme.accent),
Text(translate('OS Account')).paddingOnly(left: 10),
],
),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
descWidget(translate("os_account_desk_tip")),
DialogTextField(
title: translate(DialogTextField.kUsernameTitle),
controller: usernameController,
prefixIcon: DialogTextField.kUsernameIcon,
errorText: null,
),
PasswordWidget(controller: passwdController),
],
),
actions: [
dialogButton(
"Cancel",
icon: Icon(Icons.close_rounded),
onPressed: close,
isOutline: true,
),
dialogButton(
"OK",
icon: Icon(Icons.done_rounded),
onPressed: submit,
),
],
onSubmit: submit,
onCancel: close,
);
});
}
Widget buildNoteTextField({
required TextEditingController controller,
required VoidCallback onEscape,

View File

@@ -349,12 +349,12 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
showRequestElevationDialog(sessionId, ffi.dialogManager)),
);
}
// osAccount / osPassword
// osPassword
if (isDefaultConn && perms['keyboard'] != false) {
v.add(
TTextMenu(
child: Row(children: [
Text(translate(pi.isHeadless ? 'OS Account' : 'OS Password')),
Text(translate('OS Password')),
]),
trailingIcon: Transform.scale(
scale: (isDesktop || isWebDesktop) ? 0.8 : 1,
@@ -363,18 +363,12 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
if (isMobile && Navigator.canPop(context)) {
Navigator.pop(context);
}
if (pi.isHeadless) {
showSetOSAccount(sessionId, ffi.dialogManager);
} else {
handleOsPasswordEditIcon(sessionId, ffi.dialogManager);
}
handleOsPasswordEditIcon(sessionId, ffi.dialogManager);
},
icon: Icon(Icons.edit, color: isMobile ? MyTheme.accent : null),
),
),
onPressed: () => pi.isHeadless
? showSetOSAccount(sessionId, ffi.dialogManager)
: handleOsPasswordAction(sessionId, ffi.dialogManager),
onPressed: () => handleOsPasswordAction(sessionId, ffi.dialogManager),
),
);
}

View File

@@ -18,7 +18,6 @@ const kKeyMapMode = 'map';
const kKeyTranslateMode = 'translate';
const String kPlatformAdditionsIsWayland = "is_wayland";
const String kPlatformAdditionsHeadless = "headless";
const String kPlatformAdditionsIsInstalled = "is_installed";
const String kPlatformAdditionsIddImpl = "idd_impl";
const String kPlatformAdditionsRustDeskVirtualDisplays =
@@ -164,7 +163,6 @@ const String kOptionEnableConfirmClosingTabs = "enable-confirm-closing-tabs";
const String kOptionAllowAlwaysSoftwareRender = "allow-always-software-render";
const String kOptionEnableCheckUpdate = "enable-check-update";
const String kOptionAllowAutoUpdate = "allow-auto-update";
const String kOptionAllowLinuxHeadless = "allow-linux-headless";
const String kOptionAllowRemoveWallpaper = "allow-remove-wallpaper";
const String kOptionStopService = "stop-service";
const String kOptionDirectxCapture = "enable-directx-capture";

View File

@@ -586,10 +586,6 @@ class _GeneralState extends State<_General> {
));
}
if (!isWeb && bind.mainShowOption(key: kOptionAllowLinuxHeadless)) {
children.add(_OptionCheckBox(
context, 'Allow linux headless', kOptionAllowLinuxHeadless));
}
if (!bind.isDisableAccount()) {
children.add(_OptionCheckBox(
context,

View File

@@ -908,17 +908,12 @@ class FfiModel with ChangeNotifier {
enter2FaDialog(sessionId, dialogManager);
} else if (type == 'input-password') {
enterPasswordDialog(sessionId, dialogManager);
} else if (type == 'session-login' || type == 'session-re-login') {
enterUserLoginDialog(sessionId, dialogManager, 'login_linux_tip', true);
} else if (type == 'session-login-password') {
enterUserLoginAndPasswordDialog(
sessionId, dialogManager, 'login_linux_tip', true);
} else if (type == 'terminal-admin-login') {
enterUserLoginDialog(
sessionId, dialogManager, 'terminal-admin-login-tip', false);
sessionId, dialogManager, 'terminal-admin-login-tip');
} else if (type == 'terminal-admin-login-password') {
enterUserLoginAndPasswordDialog(
sessionId, dialogManager, 'terminal-admin-login-tip', false);
sessionId, dialogManager, 'terminal-admin-login-tip');
} else if (type == 'restarting') {
// Treat restart messages as reconnect control events. Rust still sends
// title/text for legacy UI and translation reuse; Flutter keeps the last
@@ -4168,7 +4163,6 @@ class PeerInfo with ChangeNotifier {
RxBool isSet = false.obs;
bool get isWayland => platformAdditions[kPlatformAdditionsIsWayland] == true;
bool get isHeadless => platformAdditions[kPlatformAdditionsHeadless] == true;
bool get isInstalled =>
platform != kPeerPlatformWindows ||
platformAdditions[kPlatformAdditionsIsInstalled] == true;

View File

@@ -762,10 +762,6 @@ class RustdeskImpl {
throw UnimplementedError("mainGetError");
}
bool mainShowOption({required String key, dynamic hint}) {
throw UnimplementedError("mainShowOption");
}
Future<void> mainSetOption(
{required String key, required String value, dynamic hint}) {
js.context.callMethod('setByName', [