diff --git a/libtaskmanager/virtualdesktopinfo.cpp b/libtaskmanager/virtualdesktopinfo.cpp index f89a6df0b..6bfdd59aa 100644 --- a/libtaskmanager/virtualdesktopinfo.cpp +++ b/libtaskmanager/virtualdesktopinfo.cpp @@ -1,541 +1,547 @@ /******************************************************************** Copyright 2016 Eike Hein This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #include "virtualdesktopinfo.h" #include #include #include #include #include #include #include #include #include #include #include #if HAVE_X11 #include #include #endif namespace TaskManager { class Q_DECL_HIDDEN VirtualDesktopInfo::Private : public QObject { Q_OBJECT public: Private(VirtualDesktopInfo *q); virtual ~Private() {} uint refCount = 1; virtual void init() = 0; virtual QVariant currentDesktop() const = 0; virtual int numberOfDesktops() const = 0; virtual QVariantList desktopIds() const = 0; virtual QStringList desktopNames() const = 0; virtual quint32 position(const QVariant &desktop) const = 0; virtual int desktopLayoutRows() const = 0; virtual void requestActivate(const QVariant &desktop) = 0; virtual void requestCreateDesktop(quint32 position) = 0; virtual void requestRemoveDesktop(quint32 position) = 0; Q_SIGNALS: void currentDesktopChanged() const; void numberOfDesktopsChanged() const; void desktopIdsChanged() const; void desktopNamesChanged() const; void desktopLayoutRowsChanged() const; protected: VirtualDesktopInfo *q; }; VirtualDesktopInfo::Private::Private(VirtualDesktopInfo *q) : q(q) { } #if HAVE_X11 class Q_DECL_HIDDEN VirtualDesktopInfo::XWindowPrivate : public VirtualDesktopInfo::Private { public: XWindowPrivate(VirtualDesktopInfo *q); void init() override; QVariant currentDesktop() const override; int numberOfDesktops() const override; QVariantList desktopIds() const override; QStringList desktopNames() const override; quint32 position(const QVariant &desktop) const override; int desktopLayoutRows() const override; void requestActivate(const QVariant &desktop) override; void requestCreateDesktop(quint32 position) override; void requestRemoveDesktop(quint32 position) override; }; VirtualDesktopInfo::XWindowPrivate::XWindowPrivate(VirtualDesktopInfo *q) : VirtualDesktopInfo::Private(q) { init(); } void VirtualDesktopInfo::XWindowPrivate::init() { connect(KWindowSystem::self(), &KWindowSystem::currentDesktopChanged, this, &VirtualDesktopInfo::XWindowPrivate::currentDesktopChanged); connect(KWindowSystem::self(), &KWindowSystem::numberOfDesktopsChanged, this, &VirtualDesktopInfo::XWindowPrivate::numberOfDesktopsChanged); connect(KWindowSystem::self(), &KWindowSystem::desktopNamesChanged, this, &VirtualDesktopInfo::XWindowPrivate::desktopNamesChanged); QDBusConnection dbus = QDBusConnection::sessionBus(); dbus.connect(QString(), QStringLiteral("/KWin"), QStringLiteral("org.kde.KWin"), QStringLiteral("reloadConfig"), this, SIGNAL(desktopLayoutRowsChanged())); } QVariant VirtualDesktopInfo::XWindowPrivate::currentDesktop() const { return KWindowSystem::currentDesktop(); } int VirtualDesktopInfo::XWindowPrivate::numberOfDesktops() const { return KWindowSystem::numberOfDesktops(); } QVariantList VirtualDesktopInfo::XWindowPrivate::desktopIds() const { QVariantList ids; for (int i = 1; i <= KWindowSystem::numberOfDesktops(); ++i) { ids << i; } return ids; } QStringList VirtualDesktopInfo::XWindowPrivate::desktopNames() const { QStringList names; // Virtual desktop numbers start at 1. for (int i = 1; i <= KWindowSystem::numberOfDesktops(); ++i) { names << KWindowSystem::desktopName(i); } return names; } quint32 VirtualDesktopInfo::XWindowPrivate::position(const QVariant &desktop) const { bool ok = false; const quint32 desktopNumber = desktop.toUInt(&ok); if (!ok) { return -1; } return desktopNumber; } int VirtualDesktopInfo::XWindowPrivate::desktopLayoutRows() const { const NETRootInfo info(QX11Info::connection(), NET::NumberOfDesktops | NET::DesktopNames, NET::WM2DesktopLayout); return info.desktopLayoutColumnsRows().height(); } void VirtualDesktopInfo::XWindowPrivate::requestActivate(const QVariant &desktop) { bool ok = false; const int desktopNumber = desktop.toInt(&ok); // Virtual desktop numbers start at 1. if (ok && desktopNumber > 0 && desktopNumber <= KWindowSystem::numberOfDesktops()) { KWindowSystem::setCurrentDesktop(desktopNumber); } } void VirtualDesktopInfo::XWindowPrivate::requestCreateDesktop(quint32 position) { Q_UNUSED(position) NETRootInfo info(QX11Info::connection(), NET::NumberOfDesktops); info.setNumberOfDesktops(info.numberOfDesktops() + 1); } void VirtualDesktopInfo::XWindowPrivate::requestRemoveDesktop(quint32 position) { Q_UNUSED(position) NETRootInfo info(QX11Info::connection(), NET::NumberOfDesktops); if (info.numberOfDesktops() > 1) { info.setNumberOfDesktops(info.numberOfDesktops() - 1); } } #endif static const QString s_serviceName(QStringLiteral("org.kde.KWin")); static const QString s_virtualDesktopsInterface(QStringLiteral("org.kde.KWin.VirtualDesktopManager")); static const QString s_virtDesktopsPath(QStringLiteral("/VirtualDesktopManager")); static const QString s_fdoPropertiesInterface(QStringLiteral("org.freedesktop.DBus.Properties")); class Q_DECL_HIDDEN VirtualDesktopInfo::WaylandPrivate : public VirtualDesktopInfo::Private { Q_OBJECT public: WaylandPrivate(VirtualDesktopInfo *q); QVariant currentVirtualDesktop; QStringList virtualDesktops; uint cachedDesktopLayoutRows = 1; KWayland::Client::PlasmaVirtualDesktopManagement *virtualDesktopManagement = nullptr; QDBusServiceWatcher *kwinServiceWatcher = nullptr; void init() override; void addDesktop(const QString &id, quint32 position); QVariant currentDesktop() const override; int numberOfDesktops() const override; QVariantList desktopIds() const override; QStringList desktopNames() const override; quint32 position(const QVariant &desktop) const override; int desktopLayoutRows() const override; void requestActivate(const QVariant &desktop) override; void requestCreateDesktop(quint32 position) override; void requestRemoveDesktop(quint32 position) override; public Q_SLOTS: void handleDesktopLayoutRowsChanged(uint rows); }; VirtualDesktopInfo::WaylandPrivate::WaylandPrivate(VirtualDesktopInfo *q) : VirtualDesktopInfo::Private(q) { init(); } void VirtualDesktopInfo::WaylandPrivate::init() { if (!KWindowSystem::isPlatformWayland()) { return; } KWayland::Client::ConnectionThread *connection = KWayland::Client::ConnectionThread::fromApplication(q); if (!connection) { return; } KWayland::Client::Registry *registry = new KWayland::Client::Registry(q); registry->create(connection); QObject::connect(registry, &KWayland::Client::Registry::plasmaVirtualDesktopManagementAnnounced, [this, registry] (quint32 name, quint32 version) { virtualDesktopManagement = registry->createPlasmaVirtualDesktopManagement(name, version, q); const QList &desktops = virtualDesktopManagement->desktops(); QObject::connect(virtualDesktopManagement, &KWayland::Client::PlasmaVirtualDesktopManagement::desktopCreated, q, [this](const QString &id, quint32 position) { addDesktop(id, position); } ); QObject::connect(virtualDesktopManagement, &KWayland::Client::PlasmaVirtualDesktopManagement::desktopRemoved, q, [this](const QString &id) { virtualDesktops.removeOne(id); emit numberOfDesktopsChanged(); emit desktopIdsChanged(); emit desktopNamesChanged(); if (currentVirtualDesktop == id) { currentVirtualDesktop.clear(); emit currentDesktopChanged(); } } ); } ); registry->setup(); kwinServiceWatcher = new QDBusServiceWatcher(s_serviceName, QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange); QObject::connect(kwinServiceWatcher, &QDBusServiceWatcher::serviceRegistered, this, [this]() { QDBusConnection::sessionBus().connect( s_serviceName, s_virtDesktopsPath, s_virtualDesktopsInterface, QStringLiteral("rowsChanged"), this, SLOT(handleDesktopLayoutRowsChanged(uint))); }); QObject::connect(kwinServiceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, [this]() { QDBusConnection::sessionBus().disconnect( s_serviceName, s_virtDesktopsPath, s_virtualDesktopsInterface, QStringLiteral("rowsChanged"), this, SLOT(handleDesktopLayoutRowsChanged(uint))); } ); QDBusConnection::sessionBus().connect( s_serviceName, s_virtDesktopsPath, s_virtualDesktopsInterface, QStringLiteral("rowsChanged"), this, SLOT(handleDesktopLayoutRowsChanged(uint))); auto callFinished = [this](QDBusPendingCallWatcher *call) { QDBusPendingReply reply = *call; handleDesktopLayoutRowsChanged(reply.value().toUInt()); call->deleteLater(); }; auto call = QDBusMessage::createMethodCall( s_serviceName, s_virtDesktopsPath, s_fdoPropertiesInterface, QStringLiteral("Get")); call.setArguments({s_virtualDesktopsInterface, QStringLiteral("rows")}); QDBusPendingCall pending = QDBusConnection::sessionBus().asyncCall(call); const QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pending, this); QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, callFinished); } void VirtualDesktopInfo::WaylandPrivate::addDesktop(const QString &id, quint32 position) { if (virtualDesktops.indexOf(id) != -1) { return; } virtualDesktops.insert(position, id); emit numberOfDesktopsChanged(); emit desktopIdsChanged(); emit desktopNamesChanged(); const KWayland::Client::PlasmaVirtualDesktop *desktop = virtualDesktopManagement->getVirtualDesktop(id); QObject::connect(desktop, &KWayland::Client::PlasmaVirtualDesktop::activated, q, [desktop, this]() { currentVirtualDesktop = desktop->id(); emit currentDesktopChanged(); } ); + QObject::connect(desktop, &KWayland::Client::PlasmaVirtualDesktop::done, q, + [this]() { + emit desktopNamesChanged(); + } + ); + if (desktop->isActive()) { currentVirtualDesktop = id; emit currentDesktopChanged(); } } QVariant VirtualDesktopInfo::WaylandPrivate::currentDesktop() const { return currentVirtualDesktop; } int VirtualDesktopInfo::WaylandPrivate::numberOfDesktops() const { return virtualDesktops.count(); } quint32 VirtualDesktopInfo::WaylandPrivate::position(const QVariant &desktop) const { return virtualDesktops.indexOf(desktop.toString()); } QVariantList VirtualDesktopInfo::WaylandPrivate::desktopIds() const { QVariantList ids; foreach (const QString &id, virtualDesktops) { ids << id; } return ids; } QStringList VirtualDesktopInfo::WaylandPrivate::desktopNames() const { QStringList names; foreach(const QString &id, virtualDesktops) { const KWayland::Client::PlasmaVirtualDesktop *desktop = virtualDesktopManagement->getVirtualDesktop(id); if (desktop) { names << desktop->name(); } } return names; } int VirtualDesktopInfo::WaylandPrivate::desktopLayoutRows() const { return (int)cachedDesktopLayoutRows; } void VirtualDesktopInfo::WaylandPrivate::requestActivate(const QVariant &desktop) { KWayland::Client::PlasmaVirtualDesktop *desktopObj = virtualDesktopManagement->getVirtualDesktop(desktop.toString()); if (desktopObj) { desktopObj->requestActivate(); } } void VirtualDesktopInfo::WaylandPrivate::requestCreateDesktop(quint32 position) { virtualDesktopManagement->requestCreateVirtualDesktop(i18n("New Desktop"), position); } void VirtualDesktopInfo::WaylandPrivate::requestRemoveDesktop(quint32 position) { if (virtualDesktops.count() == 1) { return; } if (position > ((quint32)virtualDesktops.count() - 1)) { return; } virtualDesktopManagement->requestRemoveVirtualDesktop(virtualDesktops.at(position)); } void VirtualDesktopInfo::WaylandPrivate::handleDesktopLayoutRowsChanged(uint rows) { if (cachedDesktopLayoutRows != rows) { cachedDesktopLayoutRows = rows; emit desktopLayoutRowsChanged(); } } VirtualDesktopInfo::Private* VirtualDesktopInfo::d = nullptr; VirtualDesktopInfo::VirtualDesktopInfo(QObject *parent) : QObject(parent) { if (!d) { #if HAVE_X11 if (KWindowSystem::isPlatformX11()) { d = new VirtualDesktopInfo::XWindowPrivate(this); } else #endif { d = new VirtualDesktopInfo::WaylandPrivate(this); } } else { ++d->refCount; } connect(d, &VirtualDesktopInfo::Private::currentDesktopChanged, this, &VirtualDesktopInfo::currentDesktopChanged); connect(d, &VirtualDesktopInfo::Private::numberOfDesktopsChanged, this, &VirtualDesktopInfo::numberOfDesktopsChanged); connect(d, &VirtualDesktopInfo::Private::desktopIdsChanged, this, &VirtualDesktopInfo::desktopIdsChanged); connect(d, &VirtualDesktopInfo::Private::desktopNamesChanged, this, &VirtualDesktopInfo::desktopNamesChanged); connect(d, &VirtualDesktopInfo::Private::desktopLayoutRowsChanged, this, &VirtualDesktopInfo::desktopLayoutRowsChanged); } VirtualDesktopInfo::~VirtualDesktopInfo() { --d->refCount; if (!d->refCount) { delete d; d = nullptr; } } QVariant VirtualDesktopInfo::currentDesktop() const { return d->currentDesktop(); } int VirtualDesktopInfo::numberOfDesktops() const { return d->numberOfDesktops(); } QVariantList VirtualDesktopInfo::desktopIds() const { return d->desktopIds(); } QStringList VirtualDesktopInfo::desktopNames() const { return d->desktopNames(); } quint32 VirtualDesktopInfo::position(const QVariant &desktop) const { return d->position(desktop); } int VirtualDesktopInfo::desktopLayoutRows() const { return d->desktopLayoutRows(); } void VirtualDesktopInfo::requestActivate(const QVariant &desktop) { d->requestActivate(desktop); } void VirtualDesktopInfo::requestCreateDesktop(quint32 position) { return d->requestCreateDesktop(position); } void VirtualDesktopInfo::requestRemoveDesktop(quint32 position) { return d->requestRemoveDesktop(position); } } #include "virtualdesktopinfo.moc"