File indexing completed on 2024-11-10 04:57:29

0001 /*
0002     SPDX-FileCopyrightText: 2018 Marco Martin <notmart@gmail.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 #include "plasmavirtualdesktop.h"
0007 #include "display.h"
0008 #include "wayland/quirks.h"
0009 
0010 #include <QDebug>
0011 #include <QTimer>
0012 
0013 #include <qwayland-server-org-kde-plasma-virtual-desktop.h>
0014 #include <wayland-server.h>
0015 
0016 namespace KWin
0017 {
0018 static const quint32 s_version = 2;
0019 
0020 class PlasmaVirtualDesktopInterfacePrivate : public QtWaylandServer::org_kde_plasma_virtual_desktop
0021 {
0022 public:
0023     PlasmaVirtualDesktopInterfacePrivate(PlasmaVirtualDesktopInterface *q);
0024     ~PlasmaVirtualDesktopInterfacePrivate();
0025 
0026     PlasmaVirtualDesktopInterface *q;
0027     QString id;
0028     QString name;
0029     bool active = false;
0030 
0031 protected:
0032     void org_kde_plasma_virtual_desktop_bind_resource(Resource *resource) override;
0033     void org_kde_plasma_virtual_desktop_request_activate(Resource *resource) override;
0034 };
0035 
0036 class PlasmaVirtualDesktopManagementInterfacePrivate : public QtWaylandServer::org_kde_plasma_virtual_desktop_management
0037 {
0038 public:
0039     PlasmaVirtualDesktopManagementInterfacePrivate(PlasmaVirtualDesktopManagementInterface *_q, Display *display);
0040 
0041     QList<PlasmaVirtualDesktopInterface *> desktops;
0042     quint32 rows = 0;
0043     quint32 columns = 0;
0044     PlasmaVirtualDesktopManagementInterface *q;
0045 
0046     inline QList<PlasmaVirtualDesktopInterface *>::const_iterator constFindDesktop(const QString &id);
0047     inline QList<PlasmaVirtualDesktopInterface *>::iterator findDesktop(const QString &id);
0048 
0049 protected:
0050     void org_kde_plasma_virtual_desktop_management_get_virtual_desktop(Resource *resource, uint32_t id, const QString &desktop_id) override;
0051     void org_kde_plasma_virtual_desktop_management_request_create_virtual_desktop(Resource *resource, const QString &name, uint32_t position) override;
0052     void org_kde_plasma_virtual_desktop_management_request_remove_virtual_desktop(Resource *resource, const QString &desktop_id) override;
0053     void org_kde_plasma_virtual_desktop_management_bind_resource(Resource *resource) override;
0054 };
0055 
0056 inline QList<PlasmaVirtualDesktopInterface *>::const_iterator PlasmaVirtualDesktopManagementInterfacePrivate::constFindDesktop(const QString &id)
0057 {
0058     return std::find_if(desktops.constBegin(), desktops.constEnd(), [id](const PlasmaVirtualDesktopInterface *desk) {
0059         return desk->id() == id;
0060     });
0061 }
0062 
0063 inline QList<PlasmaVirtualDesktopInterface *>::iterator PlasmaVirtualDesktopManagementInterfacePrivate::findDesktop(const QString &id)
0064 {
0065     return std::find_if(desktops.begin(), desktops.end(), [id](const PlasmaVirtualDesktopInterface *desk) {
0066         return desk->id() == id;
0067     });
0068 }
0069 
0070 void PlasmaVirtualDesktopManagementInterfacePrivate::org_kde_plasma_virtual_desktop_management_get_virtual_desktop(Resource *resource,
0071                                                                                                                    uint32_t id,
0072                                                                                                                    const QString &desktop_id)
0073 {
0074     auto i = constFindDesktop(desktop_id);
0075     if (i == desktops.constEnd()) {
0076         return;
0077     }
0078 
0079     (*i)->d->add(resource->client(), id, resource->version());
0080 }
0081 
0082 void PlasmaVirtualDesktopManagementInterfacePrivate::org_kde_plasma_virtual_desktop_management_request_create_virtual_desktop(Resource *resource,
0083                                                                                                                               const QString &name,
0084                                                                                                                               uint32_t position)
0085 {
0086     Q_EMIT q->desktopCreateRequested(name, std::clamp<quint32>(position, 0, desktops.size()));
0087 }
0088 
0089 void PlasmaVirtualDesktopManagementInterfacePrivate::org_kde_plasma_virtual_desktop_management_request_remove_virtual_desktop(Resource *resource,
0090                                                                                                                               const QString &desktop_id)
0091 {
0092     Q_EMIT q->desktopRemoveRequested(desktop_id);
0093 }
0094 
0095 PlasmaVirtualDesktopManagementInterfacePrivate::PlasmaVirtualDesktopManagementInterfacePrivate(PlasmaVirtualDesktopManagementInterface *_q, Display *display)
0096     : QtWaylandServer::org_kde_plasma_virtual_desktop_management(*display, s_version)
0097     , q(_q)
0098 {
0099 }
0100 
0101 void PlasmaVirtualDesktopManagementInterfacePrivate::org_kde_plasma_virtual_desktop_management_bind_resource(Resource *resource)
0102 {
0103     quint32 i = 0;
0104     for (auto it = desktops.constBegin(); it != desktops.constEnd(); ++it) {
0105         send_desktop_created(resource->handle, (*it)->id(), i++);
0106     }
0107 
0108     if (resource->version() >= ORG_KDE_PLASMA_VIRTUAL_DESKTOP_MANAGEMENT_ROWS_SINCE_VERSION) {
0109         send_rows(resource->handle, rows);
0110     }
0111 
0112     send_done(resource->handle);
0113 }
0114 
0115 PlasmaVirtualDesktopManagementInterface::PlasmaVirtualDesktopManagementInterface(Display *display, QObject *parent)
0116     : QObject(parent)
0117     , d(new PlasmaVirtualDesktopManagementInterfacePrivate(this, display))
0118 {
0119 }
0120 
0121 PlasmaVirtualDesktopManagementInterface::~PlasmaVirtualDesktopManagementInterface()
0122 {
0123     while (!d->desktops.isEmpty()) {
0124         const QString id = d->desktops[0]->id();
0125         removeDesktop(id);
0126     }
0127 }
0128 
0129 void PlasmaVirtualDesktopManagementInterface::setRows(quint32 rows)
0130 {
0131     if (rows == 0 || d->rows == rows) {
0132         return;
0133     }
0134 
0135     d->rows = rows;
0136 
0137     const auto clientResources = d->resourceMap();
0138     for (auto resource : clientResources) {
0139         if (resource->version() < ORG_KDE_PLASMA_VIRTUAL_DESKTOP_MANAGEMENT_ROWS_SINCE_VERSION) {
0140             continue;
0141         }
0142         d->send_rows(resource->handle, rows);
0143     }
0144 }
0145 
0146 PlasmaVirtualDesktopInterface *PlasmaVirtualDesktopManagementInterface::desktop(const QString &id)
0147 {
0148     auto i = d->constFindDesktop(id);
0149     if (i != d->desktops.constEnd()) {
0150         return *i;
0151     }
0152     return nullptr;
0153 }
0154 
0155 PlasmaVirtualDesktopInterface *PlasmaVirtualDesktopManagementInterface::createDesktop(const QString &id, quint32 position)
0156 {
0157     auto i = d->constFindDesktop(id);
0158     if (i != d->desktops.constEnd()) {
0159         return *i;
0160     }
0161 
0162     const quint32 actualPosition = std::min(position, (quint32)d->desktops.count());
0163 
0164     auto desktop = new PlasmaVirtualDesktopInterface();
0165     desktop->d->id = id;
0166 
0167     const auto desktopClientResources = desktop->d->resourceMap();
0168     for (auto resource : desktopClientResources) {
0169         desktop->d->send_desktop_id(resource->handle, id);
0170     }
0171 
0172     // activate the first desktop TODO: to be done here?
0173     if (d->desktops.isEmpty()) {
0174         desktop->d->active = true;
0175     }
0176 
0177     d->desktops.insert(actualPosition, desktop);
0178 
0179     const auto clientResources = d->resourceMap();
0180     for (auto resource : clientResources) {
0181         d->send_desktop_created(resource->handle, id, actualPosition);
0182     }
0183 
0184     return desktop;
0185 }
0186 
0187 void PlasmaVirtualDesktopManagementInterface::removeDesktop(const QString &id)
0188 {
0189     auto deskIt = d->findDesktop(id);
0190     if (deskIt == d->desktops.end()) {
0191         return;
0192     }
0193 
0194     PlasmaVirtualDesktopInterface *desktop = *deskIt;
0195     d->desktops.erase(deskIt);
0196     delete desktop;
0197 
0198     const auto clientResources = d->resourceMap();
0199     for (auto resource : clientResources) {
0200         d->send_desktop_removed(resource->handle, id);
0201     }
0202 }
0203 
0204 QList<PlasmaVirtualDesktopInterface *> PlasmaVirtualDesktopManagementInterface::desktops() const
0205 {
0206     return d->desktops;
0207 }
0208 
0209 void PlasmaVirtualDesktopManagementInterface::sendDone()
0210 {
0211     const auto clientResources = d->resourceMap();
0212     for (auto resource : clientResources) {
0213         d->send_done(resource->handle);
0214     }
0215 }
0216 
0217 //// PlasmaVirtualDesktopInterface
0218 
0219 void PlasmaVirtualDesktopInterfacePrivate::org_kde_plasma_virtual_desktop_request_activate(Resource *resource)
0220 {
0221     Q_EMIT q->activateRequested();
0222 }
0223 
0224 PlasmaVirtualDesktopInterfacePrivate::PlasmaVirtualDesktopInterfacePrivate(PlasmaVirtualDesktopInterface *q)
0225     : QtWaylandServer::org_kde_plasma_virtual_desktop()
0226     , q(q)
0227 {
0228 }
0229 
0230 PlasmaVirtualDesktopInterfacePrivate::~PlasmaVirtualDesktopInterfacePrivate()
0231 {
0232     const auto clientResources = resourceMap();
0233     for (Resource *resource : clientResources) {
0234         send_removed(resource->handle);
0235         wl_resource_destroy(resource->handle);
0236     }
0237 }
0238 
0239 void PlasmaVirtualDesktopInterfacePrivate::org_kde_plasma_virtual_desktop_bind_resource(Resource *resource)
0240 {
0241     send_desktop_id(resource->handle, id);
0242 
0243     if (!name.isEmpty()) {
0244         send_name(resource->handle, truncate(name));
0245     }
0246 
0247     if (active) {
0248         send_activated(resource->handle);
0249     }
0250 }
0251 
0252 PlasmaVirtualDesktopInterface::PlasmaVirtualDesktopInterface()
0253     : d(new PlasmaVirtualDesktopInterfacePrivate(this))
0254 {
0255 }
0256 
0257 PlasmaVirtualDesktopInterface::~PlasmaVirtualDesktopInterface()
0258 {
0259 }
0260 
0261 QString PlasmaVirtualDesktopInterface::id() const
0262 {
0263     return d->id;
0264 }
0265 
0266 void PlasmaVirtualDesktopInterface::setName(const QString &name)
0267 {
0268     if (d->name == name) {
0269         return;
0270     }
0271 
0272     d->name = name;
0273 
0274     const auto clientResources = d->resourceMap();
0275     for (auto resource : clientResources) {
0276         d->send_name(resource->handle, truncate(name));
0277     }
0278 }
0279 
0280 QString PlasmaVirtualDesktopInterface::name() const
0281 {
0282     return d->name;
0283 }
0284 
0285 void PlasmaVirtualDesktopInterface::setActive(bool active)
0286 {
0287     if (d->active == active) {
0288         return;
0289     }
0290 
0291     d->active = active;
0292     const auto clientResources = d->resourceMap();
0293 
0294     if (active) {
0295         for (auto resource : clientResources) {
0296             d->send_activated(resource->handle);
0297         }
0298     } else {
0299         for (auto resource : clientResources) {
0300             d->send_deactivated(resource->handle);
0301         }
0302     }
0303 }
0304 
0305 bool PlasmaVirtualDesktopInterface::isActive() const
0306 {
0307     return d->active;
0308 }
0309 
0310 void PlasmaVirtualDesktopInterface::sendDone()
0311 {
0312     const auto clientResources = d->resourceMap();
0313     for (auto resource : clientResources) {
0314         d->send_done(resource->handle);
0315     }
0316 }
0317 
0318 }
0319 
0320 #include "moc_plasmavirtualdesktop.cpp"