// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later #include "graphicsdriverapplet.h" #include #include #include #include #include #include #include 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); // 检测驱动 QString sysPath = "/sys/bus/pci/devices/0000:" + gpu.pciId + "/driver"; QDir driverDir(sysPath); if (driverDir.exists()) { gpu.driver = driverDir.dirName(); // 读取驱动版本 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//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); } } } return QString(); } D_APPLET_CLASS(GraphicsDriverApplet) DS_END_NAMESPACE #include "graphicsdriverapplet.moc"