3
0
mirror of https://github.com/Qortal/Brooklyn.git synced 2025-02-07 06:44:18 +00:00
Brooklyn/plasma/workspace/libtaskmanager/virtualdesktopinfo.cpp
2022-03-05 22:41:29 +05:00

519 lines
15 KiB
C++

/*
SPDX-FileCopyrightText: 2016 Eike Hein <hein@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "virtualdesktopinfo.h"
#include "libtaskmanager_debug.h"
#include <KLocalizedString>
#include <KWayland/Client/connection_thread.h>
#include <KWayland/Client/plasmavirtualdesktop.h>
#include <KWayland/Client/registry.h>
#include <KWindowSystem>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDBusPendingCallWatcher>
#include <QDBusPendingReply>
#include <QDebug>
#include <config-X11.h>
#if HAVE_X11
#include <QX11Info>
#include <netwm.h>
#endif
namespace TaskManager
{
class Q_DECL_HIDDEN VirtualDesktopInfo::Private : public QObject
{
Q_OBJECT
public:
Private();
virtual ~Private()
{
}
uint refCount = 1;
// Fall back to true if we get an invalid DBus response when asking for the
// user's preference since that's what it was for years and years while
// 425787 was broken.
bool navigationWrappingAround = true;
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;
void navigationWrappingAroundChanged() const;
protected Q_SLOTS:
void navigationWrappingAroundChanged(bool newVal);
};
VirtualDesktopInfo::Private::Private()
{
// Connect to navigationWrappingAroundChanged signal
const bool connection = QDBusConnection::sessionBus().connect(QStringLiteral("org.kde.KWin"),
QStringLiteral("/VirtualDesktopManager"),
QStringLiteral("org.kde.KWin.VirtualDesktopManager"),
QStringLiteral("navigationWrappingAroundChanged"),
this,
SLOT(navigationWrappingAroundChanged(bool)));
if (!connection) {
qCWarning(TASKMANAGER_DEBUG) << "Could not connect to org.kde.KWin.VirtualDesktopManager.navigationWrappingAroundChanged signal";
}
// ...Then get the property's current value
QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KWin"),
QStringLiteral("/VirtualDesktopManager"),
QStringLiteral("org.freedesktop.DBus.Properties"),
QStringLiteral("Get"));
msg.setArguments({QStringLiteral("org.kde.KWin.VirtualDesktopManager"), QStringLiteral("navigationWrappingAround")});
auto *watcher = new QDBusPendingCallWatcher(QDBusConnection::sessionBus().asyncCall(msg), this);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) {
QDBusPendingReply<QVariant> reply = *watcher;
watcher->deleteLater();
if (reply.isError()) {
qCWarning(TASKMANAGER_DEBUG) << "Failed to determine whether virtual desktop navigation wrapping is enabled: " << reply.error().message();
return;
}
navigationWrappingAroundChanged(reply.value().toBool());
});
}
void VirtualDesktopInfo::Private::navigationWrappingAroundChanged(bool newVal)
{
if (navigationWrappingAround == newVal) {
return;
}
navigationWrappingAround = newVal;
Q_EMIT navigationWrappingAroundChanged();
}
#if HAVE_X11
class Q_DECL_HIDDEN VirtualDesktopInfo::XWindowPrivate : public VirtualDesktopInfo::Private
{
Q_OBJECT
public:
XWindowPrivate();
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::Private()
{
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("/VirtualDesktopManager"),
QStringLiteral("org.kde.KWin.VirtualDesktopManager"),
QStringLiteral("rowsChanged"),
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
class Q_DECL_HIDDEN VirtualDesktopInfo::WaylandPrivate : public VirtualDesktopInfo::Private
{
Q_OBJECT
public:
WaylandPrivate();
QVariant currentVirtualDesktop;
QStringList virtualDesktops;
KWayland::Client::PlasmaVirtualDesktopManagement *virtualDesktopManagement = 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;
};
VirtualDesktopInfo::WaylandPrivate::WaylandPrivate()
: VirtualDesktopInfo::Private()
{
init();
}
void VirtualDesktopInfo::WaylandPrivate::init()
{
if (!KWindowSystem::isPlatformWayland()) {
return;
}
KWayland::Client::ConnectionThread *connection = KWayland::Client::ConnectionThread::fromApplication(this);
if (!connection) {
return;
}
KWayland::Client::Registry *registry = new KWayland::Client::Registry(this);
registry->create(connection);
QObject::connect(registry, &KWayland::Client::Registry::plasmaVirtualDesktopManagementAnnounced, [this, registry](quint32 name, quint32 version) {
virtualDesktopManagement = registry->createPlasmaVirtualDesktopManagement(name, version, this);
QObject::connect(virtualDesktopManagement,
&KWayland::Client::PlasmaVirtualDesktopManagement::desktopCreated,
this,
[this](const QString &id, quint32 position) {
addDesktop(id, position);
});
QObject::connect(virtualDesktopManagement, &KWayland::Client::PlasmaVirtualDesktopManagement::desktopRemoved, this, [this](const QString &id) {
virtualDesktops.removeOne(id);
Q_EMIT numberOfDesktopsChanged();
Q_EMIT desktopIdsChanged();
Q_EMIT desktopNamesChanged();
if (currentVirtualDesktop == id) {
currentVirtualDesktop.clear();
Q_EMIT currentDesktopChanged();
}
});
QObject::connect(virtualDesktopManagement,
&KWayland::Client::PlasmaVirtualDesktopManagement::rowsChanged,
this,
&VirtualDesktopInfo::WaylandPrivate::desktopLayoutRowsChanged);
});
registry->setup();
}
void VirtualDesktopInfo::WaylandPrivate::addDesktop(const QString &id, quint32 position)
{
if (virtualDesktops.indexOf(id) != -1) {
return;
}
virtualDesktops.insert(position, id);
Q_EMIT numberOfDesktopsChanged();
Q_EMIT desktopIdsChanged();
Q_EMIT desktopNamesChanged();
const KWayland::Client::PlasmaVirtualDesktop *desktop = virtualDesktopManagement->getVirtualDesktop(id);
QObject::connect(desktop, &KWayland::Client::PlasmaVirtualDesktop::activated, this, [desktop, this]() {
currentVirtualDesktop = desktop->id();
Q_EMIT currentDesktopChanged();
});
QObject::connect(desktop, &KWayland::Client::PlasmaVirtualDesktop::done, this, [this]() {
Q_EMIT desktopNamesChanged();
});
if (desktop->isActive()) {
currentVirtualDesktop = id;
Q_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
{
if (!virtualDesktopManagement) {
return QStringList();
}
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
{
if (!virtualDesktopManagement) {
return 0;
}
return virtualDesktopManagement->rows();
}
void VirtualDesktopInfo::WaylandPrivate::requestActivate(const QVariant &desktop)
{
if (!virtualDesktopManagement) {
return;
}
KWayland::Client::PlasmaVirtualDesktop *desktopObj = virtualDesktopManagement->getVirtualDesktop(desktop.toString());
if (desktopObj) {
desktopObj->requestActivate();
}
}
void VirtualDesktopInfo::WaylandPrivate::requestCreateDesktop(quint32 position)
{
if (!virtualDesktopManagement) {
return;
}
virtualDesktopManagement->requestCreateVirtualDesktop(i18n("New Desktop"), position);
}
void VirtualDesktopInfo::WaylandPrivate::requestRemoveDesktop(quint32 position)
{
if (!virtualDesktopManagement) {
return;
}
if (virtualDesktops.count() == 1) {
return;
}
if (position > ((quint32)virtualDesktops.count() - 1)) {
return;
}
virtualDesktopManagement->requestRemoveVirtualDesktop(virtualDesktops.at(position));
}
VirtualDesktopInfo::Private *VirtualDesktopInfo::d = nullptr;
VirtualDesktopInfo::VirtualDesktopInfo(QObject *parent)
: QObject(parent)
{
if (!d) {
#if HAVE_X11
if (KWindowSystem::isPlatformX11()) {
d = new VirtualDesktopInfo::XWindowPrivate;
} else
#endif
{
d = new VirtualDesktopInfo::WaylandPrivate;
}
} 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);
}
bool VirtualDesktopInfo::navigationWrappingAround() const
{
return d->navigationWrappingAround;
}
}
#include "virtualdesktopinfo.moc"