feat: 移除D-Bus依赖,改用 lspci 直接检测显卡,重构弹窗UI
- C++ 后端:移除 D-Bus 通信,改用 lspci -mm + /sys/bus/pci 直接检测显卡和驱动 - 新增 gpuSummary、ready 属性,通过 /sys/module 和 /proc/driver 读取驱动版本 - QML:使用 DTK 配色,卡片式布局展示 GPU 列表,每张显卡独立卡片 - 移除安装/测试/取消按钮,聚焦显卡信息展示 - 翻译精简为 5 条,同步 zh_CN / zh_TW
This commit is contained in:
+141
-207
@@ -5,29 +5,20 @@
|
||||
#include "graphicsdriverapplet.h"
|
||||
#include <pluginfactory.h>
|
||||
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusConnectionInterface>
|
||||
#include <QDBusPendingReply>
|
||||
#include <QProcess>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QRegularExpression>
|
||||
|
||||
DCORE_USE_NAMESPACE
|
||||
|
||||
DS_BEGIN_NAMESPACE
|
||||
|
||||
static const QString DBUS_SERVICE = "com.deepin.daemon.GraphicsDriver";
|
||||
static const QString DBUS_PATH = "/com/deepin/daemon/GraphicsDriver";
|
||||
static const QString DBUS_INTERFACE = "com.deepin.daemon.GraphicsDriver";
|
||||
|
||||
GraphicsDriverApplet::GraphicsDriverApplet(QObject *parent)
|
||||
: DApplet(parent)
|
||||
, m_dbusInterface(nullptr)
|
||||
, m_progressTimer(new QTimer(this))
|
||||
, m_installProgress(0)
|
||||
, m_isInstalling(false)
|
||||
, m_dbusAvailable(false)
|
||||
, m_ready(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -37,233 +28,176 @@ GraphicsDriverApplet::~GraphicsDriverApplet()
|
||||
|
||||
bool GraphicsDriverApplet::load()
|
||||
{
|
||||
initDBusConnection();
|
||||
return DApplet::load();
|
||||
}
|
||||
|
||||
bool GraphicsDriverApplet::init()
|
||||
{
|
||||
if (m_dbusAvailable) {
|
||||
refreshDeviceInfo();
|
||||
}
|
||||
detectGpus();
|
||||
return DApplet::init();
|
||||
}
|
||||
|
||||
QString GraphicsDriverApplet::currentDriver() const
|
||||
{
|
||||
return m_currentDriver;
|
||||
}
|
||||
|
||||
QString GraphicsDriverApplet::deviceInfo() const
|
||||
{
|
||||
return m_deviceInfo;
|
||||
}
|
||||
|
||||
int GraphicsDriverApplet::installProgress() const
|
||||
QString GraphicsDriverApplet::currentDriver() const
|
||||
{
|
||||
return m_installProgress;
|
||||
return m_currentDriver;
|
||||
}
|
||||
|
||||
bool GraphicsDriverApplet::isInstalling() const
|
||||
QString GraphicsDriverApplet::gpuSummary() const
|
||||
{
|
||||
return m_isInstalling;
|
||||
return m_gpuSummary;
|
||||
}
|
||||
|
||||
bool GraphicsDriverApplet::dbusAvailable() const
|
||||
bool GraphicsDriverApplet::ready() const
|
||||
{
|
||||
return m_dbusAvailable;
|
||||
return m_ready;
|
||||
}
|
||||
|
||||
void GraphicsDriverApplet::refreshDeviceInfo()
|
||||
{
|
||||
if (!m_dbusInterface || !m_dbusInterface->isValid()) {
|
||||
qWarning() << "DBus interface is not valid";
|
||||
return;
|
||||
}
|
||||
|
||||
// Get device info
|
||||
QDBusPendingCall deviceCall = m_dbusInterface->asyncCall("GetDevice");
|
||||
QDBusPendingCallWatcher *deviceWatcher = new QDBusPendingCallWatcher(deviceCall, this);
|
||||
connect(deviceWatcher, &QDBusPendingCallWatcher::finished, this, &GraphicsDriverApplet::onGetDeviceReply);
|
||||
|
||||
// Get current driver
|
||||
QDBusPendingCall currCall = m_dbusInterface->asyncCall("GetCurrDriverName");
|
||||
QDBusPendingCallWatcher *currWatcher = new QDBusPendingCallWatcher(currCall, this);
|
||||
connect(currWatcher, &QDBusPendingCallWatcher::finished, this, &GraphicsDriverApplet::onGetCurrDriverReply);
|
||||
detectGpus();
|
||||
}
|
||||
|
||||
void GraphicsDriverApplet::prepareInstall(const QString &driverName)
|
||||
void GraphicsDriverApplet::detectGpus()
|
||||
{
|
||||
if (!m_dbusInterface || !m_dbusInterface->isValid()) {
|
||||
emit installFailed("DBus interface is not valid");
|
||||
return;
|
||||
}
|
||||
m_gpus.clear();
|
||||
|
||||
QLocale locale;
|
||||
QString language = locale.name();
|
||||
// 通过 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)) {
|
||||
|
||||
QDBusPendingCall call = m_dbusInterface->asyncCall("PrepareInstall", driverName, language);
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
|
||||
connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *call) {
|
||||
QDBusPendingReply<> reply = *call;
|
||||
if (reply.isError()) {
|
||||
qWarning() << "Failed to prepare install:" << reply.error().message();
|
||||
emit installFailed(reply.error().message());
|
||||
} else {
|
||||
qDebug() << "Prepare install succeeded";
|
||||
}
|
||||
call->deleteLater();
|
||||
});
|
||||
}
|
||||
GpuInfo gpu;
|
||||
// lspci -mm 格式: "Class" "Vendor" "Device" ...
|
||||
// 提取 PCI ID(行首的 01:00.0 等)
|
||||
int spaceIdx = line.indexOf(' ');
|
||||
if (spaceIdx > 0) {
|
||||
gpu.pciId = line.left(spaceIdx);
|
||||
}
|
||||
|
||||
void GraphicsDriverApplet::testInstall()
|
||||
{
|
||||
if (!m_dbusInterface || !m_dbusInterface->isValid()) {
|
||||
emit installFailed("DBus interface is not valid");
|
||||
return;
|
||||
}
|
||||
gpu.name = parseGpuName(line);
|
||||
|
||||
setInstalling(true);
|
||||
// 检测驱动
|
||||
QString sysPath = "/sys/bus/pci/devices/0000:" + gpu.pciId + "/driver";
|
||||
QDir driverDir(sysPath);
|
||||
if (driverDir.exists()) {
|
||||
gpu.driver = driverDir.dirName();
|
||||
|
||||
QDBusPendingCall call = m_dbusInterface->asyncCall("TestInstall");
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
|
||||
connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *call) {
|
||||
QDBusPendingReply<> reply = *call;
|
||||
if (reply.isError()) {
|
||||
qWarning() << "Failed to test install:" << reply.error().message();
|
||||
emit installFailed(reply.error().message());
|
||||
setInstalling(false);
|
||||
} else {
|
||||
qDebug() << "Test install succeeded";
|
||||
realInstall();
|
||||
}
|
||||
call->deleteLater();
|
||||
});
|
||||
}
|
||||
// 读取驱动版本
|
||||
gpu.driverVersion = readDriverVersion(gpu.driver);
|
||||
} else {
|
||||
gpu.driver = "unknown";
|
||||
}
|
||||
|
||||
void GraphicsDriverApplet::realInstall()
|
||||
{
|
||||
if (!m_dbusInterface || !m_dbusInterface->isValid()) {
|
||||
emit installFailed("DBus interface is not valid");
|
||||
return;
|
||||
}
|
||||
|
||||
QDBusPendingCall call = m_dbusInterface->asyncCall("RealInstall");
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
|
||||
connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *call) {
|
||||
QDBusPendingReply<> reply = *call;
|
||||
if (reply.isError()) {
|
||||
qWarning() << "Failed to real install:" << reply.error().message();
|
||||
emit installFailed(reply.error().message());
|
||||
setInstalling(false);
|
||||
} else {
|
||||
qDebug() << "Real install succeeded";
|
||||
setInstalling(false);
|
||||
emit installSuccess();
|
||||
emit requestReboot();
|
||||
}
|
||||
call->deleteLater();
|
||||
});
|
||||
}
|
||||
|
||||
void GraphicsDriverApplet::cancelInstall()
|
||||
{
|
||||
if (!m_dbusInterface || !m_dbusInterface->isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_dbusInterface->asyncCall("CancelInstall");
|
||||
setInstalling(false);
|
||||
}
|
||||
|
||||
void GraphicsDriverApplet::onGetDeviceReply(QDBusPendingCallWatcher *call)
|
||||
{
|
||||
QDBusPendingReply<QString> reply = *call;
|
||||
if (reply.isError()) {
|
||||
qWarning() << "Failed to get device:" << reply.error().message();
|
||||
} else {
|
||||
m_deviceInfo = reply.value();
|
||||
qDebug() << "Device info:" << m_deviceInfo;
|
||||
emit deviceInfoChanged();
|
||||
}
|
||||
call->deleteLater();
|
||||
}
|
||||
|
||||
void GraphicsDriverApplet::onGetCurrDriverReply(QDBusPendingCallWatcher *call)
|
||||
{
|
||||
QDBusPendingReply<QString> reply = *call;
|
||||
if (reply.isError()) {
|
||||
qWarning() << "Failed to get current driver:" << reply.error().message();
|
||||
} else {
|
||||
m_currentDriver = reply.value();
|
||||
qDebug() << "Current driver:" << m_currentDriver;
|
||||
emit currentDriverChanged();
|
||||
}
|
||||
call->deleteLater();
|
||||
}
|
||||
|
||||
void GraphicsDriverApplet::onReportProgress(const QString &ratio)
|
||||
{
|
||||
bool ok;
|
||||
int progress = ratio.toInt(&ok);
|
||||
if (ok) {
|
||||
m_installProgress = progress;
|
||||
emit installProgressChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsDriverApplet::initDBusConnection()
|
||||
{
|
||||
QDBusConnection bus = QDBusConnection::sessionBus();
|
||||
|
||||
if (!bus.isConnected()) {
|
||||
qWarning() << "Cannot connect to D-Bus session bus";
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查服务是否已注册
|
||||
bool registered = bus.interface()->isServiceRegistered(DBUS_SERVICE);
|
||||
if (!registered) {
|
||||
qWarning() << "GraphicsDriver D-Bus service is not registered";
|
||||
return;
|
||||
}
|
||||
|
||||
m_dbusInterface = new QDBusInterface(
|
||||
DBUS_SERVICE,
|
||||
DBUS_PATH,
|
||||
DBUS_INTERFACE,
|
||||
bus,
|
||||
this
|
||||
);
|
||||
|
||||
if (!m_dbusInterface->isValid()) {
|
||||
qWarning() << "DBus interface is not valid:" << m_dbusInterface->lastError().message();
|
||||
return;
|
||||
}
|
||||
|
||||
m_dbusAvailable = true;
|
||||
emit dbusAvailableChanged();
|
||||
|
||||
connect(m_dbusInterface, SIGNAL(ReportProgress(QString)),
|
||||
this, SLOT(onReportProgress(QString)));
|
||||
|
||||
qDebug() << "GraphicsDriver D-Bus connected successfully";
|
||||
}
|
||||
|
||||
void GraphicsDriverApplet::setInstalling(bool installing)
|
||||
{
|
||||
if (m_isInstalling != installing) {
|
||||
m_isInstalling = installing;
|
||||
emit isInstallingChanged();
|
||||
|
||||
if (installing) {
|
||||
m_progressTimer->start(1000);
|
||||
} else {
|
||||
m_progressTimer->stop();
|
||||
m_installProgress = 0;
|
||||
emit installProgressChanged();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
D_APPLET_CLASS(GraphicsDriverApplet)
|
||||
|
||||
Reference in New Issue
Block a user