Warning, file /plasma/plasma-mobile/containments/homescreens/folio/applicationlistmodel.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 // SPDX-FileCopyrightText: 2014 Antonis Tsiapaliokas <antonis.tsiapaliokas@kde.org> 0002 // SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org> 0003 // SPDX-License-Identifier: GPL-2.0-or-later 0004 0005 #include "applicationlistmodel.h" 0006 0007 #include <QByteArray> 0008 #include <QDebug> 0009 #include <QModelIndex> 0010 #include <QProcess> 0011 #include <QQuickWindow> 0012 0013 #include <KApplicationTrader> 0014 #include <KConfigGroup> 0015 #include <KIO/ApplicationLauncherJob> 0016 #include <KNotificationJobUiDelegate> 0017 #include <KService> 0018 #include <KSharedConfig> 0019 #include <KSycoca> 0020 0021 ApplicationListModel::ApplicationListModel(QObject *parent) 0022 : QAbstractListModel(parent) 0023 { 0024 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0025 connect(KSycoca::self(), qOverload<const QStringList &>(&KSycoca::databaseChanged), this, &ApplicationListModel::sycocaDbChanged); 0026 #else 0027 connect(KSycoca::self(), &KSycoca::databaseChanged, this, &ApplicationListModel::sycocaDbChanged); 0028 #endif 0029 0030 // initialize wayland window checking 0031 KWayland::Client::ConnectionThread *connection = KWayland::Client::ConnectionThread::fromApplication(this); 0032 if (!connection) { 0033 return; 0034 } 0035 0036 auto *registry = new KWayland::Client::Registry(this); 0037 registry->create(connection); 0038 0039 connect(registry, &KWayland::Client::Registry::plasmaWindowManagementAnnounced, this, [this, registry](quint32 name, quint32 version) { 0040 m_windowManagement = registry->createPlasmaWindowManagement(name, version, this); 0041 qRegisterMetaType<QVector<int>>("QVector<int>"); 0042 connect(m_windowManagement, &KWayland::Client::PlasmaWindowManagement::windowCreated, this, &ApplicationListModel::windowCreated); 0043 }); 0044 0045 registry->setup(); 0046 connection->roundtrip(); 0047 } 0048 0049 ApplicationListModel::~ApplicationListModel() = default; 0050 0051 QHash<int, QByteArray> ApplicationListModel::roleNames() const 0052 { 0053 return {{ApplicationNameRole, QByteArrayLiteral("applicationName")}, 0054 {ApplicationIconRole, QByteArrayLiteral("applicationIcon")}, 0055 {ApplicationStorageIdRole, QByteArrayLiteral("applicationStorageId")}, 0056 {ApplicationEntryPathRole, QByteArrayLiteral("applicationEntryPath")}, 0057 {ApplicationStartupNotifyRole, QByteArrayLiteral("applicationStartupNotify")}, 0058 {ApplicationRunningRole, QByteArrayLiteral("applicationRunning")}, 0059 {ApplicationUniqueIdRole, QByteArrayLiteral("applicationUniqueId")}, 0060 {ApplicationLocationRole, QByteArrayLiteral("applicationLocation")}}; 0061 } 0062 0063 void ApplicationListModel::sycocaDbChanged() 0064 { 0065 load(); 0066 } 0067 0068 void ApplicationListModel::windowCreated(KWayland::Client::PlasmaWindow *window) 0069 { 0070 if (window->appId() == QStringLiteral("org.kde.plasmashell")) { 0071 return; 0072 } 0073 int idx = 0; 0074 for (auto i = m_applicationList.begin(); i != m_applicationList.end(); i++) { 0075 if ((*i).storageId == window->appId() + QStringLiteral(".desktop")) { 0076 (*i).window = window; 0077 Q_EMIT dataChanged(index(idx, 0), index(idx, 0)); 0078 connect(window, &KWayland::Client::PlasmaWindow::unmapped, this, [this, window]() { 0079 int idx = 0; 0080 for (auto i = m_applicationList.begin(); i != m_applicationList.end(); i++) { 0081 if ((*i).storageId == window->appId() + QStringLiteral(".desktop")) { 0082 (*i).window = nullptr; 0083 Q_EMIT dataChanged(index(idx, 0), index(idx, 0)); 0084 break; 0085 } 0086 idx++; 0087 } 0088 }); 0089 break; 0090 } 0091 idx++; 0092 } 0093 } 0094 0095 void ApplicationListModel::load() 0096 { 0097 auto cfg = KSharedConfig::openConfig(QStringLiteral("applications-blacklistrc")); 0098 auto blgroup = KConfigGroup(cfg, QStringLiteral("Applications")); 0099 0100 const QStringList blacklist = blgroup.readEntry("blacklist", QStringList()); 0101 0102 beginResetModel(); 0103 0104 m_applicationList.clear(); 0105 0106 QList<ApplicationData> unorderedList; 0107 0108 auto filter = [blacklist](const KService::Ptr &service) -> bool { 0109 if (service->noDisplay()) { 0110 return false; 0111 } 0112 0113 if (!service->showOnCurrentPlatform()) { 0114 return false; 0115 } 0116 0117 if (blacklist.contains(service->desktopEntryName())) { 0118 return false; 0119 } 0120 0121 return true; 0122 }; 0123 0124 const KService::List apps = KApplicationTrader::query(filter); 0125 0126 for (const KService::Ptr &service : apps) { 0127 ApplicationData data; 0128 data.name = service->name(); 0129 data.icon = service->icon(); 0130 data.storageId = service->storageId(); 0131 data.uniqueId = service->storageId(); 0132 data.entryPath = service->exec(); 0133 data.startupNotify = service->property(QStringLiteral("StartupNotify")).toBool(); 0134 unorderedList << data; 0135 } 0136 0137 std::sort(unorderedList.begin(), unorderedList.end(), [](const ApplicationListModel::ApplicationData &a1, const ApplicationListModel::ApplicationData &a2) { 0138 return a1.name.compare(a2.name, Qt::CaseInsensitive) < 0; 0139 }); 0140 0141 m_applicationList << unorderedList; 0142 0143 endResetModel(); 0144 } 0145 0146 QVariant ApplicationListModel::data(const QModelIndex &index, int role) const 0147 { 0148 if (!index.isValid()) { 0149 return QVariant(); 0150 } 0151 0152 switch (role) { 0153 case Qt::DisplayRole: 0154 case ApplicationNameRole: 0155 return m_applicationList.at(index.row()).name; 0156 case ApplicationIconRole: 0157 return m_applicationList.at(index.row()).icon; 0158 case ApplicationStorageIdRole: 0159 return m_applicationList.at(index.row()).storageId; 0160 case ApplicationEntryPathRole: 0161 return m_applicationList.at(index.row()).entryPath; 0162 case ApplicationStartupNotifyRole: 0163 return m_applicationList.at(index.row()).startupNotify; 0164 case ApplicationRunningRole: 0165 return m_applicationList.at(index.row()).window != nullptr; 0166 case ApplicationUniqueIdRole: 0167 return m_applicationList.at(index.row()).uniqueId; 0168 case ApplicationLocationRole: 0169 return m_applicationList.at(index.row()).location; 0170 default: 0171 return QVariant(); 0172 } 0173 } 0174 0175 int ApplicationListModel::rowCount(const QModelIndex &parent) const 0176 { 0177 if (parent.isValid()) { 0178 return 0; 0179 } 0180 0181 return m_applicationList.count(); 0182 } 0183 0184 void ApplicationListModel::setMinimizedDelegate(int row, QQuickItem *delegate) 0185 { 0186 if (row < 0 || row >= m_applicationList.count()) { 0187 return; 0188 } 0189 0190 QWindow *delegateWindow = delegate->window(); 0191 if (!delegateWindow) { 0192 return; 0193 } 0194 0195 KWayland::Client::PlasmaWindow *window = m_applicationList[row].window; 0196 if (!window) { 0197 return; 0198 } 0199 0200 KWayland::Client::Surface *surface = KWayland::Client::Surface::fromWindow(delegateWindow); 0201 if (!surface) { 0202 return; 0203 } 0204 0205 QRect rect = delegate->mapRectToScene(QRectF(0, 0, delegate->width(), delegate->height())).toRect(); 0206 0207 window->setMinimizedGeometry(surface, rect); 0208 } 0209 0210 void ApplicationListModel::unsetMinimizedDelegate(int row, QQuickItem *delegate) 0211 { 0212 if (row < 0 || row >= m_applicationList.count()) { 0213 return; 0214 } 0215 0216 QWindow *delegateWindow = delegate->window(); 0217 if (!delegateWindow) { 0218 return; 0219 } 0220 0221 KWayland::Client::PlasmaWindow *window = m_applicationList[row].window; 0222 if (!window) { 0223 return; 0224 } 0225 0226 KWayland::Client::Surface *surface = KWayland::Client::Surface::fromWindow(delegateWindow); 0227 if (!surface) { 0228 return; 0229 } 0230 0231 window->unsetMinimizedGeometry(surface); 0232 }