7#include "virtualdesktopinfo.h"
8#include "libtaskmanager_debug.h"
10#include <KLocalizedString>
11#include <KWindowSystem>
14#include <qwayland-org-kde-plasma-virtual-desktop.h>
16#include <QDBusConnection>
17#include <QDBusMessage>
18#include <QDBusPendingCallWatcher>
19#include <QDBusPendingReply>
20#include <QGuiApplication>
21#include <QWaylandClientExtension>
23#include <config-X11.h>
31[[nodiscard]]
inline auto connection()
39class Q_DECL_HIDDEN VirtualDesktopInfo::Private :
public QObject
53 bool navigationWrappingAround =
true;
55 virtual void init() = 0;
56 virtual QVariant currentDesktop()
const = 0;
57 virtual int numberOfDesktops()
const = 0;
58 virtual QVariantList desktopIds()
const = 0;
60 virtual quint32 position(
const QVariant &desktop)
const = 0;
61 virtual int desktopLayoutRows()
const = 0;
62 virtual void requestActivate(
const QVariant &desktop) = 0;
63 virtual void requestCreateDesktop(quint32 position) = 0;
64 virtual void requestRemoveDesktop(quint32 position) = 0;
67 void currentDesktopChanged()
const;
68 void numberOfDesktopsChanged()
const;
69 void desktopIdsChanged()
const;
70 void desktopNamesChanged()
const;
71 void desktopLayoutRowsChanged()
const;
72 void navigationWrappingAroundChanged()
const;
75 void navigationWrappingAroundChanged(
bool newVal);
78VirtualDesktopInfo::Private::Private()
82 QStringLiteral(
"/VirtualDesktopManager"),
83 QStringLiteral(
"org.kde.KWin.VirtualDesktopManager"),
84 QStringLiteral(
"navigationWrappingAroundChanged"),
86 SLOT(navigationWrappingAroundChanged(
bool)));
88 qCWarning(TASKMANAGER_DEBUG) <<
"Could not connect to org.kde.KWin.VirtualDesktopManager.navigationWrappingAroundChanged signal";
93 QStringLiteral(
"/VirtualDesktopManager"),
94 QStringLiteral(
"org.freedesktop.DBus.Properties"),
95 QStringLiteral(
"Get"));
96 msg.
setArguments({QStringLiteral(
"org.kde.KWin.VirtualDesktopManager"), QStringLiteral(
"navigationWrappingAround")});
103 qCWarning(TASKMANAGER_DEBUG) <<
"Failed to determine whether virtual desktop navigation wrapping is enabled: " << reply.
error().
message();
107 navigationWrappingAroundChanged(reply.
value().toBool());
111void VirtualDesktopInfo::Private::navigationWrappingAroundChanged(
bool newVal)
113 if (navigationWrappingAround == newVal) {
116 navigationWrappingAround = newVal;
117 Q_EMIT navigationWrappingAroundChanged();
121class Q_DECL_HIDDEN VirtualDesktopInfo::XWindowPrivate :
public VirtualDesktopInfo::Private
127 void init()
override;
128 QVariant currentDesktop()
const override;
129 int numberOfDesktops()
const override;
130 QVariantList desktopIds()
const override;
132 quint32 position(
const QVariant &desktop)
const override;
133 int desktopLayoutRows()
const override;
134 void requestActivate(
const QVariant &desktop)
override;
135 void requestCreateDesktop(quint32 position)
override;
136 void requestRemoveDesktop(quint32 position)
override;
139VirtualDesktopInfo::XWindowPrivate::XWindowPrivate()
140 : VirtualDesktopInfo::Private()
145void VirtualDesktopInfo::XWindowPrivate::init()
155 QStringLiteral(
"/VirtualDesktopManager"),
156 QStringLiteral(
"org.kde.KWin.VirtualDesktopManager"),
157 QStringLiteral(
"rowsChanged"),
159 SIGNAL(desktopLayoutRowsChanged()));
162QVariant VirtualDesktopInfo::XWindowPrivate::currentDesktop()
const
167int VirtualDesktopInfo::XWindowPrivate::numberOfDesktops()
const
172QVariantList VirtualDesktopInfo::XWindowPrivate::desktopIds()
const
183QStringList VirtualDesktopInfo::XWindowPrivate::desktopNames()
const
195quint32 VirtualDesktopInfo::XWindowPrivate::position(
const QVariant &desktop)
const
199 const quint32 desktopNumber = desktop.
toUInt(&ok);
205 return desktopNumber;
208int VirtualDesktopInfo::XWindowPrivate::desktopLayoutRows()
const
210 const NETRootInfo info(X11Info::connection(), NET::NumberOfDesktops | NET::DesktopNames, NET::WM2DesktopLayout);
211 return info.desktopLayoutColumnsRows().height();
214void VirtualDesktopInfo::XWindowPrivate::requestActivate(
const QVariant &desktop)
217 const int desktopNumber = desktop.
toInt(&ok);
225void VirtualDesktopInfo::XWindowPrivate::requestCreateDesktop(quint32 position)
229 NETRootInfo info(X11Info::connection(), NET::NumberOfDesktops);
230 info.setNumberOfDesktops(info.numberOfDesktops() + 1);
233void VirtualDesktopInfo::XWindowPrivate::requestRemoveDesktop(quint32 position)
237 NETRootInfo info(X11Info::connection(), NET::NumberOfDesktops);
239 if (info.numberOfDesktops() > 1) {
240 info.setNumberOfDesktops(info.numberOfDesktops() - 1);
245class PlasmaVirtualDesktop :
public QObject,
public QtWayland::org_kde_plasma_virtual_desktop
249 PlasmaVirtualDesktop(::org_kde_plasma_virtual_desktop *
object,
const QString &
id)
250 : org_kde_plasma_virtual_desktop(object)
254 ~PlasmaVirtualDesktop()
256 wl_proxy_destroy(
reinterpret_cast<wl_proxy *
>(
object()));
265 void org_kde_plasma_virtual_desktop_name(
const QString &name)
override
269 void org_kde_plasma_virtual_desktop_done()
override
273 void org_kde_plasma_virtual_desktop_activated()
override
279class PlasmaVirtualDesktopManagement :
public QWaylandClientExtensionTemplate<PlasmaVirtualDesktopManagement>,
280 public QtWayland::org_kde_plasma_virtual_desktop_management
284 PlasmaVirtualDesktopManagement()
285 : QWaylandClientExtensionTemplate(2)
287 connect(
this, &QWaylandClientExtension::activeChanged,
this, [
this] {
289 wl_proxy_destroy(
reinterpret_cast<wl_proxy *
>(
object()));
293 ~PlasmaVirtualDesktopManagement()
296 wl_proxy_destroy(
reinterpret_cast<wl_proxy *
>(
object()));
300 void desktopCreated(
const QString &
id, quint32 position);
301 void desktopRemoved(
const QString &
id);
302 void rowsChanged(
const quint32 rows);
305 void org_kde_plasma_virtual_desktop_management_desktop_created(
const QString &desktop_id, uint32_t position)
override
307 Q_EMIT desktopCreated(desktop_id, position);
309 void org_kde_plasma_virtual_desktop_management_desktop_removed(
const QString &desktop_id)
override
311 Q_EMIT desktopRemoved(desktop_id);
313 void org_kde_plasma_virtual_desktop_management_rows(uint32_t rows)
override
315 Q_EMIT rowsChanged(rows);
319class Q_DECL_HIDDEN VirtualDesktopInfo::WaylandPrivate :
public VirtualDesktopInfo::Private
326 std::vector<std::unique_ptr<PlasmaVirtualDesktop>> virtualDesktops;
327 std::unique_ptr<PlasmaVirtualDesktopManagement> virtualDesktopManagement;
330 auto findDesktop(
const QString &
id)
const;
332 void init()
override;
333 void addDesktop(
const QString &
id, quint32 position);
334 QVariant currentDesktop()
const override;
335 int numberOfDesktops()
const override;
336 QVariantList desktopIds()
const override;
338 quint32 position(
const QVariant &desktop)
const override;
339 int desktopLayoutRows()
const override;
340 void requestActivate(
const QVariant &desktop)
override;
341 void requestCreateDesktop(quint32 position)
override;
342 void requestRemoveDesktop(quint32 position)
override;
345VirtualDesktopInfo::WaylandPrivate::WaylandPrivate()
346 : VirtualDesktopInfo::Private()
351auto VirtualDesktopInfo::WaylandPrivate::findDesktop(
const QString &
id)
const
353 return std::find_if(virtualDesktops.begin(), virtualDesktops.end(), [&
id](
const std::unique_ptr<PlasmaVirtualDesktop> &desktop) {
354 return desktop->id == id;
358void VirtualDesktopInfo::WaylandPrivate::init()
364 virtualDesktopManagement = std::make_unique<PlasmaVirtualDesktopManagement>();
366 connect(virtualDesktopManagement.get(), &PlasmaVirtualDesktopManagement::activeChanged,
this, [
this] {
367 if (!virtualDesktopManagement->isActive()) {
369 virtualDesktops.clear();
370 currentVirtualDesktop.clear();
371 Q_EMIT currentDesktopChanged();
372 Q_EMIT numberOfDesktopsChanged();
373 Q_EMIT navigationWrappingAroundChanged();
374 Q_EMIT desktopIdsChanged();
375 Q_EMIT desktopNamesChanged();
376 Q_EMIT desktopLayoutRowsChanged();
380 connect(virtualDesktopManagement.get(), &PlasmaVirtualDesktopManagement::desktopCreated,
this, &WaylandPrivate::addDesktop);
382 connect(virtualDesktopManagement.get(), &PlasmaVirtualDesktopManagement::desktopRemoved,
this, [
this](
const QString &
id) {
383 std::erase_if(virtualDesktops, [id](const std::unique_ptr<PlasmaVirtualDesktop> &desktop) {
384 return desktop->id == id;
387 Q_EMIT numberOfDesktopsChanged();
388 Q_EMIT desktopIdsChanged();
389 Q_EMIT desktopNamesChanged();
391 if (currentVirtualDesktop ==
id) {
392 currentVirtualDesktop.clear();
393 Q_EMIT currentDesktopChanged();
397 connect(virtualDesktopManagement.get(), &PlasmaVirtualDesktopManagement::rowsChanged,
this, [
this](quint32 rows) {
399 Q_EMIT desktopLayoutRowsChanged();
403void VirtualDesktopInfo::WaylandPrivate::addDesktop(
const QString &
id, quint32 position)
405 if (findDesktop(
id) != virtualDesktops.end()) {
409 auto desktop = std::make_unique<PlasmaVirtualDesktop>(virtualDesktopManagement->get_virtual_desktop(
id),
id);
411 connect(desktop.
get(), &PlasmaVirtualDesktop::activated,
this, [
id,
this]() {
412 currentVirtualDesktop = id;
413 Q_EMIT currentDesktopChanged();
416 connect(desktop.
get(), &PlasmaVirtualDesktop::done,
this, [
this]() {
417 Q_EMIT desktopNamesChanged();
420 virtualDesktops.insert(std::next(virtualDesktops.begin(), position), std::move(desktop));
422 Q_EMIT numberOfDesktopsChanged();
423 Q_EMIT desktopIdsChanged();
424 Q_EMIT desktopNamesChanged();
427QVariant VirtualDesktopInfo::WaylandPrivate::currentDesktop()
const
429 return currentVirtualDesktop;
432int VirtualDesktopInfo::WaylandPrivate::numberOfDesktops()
const
434 return virtualDesktops.size();
437quint32 VirtualDesktopInfo::WaylandPrivate::position(
const QVariant &desktop)
const
439 return std::distance(virtualDesktops.begin(), findDesktop(desktop.
toString()));
442QVariantList VirtualDesktopInfo::WaylandPrivate::desktopIds()
const
445 ids.reserve(virtualDesktops.size());
447 std::transform(virtualDesktops.cbegin(), virtualDesktops.cend(), std::back_inserter(ids), [](
const std::unique_ptr<PlasmaVirtualDesktop> &desktop) {
453QStringList VirtualDesktopInfo::WaylandPrivate::desktopNames()
const
455 if (!virtualDesktopManagement->isActive()) {
459 names.
reserve(virtualDesktops.size());
461 std::transform(virtualDesktops.cbegin(), virtualDesktops.cend(), std::back_inserter(names), [](
const std::unique_ptr<PlasmaVirtualDesktop> &desktop) {
462 return desktop->name;
467int VirtualDesktopInfo::WaylandPrivate::desktopLayoutRows()
const
469 if (!virtualDesktopManagement->isActive()) {
476void VirtualDesktopInfo::WaylandPrivate::requestActivate(
const QVariant &desktop)
478 if (!virtualDesktopManagement->isActive()) {
482 if (
auto it = findDesktop(desktop.
toString()); it != virtualDesktops.end()) {
483 (*it)->request_activate();
487void VirtualDesktopInfo::WaylandPrivate::requestCreateDesktop(quint32 position)
489 if (!virtualDesktopManagement->isActive()) {
492 virtualDesktopManagement->request_create_virtual_desktop(
i18n(
"New Desktop"), position);
495void VirtualDesktopInfo::WaylandPrivate::requestRemoveDesktop(quint32 position)
497 if (!virtualDesktopManagement->isActive()) {
500 if (virtualDesktops.size() == 1) {
504 if (position > (virtualDesktops.size() - 1)) {
508 virtualDesktopManagement->request_remove_virtual_desktop(virtualDesktops.at(position)->id);
511VirtualDesktopInfo::Private *VirtualDesktopInfo::d =
nullptr;
513VirtualDesktopInfo::VirtualDesktopInfo(
QObject *parent)
519 d =
new VirtualDesktopInfo::XWindowPrivate;
523 d =
new VirtualDesktopInfo::WaylandPrivate;
529 connect(d, &VirtualDesktopInfo::Private::currentDesktopChanged,
this, &VirtualDesktopInfo::currentDesktopChanged);
530 connect(d, &VirtualDesktopInfo::Private::numberOfDesktopsChanged,
this, &VirtualDesktopInfo::numberOfDesktopsChanged);
531 connect(d, &VirtualDesktopInfo::Private::desktopIdsChanged,
this, &VirtualDesktopInfo::desktopIdsChanged);
532 connect(d, &VirtualDesktopInfo::Private::desktopNamesChanged,
this, &VirtualDesktopInfo::desktopNamesChanged);
533 connect(d, &VirtualDesktopInfo::Private::desktopLayoutRowsChanged,
this, &VirtualDesktopInfo::desktopLayoutRowsChanged);
536VirtualDesktopInfo::~VirtualDesktopInfo()
548 return d->currentDesktop();
551int VirtualDesktopInfo::numberOfDesktops()
const
553 return d->numberOfDesktops();
556QVariantList VirtualDesktopInfo::desktopIds()
const
558 return d->desktopIds();
563 return d->desktopNames();
566quint32 VirtualDesktopInfo::position(
const QVariant &desktop)
const
568 return d->position(desktop);
571int VirtualDesktopInfo::desktopLayoutRows()
const
573 return d->desktopLayoutRows();
576void VirtualDesktopInfo::requestActivate(
const QVariant &desktop)
578 d->requestActivate(desktop);
581void VirtualDesktopInfo::requestCreateDesktop(quint32 position)
583 return d->requestCreateDesktop(position);
586void VirtualDesktopInfo::requestRemoveDesktop(quint32 position)
588 return d->requestRemoveDesktop(position);
591bool VirtualDesktopInfo::navigationWrappingAround()
const
593 return d->navigationWrappingAround;
598#include "virtualdesktopinfo.moc"
static bool isPlatformX11()
static bool isPlatformWayland()
QString i18n(const char *text, const TYPE &arg...)
QString name(StandardAction id)
bool connect(const QString &service, const QString &path, const QString &interface, const QString &name, QObject *receiver, const char *slot)
QDBusConnection sessionBus()
QString message() const const
QDBusMessage createMethodCall(const QString &service, const QString &path, const QString &interface, const QString &method)
void setArguments(const QList< QVariant > &arguments)
void finished(QDBusPendingCallWatcher *self)
QDBusError error() const const
bool isError() const const
typename Select< 0 >::Type value() const const
void reserve(qsizetype size)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
int toInt(bool *ok) const const
QString toString() const const
uint toUInt(bool *ok) const const