bc371fbac5
- 修复 driver 名称获取:使用 QFileInfo::symLinkTarget() 替代 QDir::dirName(), 解决驱动名恒为 'driver' 的问题 - 添加开源内核驱动版本号支持:amdgpu/radeon/nouveau/i915 等显示内核版本 - 添加卡片 tooltip 三行信息(显卡/驱动/版本号)的翻译条目
221 lines
6.2 KiB
C++
221 lines
6.2 KiB
C++
// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
|
|
//
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
#include "graphicsdriverapplet.h"
|
|
#include <pluginfactory.h>
|
|
|
|
#include <QProcess>
|
|
#include <QDir>
|
|
#include <QDebug>
|
|
#include <QFile>
|
|
#include <QTextStream>
|
|
#include <QRegularExpression>
|
|
|
|
DCORE_USE_NAMESPACE
|
|
|
|
DS_BEGIN_NAMESPACE
|
|
|
|
GraphicsDriverApplet::GraphicsDriverApplet(QObject *parent)
|
|
: DApplet(parent)
|
|
, m_ready(false)
|
|
{
|
|
}
|
|
|
|
GraphicsDriverApplet::~GraphicsDriverApplet()
|
|
{
|
|
}
|
|
|
|
bool GraphicsDriverApplet::load()
|
|
{
|
|
return DApplet::load();
|
|
}
|
|
|
|
bool GraphicsDriverApplet::init()
|
|
{
|
|
detectGpus();
|
|
return DApplet::init();
|
|
}
|
|
|
|
QString GraphicsDriverApplet::deviceInfo() const
|
|
{
|
|
return m_deviceInfo;
|
|
}
|
|
|
|
QString GraphicsDriverApplet::currentDriver() const
|
|
{
|
|
return m_currentDriver;
|
|
}
|
|
|
|
QString GraphicsDriverApplet::gpuSummary() const
|
|
{
|
|
return m_gpuSummary;
|
|
}
|
|
|
|
bool GraphicsDriverApplet::ready() const
|
|
{
|
|
return m_ready;
|
|
}
|
|
|
|
void GraphicsDriverApplet::refreshDeviceInfo()
|
|
{
|
|
detectGpus();
|
|
}
|
|
|
|
void GraphicsDriverApplet::detectGpus()
|
|
{
|
|
m_gpus.clear();
|
|
|
|
// 通过 lspci 检测显卡
|
|
QStringList lines = runCommand("lspci", {"-mm"});
|
|
for (const QString &line : lines) {
|
|
if (line.contains("VGA compatible controller", Qt::CaseInsensitive) ||
|
|
line.contains("3D controller", Qt::CaseInsensitive) ||
|
|
line.contains("Display controller", Qt::CaseInsensitive)) {
|
|
|
|
GpuInfo gpu;
|
|
// lspci -mm 格式: "Class" "Vendor" "Device" ...
|
|
// 提取 PCI ID(行首的 01:00.0 等)
|
|
int spaceIdx = line.indexOf(' ');
|
|
if (spaceIdx > 0) {
|
|
gpu.pciId = line.left(spaceIdx);
|
|
}
|
|
|
|
gpu.name = parseGpuName(line);
|
|
|
|
// 检测驱动:通过 symlink 目标获取真实驱动名
|
|
QString sysPath = "/sys/bus/pci/devices/0000:" + gpu.pciId + "/driver";
|
|
QFileInfo driverLink(sysPath);
|
|
if (driverLink.exists() && driverLink.isSymLink()) {
|
|
QString target = driverLink.symLinkTarget();
|
|
// symLinkTarget 返回如 ".../drivers/nvidia",提取最后一段
|
|
gpu.driver = target.section('/', -1);
|
|
|
|
// 读取驱动版本
|
|
gpu.driverVersion = readDriverVersion(gpu.driver);
|
|
} else {
|
|
gpu.driver = "unknown";
|
|
}
|
|
|
|
m_gpus.append(gpu);
|
|
}
|
|
}
|
|
|
|
// 生成摘要信息
|
|
QStringList parts;
|
|
QStringList driverParts;
|
|
for (const GpuInfo &gpu : m_gpus) {
|
|
QString info = gpu.name;
|
|
if (!gpu.driver.isEmpty() && gpu.driver != "unknown") {
|
|
info += " (" + gpu.driver;
|
|
if (!gpu.driverVersion.isEmpty()) {
|
|
info += " " + gpu.driverVersion;
|
|
}
|
|
info += ")";
|
|
}
|
|
parts << info;
|
|
if (!gpu.driver.isEmpty() && !driverParts.contains(gpu.driver)) {
|
|
driverParts << gpu.driver;
|
|
}
|
|
}
|
|
|
|
m_deviceInfo = parts.join("\n");
|
|
m_currentDriver = driverParts.join(", ");
|
|
m_gpuSummary = parts.join(" | ");
|
|
m_ready = !m_gpus.isEmpty();
|
|
|
|
qDebug() << "Detected GPUs:" << m_deviceInfo;
|
|
qDebug() << "Current drivers:" << m_currentDriver;
|
|
|
|
emit deviceInfoChanged();
|
|
emit currentDriverChanged();
|
|
emit gpuSummaryChanged();
|
|
emit readyChanged();
|
|
}
|
|
|
|
QStringList GraphicsDriverApplet::runCommand(const QString &cmd, const QStringList &args)
|
|
{
|
|
QProcess process;
|
|
process.start(cmd, args);
|
|
process.waitForFinished(5000);
|
|
QString output = QString::fromUtf8(process.readAllStandardOutput());
|
|
return output.split('\n', Qt::SkipEmptyParts);
|
|
}
|
|
|
|
QString GraphicsDriverApplet::parseGpuName(const QString &line)
|
|
{
|
|
// lspci -mm 格式示例:
|
|
// 01:00.0 "VGA compatible controller" "NVIDIA Corporation" "GA106M [GeForce RTX 3060 Mobile / Max-Q]" "ASUSTeK Computer Inc." "Device 10a2"
|
|
// 提取引号中的内容
|
|
QStringList parts;
|
|
int pos = 0;
|
|
while (pos < line.length()) {
|
|
int start = line.indexOf('"', pos);
|
|
if (start < 0) break;
|
|
int end = line.indexOf('"', start + 1);
|
|
if (end < 0) break;
|
|
parts << line.mid(start + 1, end - start - 1);
|
|
pos = end + 1;
|
|
}
|
|
|
|
if (parts.size() >= 3) {
|
|
// parts[0] = class, parts[1] = vendor, parts[2] = device
|
|
QString vendor = parts[1];
|
|
QString device = parts[2];
|
|
// 去掉方括号内的别名,保留主要名称
|
|
int bracket = device.indexOf('[');
|
|
if (bracket > 0) {
|
|
// 保留完整名称,方括号内是子系统信息
|
|
}
|
|
return vendor + " " + device;
|
|
}
|
|
|
|
return line;
|
|
}
|
|
|
|
QString GraphicsDriverApplet::readDriverVersion(const QString &driverName)
|
|
{
|
|
// 尝试从 /sys/module/<driver>/version 读取版本
|
|
QString path = "/sys/module/" + driverName + "/version";
|
|
QFile file(path);
|
|
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
|
QString version = QTextStream(&file).readAll().trimmed();
|
|
if (!version.isEmpty()) {
|
|
return version;
|
|
}
|
|
}
|
|
|
|
// nvidia 特殊处理:从 /proc/driver/nvidia/version 读取
|
|
if (driverName == "nvidia") {
|
|
QFile nvFile("/proc/driver/nvidia/version");
|
|
if (nvFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
|
QString content = QTextStream(&nvFile).readAll();
|
|
// 格式: NVRM version: NVIDIA UNIX x86_64 Kernel Module 535.183.01 ...
|
|
QRegularExpression re("Kernel Module\\s+(\\d+\\.\\d+\\.\\d+)");
|
|
auto match = re.match(content);
|
|
if (match.hasMatch()) {
|
|
return match.captured(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 开源内核驱动(如 amdgpu, radeon, nouveau, i915)无独立版本号,版本跟随内核
|
|
static const QStringList kernelDrivers = {
|
|
"amdgpu", "radeon", "nouveau", "i915", "i965", "mgag200", "ast", "vmwgfx"
|
|
};
|
|
if (kernelDrivers.contains(driverName)) {
|
|
QFile osrelease("/proc/sys/kernel/osrelease");
|
|
if (osrelease.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
|
return "Linux " + QTextStream(&osrelease).readAll().trimmed();
|
|
}
|
|
}
|
|
|
|
return QString();
|
|
}
|
|
|
|
D_APPLET_CLASS(GraphicsDriverApplet)
|
|
|
|
DS_END_NAMESPACE
|
|
|
|
#include "graphicsdriverapplet.moc"
|