feat: GPU切换回退保护逻辑

- switchGpu切换前写入备份文件(.gpu-switch-backup)记录之前模式
- init()检测未确认的切换,启动30秒自动回退计时器
- QML弹出'显示是否正常'确认覆盖层,支持手动确认/回退/超时自动回退
- confirmSwitchSuccess()用户确认正常后删除备份
- restoreFromBackup()自动恢复之前模式并发送通知
- primeOffloadEnabled属性检测当前PRIME offload状态
- switchGpu改用environment.d方式,不需要root/pkexec
- 翻译更新:回退确认相关8条新增
This commit is contained in:
2026-07-14 22:15:52 +08:00
parent 64408bf842
commit 9e474de717
5 changed files with 349 additions and 11 deletions
+94 -7
View File
@@ -28,13 +28,8 @@ AppletItem {
// 当前 PRIME 模式(nvidia/on-demand/intel
readonly property string currentPrimeMode: {
if (root.gpuMode !== "PRIME" || !root.applet || !root.applet.gpuPrimary) return ""
var lines = root.deviceInfo.split("\n").filter(function(l) { return l.trim().length > 0 })
for (var i = 0; i < lines.length; i++) {
if (/nvidia/i.test(lines[i]) && root.applet.gpuPrimary[i] === "true") {
return "nvidia"
}
}
if (root.gpuMode !== "PRIME") return ""
if (root.applet && root.applet.primeOffloadEnabled) return "nvidia"
return "on-demand"
}
@@ -1071,6 +1066,98 @@ AppletItem {
}
}
// GPU 切换回退确认覆盖层(启动时检测到未确认的切换)
Rectangle {
id: restoreOverlay
anchors.fill: parent
color: Qt.rgba(0, 0, 0, 0.75)
radius: 12
visible: root.applet && root.applet.switchPending
z: 100
ColumnLayout {
anchors.centerIn: parent
width: parent.width - 48
spacing: 16
// 警告图标
Text {
Layout.alignment: Qt.AlignHCenter
text: "⚠"
font.pixelSize: 36
color: Qt.rgba(245/255, 158/255, 11/255, 1)
}
// 标题
Text {
Layout.alignment: Qt.AlignHCenter
text: qsTr("Display OK?")
font.pixelSize: 18
font.bold: true
color: "#e8e8e8"
}
// 说明
Text {
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
text: qsTr("GPU mode was changed. If display is abnormal, it will auto-revert in %1s.").arg(root.applet ? root.applet.restoreCountdown : 0)
font.pixelSize: 12
color: "#a0a0a0"
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
}
// 按钮行
RowLayout {
Layout.fillWidth: true
spacing: 12
// 回退按钮
Button {
Layout.fillWidth: true
Layout.preferredHeight: 34
font.pixelSize: 12
background: Rectangle {
color: parent.hovered ? Qt.rgba(220/255, 38/255, 38/255, 0.8) : Qt.rgba(220/255, 38/255, 38/255, 0.3)
radius: 8
border.width: 1
border.color: Qt.rgba(220/255, 38/255, 38/255, 0.6)
}
contentItem: Text {
text: qsTr("Revert")
color: "#ff6b6b"
font.pixelSize: 12
font.bold: true
horizontalAlignment: Text.AlignHCenter
}
onClicked: if (root.applet) root.applet.restoreSwitch()
}
// 确认正常按钮
Button {
Layout.fillWidth: true
Layout.preferredHeight: 34
font.pixelSize: 12
background: Rectangle {
color: parent.hovered ? Qt.darker(root.accentBlue, 1.2) : root.accentBlue
radius: 8
}
contentItem: Text {
text: qsTr("Display OK")
color: "white"
font.pixelSize: 12
font.bold: true
horizontalAlignment: Text.AlignHCenter
}
onClicked: if (root.applet) root.applet.confirmSwitchSuccess()
}
}
}
}
Component.onCompleted: {
DockPanelPositioner.bounding = Qt.binding(function () {
const point = root.mapToItem(null, root.width / 2, root.height / 2)