feat: 添加GPU温度/使用率/显存实时监控
- C++后端:GpuInfo扩展统计字段,readGpuStats()支持NVIDIA(nvidia-smi)和AMD(sysfs) - PCI到DRM card映射,新增gpuStats属性和refreshStats方法 - QML前端:弹窗卡片显示温度(带颜色)、GPU使用率进度条、显存使用 - 任务栏tooltip显示简洁摘要(厂商简称+温度+使用率) - 定时刷新:弹窗和tooltip打开时每2秒刷新,关闭时停止 - 优化卡片布局:压缩高度和间距,弹窗高度调整至420px
This commit is contained in:
@@ -11,6 +11,7 @@
|
|||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
DCORE_USE_NAMESPACE
|
DCORE_USE_NAMESPACE
|
||||||
|
|
||||||
@@ -57,11 +58,21 @@ bool GraphicsDriverApplet::ready() const
|
|||||||
return m_ready;
|
return m_ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList GraphicsDriverApplet::gpuStats() const
|
||||||
|
{
|
||||||
|
return m_gpuStats;
|
||||||
|
}
|
||||||
|
|
||||||
void GraphicsDriverApplet::refreshDeviceInfo()
|
void GraphicsDriverApplet::refreshDeviceInfo()
|
||||||
{
|
{
|
||||||
detectGpus();
|
detectGpus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GraphicsDriverApplet::refreshStats()
|
||||||
|
{
|
||||||
|
readGpuStats();
|
||||||
|
}
|
||||||
|
|
||||||
void GraphicsDriverApplet::detectGpus()
|
void GraphicsDriverApplet::detectGpus()
|
||||||
{
|
{
|
||||||
m_gpus.clear();
|
m_gpus.clear();
|
||||||
@@ -74,6 +85,14 @@ void GraphicsDriverApplet::detectGpus()
|
|||||||
line.contains("Display controller", Qt::CaseInsensitive)) {
|
line.contains("Display controller", Qt::CaseInsensitive)) {
|
||||||
|
|
||||||
GpuInfo gpu;
|
GpuInfo gpu;
|
||||||
|
// 初始化统计字段
|
||||||
|
gpu.drmCard = -1;
|
||||||
|
gpu.temperature = -1;
|
||||||
|
gpu.gpuUsage = -1;
|
||||||
|
gpu.memUsage = -1;
|
||||||
|
gpu.memTotal = -1;
|
||||||
|
gpu.memUsed = -1;
|
||||||
|
|
||||||
// lspci -mm 格式: "Class" "Vendor" "Device" ...
|
// lspci -mm 格式: "Class" "Vendor" "Device" ...
|
||||||
// 提取 PCI ID(行首的 01:00.0 等)
|
// 提取 PCI ID(行首的 01:00.0 等)
|
||||||
int spaceIdx = line.indexOf(' ');
|
int spaceIdx = line.indexOf(' ');
|
||||||
@@ -97,6 +116,9 @@ void GraphicsDriverApplet::detectGpus()
|
|||||||
gpu.driver = "unknown";
|
gpu.driver = "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 查找 DRM 卡号
|
||||||
|
gpu.drmCard = findDrmCard(gpu.pciId);
|
||||||
|
|
||||||
m_gpus.append(gpu);
|
m_gpus.append(gpu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,6 +153,9 @@ void GraphicsDriverApplet::detectGpus()
|
|||||||
emit currentDriverChanged();
|
emit currentDriverChanged();
|
||||||
emit gpuSummaryChanged();
|
emit gpuSummaryChanged();
|
||||||
emit readyChanged();
|
emit readyChanged();
|
||||||
|
|
||||||
|
// 读取实时统计信息
|
||||||
|
readGpuStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList GraphicsDriverApplet::runCommand(const QString &cmd, const QStringList &args)
|
QStringList GraphicsDriverApplet::runCommand(const QString &cmd, const QStringList &args)
|
||||||
@@ -213,6 +238,113 @@ QString GraphicsDriverApplet::readDriverVersion(const QString &driverName)
|
|||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int GraphicsDriverApplet::findDrmCard(const QString &pciId)
|
||||||
|
{
|
||||||
|
// 扫描 /sys/bus/pci/devices/0000:XX:XX.X/drm/ 目录,找到 cardN 条目
|
||||||
|
QString drmPath = "/sys/bus/pci/devices/0000:" + pciId + "/drm";
|
||||||
|
QDir dir(drmPath);
|
||||||
|
if (!dir.exists()) return -1;
|
||||||
|
|
||||||
|
QStringList entries = dir.entryList(QStringList() << "card*", QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
|
for (const QString &entry : entries) {
|
||||||
|
// 匹配 "card0" "card1" 等,排除 "card0-DP-1" 等连接器
|
||||||
|
QRegularExpression re("^card(\\d+)$");
|
||||||
|
auto match = re.match(entry);
|
||||||
|
if (match.hasMatch()) {
|
||||||
|
return match.captured(1).toInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphicsDriverApplet::readGpuStats()
|
||||||
|
{
|
||||||
|
// 先处理 NVIDIA GPU(单次 nvidia-smi 调用获取所有 NVIDIA GPU 数据)
|
||||||
|
// nvidia-smi 输出格式: pci.bus_id,temperature.gpu,utilization.gpu,utilization.memory,memory.total,memory.used
|
||||||
|
QMap<QString, QStringList> nvidiaData; // pciId -> stats
|
||||||
|
QStringList nvLines = runCommand("nvidia-smi", {
|
||||||
|
"--query-gpu=pci.bus_id,temperature.gpu,utilization.gpu,utilization.memory,memory.total,memory.used",
|
||||||
|
"--format=csv,noheader,nounits"
|
||||||
|
});
|
||||||
|
for (const QString &line : nvLines) {
|
||||||
|
QStringList parts = line.split(",");
|
||||||
|
if (parts.size() >= 6) {
|
||||||
|
// nvidia-smi pci.bus_id 格式: 00000000:01:00.0,提取后半部分匹配
|
||||||
|
QString busId = parts[0].trimmed();
|
||||||
|
QString shortId = busId.section(':', -2); // "01:00.0"
|
||||||
|
nvidiaData[shortId] = parts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 逐个 GPU 读取统计
|
||||||
|
for (GpuInfo &gpu : m_gpus) {
|
||||||
|
if (gpu.driver == "nvidia" && nvidiaData.contains(gpu.pciId)) {
|
||||||
|
// NVIDIA: 使用 nvidia-smi 数据
|
||||||
|
QStringList &parts = nvidiaData[gpu.pciId];
|
||||||
|
gpu.temperature = parts[1].trimmed().toInt();
|
||||||
|
gpu.gpuUsage = parts[2].trimmed().toInt();
|
||||||
|
gpu.memUsage = parts[3].trimmed().toInt();
|
||||||
|
gpu.memTotal = parts[4].trimmed().toInt();
|
||||||
|
gpu.memUsed = parts[5].trimmed().toInt();
|
||||||
|
} else if (gpu.drmCard >= 0) {
|
||||||
|
// AMD / Intel / 其他: 使用 sysfs
|
||||||
|
QString cardPath = QString("/sys/class/drm/card%1/device").arg(gpu.drmCard);
|
||||||
|
|
||||||
|
// GPU 使用率
|
||||||
|
QFile busyFile(cardPath + "/gpu_busy_percent");
|
||||||
|
if (busyFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
gpu.gpuUsage = QTextStream(&busyFile).readAll().trimmed().toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显存 (字节,转换为 MB)
|
||||||
|
QFile vramTotal(cardPath + "/mem_info_vram_total");
|
||||||
|
QFile vramUsed(cardPath + "/mem_info_vram_used");
|
||||||
|
if (vramTotal.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
gpu.memTotal = QTextStream(&vramTotal).readAll().trimmed().toLongLong() / 1024 / 1024;
|
||||||
|
}
|
||||||
|
if (vramUsed.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
gpu.memUsed = QTextStream(&vramUsed).readAll().trimmed().toLongLong() / 1024 / 1024;
|
||||||
|
}
|
||||||
|
if (gpu.memTotal > 0 && gpu.memUsed >= 0) {
|
||||||
|
gpu.memUsage = gpu.memUsed * 100 / gpu.memTotal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 温度: 查找 hwmon 子目录
|
||||||
|
QDir hwmonDir(cardPath + "/hwmon");
|
||||||
|
if (hwmonDir.exists()) {
|
||||||
|
QStringList hwmons = hwmonDir.entryList(QStringList() << "hwmon*", QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
|
for (const QString &hwmon : hwmons) {
|
||||||
|
QFile nameFile(hwmonDir.absoluteFilePath(hwmon + "/name"));
|
||||||
|
if (nameFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
QString name = QTextStream(&nameFile).readAll().trimmed();
|
||||||
|
if (name == gpu.driver || name == "amdgpu" || name == "radeon") {
|
||||||
|
QFile tempFile(hwmonDir.absoluteFilePath(hwmon + "/temp1_input"));
|
||||||
|
if (tempFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
int tempMilli = QTextStream(&tempFile).readAll().trimmed().toInt();
|
||||||
|
gpu.temperature = tempMilli / 1000;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成统计数据 (格式: temp|gpuUsage|memUsage|memUsed|memTotal)
|
||||||
|
m_gpuStats.clear();
|
||||||
|
for (const GpuInfo &gpu : m_gpus) {
|
||||||
|
m_gpuStats << QString("%1|%2|%3|%4|%5")
|
||||||
|
.arg(gpu.temperature)
|
||||||
|
.arg(gpu.gpuUsage)
|
||||||
|
.arg(gpu.memUsage)
|
||||||
|
.arg(gpu.memUsed)
|
||||||
|
.arg(gpu.memTotal);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit gpuStatsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
D_APPLET_CLASS(GraphicsDriverApplet)
|
D_APPLET_CLASS(GraphicsDriverApplet)
|
||||||
|
|
||||||
DS_END_NAMESPACE
|
DS_END_NAMESPACE
|
||||||
|
|||||||
@@ -17,6 +17,14 @@ struct GpuInfo {
|
|||||||
QString driver; // 驱动模块名,如 "nvidia"
|
QString driver; // 驱动模块名,如 "nvidia"
|
||||||
QString driverVersion; // 驱动版本
|
QString driverVersion; // 驱动版本
|
||||||
QString pciId; // PCI ID,如 "01:00.0"
|
QString pciId; // PCI ID,如 "01:00.0"
|
||||||
|
int drmCard; // DRM 卡号,如 0, 1(-1 表示未找到)
|
||||||
|
|
||||||
|
// 实时统计
|
||||||
|
int temperature; // 温度 (°C),-1 表示不可用
|
||||||
|
int gpuUsage; // GPU 使用率 (%),-1 表示不可用
|
||||||
|
int memUsage; // 显存使用率 (%),-1 表示不可用
|
||||||
|
int memTotal; // 显存总量 (MB),-1 表示不可用
|
||||||
|
int memUsed; // 显存已用 (MB),-1 表示不可用
|
||||||
};
|
};
|
||||||
|
|
||||||
class GraphicsDriverApplet : public DApplet
|
class GraphicsDriverApplet : public DApplet
|
||||||
@@ -26,6 +34,7 @@ class GraphicsDriverApplet : public DApplet
|
|||||||
Q_PROPERTY(QString deviceInfo READ deviceInfo NOTIFY deviceInfoChanged)
|
Q_PROPERTY(QString deviceInfo READ deviceInfo NOTIFY deviceInfoChanged)
|
||||||
Q_PROPERTY(QString currentDriver READ currentDriver NOTIFY currentDriverChanged)
|
Q_PROPERTY(QString currentDriver READ currentDriver NOTIFY currentDriverChanged)
|
||||||
Q_PROPERTY(QString gpuSummary READ gpuSummary NOTIFY gpuSummaryChanged)
|
Q_PROPERTY(QString gpuSummary READ gpuSummary NOTIFY gpuSummaryChanged)
|
||||||
|
Q_PROPERTY(QStringList gpuStats READ gpuStats NOTIFY gpuStatsChanged)
|
||||||
Q_PROPERTY(bool ready READ ready NOTIFY readyChanged)
|
Q_PROPERTY(bool ready READ ready NOTIFY readyChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -38,18 +47,23 @@ public:
|
|||||||
QString deviceInfo() const;
|
QString deviceInfo() const;
|
||||||
QString currentDriver() const;
|
QString currentDriver() const;
|
||||||
QString gpuSummary() const;
|
QString gpuSummary() const;
|
||||||
|
QStringList gpuStats() const;
|
||||||
bool ready() const;
|
bool ready() const;
|
||||||
|
|
||||||
Q_INVOKABLE void refreshDeviceInfo();
|
Q_INVOKABLE void refreshDeviceInfo();
|
||||||
|
Q_INVOKABLE void refreshStats();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void deviceInfoChanged();
|
void deviceInfoChanged();
|
||||||
void currentDriverChanged();
|
void currentDriverChanged();
|
||||||
void gpuSummaryChanged();
|
void gpuSummaryChanged();
|
||||||
|
void gpuStatsChanged();
|
||||||
void readyChanged();
|
void readyChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void detectGpus();
|
void detectGpus();
|
||||||
|
void readGpuStats();
|
||||||
|
static int findDrmCard(const QString &pciId);
|
||||||
static QStringList runCommand(const QString &cmd, const QStringList &args);
|
static QStringList runCommand(const QString &cmd, const QStringList &args);
|
||||||
static QString parseGpuName(const QString &line);
|
static QString parseGpuName(const QString &line);
|
||||||
static QString readDriverVersion(const QString &driverName);
|
static QString readDriverVersion(const QString &driverName);
|
||||||
@@ -58,6 +72,7 @@ private:
|
|||||||
QString m_deviceInfo;
|
QString m_deviceInfo;
|
||||||
QString m_currentDriver;
|
QString m_currentDriver;
|
||||||
QString m_gpuSummary;
|
QString m_gpuSummary;
|
||||||
|
QStringList m_gpuStats;
|
||||||
bool m_ready;
|
bool m_ready;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+165
-7
@@ -55,11 +55,23 @@ AppletItem {
|
|||||||
// 悬停提示
|
// 悬停提示
|
||||||
PanelToolTip {
|
PanelToolTip {
|
||||||
id: toolTip
|
id: toolTip
|
||||||
text: root.ready ? root.deviceInfo.replace(/\n/g, "\n") : qsTr("No GPU detected")
|
text: root.ready ? buildToolTipText() : qsTr("No GPU detected")
|
||||||
toolTipX: DockPanelPositioner.x
|
toolTipX: DockPanelPositioner.x
|
||||||
toolTipY: DockPanelPositioner.y
|
toolTipY: DockPanelPositioner.y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 统计数据刷新定时器
|
||||||
|
Timer {
|
||||||
|
id: statsRefreshTimer
|
||||||
|
interval: 2000
|
||||||
|
repeat: true
|
||||||
|
onTriggered: {
|
||||||
|
if (root.applet) {
|
||||||
|
root.applet.refreshStats()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: toolTipShowTimer
|
id: toolTipShowTimer
|
||||||
interval: 50
|
interval: 50
|
||||||
@@ -74,11 +86,18 @@ AppletItem {
|
|||||||
onHoveredChanged: {
|
onHoveredChanged: {
|
||||||
if (hovered && !driverPopup.popupVisible) {
|
if (hovered && !driverPopup.popupVisible) {
|
||||||
toolTipShowTimer.start()
|
toolTipShowTimer.start()
|
||||||
|
if (root.applet) {
|
||||||
|
root.applet.refreshStats()
|
||||||
|
}
|
||||||
|
statsRefreshTimer.start()
|
||||||
} else {
|
} else {
|
||||||
if (toolTipShowTimer.running) {
|
if (toolTipShowTimer.running) {
|
||||||
toolTipShowTimer.stop()
|
toolTipShowTimer.stop()
|
||||||
}
|
}
|
||||||
toolTip.close()
|
toolTip.close()
|
||||||
|
if (!driverPopup.popupVisible) {
|
||||||
|
statsRefreshTimer.stop()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,13 +106,19 @@ AppletItem {
|
|||||||
PanelPopup {
|
PanelPopup {
|
||||||
id: driverPopup
|
id: driverPopup
|
||||||
width: 360
|
width: 360
|
||||||
height: 320
|
height: 420
|
||||||
popupX: DockPanelPositioner.x
|
popupX: DockPanelPositioner.x
|
||||||
popupY: DockPanelPositioner.y
|
popupY: DockPanelPositioner.y
|
||||||
|
|
||||||
onPopupVisibleChanged: {
|
onPopupVisibleChanged: {
|
||||||
if (popupVisible) {
|
if (popupVisible) {
|
||||||
toolTip.close()
|
toolTip.close()
|
||||||
|
statsRefreshTimer.start()
|
||||||
|
if (root.applet) {
|
||||||
|
root.applet.refreshStats()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
statsRefreshTimer.stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,12 +213,53 @@ AppletItem {
|
|||||||
delegate: Rectangle {
|
delegate: Rectangle {
|
||||||
id: gpuCard
|
id: gpuCard
|
||||||
width: gpuColumn.width
|
width: gpuColumn.width
|
||||||
height: 72
|
height: 98
|
||||||
color: root.cardBackground
|
color: root.cardBackground
|
||||||
radius: 10
|
radius: 10
|
||||||
border.width: 1
|
border.width: 1
|
||||||
border.color: root.cardBorder
|
border.color: root.cardBorder
|
||||||
|
|
||||||
|
property string statsLine: root.applet && root.applet.gpuStats ? (root.applet.gpuStats[index] || "") : ""
|
||||||
|
property string tempStr: {
|
||||||
|
var parts = statsLine.split("|")
|
||||||
|
var temp = parts[0]
|
||||||
|
return temp === "-1" || temp === "" ? "—" : temp
|
||||||
|
}
|
||||||
|
property string gpuUsageStr: {
|
||||||
|
var parts = statsLine.split("|")
|
||||||
|
var usage = parts[1]
|
||||||
|
return usage === "-1" || usage === "" ? "—" : usage
|
||||||
|
}
|
||||||
|
property string memUsageStr: {
|
||||||
|
var parts = statsLine.split("|")
|
||||||
|
var usage = parts[2]
|
||||||
|
return usage === "-1" || usage === "" ? "—" : usage
|
||||||
|
}
|
||||||
|
property string memUsedStr: {
|
||||||
|
var parts = statsLine.split("|")
|
||||||
|
var used = parts[3]
|
||||||
|
return used === "-1" || used === "" ? "—" : used
|
||||||
|
}
|
||||||
|
property string memTotalStr: {
|
||||||
|
var parts = statsLine.split("|")
|
||||||
|
var total = parts[4]
|
||||||
|
return total === "-1" || total === "" ? "—" : total
|
||||||
|
}
|
||||||
|
property real gpuUsagePercent: {
|
||||||
|
var parts = statsLine.split("|")
|
||||||
|
var usage = parts[1]
|
||||||
|
if (usage === "-1" || usage === "") return 0
|
||||||
|
return parseFloat(usage)
|
||||||
|
}
|
||||||
|
property color tempColor: {
|
||||||
|
var parts = statsLine.split("|")
|
||||||
|
var temp = parseInt(parts[0])
|
||||||
|
if (isNaN(temp) || temp === -1) return root.primaryText
|
||||||
|
if (temp >= 80) return Qt.rgba(220/255, 38/255, 38/255, 1)
|
||||||
|
if (temp >= 60) return Qt.rgba(245/255, 158/255, 11/255, 1)
|
||||||
|
return Qt.rgba(22/255, 163/255, 74/255, 1)
|
||||||
|
}
|
||||||
|
|
||||||
ToolTip.text: qsTr("GPU: ") + parseGpuName(modelData) + "\n"
|
ToolTip.text: qsTr("GPU: ") + parseGpuName(modelData) + "\n"
|
||||||
+ qsTr("Driver: ") + parseDriverName(modelData) + "\n"
|
+ qsTr("Driver: ") + parseDriverName(modelData) + "\n"
|
||||||
+ qsTr("Version: ") + (parseDriverVersion(modelData) || qsTr("Unknown"))
|
+ qsTr("Version: ") + (parseDriverVersion(modelData) || qsTr("Unknown"))
|
||||||
@@ -204,15 +270,19 @@ AppletItem {
|
|||||||
id: cardHover
|
id: cardHover
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: 12
|
anchors.margins: 10
|
||||||
|
spacing: 6
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
spacing: 12
|
spacing: 12
|
||||||
|
|
||||||
// GPU 图标
|
// GPU 图标
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: 44
|
width: 36
|
||||||
height: 44
|
height: 36
|
||||||
color: root.accentBlueLight
|
color: root.accentBlueLight
|
||||||
radius: 8
|
radius: 8
|
||||||
|
|
||||||
@@ -248,6 +318,68 @@ AppletItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 统计数据区域
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 6
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 12
|
||||||
|
|
||||||
|
// 温度
|
||||||
|
Text {
|
||||||
|
text: tempStr !== "—" ? tempStr + "°C" : "—"
|
||||||
|
font.pixelSize: 12
|
||||||
|
color: gpuCard.tempColor
|
||||||
|
font.bold: tempStr !== "—"
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { Layout.fillWidth: true }
|
||||||
|
|
||||||
|
// 显存信息
|
||||||
|
Text {
|
||||||
|
text: (memUsedStr !== "—" && memTotalStr !== "—") ? memUsedStr + "/" + memTotalStr + " MB" : "—"
|
||||||
|
font.pixelSize: 11
|
||||||
|
color: root.secondaryText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GPU 使用率进度条
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: "GPU"
|
||||||
|
font.pixelSize: 11
|
||||||
|
color: root.tertiaryText
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
height: 4
|
||||||
|
color: root.cardBorder
|
||||||
|
radius: 2
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: Math.min(gpuCard.gpuUsagePercent, 100) * parent.width / 100
|
||||||
|
height: parent.height
|
||||||
|
color: root.accentBlue
|
||||||
|
radius: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: gpuUsageStr !== "—" ? gpuUsageStr + "%" : "—"
|
||||||
|
font.pixelSize: 11
|
||||||
|
color: root.secondaryText
|
||||||
|
font.bold: gpuUsageStr !== "—"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -366,6 +498,32 @@ AppletItem {
|
|||||||
return "GPU"
|
return "GPU"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 构建 tooltip 文本
|
||||||
|
function buildToolTipText() {
|
||||||
|
if (!root.applet || !root.applet.gpuStats) {
|
||||||
|
return root.currentDriver || qsTr("No GPU detected")
|
||||||
|
}
|
||||||
|
|
||||||
|
var lines = root.deviceInfo.split("\n").filter(function(line) { return line.trim().length > 0 })
|
||||||
|
var result = []
|
||||||
|
|
||||||
|
for (var i = 0; i < lines.length; i++) {
|
||||||
|
var vendor = parseGpuVendorShort(lines[i])
|
||||||
|
var statsLine = root.applet.gpuStats[i] || ""
|
||||||
|
var parts = statsLine.split("|")
|
||||||
|
|
||||||
|
var temp = parts[0]
|
||||||
|
var gpuUsage = parts[1]
|
||||||
|
|
||||||
|
var tempStr = (temp === "-1" || temp === "") ? "" : temp + "°C"
|
||||||
|
var gpuUsageStr = (gpuUsage === "-1" || gpuUsage === "") ? "" : gpuUsage + "%"
|
||||||
|
|
||||||
|
result.push(vendor + " " + tempStr + " " + gpuUsageStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.join(" | ")
|
||||||
|
}
|
||||||
|
|
||||||
// 点击处理
|
// 点击处理
|
||||||
TapHandler {
|
TapHandler {
|
||||||
acceptedButtons: Qt.LeftButton
|
acceptedButtons: Qt.LeftButton
|
||||||
|
|||||||
Reference in New Issue
Block a user