parent
7059ef56ab
commit
73c378832b
5 changed files with 244 additions and 1 deletions
@ -0,0 +1,207 @@ |
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org> |
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL |
||||
*/ |
||||
|
||||
#include "waylandstartuptasksmodel.h" |
||||
#include "tasktools.h" |
||||
|
||||
#include <KConfigGroup> |
||||
#include <KConfigWatcher> |
||||
#include <KWayland/Client/connection_thread.h> |
||||
#include <KWayland/Client/plasmawindowmanagement.h> |
||||
#include <KWayland/Client/registry.h> |
||||
|
||||
#include <QDebug> |
||||
#include <QTimer> |
||||
#include <QUrl> |
||||
|
||||
namespace TaskManager |
||||
{ |
||||
class Q_DECL_HIDDEN WaylandStartupTasksModel::Private |
||||
{ |
||||
public: |
||||
Private(WaylandStartupTasksModel *q); |
||||
|
||||
void addActivation(KWayland::Client::PlasmaActivation *activation); |
||||
void removeActivation(KWayland::Client::PlasmaActivation *activation); |
||||
|
||||
void init(); |
||||
void loadConfig(); |
||||
|
||||
struct Startup { |
||||
QString name; |
||||
QIcon icon; |
||||
QString applicationId; |
||||
QUrl launcherUrl; |
||||
KWayland::Client::PlasmaActivation *activation; |
||||
}; |
||||
|
||||
WaylandStartupTasksModel *q; |
||||
KConfigWatcher::Ptr configWatcher = nullptr; |
||||
KWayland::Client::PlasmaActivationFeedback *feedback = nullptr; |
||||
KWayland::Client::Registry *registry = nullptr; |
||||
QVector<Startup> startups; |
||||
std::chrono::seconds startupTimeout = std::chrono::seconds::zero(); |
||||
}; |
||||
|
||||
WaylandStartupTasksModel::Private::Private(WaylandStartupTasksModel *q) |
||||
: q(q) |
||||
{ |
||||
} |
||||
|
||||
void WaylandStartupTasksModel::Private::init() |
||||
{ |
||||
configWatcher = KConfigWatcher::create(KSharedConfig::openConfig(QStringLiteral("klaunchrc"))); |
||||
QObject::connect(configWatcher.data(), &KConfigWatcher::configChanged, q, [this]() { |
||||
loadConfig(); |
||||
}); |
||||
|
||||
loadConfig(); |
||||
} |
||||
|
||||
void WaylandStartupTasksModel::Private::loadConfig() |
||||
{ |
||||
KConfigGroup feedbackConfig(configWatcher->config(), "FeedbackStyle"); |
||||
|
||||
if (!feedbackConfig.readEntry("TaskbarButton", true)) { |
||||
delete feedback; |
||||
feedback = nullptr; |
||||
delete registry; |
||||
registry = nullptr; |
||||
|
||||
q->beginResetModel(); |
||||
startups.clear(); |
||||
q->endResetModel(); |
||||
return; |
||||
} |
||||
|
||||
const KConfigGroup taskbarButtonConfig(configWatcher->config(), "TaskbarButtonSettings"); |
||||
startupTimeout = std::chrono::seconds(taskbarButtonConfig.readEntry("Timeout", 5)); |
||||
|
||||
if (!registry) { |
||||
using namespace KWayland::Client; |
||||
|
||||
ConnectionThread *connection = ConnectionThread::fromApplication(q); |
||||
if (!connection) { |
||||
return; |
||||
} |
||||
|
||||
registry = new Registry(q); |
||||
registry->create(connection); |
||||
|
||||
QObject::connect(registry, &Registry::plasmaActivationFeedbackAnnounced, q, [this](quint32 name, quint32 version) { |
||||
feedback = registry->createPlasmaActivationFeedback(name, version, q); |
||||
|
||||
QObject::connect(feedback, &PlasmaActivationFeedback::interfaceAboutToBeReleased, q, [this] { |
||||
q->beginResetModel(); |
||||
startups.clear(); |
||||
q->endResetModel(); |
||||
}); |
||||
|
||||
QObject::connect(feedback, &PlasmaActivationFeedback::activation, q, [this](PlasmaActivation *activation) { |
||||
addActivation(activation); |
||||
}); |
||||
}); |
||||
|
||||
registry->setup(); |
||||
} |
||||
} |
||||
|
||||
void WaylandStartupTasksModel::Private::addActivation(KWayland::Client::PlasmaActivation *activation) |
||||
{ |
||||
QObject::connect(activation, &KWayland::Client::PlasmaActivation::applicationId, q, [this, activation](const QString &appId) { |
||||
// The application id is guaranteed to be the desktop filename without ".desktop"
|
||||
const QString desktopFileName = appId + QLatin1String(".desktop"); |
||||
const QString desktopFilePath = QStandardPaths::locate(QStandardPaths::ApplicationsLocation, desktopFileName); |
||||
if (desktopFilePath.isEmpty()) { |
||||
qWarning() << "Got invalid activation app_id:" << appId; |
||||
return; |
||||
} |
||||
|
||||
const QUrl launcherUrl(QStringLiteral("applications:") + desktopFileName); |
||||
const AppData appData = appDataFromUrl(QUrl::fromLocalFile(desktopFilePath)); |
||||
|
||||
const int count = startups.count(); |
||||
q->beginInsertRows(QModelIndex(), count, count); |
||||
startups.append(Startup{ |
||||
.name = appData.name, |
||||
.icon = appData.icon, |
||||
.applicationId = appId, |
||||
.launcherUrl = launcherUrl, |
||||
.activation = activation, |
||||
}); |
||||
q->endInsertRows(); |
||||
|
||||
// Remove the activation if it doesn't finish within certain time interval.
|
||||
QTimer *timeoutTimer = new QTimer(activation); |
||||
QObject::connect(timeoutTimer, &QTimer::timeout, q, [this, activation]() { |
||||
removeActivation(activation); |
||||
}); |
||||
timeoutTimer->setSingleShot(true); |
||||
timeoutTimer->start(startupTimeout); |
||||
}); |
||||
|
||||
QObject::connect(activation, &KWayland::Client::PlasmaActivation::finished, q, [this, activation]() { |
||||
removeActivation(activation); |
||||
}); |
||||
} |
||||
|
||||
void WaylandStartupTasksModel::Private::removeActivation(KWayland::Client::PlasmaActivation *activation) |
||||
{ |
||||
int position = -1; |
||||
for (int i = 0; i < startups.count(); ++i) { |
||||
if (startups[i].activation == activation) { |
||||
position = i; |
||||
break; |
||||
} |
||||
} |
||||
if (position != -1) { |
||||
q->beginRemoveRows(QModelIndex(), position, position); |
||||
startups.removeAt(position); |
||||
q->endRemoveRows(); |
||||
} |
||||
} |
||||
|
||||
WaylandStartupTasksModel::WaylandStartupTasksModel(QObject *parent) |
||||
: AbstractTasksModel(parent) |
||||
, d(new Private(this)) |
||||
{ |
||||
d->init(); |
||||
} |
||||
|
||||
WaylandStartupTasksModel::~WaylandStartupTasksModel() |
||||
{ |
||||
} |
||||
|
||||
QVariant WaylandStartupTasksModel::data(const QModelIndex &index, int role) const |
||||
{ |
||||
if (!index.isValid() || index.row() >= d->startups.count()) { |
||||
return QVariant(); |
||||
} |
||||
|
||||
const auto &data = d->startups[index.row()]; |
||||
if (role == Qt::DisplayRole) { |
||||
return data.name; |
||||
} else if (role == Qt::DecorationRole) { |
||||
return data.icon; |
||||
} else if (role == AppId) { |
||||
return data.applicationId; |
||||
} else if (role == AppName) { |
||||
return data.name; |
||||
} else if (role == LauncherUrl || role == LauncherUrlWithoutIcon) { |
||||
return data.launcherUrl; |
||||
} else if (role == IsStartup) { |
||||
return true; |
||||
} |
||||
|
||||
return QVariant(); |
||||
} |
||||
|
||||
int WaylandStartupTasksModel::rowCount(const QModelIndex &parent) const |
||||
{ |
||||
return parent.isValid() ? 0 : d->startups.count(); |
||||
} |
||||
|
||||
} // namespace TaskManager
|
||||
@ -0,0 +1,29 @@ |
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org> |
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL |
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include "abstracttasksmodel.h" |
||||
|
||||
namespace TaskManager |
||||
{ |
||||
class TASKMANAGER_EXPORT WaylandStartupTasksModel : public AbstractTasksModel |
||||
{ |
||||
Q_OBJECT |
||||
|
||||
public: |
||||
explicit WaylandStartupTasksModel(QObject *parent = nullptr); |
||||
~WaylandStartupTasksModel() override; |
||||
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; |
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override; |
||||
|
||||
private: |
||||
class Private; |
||||
QScopedPointer<Private> d; |
||||
}; |
||||
|
||||
} // namespace TaskManager
|
||||
Loading…
Reference in new issue