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 }