Files
JSwitchDisplayApplet/package/driverview.qml
T
Jokul bc371fbac5 fix: 修复驱动检测与版本号显示
- 修复 driver 名称获取:使用 QFileInfo::symLinkTarget() 替代 QDir::dirName(),
  解决驱动名恒为 'driver' 的问题
- 添加开源内核驱动版本号支持:amdgpu/radeon/nouveau/i915 等显示内核版本
- 添加卡片 tooltip 三行信息(显卡/驱动/版本号)的翻译条目
2026-07-13 22:10:38 +08:00

387 lines
14 KiB
QML

// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import org.deepin.ds 1.0
import org.deepin.ds.dock 1.0
import org.deepin.dtk 1.0
AppletItem {
id: root
objectName: "graphics driver applet"
property int dockOrder: 21
property int dockSize: Panel.rootObject.dockItemMaxSize || 48
implicitWidth: dockSize
implicitHeight: dockSize
readonly property var applet: Applet
readonly property bool ready: applet ? applet.ready : false
readonly property string gpuSummary: applet ? (applet.gpuSummary || qsTr("No GPU detected")) : qsTr("No GPU detected")
readonly property string deviceInfo: applet ? (applet.deviceInfo || qsTr("Unknown")) : qsTr("Unknown")
readonly property string currentDriver: applet ? (applet.currentDriver || qsTr("Unknown")) : qsTr("Unknown")
property Palette basePalette: DockPalette.iconTextPalette
readonly property color primaryText: Qt.rgba(basePalette.r, basePalette.g, basePalette.b, 0.9)
readonly property color secondaryText: Qt.rgba(basePalette.r, basePalette.g, basePalette.b, 0.65)
readonly property color tertiaryText: Qt.rgba(basePalette.r, basePalette.g, basePalette.b, 0.5)
readonly property color cardBackground: Qt.rgba(basePalette.r, basePalette.g, basePalette.b, 0.06)
readonly property color cardBorder: Qt.rgba(basePalette.r, basePalette.g, basePalette.b, 0.1)
readonly property color accentBlue: Qt.rgba(20 / 255, 80 / 255, 160 / 255, 1)
readonly property color accentBlueLight: Qt.rgba(20 / 255, 80 / 255, 160 / 255, 0.12)
// 图标区域
Rectangle {
anchors.centerIn: parent
width: dockSize * 0.7
height: dockSize * 0.7
color: "transparent"
radius: width * 0.45
border.width: 1
border.color: root.secondaryText
Text {
anchors.centerIn: parent
text: "GPU"
font.pixelSize: root.dockSize * 0.22
font.bold: true
color: root.primaryText
}
}
// 悬停提示
PanelToolTip {
id: toolTip
text: root.ready ? root.deviceInfo.replace(/\n/g, "\n") : qsTr("No GPU detected")
toolTipX: DockPanelPositioner.x
toolTipY: DockPanelPositioner.y
}
Timer {
id: toolTipShowTimer
interval: 50
onTriggered: {
const point = root.mapToItem(null, root.width / 2, root.height / 2)
toolTip.DockPanelPositioner.bounding = Qt.rect(point.x, point.y, toolTip.width, toolTip.height)
toolTip.open()
}
}
HoverHandler {
onHoveredChanged: {
if (hovered && !driverPopup.popupVisible) {
toolTipShowTimer.start()
} else {
if (toolTipShowTimer.running) {
toolTipShowTimer.stop()
}
toolTip.close()
}
}
}
// 弹出窗口
PanelPopup {
id: driverPopup
width: 360
height: 320
popupX: DockPanelPositioner.x
popupY: DockPanelPositioner.y
onPopupVisibleChanged: {
if (popupVisible) {
toolTip.close()
}
}
Control {
id: popupContainer
anchors.fill: parent
padding: 16
contentItem: ColumnLayout {
spacing: 14
// 标题区域
RowLayout {
Layout.fillWidth: true
spacing: 10
Item { Layout.fillWidth: true }
Rectangle {
width: 28
height: 28
color: accentBlueLight
radius: 8
Text {
anchors.centerIn: parent
text: "GPU"
font.pixelSize: 12
font.bold: true
color: accentBlue
}
}
Text {
text: qsTr("Graphics Driver Manager")
font.pixelSize: 16
font.bold: true
color: root.primaryText
}
Item { Layout.fillWidth: true }
}
// 分隔线
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 1
color: root.cardBorder
}
// 当前驱动信息
RowLayout {
Layout.fillWidth: true
spacing: 8
visible: root.ready
Text {
text: qsTr("Current Driver:")
font.pixelSize: 12
color: root.secondaryText
}
Text {
text: root.currentDriver
font.pixelSize: 12
font.bold: true
color: root.primaryText
Layout.fillWidth: true
elide: Text.ElideRight
}
}
// GPU 列表区域
Flickable {
id: gpuListFlick
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
contentWidth: width
contentHeight: gpuColumn.height
boundsBehavior: Flickable.StopAtBounds
Column {
id: gpuColumn
width: gpuListFlick.width
spacing: 10
visible: root.ready
Repeater {
model: root.ready ? root.deviceInfo.split("\n").filter(function(line) { return line.trim().length > 0 }) : []
delegate: Rectangle {
id: gpuCard
width: gpuColumn.width
height: 72
color: root.cardBackground
radius: 10
border.width: 1
border.color: root.cardBorder
ToolTip.text: qsTr("GPU: ") + parseGpuName(modelData) + "\n"
+ qsTr("Driver: ") + parseDriverName(modelData) + "\n"
+ qsTr("Version: ") + (parseDriverVersion(modelData) || qsTr("Unknown"))
ToolTip.visible: cardHover.hovered
ToolTip.delay: 300
HoverHandler {
id: cardHover
}
RowLayout {
anchors.fill: parent
anchors.margins: 12
spacing: 12
// GPU 图标
Rectangle {
width: 44
height: 44
color: root.accentBlueLight
radius: 8
Text {
anchors.centerIn: parent
text: parseGpuVendorShort(modelData)
font.pixelSize: 14
font.bold: true
color: root.accentBlue
}
}
// GPU 信息
ColumnLayout {
spacing: 4
Layout.fillWidth: true
Text {
text: parseGpuName(modelData)
font.pixelSize: 13
font.bold: true
color: root.primaryText
Layout.fillWidth: true
elide: Text.ElideRight
}
Text {
text: parseDriverInfo(modelData)
font.pixelSize: 11
color: root.secondaryText
Layout.fillWidth: true
elide: Text.ElideRight
}
}
}
}
}
}
// 未检测到 GPU 提示
Rectangle {
anchors.centerIn: parent
width: gpuListFlick.width - 32
height: 80
color: root.cardBackground
radius: 10
border.width: 1
border.color: root.cardBorder
visible: !root.ready
ColumnLayout {
anchors.centerIn: parent
spacing: 6
Text {
text: "⚠"
font.pixelSize: 24
}
Text {
text: qsTr("No GPU detected")
font.pixelSize: 13
color: root.secondaryText
}
}
}
}
// 刷新按钮
Button {
id: refreshBtn
text: qsTr("Refresh")
Layout.fillWidth: true
Layout.preferredHeight: 36
font.pixelSize: 13
background: Rectangle {
color: refreshBtn.hovered ? Qt.darker(root.accentBlue, 1.2) : root.accentBlue
radius: 8
}
contentItem: Text {
text: refreshBtn.text
color: "white"
font.pixelSize: refreshBtn.font.pixelSize
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
onClicked: {
if (root.applet) {
root.applet.refreshDeviceInfo()
}
}
}
}
}
Component.onCompleted: {
DockPanelPositioner.bounding = Qt.binding(function () {
const point = root.mapToItem(null, root.width / 2, root.height / 2)
return Qt.rect(point.x, point.y, driverPopup.width, driverPopup.height)
})
}
}
// 解析 GPU 名称的辅助函数
function parseGpuName(info) {
var parts = info.split("(")
if (parts.length > 0) {
return parts[0].trim()
}
return info
}
// 解析驱动信息的辅助函数
function parseDriverInfo(info) {
var startIndex = info.indexOf("(")
var endIndex = info.lastIndexOf(")")
if (startIndex !== -1 && endIndex !== -1) {
return info.substring(startIndex + 1, endIndex)
}
return info
}
// 解析驱动名称
function parseDriverName(info) {
var driver = parseDriverInfo(info)
var parts = driver.split(" ")
return parts[0] || qsTr("Unknown")
}
// 解析驱动版本号
function parseDriverVersion(info) {
var driver = parseDriverInfo(info)
var parts = driver.split(" ")
if (parts.length > 1) {
return parts[1]
}
return ""
}
// 识别 GPU 厂商简称
function parseGpuVendorShort(info) {
var name = info.toLowerCase()
if (name.indexOf("nvidia") !== -1) return "NV"
if (name.indexOf("amd") !== -1 || name.indexOf("ati") !== -1 || name.indexOf("advanced micro") !== -1) return "AMD"
if (name.indexOf("intel") !== -1) return "Intel"
if (name.indexOf("qualcomm") !== -1) return "QC"
if (name.indexOf("microsoft") !== -1) return "MS"
return "GPU"
}
// 点击处理
TapHandler {
acceptedButtons: Qt.LeftButton
gesturePolicy: TapHandler.ReleaseWithinBounds
onTapped: {
if (driverPopup.popupVisible) {
driverPopup.close()
} else {
Panel.requestClosePopup()
const point = root.mapToItem(null, root.width / 2, root.height / 2)
driverPopup.DockPanelPositioner.bounding = Qt.rect(point.x, point.y, driverPopup.width, driverPopup.height)
driverPopup.open()
}
toolTip.close()
}
}
}