File indexing completed on 2024-05-19 05:49:20
0001 /* 0002 * Copyright 2014 Rohan Garg <rohan@kde.org> 0003 * Copyright 2021 Harald Sitter <sitter@kde.org> 0004 * 0005 * This program is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU General Public License as 0007 * published by the Free Software Foundation; either version 2 of 0008 * the License or (at your option) version 3 or any later version 0009 * accepted by the membership of KDE e.V. (or its successor approved 0010 * by the membership of KDE e.V.), which shall act as a proxy 0011 * defined in Section 14 of version 3 of the license. 0012 * 0013 * This program is distributed in the hope that it will be useful, 0014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0016 * GNU General Public License for more details. 0017 * 0018 * You should have received a copy of the GNU General Public License 0019 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0020 * 0021 */ 0022 0023 #include "driverevent.h" 0024 #include <drivermanager_interface.h> 0025 0026 #include <QDBusConnection> 0027 #include <QDebug> 0028 0029 #include <QApt/Backend> 0030 0031 #include <KToolInvocation> 0032 #include <KConfig> 0033 #include <KConfigGroup> 0034 0035 DriverEvent::DriverEvent(QObject *parent) 0036 : Event(parent, "Driver") 0037 , m_showNotification(false) 0038 , m_aptBackendInitialized(false) 0039 { 0040 qDBusRegisterMetaType<DeviceList>(); 0041 0042 show(); 0043 } 0044 0045 void DriverEvent::show() 0046 { 0047 if (isHidden()) { 0048 return; 0049 } 0050 0051 if (!m_aptBackendInitialized) { 0052 m_aptBackend = new QApt::Backend(this); 0053 if (!m_aptBackend->init()) { 0054 qWarning() << m_aptBackend->initErrorMessage(); 0055 m_aptBackendInitialized = false; 0056 } else { 0057 m_aptBackendInitialized = true; 0058 } 0059 } 0060 if (m_aptBackendInitialized) { 0061 if(m_aptBackend->xapianIndexNeedsUpdate()) { 0062 m_aptBackend->updateXapianIndex(); 0063 connect(m_aptBackend, SIGNAL(xapianUpdateFinished()), SLOT(updateFinished())); 0064 } else { 0065 updateFinished(); 0066 } 0067 } 0068 } 0069 0070 void DriverEvent::updateFinished() 0071 { 0072 if (!m_aptBackend->openXapianIndex()) { 0073 qDebug() << "Xapian update could not be opened, probably broken."; 0074 return; 0075 } 0076 0077 m_manager = new OrgKubuntuDriverManagerInterface("org.kubuntu.DriverManager", "/DriverManager", QDBusConnection::sessionBus()); 0078 0079 // Force no dbus timeout. 0080 // There is exactly one method we use and it must always return. The only 0081 // situations where it does not return are those when something is terribly 0082 // wrong, however we cannot necessarily detect that with an async connection 0083 // either, so instead of asyncyfing the connection, we simply force no timeout. 0084 // TODO: this may be practical and equivalent to async connection 0085 // but is really shitty and should be replaced by async connections. 0086 // alas, those have their own unique problems with timer handling in 0087 // python... 0088 m_manager->setTimeout(INT_MAX); 0089 0090 QDBusPendingReply<DeviceList> reply = m_manager->devices(); 0091 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); 0092 connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), 0093 this, SLOT(onDevicesReady(QDBusPendingCallWatcher*))); 0094 } 0095 0096 void DriverEvent::onDevicesReady(QDBusPendingCallWatcher *call) 0097 { 0098 QDBusPendingReply<DeviceList> reply = *call; 0099 0100 if (reply.isError()) { 0101 qDebug() << "got dbus error; abort"; 0102 return; 0103 } 0104 0105 DeviceList devices = reply.value(); 0106 call->deleteLater(); // deep copy, delete caller 0107 0108 qDebug() << "data " << devices; 0109 0110 KConfig driver_manager("kcmdrivermanagerrc"); 0111 KConfigGroup pciGroup( &driver_manager, "PCI" ); 0112 0113 foreach (Device device, devices) { 0114 if (pciGroup.readEntry(device.id) != QLatin1String("true")) { 0115 // Not seen before, check whether we have recommended drivers. 0116 for (int i = 0; i < device.drivers.length(); ++i) { 0117 // Supposedly Driver is not a pod due to ctor, so it can't 0118 // be fully used by QList :'< 0119 // Manually iter instead. 0120 Driver driver = device.drivers.at(i); 0121 // If there is only one driver listed, we consider it an option. 0122 // This works around an issue with virtualbox where the one and 0123 // only driver is not marked as recommended. However, from 0124 // a notification point of view it makes sense to notify about 0125 // single-option drivers all the same as even if not considered 0126 // recommended they probably should be looked at by the user. 0127 if (driver.recommended || device.drivers.length() == 1) { 0128 QApt::Package *package = m_aptBackend->package(driver.packageName); 0129 if (package) { 0130 if (!package->isInstalled()) { 0131 m_showNotification = true; 0132 break; 0133 } 0134 } else { 0135 qDebug() << "package" << driver.packageName << "could not be found"; 0136 } 0137 } 0138 } 0139 } else { 0140 qDebug() << device.id << "has already been processed by the KCM"; 0141 } 0142 } 0143 0144 if (m_showNotification) { 0145 QString icon = QString("hwinfo"); 0146 QString text(i18nc("Notification when additional packages are required for activating proprietary hardware", 0147 "Proprietary drivers might be required to enable additional features")); 0148 QStringList actions; 0149 actions << i18nc("Launches KDE Control Module to manage drivers", "Manage Drivers"); 0150 actions << i18nc("Button to dismiss this notification once", "Ignore for now"); 0151 actions << i18nc("Button to make this notification never show up again", 0152 "Never show again"); 0153 Event::show(icon, text, actions); 0154 } 0155 } 0156 0157 void DriverEvent::run() 0158 { 0159 KToolInvocation::kdeinitExec("kcmshell5", QStringList() << "kcm_driver_manager"); 0160 Event::run(); 0161 } 0162