File indexing completed on 2024-05-12 17:00:16
0001 /* 0002 SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl> 0003 0004 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "osinfo.h" 0008 0009 #include <QDBusConnection> 0010 #include <QDBusMessage> 0011 #include <QDBusPendingCallWatcher> 0012 #include <QDBusPendingReply> 0013 0014 #include <KPluginFactory> 0015 #include <KLocalizedString> 0016 #include <KCoreAddons> 0017 #include <KOSRelease> 0018 0019 #include <systemstats/SensorContainer.h> 0020 #include <systemstats/SensorObject.h> 0021 #include <systemstats/SensorProperty.h> 0022 0023 #ifdef Q_OS_LINUX 0024 #include <sys/sysinfo.h> 0025 #endif 0026 #include <time.h> 0027 0028 // Uppercase the first letter of each word. 0029 QString upperCaseFirst(const QString &input) 0030 { 0031 auto parts = input.split(QLatin1Char(' '), Qt::SkipEmptyParts); 0032 for (auto &part : parts) { 0033 part[0] = part[0].toUpper(); 0034 } 0035 return parts.join(QLatin1Char(' ')); 0036 } 0037 0038 // Helper to simplify async dbus calls. 0039 template <typename T> 0040 QDBusPendingCallWatcher *dbusCall( 0041 const QDBusConnection &bus, 0042 const QString &service, 0043 const QString &object, 0044 const QString &interface, 0045 const QString &method, 0046 const QVariantList &arguments, 0047 std::function<void(const QDBusPendingReply<T>&)> callback 0048 ) 0049 { 0050 auto message = QDBusMessage::createMethodCall(service, object, interface, method); 0051 message.setArguments(arguments); 0052 auto watcher = new QDBusPendingCallWatcher{bus.asyncCall(message)}; 0053 QObject::connect(watcher, &QDBusPendingCallWatcher::finished, watcher, [callback](QDBusPendingCallWatcher *watcher) { 0054 QDBusPendingReply<T> reply = watcher->reply(); 0055 callback(reply); 0056 watcher->deleteLater(); 0057 }); 0058 return watcher; 0059 } 0060 0061 class OSInfoPrivate 0062 { 0063 public: 0064 OSInfoPrivate(OSInfoPlugin *qq); 0065 virtual ~OSInfoPrivate() = default; 0066 0067 virtual void update(); 0068 virtual void init(); 0069 0070 OSInfoPlugin *q; 0071 0072 KSysGuard::SensorContainer *container = nullptr; 0073 0074 KSysGuard::SensorObject *kernelObject = nullptr; 0075 KSysGuard::SensorProperty *kernelNameProperty = nullptr; 0076 KSysGuard::SensorProperty *kernelVersionProperty = nullptr; 0077 KSysGuard::SensorProperty *kernelPrettyNameProperty = nullptr; 0078 0079 KSysGuard::SensorObject *systemObject = nullptr; 0080 KSysGuard::SensorProperty *hostnameProperty = nullptr; 0081 KSysGuard::SensorProperty *osNameProperty = nullptr; 0082 KSysGuard::SensorProperty *osVersionProperty = nullptr; 0083 KSysGuard::SensorProperty *osPrettyNameProperty = nullptr; 0084 KSysGuard::SensorProperty *osLogoProperty = nullptr; 0085 KSysGuard::SensorProperty *osUrlProperty = nullptr; 0086 KSysGuard::SensorProperty *uptimeProperty = nullptr; 0087 0088 KSysGuard::SensorObject *plasmaObject = nullptr; 0089 KSysGuard::SensorProperty *qtVersionProperty = nullptr; 0090 KSysGuard::SensorProperty *kfVersionProperty = nullptr; 0091 KSysGuard::SensorProperty *plasmaVersionProperty = nullptr; 0092 KSysGuard::SensorProperty *windowSystemProperty = nullptr; 0093 }; 0094 0095 class LinuxPrivate : public OSInfoPrivate 0096 { 0097 public: 0098 LinuxPrivate(OSInfoPlugin *qq) : OSInfoPrivate(qq) { } 0099 0100 void init() override; 0101 }; 0102 0103 OSInfoPrivate::OSInfoPrivate(OSInfoPlugin *qq) 0104 : q(qq) 0105 { 0106 container = new KSysGuard::SensorContainer(QStringLiteral("os"), i18nc("@title", "Operating System"), q); 0107 0108 kernelObject = new KSysGuard::SensorObject(QStringLiteral("kernel"), i18nc("@title", "Kernel"), container); 0109 kernelNameProperty = new KSysGuard::SensorProperty(QStringLiteral("name"), i18nc("@title", "Kernel Name"), kernelObject); 0110 kernelVersionProperty = new KSysGuard::SensorProperty(QStringLiteral("version"), i18nc("@title", "Kernel Version"), kernelObject); 0111 kernelPrettyNameProperty = new KSysGuard::SensorProperty(QStringLiteral("prettyName"), i18nc("@title", "Kernel Name and Version"), kernelObject); 0112 kernelPrettyNameProperty->setShortName(i18nc("@title Kernel Name and Version", "Kernel")); 0113 0114 systemObject = new KSysGuard::SensorObject(QStringLiteral("system"), i18nc("@title", "System"), container); 0115 hostnameProperty = new KSysGuard::SensorProperty(QStringLiteral("hostname"), i18nc("@title", "Hostname"), systemObject); 0116 osNameProperty = new KSysGuard::SensorProperty(QStringLiteral("name"), i18nc("@title", "Operating System Name"), systemObject); 0117 osVersionProperty = new KSysGuard::SensorProperty(QStringLiteral("version"), i18nc("@title", "Operating System Version"), systemObject); 0118 osPrettyNameProperty = new KSysGuard::SensorProperty(QStringLiteral("prettyName"), i18nc("@title", "Operating System Name and Version"), systemObject); 0119 osPrettyNameProperty->setShortName(i18nc("@title Operating System Name and Version", "OS")); 0120 osLogoProperty = new KSysGuard::SensorProperty(QStringLiteral("logo"), i18nc("@title", "Operating System Logo"), systemObject); 0121 osUrlProperty = new KSysGuard::SensorProperty(QStringLiteral("url"), i18nc("@title", "Operating System URL"), systemObject); 0122 uptimeProperty = new KSysGuard::SensorProperty(QStringLiteral("uptime"), i18nc("@title", "Uptime"), systemObject); 0123 uptimeProperty->setUnit(KSysGuard::UnitTime); 0124 0125 plasmaObject = new KSysGuard::SensorObject(QStringLiteral("plasma"), i18nc("@title", "KDE Plasma"), container); 0126 qtVersionProperty = new KSysGuard::SensorProperty(QStringLiteral("qtVersion"), i18nc("@title", "Qt Version"), plasmaObject); 0127 kfVersionProperty = new KSysGuard::SensorProperty(QStringLiteral("kfVersion"), i18nc("@title", "KDE Frameworks Version"), plasmaObject); 0128 plasmaVersionProperty = new KSysGuard::SensorProperty(QStringLiteral("plasmaVersion"), i18nc("@title", "KDE Plasma Version"), plasmaObject); 0129 windowSystemProperty = new KSysGuard::SensorProperty(QStringLiteral("windowsystem"), i18nc("@title", "Window System"), plasmaObject); 0130 } 0131 0132 OSInfoPlugin::~OSInfoPlugin() = default; 0133 0134 void OSInfoPrivate::init() 0135 { 0136 auto kernelName = upperCaseFirst(QSysInfo::kernelType()); 0137 kernelNameProperty->setValue(kernelName); 0138 kernelVersionProperty->setValue(QSysInfo::kernelVersion()); 0139 kernelPrettyNameProperty->setValue(QString{kernelName % QLatin1Char(' ') % QSysInfo::kernelVersion()}); 0140 hostnameProperty->setValue(QSysInfo::machineHostName()); 0141 0142 KOSRelease os; 0143 osNameProperty->setValue(os.name()); 0144 osVersionProperty->setValue(os.version()); 0145 osPrettyNameProperty->setValue(os.prettyName()); 0146 osLogoProperty->setValue(os.logo()); 0147 osUrlProperty->setValue(os.homeUrl()); 0148 0149 qtVersionProperty->setValue(QString::fromLatin1(qVersion())); 0150 kfVersionProperty->setValue(KCoreAddons::versionString()); 0151 windowSystemProperty->setValue(qgetenv("XDG_SESSION_TYPE").compare("x11", Qt::CaseInsensitive) == 0 ? QStringLiteral("X11") : QStringLiteral("Wayland")); 0152 0153 dbusCall<QVariant>( 0154 QDBusConnection::sessionBus(), 0155 QStringLiteral("org.kde.plasmashell"), 0156 QStringLiteral("/MainApplication"), 0157 QStringLiteral("org.freedesktop.DBus.Properties"), 0158 QStringLiteral("Get"), 0159 { QStringLiteral("org.qtproject.Qt.QCoreApplication"), QStringLiteral("applicationVersion") }, 0160 [this](const QDBusPendingReply<QVariant> &reply) { 0161 if (reply.isError()) { 0162 qWarning() << "Could not determine Plasma version, got: " << reply.error().message(); 0163 plasmaVersionProperty->setValue(i18nc("@info", "Unknown")); 0164 } else { 0165 plasmaVersionProperty->setValue(reply.value()); 0166 } 0167 } 0168 ); 0169 } 0170 0171 void OSInfoPrivate::update() 0172 { 0173 #if defined Q_OS_LINUX 0174 struct sysinfo info; 0175 sysinfo(&info); 0176 // can't send a long over the bus 0177 uptimeProperty->setValue(QVariant::fromValue<qlonglong>(info.uptime)); 0178 #elif defined Q_OS_FREEBSD 0179 timespec time; 0180 clock_gettime(CLOCK_UPTIME, &time); 0181 uptimeProperty->setValue(QVariant::fromValue<qlonglong>(time.tv_sec)); 0182 #endif 0183 } 0184 0185 void LinuxPrivate::init() 0186 { 0187 OSInfoPrivate::init(); 0188 0189 // Override some properties with values from hostnamed, if available. 0190 dbusCall<QVariantMap>( 0191 QDBusConnection::systemBus(), 0192 QStringLiteral("org.freedesktop.hostname1"), 0193 QStringLiteral("/org/freedesktop/hostname1"), 0194 QStringLiteral("org.freedesktop.DBus.Properties"), 0195 QStringLiteral("GetAll"), 0196 { QStringLiteral("org.freedesktop.hostname1") }, 0197 [this](const QDBusPendingReply<QVariantMap> &reply) { 0198 if (reply.isError()) { 0199 qWarning() << "Could not contact hostnamed, got: " << reply.error().message(); 0200 } else { 0201 auto properties = reply.value(); 0202 auto kernelName = properties.value(QStringLiteral("KernelName"), kernelNameProperty->value()).toString(); 0203 kernelNameProperty->setValue(kernelName); 0204 auto kernelVersion = properties.value(QStringLiteral("KernelRelease"), kernelVersionProperty->value()).toString(); 0205 kernelVersionProperty->setValue(kernelVersion); 0206 kernelPrettyNameProperty->setValue(QString{kernelName % QLatin1Char(' ') % kernelVersion}); 0207 0208 auto prettyHostName = properties.value(QStringLiteral("PrettyHostname"), QString{}).toString(); 0209 if (!prettyHostName.isEmpty()) { 0210 hostnameProperty->setValue(prettyHostName); 0211 } else { 0212 hostnameProperty->setValue(properties.value(QStringLiteral("Hostname"), hostnameProperty->value())); 0213 } 0214 } 0215 } 0216 ); 0217 } 0218 0219 OSInfoPlugin::OSInfoPlugin(QObject *parent, const QVariantList &args) 0220 : SensorPlugin(parent, args) 0221 { 0222 #ifdef Q_OS_LINUX 0223 d = std::make_unique<LinuxPrivate>(this); 0224 #else 0225 d = std::make_unique<OSInfoPrivate>(this); 0226 #endif 0227 d->init(); 0228 } 0229 0230 void OSInfoPlugin::update() 0231 { 0232 d->update(); 0233 } 0234 0235 K_PLUGIN_CLASS_WITH_JSON(OSInfoPlugin, "metadata.json") 0236 0237 #include "osinfo.moc"