File indexing completed on 2024-04-28 16:54:38
0001 /* 0002 SPDX-FileCopyrightText: 2019 Kai Uwe Broulik <kde@privat.broulik.de> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #include "utils_p.h" 0008 0009 #include "notifications.h" 0010 0011 #include <QAbstractItemModel> 0012 #include <QAbstractProxyModel> 0013 #include <QConcatenateTablesProxyModel> 0014 #include <QCoreApplication> 0015 #include <QDBusConnection> 0016 #include <QDBusConnectionInterface> 0017 #include <QFile> 0018 #include <QFileInfo> 0019 #include <QMetaEnum> 0020 #include <QSettings> 0021 #include <QTextStream> 0022 0023 #include <KProcessList> 0024 0025 using namespace NotificationManager; 0026 0027 QHash<int, QByteArray> Utils::roleNames() 0028 { 0029 static QHash<int, QByteArray> s_roles; 0030 0031 if (s_roles.isEmpty()) { 0032 // This generates role names from the Roles enum in the form of: FooRole -> foo 0033 const QMetaEnum e = QMetaEnum::fromType<Notifications::Roles>(); 0034 0035 // Qt built-in roles we use 0036 s_roles.insert(Qt::DisplayRole, QByteArrayLiteral("display")); 0037 s_roles.insert(Qt::DecorationRole, QByteArrayLiteral("decoration")); 0038 s_roles.insert(Qt::AccessibleDescriptionRole, QByteArrayLiteral("accessibleDescription")); 0039 0040 for (int i = 0; i < e.keyCount(); ++i) { 0041 const int value = e.value(i); 0042 0043 QByteArray key(e.key(i)); 0044 key[0] = key[0] + 32; // lower case first letter 0045 key.chop(4); // strip "Role" suffix 0046 0047 s_roles.insert(value, key); 0048 } 0049 0050 s_roles.insert(Notifications::IdRole, QByteArrayLiteral("notificationId")); // id is QML-reserved 0051 } 0052 0053 return s_roles; 0054 } 0055 0056 QString Utils::processNameFromPid(uint pid) 0057 { 0058 auto processInfo = KProcessList::processInfo(pid); 0059 0060 if (!processInfo.isValid()) { 0061 return QString(); 0062 } 0063 0064 return processInfo.name(); 0065 } 0066 0067 QString Utils::desktopEntryFromPid(uint pid) 0068 { 0069 const QString flatpakInfoPath = QStringLiteral("/proc/%1/root/.flatpak-info").arg(QString::number(pid)); 0070 if (QFileInfo::exists(flatpakInfoPath)) { 0071 QSettings flatpakInfo(flatpakInfoPath, QSettings::IniFormat); 0072 0073 const QString name = flatpakInfo.value("Application/name").toString(); 0074 if (!name.isEmpty()) { 0075 return name; 0076 } 0077 0078 // If it's a flatpak, can't be a snap, bail out. 0079 return QString(); 0080 } 0081 0082 QFile environFile(QStringLiteral("/proc/%1/environ").arg(QString::number(pid))); 0083 if (environFile.open(QIODevice::ReadOnly | QIODevice::Text)) { 0084 const QByteArray bamfDesktopFileHint = QByteArrayLiteral("BAMF_DESKTOP_FILE_HINT"); 0085 0086 const auto lines = environFile.readAll().split('\0'); 0087 for (const QByteArray &line : lines) { 0088 const int equalsIdx = line.indexOf('='); 0089 if (equalsIdx <= 0) { 0090 continue; 0091 } 0092 0093 const QByteArray key = line.left(equalsIdx); 0094 if (key == bamfDesktopFileHint) { 0095 const QByteArray value = line.mid(equalsIdx + 1); 0096 return value; 0097 } 0098 } 0099 } 0100 0101 return QString(); 0102 } 0103 0104 QModelIndex Utils::mapToModel(const QModelIndex &idx, const QAbstractItemModel *sourceModel) 0105 { 0106 // KModelIndexProxyMapper can only map different indices to a single source 0107 // but we have the other way round, a single index that splits into different source models 0108 QModelIndex resolvedIdx = idx; 0109 while (resolvedIdx.isValid() && resolvedIdx.model() != sourceModel) { 0110 if (auto *proxyModel = qobject_cast<const QAbstractProxyModel *>(resolvedIdx.model())) { 0111 resolvedIdx = proxyModel->mapToSource(resolvedIdx); 0112 // QConcatenateTablesProxyModel isn't a "real" proxy model, so we need to special case for it :( 0113 } else if (auto *concatenateModel = qobject_cast<const QConcatenateTablesProxyModel *>(resolvedIdx.model())) { 0114 resolvedIdx = concatenateModel->mapToSource(resolvedIdx); 0115 } else { 0116 if (resolvedIdx.model() != sourceModel) { 0117 resolvedIdx = QModelIndex(); // give up 0118 } 0119 } 0120 } 0121 return resolvedIdx; 0122 } 0123 0124 bool Utils::isDBusMaster() 0125 { 0126 return qApp->property("_plasma_dbus_master").toBool(); 0127 }