powermenu: reboot into firmware setup from the power menu (#3877)

port 2.0
This commit is contained in:
Matt Jiang
2026-10-23 09:29:31 -04:00
committed by GitHub
parent efd9324a4d
commit e50bb088b6
6 changed files with 92 additions and 9 deletions
+1
View File
@@ -1126,6 +1126,7 @@ Singleton {
property string customPowerActionPowerOff: Spec.SPEC.customPowerActionPowerOff.def
property var customPowerButtons: Spec.SPEC.customPowerButtons.def
property var powerMenuBootEntries: Spec.SPEC.powerMenuBootEntries.def
property bool powerMenuFirmwareSetup: Spec.SPEC.powerMenuFirmwareSetup.def
property bool updaterCheckOnStart: Spec.SPEC.updaterCheckOnStart.def
property bool updaterUseCustomCommand: Spec.SPEC.updaterUseCustomCommand.def
@@ -1445,6 +1445,9 @@ var LOCAL_SPEC = {
powerMenuBootEntries: {
def: []
},
powerMenuFirmwareSetup: {
def: false
},
updaterCheckOnStart: {
def: false
},
+13 -3
View File
@@ -278,14 +278,24 @@ Item {
SettingsCard {
width: parent.width
iconName: "restart_alt"
title: I18n.tr("Reboot to another OS", "settings card title, lists EFI boot entries the power menu can reboot into")
title: I18n.tr("Reboot targets", "settings card title, firmware setup and EFI boot entries the power menu can reboot into once")
settingKey: "powerMenuBootEntries"
tags: ["power", "menu", "reboot", "boot", "efi", "uefi", "windows", "dual boot", "bootnext"]
tags: ["power", "menu", "reboot", "boot", "efi", "uefi", "bios", "firmware", "windows", "dual boot", "bootnext"]
// Saved entries stay listed wherever this config lands, so they can always be removed
visible: SettingsData.powerMenuBootEntries.length > 0 || (BootEntryService.status !== "unknown" && BootEntryService.status !== "noEfi")
visible: SessionService.firmwareSetupSupported || SettingsData.powerMenuBootEntries.length > 0 || (BootEntryService.status !== "unknown" && BootEntryService.status !== "noEfi")
Component.onCompleted: BootEntryService.refresh()
SettingsToggleRow {
settingKey: "powerMenuFirmwareSetup"
tags: ["power", "menu", "reboot", "firmware", "setup", "bios", "uefi"]
visible: SessionService.firmwareSetupSupported
iconName: "developer_board"
text: I18n.tr("Firmware setup", "settings toggle, adds a power menu action that reboots into the UEFI/BIOS settings screen")
checked: SettingsData.powerMenuFirmwareSetup
onToggled: checked => SettingsData.set("powerMenuFirmwareSetup", checked)
}
SettingsRow {
visible: BootEntryService.unavailableReason !== ""
title: BootEntryService.unavailableReason
+1
View File
@@ -361,6 +361,7 @@ Singleton {
hibernate: ["hibernate"],
reboot: ["reboot", "restart"],
softreboot: ["soft reboot"],
firmwaresetup: ["firmware", "bios", "uefi"],
poweroff: ["poweroff", "shutdown", "halt"],
restart: ["restart", "shell", "reload"]
})
+44 -4
View File
@@ -23,6 +23,9 @@ Singleton {
property bool userManagerAvailable: false
property bool hibernateSupported: false
readonly property bool softRebootSupported: systemctlCommandAvailable
// The firmware advertises boot-to-setup in OsIndicationsSupported, the same bit logind checks
property bool firmwareSetupAdvertised: false
readonly property bool firmwareSetupSupported: !isBSD && firmwareSetupAdvertised && (systemctlCommandAvailable || loginctlCommandAvailable)
property bool inhibitorAvailable: true
property bool idleInhibited: false
property string inhibitReason: "Keep system awake"
@@ -111,9 +114,10 @@ loginctl=0; command -v loginctl >/dev/null 2>&1 && loginctl=1
systemctl=0; usermgr=0
if command -v systemctl >/dev/null 2>&1; then systemctl=1; systemctl --user --no-pager show-environment >/dev/null 2>&1 && usermgr=1; fi
hibernate=0; grep -q disk /sys/power/state 2>/dev/null && hibernate=1
fwsetup=0; b=$(od -An -tu1 -j4 -N1 /sys/firmware/efi/efivars/OsIndicationsSupported-8be4df61-93ca-11d2-aa0d-00e098032b8c 2>/dev/null); [ -n "$b" ] && [ $(($b & 1)) = 1 ] && fwsetup=1
nvidia=; command -v prime-run >/dev/null 2>&1 && nvidia=prime-run
[ -z "$nvidia" ] && command -v nvidia-offload >/dev/null 2>&1 && nvidia=nvidia-offload
printf 'uwsm=%s\nelogind=%s\nloginctl=%s\nsystemctl=%s\nusermgr=%s\nhibernate=%s\nnvidia=%s\n' "$uwsm" "$elogind" "$loginctl" "$systemctl" "$usermgr" "$hibernate" "$nvidia"`]
printf 'uwsm=%s\nelogind=%s\nloginctl=%s\nsystemctl=%s\nusermgr=%s\nhibernate=%s\nfwsetup=%s\nnvidia=%s\n' "$uwsm" "$elogind" "$loginctl" "$systemctl" "$usermgr" "$hibernate" "$fwsetup" "$nvidia"`]
stdout: SplitParser {
splitMarker: "\n"
@@ -141,6 +145,9 @@ printf 'uwsm=%s\nelogind=%s\nloginctl=%s\nsystemctl=%s\nusermgr=%s\nhibernate=%s
case "hibernate":
root.hibernateSupported = !root.isBSD && value === "1";
return;
case "fwsetup":
root.firmwareSetupAdvertised = value === "1";
return;
case "nvidia":
root.nvidiaCommand = value;
return;
@@ -587,6 +594,27 @@ printf 'uwsm=%s\nelogind=%s\nloginctl=%s\nsystemctl=%s\nusermgr=%s\nhibernate=%s
Quickshell.execDetached(["systemctl", "soft-reboot"]);
}
// Skips customPowerActionReboot: no systemctl or loginctl command sets the firmware flag without also rebooting.
function rebootToFirmwareSetup() {
firmwareSetupProcess.running = true;
}
Process {
id: firmwareSetupProcess
running: false
command: root.powerManagerCommand("reboot").concat(["--firmware-setup"])
stderr: StdioCollector {
id: firmwareSetupErrors
}
onExited: exitCode => {
if (exitCode === 0)
return;
ToastService.showError(I18n.tr("Failed to reboot to firmware setup", "error toast, firmware setup is the UEFI/BIOS settings screen"), firmwareSetupErrors.text.trim());
}
}
function poweroff() {
if (SettingsData.customPowerActionPowerOff.length === 0) {
Quickshell.execDetached(powerManagerCommand("poweroff"));
@@ -595,11 +623,12 @@ printf 'uwsm=%s\nelogind=%s\nloginctl=%s\nsystemctl=%s\nusermgr=%s\nhibernate=%s
}
}
// Actions added in settings, listed after the built-in ones: boot entries, then custom buttons.
// Each list lines up index for index with its setting.
// Actions added in settings, listed after the built-in ones: firmware setup, boot entries, then custom buttons.
// The boot entry and custom lists line up index for index with their setting.
readonly property var bootEntryActions: (SettingsData.powerMenuBootEntries || []).map(entry => "bootnext:" + entry.id)
readonly property var firmwareSetupActions: SettingsData.powerMenuFirmwareSetup && firmwareSetupSupported ? ["firmwaresetup"] : []
readonly property var customPowerActions: (SettingsData.customPowerButtons || []).map((button, i) => "custom:" + i)
readonly property var extraPowerActions: bootEntryActions.concat(customPowerActions)
readonly property var extraPowerActions: firmwareSetupActions.concat(bootEntryActions, customPowerActions)
function isPowerActionSupported(action) {
switch (action) {
@@ -642,6 +671,11 @@ printf 'uwsm=%s\nelogind=%s\nloginctl=%s\nsystemctl=%s\nusermgr=%s\nhibernate=%s
case "softreboot":
softReboot();
return true;
case "firmwaresetup":
if (!firmwareSetupSupported)
return false;
rebootToFirmwareSetup();
return true;
case "poweroff":
poweroff();
return true;
@@ -685,6 +719,12 @@ printf 'uwsm=%s\nelogind=%s\nloginctl=%s\nsystemctl=%s\nusermgr=%s\nhibernate=%s
"label": I18n.tr("Soft reboot"),
"key": "B"
};
case "firmwaresetup":
return {
"icon": "developer_board",
"label": I18n.tr("Reboot to firmware setup", "power menu action, firmware setup is the UEFI/BIOS settings screen"),
"key": "F"
};
case "logout":
return {
"icon": "logout",
@@ -9302,6 +9302,32 @@
"parentLabel": "Power & battery",
"description": "Fades the screen out first. Input during the fade cancels it"
},
{
"section": "powerMenuFirmwareSetup",
"label": "Firmware setup",
"tabIndex": 21,
"category": "Power & sleep",
"keywords": [
"battery",
"bios",
"charge",
"charging",
"energy",
"firmware",
"hibernate",
"menu",
"power",
"reboot",
"restart",
"setup",
"shutdown",
"sleep",
"suspend",
"uefi"
],
"parentLabel": "Power & battery",
"icon": "developer_board"
},
{
"section": "powerMenuGridLayout",
"label": "Grid layout",
@@ -9486,12 +9512,12 @@
},
{
"section": "powerMenuBootEntries",
"label": "Reboot to another OS",
"label": "Reboot targets",
"tabIndex": 21,
"category": "Power & sleep",
"keywords": [
"another",
"battery",
"bios",
"boot",
"bootnext",
"charge",
@@ -9499,6 +9525,7 @@
"dual boot",
"efi",
"energy",
"firmware",
"hibernate",
"menu",
"power",
@@ -9507,6 +9534,7 @@
"shutdown",
"sleep",
"suspend",
"targets",
"uefi",
"windows"
],