Commit ef455461 authored by Devin Lin's avatar Devin Lin 🎨
Browse files

homescreens/halcyon: Port to new model

parent b41e1f2b
Pipeline #192622 passed with stage
in 1 minute and 10 seconds
/*
* SPDX-FileCopyrightText: 2014 Antonis Tsiapaliokas <antonis.tsiapaliokas@kde.org>
* SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
// Self
// SPDX-FileCopyrightText: 2014 Antonis Tsiapaliokas <antonis.tsiapaliokas@kde.org>
// SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "applicationlistmodel.h"
// Qt
#include <QByteArray>
#include <QDebug>
#include <QModelIndex>
......@@ -16,7 +11,6 @@
#include <QQuickItem>
#include <QQuickWindow>
// KDE
#include <KApplicationTrader>
#include <KConfigGroup>
#include <KIO/ApplicationLauncherJob>
......@@ -25,11 +19,6 @@
#include <KSharedConfig>
#include <KSycoca>
#include <KWayland/Client/connection_thread.h>
#include <KWayland/Client/plasmawindowmanagement.h>
#include <KWayland/Client/registry.h>
#include <KWayland/Client/surface.h>
ApplicationListModel::ApplicationListModel(QObject *parent)
: QAbstractListModel(parent)
{
......@@ -72,12 +61,6 @@ QHash<int, QByteArray> ApplicationListModel::roleNames() const
{ApplicationLocationRole, QByteArrayLiteral("applicationLocation")}};
}
ApplicationListModel *ApplicationListModel::instance()
{
static ApplicationListModel *model = new ApplicationListModel;
return model;
}
void ApplicationListModel::sycocaDbChanged()
{
m_applicationList.clear();
......@@ -232,19 +215,16 @@ void ApplicationListModel::setMinimizedDelegate(int row, QQuickItem *delegate)
}
QWindow *delegateWindow = delegate->window();
if (!delegateWindow) {
return;
}
using namespace KWayland::Client;
KWayland::Client::PlasmaWindow *window = m_applicationList[row].window;
if (!window) {
return;
}
Surface *surface = Surface::fromWindow(delegateWindow);
KWayland::Client::Surface *surface = KWayland::Client::Surface::fromWindow(delegateWindow);
if (!surface) {
return;
}
......@@ -261,19 +241,16 @@ void ApplicationListModel::unsetMinimizedDelegate(int row, QQuickItem *delegate)
}
QWindow *delegateWindow = delegate->window();
if (!delegateWindow) {
return;
}
using namespace KWayland::Client;
KWayland::Client::PlasmaWindow *window = m_applicationList[row].window;
if (!window) {
return;
}
Surface *surface = Surface::fromWindow(delegateWindow);
KWayland::Client::Surface *surface = KWayland::Client::Surface::fromWindow(delegateWindow);
if (!surface) {
return;
}
......
/*
* SPDX-FileCopyrightText: 2014 Antonis Tsiapaliokas <antonis.tsiapaliokas@kde.org>
* SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
// SPDX-FileCopyrightText: 2014 Antonis Tsiapaliokas <antonis.tsiapaliokas@kde.org>
// SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
// Qt
#include <QAbstractListModel>
#include <QList>
#include <QObject>
#include <QQuickItem>
#include <QSet>
class QString;
namespace KWayland
{
namespace Client
{
class PlasmaWindowManagement;
class PlasmaWindow;
}
}
#include <KWayland/Client/connection_thread.h>
#include <KWayland/Client/plasmawindowmanagement.h>
#include <KWayland/Client/registry.h>
#include <KWayland/Client/surface.h>
/**
* @short The base application list, used directly by the app drawer.
......@@ -64,8 +54,6 @@ public:
ApplicationListModel(QObject *parent = nullptr);
~ApplicationListModel() override;
static ApplicationListModel *instance();
int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE;
......
......@@ -3,6 +3,11 @@
set(homescreen_SRCS
homescreen.cpp
application.cpp
applicationfolder.cpp
applicationlistmodel.cpp
pinnedmodel.cpp
windowlistener.cpp
)
add_library(plasma_containment_phone_homescreen_halcyon MODULE ${homescreen_SRCS})
......
// SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "application.h"
#include "windowlistener.h"
#include <QQuickWindow>
#include <KIO/ApplicationLauncherJob>
#include <KNotificationJobUiDelegate>
#include <KService>
Application::Application(QObject *parent, KService::Ptr service)
: QObject{parent}
, m_running{false}
, m_name{service->name()}
, m_icon{service->icon()}
, m_storageId{service->storageId()}
{
auto windows = WindowListener::instance()->windowsFromStorageId(m_storageId);
if (windows.empty()) {
m_window = nullptr;
} else {
m_window = windows[0];
}
connect(WindowListener::instance(), &WindowListener::windowChanged, this, [this](QString storageId) {
if (storageId == m_storageId) {
auto windows = WindowListener::instance()->windowsFromStorageId(m_storageId);
if (windows.empty()) {
setWindow(nullptr);
} else {
setWindow(windows[0]);
}
}
});
}
Application *Application::fromJson(QJsonObject &obj, QObject *parent)
{
QString storageId = obj[QStringLiteral("storageId")].toString();
if (KService::Ptr service = KService::serviceByStorageId(storageId)) {
return new Application(parent, service);
}
return nullptr;
}
QJsonObject Application::toJson()
{
QJsonObject obj;
obj[QStringLiteral("type")] = "application";
obj[QStringLiteral("storageId")] = m_storageId;
return obj;
}
bool Application::running() const
{
return m_window != nullptr;
}
QString Application::name() const
{
return m_name;
}
QString Application::icon() const
{
return m_icon;
}
QString Application::storageId() const
{
return m_storageId;
}
KWayland::Client::PlasmaWindow *Application::window() const
{
return m_window;
}
void Application::setName(QString &name)
{
m_name = name;
Q_EMIT nameChanged();
}
void Application::setIcon(QString &icon)
{
m_icon = icon;
Q_EMIT iconChanged();
}
void Application::setStorageId(QString &storageId)
{
m_storageId = storageId;
Q_EMIT storageIdChanged();
}
void Application::setWindow(KWayland::Client::PlasmaWindow *window)
{
m_window = window;
Q_EMIT windowChanged();
}
void Application::runApplication()
{
if (m_window) {
m_window->requestActivate();
return;
}
KService::Ptr service = KService::serviceByStorageId(m_storageId);
KIO::ApplicationLauncherJob *job = new KIO::ApplicationLauncherJob(service);
job->setUiDelegate(new KNotificationJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled));
job->start();
}
void Application::setMinimizedDelegate(QQuickItem *delegate)
{
QWindow *delegateWindow = delegate->window();
if (!delegateWindow) {
return;
}
if (!m_window) {
return;
}
KWayland::Client::Surface *surface = KWayland::Client::Surface::fromWindow(delegateWindow);
if (!surface) {
return;
}
QRect rect = delegate->mapRectToScene(QRectF(0, 0, delegate->width(), delegate->height())).toRect();
m_window->setMinimizedGeometry(surface, rect);
}
void Application::unsetMinimizedDelegate(QQuickItem *delegate)
{
QWindow *delegateWindow = delegate->window();
if (!delegateWindow) {
return;
}
if (!m_window) {
return;
}
KWayland::Client::Surface *surface = KWayland::Client::Surface::fromWindow(delegateWindow);
if (!surface) {
return;
}
m_window->unsetMinimizedGeometry(surface);
}
// SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QJsonObject>
#include <QObject>
#include <QQuickItem>
#include <QString>
#include <KService>
#include <KWayland/Client/connection_thread.h>
#include <KWayland/Client/plasmawindowmanagement.h>
#include <KWayland/Client/registry.h>
#include <KWayland/Client/surface.h>
class Application : public QObject
{
Q_OBJECT
Q_PROPERTY(bool running READ running NOTIFY windowChanged)
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
Q_PROPERTY(QString icon READ icon NOTIFY iconChanged)
Q_PROPERTY(QString storageId READ storageId NOTIFY storageIdChanged)
public:
Application(QObject *parent = nullptr, KService::Ptr service = QExplicitlySharedDataPointer<KService>{nullptr});
static Application *fromJson(QJsonObject &obj, QObject *parent); // may return nullptr
QJsonObject toJson();
bool running() const;
QString name() const;
QString icon() const;
QString storageId() const;
KWayland::Client::PlasmaWindow *window() const;
void setName(QString &name);
void setIcon(QString &icon);
void setStorageId(QString &storageId);
void setWindow(KWayland::Client::PlasmaWindow *window);
Q_INVOKABLE void runApplication();
Q_INVOKABLE void setMinimizedDelegate(QQuickItem *delegate);
Q_INVOKABLE void unsetMinimizedDelegate(QQuickItem *delegate);
Q_SIGNALS:
void nameChanged();
void iconChanged();
void storageIdChanged();
void windowChanged();
private:
bool m_running;
QString m_name;
QString m_icon;
QString m_storageId;
KWayland::Client::PlasmaWindow *m_window = nullptr;
};
// SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "applicationfolder.h"
#include <QJsonArray>
ApplicationFolder::ApplicationFolder(QObject *parent)
{
}
ApplicationFolder *ApplicationFolder::fromJson(QJsonObject &obj, QObject *parent)
{
QString name = obj[QStringLiteral("name")].toString();
QList<Application *> apps;
for (auto storageId : obj[QStringLiteral("apps")].toArray()) {
if (KService::Ptr service = KService::serviceByStorageId(storageId.toString())) {
apps.append(new Application(parent, service));
}
}
ApplicationFolder *folder = new ApplicationFolder(parent);
folder->setName(name);
folder->setApplications(apps);
return folder;
}
QJsonObject ApplicationFolder::toJson()
{
QJsonObject obj;
obj[QStringLiteral("type")] = "folder";
obj[QStringLiteral("name")] = m_name;
QJsonArray arr;
for (auto *application : m_applications) {
arr.append(QJsonValue::fromVariant(application->storageId()));
}
obj[QStringLiteral("apps")] = arr;
return obj;
}
QString ApplicationFolder::name() const
{
return m_name;
}
void ApplicationFolder::setName(QString &name)
{
m_name = name;
Q_EMIT nameChanged();
}
QList<Application *> ApplicationFolder::applications()
{
return m_applications;
}
void ApplicationFolder::setApplications(QList<Application *> applications)
{
m_applications = applications;
Q_EMIT applicationsChanged();
}
// SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "application.h"
#include <QObject>
#include <QString>
#include <KService>
#include <KWayland/Client/connection_thread.h>
#include <KWayland/Client/plasmawindowmanagement.h>
#include <KWayland/Client/registry.h>
#include <KWayland/Client/surface.h>
class ApplicationFolder : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
Q_PROPERTY(QList<Application *> applications READ applications NOTIFY applicationsChanged)
public:
ApplicationFolder(QObject *parent = nullptr);
static ApplicationFolder *fromJson(QJsonObject &obj, QObject *parent);
QJsonObject toJson();
QString name() const;
void setName(QString &name);
QList<Application *> applications();
void setApplications(QList<Application *> applications);
Q_SIGNALS:
void nameChanged();
void applicationsChanged();
private:
QString m_name;
QList<Application *> m_applications;
};
// SPDX-FileCopyrightText: 2014 Antonis Tsiapaliokas <antonis.tsiapaliokas@kde.org>
// SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "applicationlistmodel.h"
#include <QByteArray>
#include <QDebug>
#include <QModelIndex>
#include <QProcess>
#include <QQuickItem>
#include <QQuickWindow>
#include <KApplicationTrader>
#include <KConfigGroup>
#include <KIO/ApplicationLauncherJob>
#include <KNotificationJobUiDelegate>
#include <KService>
#include <KSharedConfig>
#include <KSycoca>
ApplicationListModel::ApplicationListModel(QObject *parent)
: QAbstractListModel(parent)
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
connect(KSycoca::self(), qOverload<const QStringList &>(&KSycoca::databaseChanged), this, &ApplicationListModel::sycocaDbChanged);
#else
connect(KSycoca::self(), &KSycoca::databaseChanged, this, &ApplicationListModel::sycocaDbChanged);
#endif
}
ApplicationListModel::~ApplicationListModel() = default;
QHash<int, QByteArray> ApplicationListModel::roleNames() const
{
return {{ApplicationRole, QByteArrayLiteral("application")}};
}
void ApplicationListModel::sycocaDbChanged()
{
m_applicationList.clear();
loadApplications();
}
void ApplicationListModel::loadApplications()
{
auto cfg = KSharedConfig::openConfig(QStringLiteral("applications-blacklistrc"));
auto blgroup = KConfigGroup(cfg, QStringLiteral("Applications"));
const QStringList blacklist = blgroup.readEntry("blacklist", QStringList());
beginResetModel();
m_applicationList.clear();
QList<Application *> unorderedList;
auto filter = [blacklist](const KService::Ptr &service) -> bool {
if (service->noDisplay()) {
return false;
}
if (!service->showOnCurrentPlatform()) {
return false;
}
if (blacklist.contains(service->desktopEntryName())) {
return false;
}
return true;
};
const KService::List apps = KApplicationTrader::query(filter);
for (const KService::Ptr &service : apps) {
Application *application = new Application{this, service};
unorderedList.append(application);
}
std::sort(unorderedList.begin(), unorderedList.end(), [](const Application *a1, const Application *a2) {
return a1->name().compare(a2->name(), Qt::CaseInsensitive) < 0;
});
m_applicationList << unorderedList;
endResetModel();
}
QVariant ApplicationListModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) {
return QVariant();
}
return QVariant::fromValue(m_applicationList.at(index.row()));
}
int ApplicationListModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
return 0;
}
return m_applicationList.count();
}
// SPDX-FileCopyrightText: 2014 Antonis Tsiapaliokas <antonis.tsiapaliokas@kde.org>
// SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "application.h"
#include <QAbstractListModel>
#include <QList>
#include <QObject>
#include <QQuickItem>
#include <QSet>
/**
* @short The base application list, used directly by the app drawer.
*/
class ApplicationListModel : public QAbstractListModel