File indexing completed on 2024-05-19 05:32:39

0001 /*
0002     SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 #include "plasmawindowmanagement.h"
0007 #include "display.h"
0008 #include "output.h"
0009 #include "plasmavirtualdesktop.h"
0010 #include "surface.h"
0011 #include "utils/common.h"
0012 #include "wayland/quirks.h"
0013 
0014 #include <QFile>
0015 #include <QHash>
0016 #include <QIcon>
0017 #include <QList>
0018 #include <QPointer>
0019 #include <QRect>
0020 #include <QThreadPool>
0021 #include <QUuid>
0022 
0023 #include <qwayland-server-plasma-window-management.h>
0024 
0025 namespace KWin
0026 {
0027 static const quint32 s_version = 16;
0028 static const quint32 s_activationVersion = 1;
0029 
0030 class PlasmaWindowManagementInterfacePrivate : public QtWaylandServer::org_kde_plasma_window_management
0031 {
0032 public:
0033     PlasmaWindowManagementInterfacePrivate(PlasmaWindowManagementInterface *_q, Display *display);
0034     void sendShowingDesktopState();
0035     void sendShowingDesktopState(wl_resource *resource);
0036     void sendStackingOrderChanged();
0037     void sendStackingOrderChanged(wl_resource *resource);
0038     void sendStackingOrderUuidsChanged();
0039     void sendStackingOrderUuidsChanged(wl_resource *resource);
0040 
0041     PlasmaWindowManagementInterface::ShowingDesktopState state = PlasmaWindowManagementInterface::ShowingDesktopState::Disabled;
0042     QList<PlasmaWindowInterface *> windows;
0043     QPointer<PlasmaVirtualDesktopManagementInterface> plasmaVirtualDesktopManagementInterface = nullptr;
0044     quint32 windowIdCounter = 0;
0045     QList<quint32> stackingOrder;
0046     QList<QString> stackingOrderUuids;
0047     PlasmaWindowManagementInterface *q;
0048 
0049 protected:
0050     void org_kde_plasma_window_management_bind_resource(Resource *resource) override;
0051     void org_kde_plasma_window_management_show_desktop(Resource *resource, uint32_t state) override;
0052     void org_kde_plasma_window_management_get_window(Resource *resource, uint32_t id, uint32_t internal_window_id) override;
0053     void org_kde_plasma_window_management_get_window_by_uuid(Resource *resource, uint32_t id, const QString &internal_window_uuid) override;
0054 };
0055 
0056 class PlasmaWindowInterfacePrivate : public QtWaylandServer::org_kde_plasma_window
0057 {
0058 public:
0059     PlasmaWindowInterfacePrivate(PlasmaWindowManagementInterface *wm, PlasmaWindowInterface *q);
0060     ~PlasmaWindowInterfacePrivate();
0061 
0062     class PlasmaWindowResource : public QtWaylandServer::org_kde_plasma_window::Resource
0063     {
0064     public:
0065         QtWaylandServer::org_kde_plasma_window_management::Resource *wmResource = nullptr;
0066     };
0067 
0068     void setTitle(const QString &title);
0069     void setAppId(const QString &appId);
0070     void setPid(quint32 pid);
0071     void setThemedIconName(const QString &iconName);
0072     void setIcon(const QIcon &icon);
0073     void unmap();
0074     void setState(org_kde_plasma_window_management_state flag, bool set);
0075     void setParentWindow(PlasmaWindowInterface *parent);
0076     void setGeometry(const QRect &geometry);
0077     void setApplicationMenuPaths(const QString &service, const QString &object);
0078     void setResourceName(const QString &resourceName);
0079     void sendInitialState(Resource *resource);
0080     wl_resource *resourceForParent(PlasmaWindowInterface *parent, Resource *child) const;
0081 
0082     quint32 windowId = 0;
0083     QHash<SurfaceInterface *, QRect> minimizedGeometries;
0084     PlasmaWindowManagementInterface *wm;
0085 
0086     bool unmapped = false;
0087     PlasmaWindowInterface *parentWindow = nullptr;
0088     QMetaObject::Connection parentWindowDestroyConnection;
0089     QStringList plasmaVirtualDesktops;
0090     QStringList plasmaActivities;
0091     QRect geometry;
0092     PlasmaWindowInterface *q;
0093     QString m_title;
0094     QString m_appId;
0095     quint32 m_pid = 0;
0096     QString m_themedIconName;
0097     QString m_appServiceName;
0098     QString m_appObjectPath;
0099     QIcon m_icon;
0100     quint32 m_state = 0;
0101     QString uuid;
0102     QString m_resourceName;
0103 
0104 protected:
0105     Resource *org_kde_plasma_window_allocate() override;
0106     void org_kde_plasma_window_set_state(Resource *resource, uint32_t flags, uint32_t state) override;
0107     void org_kde_plasma_window_set_virtual_desktop(Resource *resource, uint32_t number) override;
0108     void org_kde_plasma_window_set_minimized_geometry(Resource *resource, wl_resource *panel, uint32_t x, uint32_t y, uint32_t width, uint32_t height) override;
0109     void org_kde_plasma_window_unset_minimized_geometry(Resource *resource, wl_resource *panel) override;
0110     void org_kde_plasma_window_close(Resource *resource) override;
0111     void org_kde_plasma_window_request_move(Resource *resource) override;
0112     void org_kde_plasma_window_request_resize(Resource *resource) override;
0113     void org_kde_plasma_window_destroy(Resource *resource) override;
0114     void org_kde_plasma_window_get_icon(Resource *resource, int32_t fd) override;
0115     void org_kde_plasma_window_request_enter_virtual_desktop(Resource *resource, const QString &id) override;
0116     void org_kde_plasma_window_request_enter_new_virtual_desktop(Resource *resource) override;
0117     void org_kde_plasma_window_request_leave_virtual_desktop(Resource *resource, const QString &id) override;
0118     void org_kde_plasma_window_request_enter_activity(Resource *resource, const QString &id) override;
0119     void org_kde_plasma_window_request_leave_activity(Resource *resource, const QString &id) override;
0120     void org_kde_plasma_window_send_to_output(Resource *resource, struct wl_resource *output) override;
0121 };
0122 
0123 PlasmaWindowManagementInterfacePrivate::PlasmaWindowManagementInterfacePrivate(PlasmaWindowManagementInterface *_q, Display *display)
0124     : QtWaylandServer::org_kde_plasma_window_management(*display, s_version)
0125     , q(_q)
0126 {
0127 }
0128 
0129 void PlasmaWindowManagementInterfacePrivate::sendShowingDesktopState()
0130 {
0131     const auto clientResources = resourceMap();
0132     for (auto resource : clientResources) {
0133         sendShowingDesktopState(resource->handle);
0134     }
0135 }
0136 
0137 void PlasmaWindowManagementInterfacePrivate::sendShowingDesktopState(wl_resource *r)
0138 {
0139     uint32_t s = 0;
0140     switch (state) {
0141     case PlasmaWindowManagementInterface::ShowingDesktopState::Enabled:
0142         s = QtWaylandServer::org_kde_plasma_window_management::show_desktop_enabled;
0143         break;
0144     case PlasmaWindowManagementInterface::ShowingDesktopState::Disabled:
0145         s = QtWaylandServer::org_kde_plasma_window_management::show_desktop_disabled;
0146         break;
0147     default:
0148         Q_UNREACHABLE();
0149         break;
0150     }
0151     send_show_desktop_changed(r, s);
0152 }
0153 
0154 void PlasmaWindowManagementInterfacePrivate::sendStackingOrderChanged()
0155 {
0156     const auto clientResources = resourceMap();
0157     for (auto resource : clientResources) {
0158         sendStackingOrderChanged(resource->handle);
0159     }
0160 }
0161 
0162 void PlasmaWindowManagementInterfacePrivate::sendStackingOrderChanged(wl_resource *r)
0163 {
0164     if (wl_resource_get_version(r) < ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STACKING_ORDER_CHANGED_SINCE_VERSION) {
0165         return;
0166     }
0167 
0168     send_stacking_order_changed(r, QByteArray::fromRawData(reinterpret_cast<const char *>(stackingOrder.constData()), sizeof(uint32_t) * stackingOrder.size()));
0169 }
0170 
0171 void PlasmaWindowManagementInterfacePrivate::sendStackingOrderUuidsChanged()
0172 {
0173     const auto clientResources = resourceMap();
0174     for (auto resource : clientResources) {
0175         sendStackingOrderUuidsChanged(resource->handle);
0176     }
0177 }
0178 
0179 void PlasmaWindowManagementInterfacePrivate::sendStackingOrderUuidsChanged(wl_resource *r)
0180 {
0181     if (wl_resource_get_version(r) < ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STACKING_ORDER_UUID_CHANGED_SINCE_VERSION) {
0182         return;
0183     }
0184 
0185     QString uuids;
0186     for (const auto &uuid : std::as_const(stackingOrderUuids)) {
0187         uuids += uuid;
0188         uuids += QLatin1Char(';');
0189     }
0190     // Remove the trailing ';', on the receiving side this is interpreted as an empty uuid.
0191     if (stackingOrderUuids.size() > 0) {
0192         uuids.remove(uuids.length() - 1, 1);
0193     }
0194     send_stacking_order_uuid_changed(r, uuids);
0195 }
0196 
0197 void PlasmaWindowManagementInterfacePrivate::org_kde_plasma_window_management_bind_resource(Resource *resource)
0198 {
0199     for (const auto window : std::as_const(windows)) {
0200         if (resource->version() >= ORG_KDE_PLASMA_WINDOW_MANAGEMENT_WINDOW_WITH_UUID_SINCE_VERSION) {
0201             send_window_with_uuid(resource->handle, window->d->windowId, window->d->uuid);
0202         } else {
0203             send_window(resource->handle, window->d->windowId);
0204         }
0205     }
0206     sendStackingOrderChanged(resource->handle);
0207     sendStackingOrderUuidsChanged(resource->handle);
0208 }
0209 
0210 void PlasmaWindowManagementInterfacePrivate::org_kde_plasma_window_management_show_desktop(Resource *resource, uint32_t state)
0211 {
0212     PlasmaWindowManagementInterface::ShowingDesktopState s = PlasmaWindowManagementInterface::ShowingDesktopState::Disabled;
0213     switch (state) {
0214     case ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_ENABLED:
0215         s = PlasmaWindowManagementInterface::ShowingDesktopState::Enabled;
0216         break;
0217     case ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_DISABLED:
0218     default:
0219         s = PlasmaWindowManagementInterface::ShowingDesktopState::Disabled;
0220         break;
0221     }
0222     Q_EMIT q->requestChangeShowingDesktop(s);
0223 }
0224 
0225 void PlasmaWindowManagementInterfacePrivate::org_kde_plasma_window_management_get_window(Resource *resource, uint32_t id, uint32_t internal_window_id)
0226 {
0227     for (const auto window : std::as_const(windows)) {
0228         if (window->d->windowId == internal_window_id) {
0229             auto windowResource = window->d->add(resource->client(), id, resource->version());
0230             static_cast<PlasmaWindowInterfacePrivate::PlasmaWindowResource *>(windowResource)->wmResource = resource;
0231             window->d->sendInitialState(windowResource);
0232         }
0233     }
0234     // create a temp window just for the resource, bind then immediately delete it, sending an unmap event
0235     PlasmaWindowInterface window(q, q);
0236     auto windowResource = window.d->add(resource->client(), id, resource->version());
0237     window.d->sendInitialState(windowResource);
0238 }
0239 
0240 void PlasmaWindowManagementInterfacePrivate::org_kde_plasma_window_management_get_window_by_uuid(Resource *resource,
0241                                                                                                  uint32_t id,
0242                                                                                                  const QString &internal_window_uuid)
0243 {
0244     auto it = std::find_if(windows.constBegin(), windows.constEnd(), [internal_window_uuid](PlasmaWindowInterface *window) {
0245         return window->d->uuid == internal_window_uuid;
0246     });
0247     if (it == windows.constEnd()) {
0248         qCWarning(KWIN_CORE) << "Could not find window with uuid" << internal_window_uuid;
0249         // create a temp window just for the resource, bind then immediately delete it, sending an unmap event
0250         PlasmaWindowInterface window(q, q);
0251         auto windowResource = window.d->add(resource->client(), id, resource->version());
0252         window.d->sendInitialState(windowResource);
0253         return;
0254     }
0255     auto windowResource = (*it)->d->add(resource->client(), id, resource->version());
0256     static_cast<PlasmaWindowInterfacePrivate::PlasmaWindowResource *>(windowResource)->wmResource = resource;
0257     (*it)->d->sendInitialState(windowResource);
0258 }
0259 
0260 PlasmaWindowManagementInterface::PlasmaWindowManagementInterface(Display *display, QObject *parent)
0261     : QObject(parent)
0262     , d(new PlasmaWindowManagementInterfacePrivate(this, display))
0263 {
0264 }
0265 
0266 PlasmaWindowManagementInterface::~PlasmaWindowManagementInterface() = default;
0267 
0268 void PlasmaWindowManagementInterface::setShowingDesktopState(PlasmaWindowManagementInterface::ShowingDesktopState state)
0269 {
0270     if (d->state == state) {
0271         return;
0272     }
0273     d->state = state;
0274     d->sendShowingDesktopState();
0275 }
0276 
0277 PlasmaWindowInterface *PlasmaWindowManagementInterface::createWindow(QObject *parent, const QUuid &uuid)
0278 {
0279     PlasmaWindowInterface *window = new PlasmaWindowInterface(this, parent);
0280 
0281     window->d->uuid = uuid.toString();
0282     window->d->windowId = ++d->windowIdCounter; // NOTE the window id is deprecated
0283 
0284     const auto clientResources = d->resourceMap();
0285     for (auto resource : clientResources) {
0286         if (resource->version() >= ORG_KDE_PLASMA_WINDOW_MANAGEMENT_WINDOW_WITH_UUID_SINCE_VERSION) {
0287             d->send_window_with_uuid(resource->handle, window->d->windowId, window->d->uuid);
0288         } else {
0289             d->send_window(resource->handle, window->d->windowId);
0290         }
0291     }
0292     d->windows << window;
0293     connect(window, &QObject::destroyed, this, [this, window] {
0294         d->windows.removeAll(window);
0295     });
0296     return window;
0297 }
0298 
0299 QList<PlasmaWindowInterface *> PlasmaWindowManagementInterface::windows() const
0300 {
0301     return d->windows;
0302 }
0303 
0304 void PlasmaWindowManagementInterface::setStackingOrder(const QList<quint32> &stackingOrder)
0305 {
0306     if (d->stackingOrder == stackingOrder) {
0307         return;
0308     }
0309     d->stackingOrder = stackingOrder;
0310     d->sendStackingOrderChanged();
0311 }
0312 
0313 void PlasmaWindowManagementInterface::setStackingOrderUuids(const QList<QString> &stackingOrderUuids)
0314 {
0315     if (d->stackingOrderUuids == stackingOrderUuids) {
0316         return;
0317     }
0318     d->stackingOrderUuids = stackingOrderUuids;
0319     d->sendStackingOrderUuidsChanged();
0320 }
0321 
0322 void PlasmaWindowManagementInterface::setPlasmaVirtualDesktopManagementInterface(PlasmaVirtualDesktopManagementInterface *manager)
0323 {
0324     if (d->plasmaVirtualDesktopManagementInterface == manager) {
0325         return;
0326     }
0327     d->plasmaVirtualDesktopManagementInterface = manager;
0328 }
0329 
0330 PlasmaVirtualDesktopManagementInterface *PlasmaWindowManagementInterface::plasmaVirtualDesktopManagementInterface() const
0331 {
0332     return d->plasmaVirtualDesktopManagementInterface;
0333 }
0334 
0335 //////PlasmaWindow
0336 PlasmaWindowInterfacePrivate::PlasmaWindowInterfacePrivate(PlasmaWindowManagementInterface *wm, PlasmaWindowInterface *q)
0337     : QtWaylandServer::org_kde_plasma_window()
0338     , wm(wm)
0339     , q(q)
0340 {
0341 }
0342 
0343 PlasmaWindowInterfacePrivate::~PlasmaWindowInterfacePrivate()
0344 {
0345     unmap();
0346 }
0347 
0348 QtWaylandServer::org_kde_plasma_window::Resource *PlasmaWindowInterfacePrivate::org_kde_plasma_window_allocate()
0349 {
0350     return new PlasmaWindowResource;
0351 }
0352 
0353 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_destroy(Resource *resource)
0354 {
0355     wl_resource_destroy(resource->handle);
0356 }
0357 
0358 void PlasmaWindowInterfacePrivate::sendInitialState(Resource *resource)
0359 {
0360     for (const auto &desk : std::as_const(plasmaVirtualDesktops)) {
0361         send_virtual_desktop_entered(resource->handle, desk);
0362     }
0363     for (const auto &activity : std::as_const(plasmaActivities)) {
0364         if (resource->version() >= ORG_KDE_PLASMA_WINDOW_ACTIVITY_ENTERED_SINCE_VERSION) {
0365             send_activity_entered(resource->handle, activity);
0366         }
0367     }
0368     if (!m_appId.isEmpty()) {
0369         send_app_id_changed(resource->handle, truncate(m_appId));
0370     }
0371     if (m_pid != 0) {
0372         send_pid_changed(resource->handle, m_pid);
0373     }
0374     if (!m_title.isEmpty()) {
0375         send_title_changed(resource->handle, truncate(m_title));
0376     }
0377     if (!m_appObjectPath.isEmpty() || !m_appServiceName.isEmpty()) {
0378         send_application_menu(resource->handle, m_appServiceName, m_appObjectPath);
0379     }
0380     send_state_changed(resource->handle, m_state);
0381     if (!m_themedIconName.isEmpty()) {
0382         send_themed_icon_name_changed(resource->handle, m_themedIconName);
0383     } else if (!m_icon.isNull()) {
0384         if (resource->version() >= ORG_KDE_PLASMA_WINDOW_ICON_CHANGED_SINCE_VERSION) {
0385             send_icon_changed(resource->handle);
0386         }
0387     }
0388 
0389     send_parent_window(resource->handle, resourceForParent(parentWindow, resource));
0390 
0391     if (geometry.isValid() && resource->version() >= ORG_KDE_PLASMA_WINDOW_GEOMETRY_SINCE_VERSION) {
0392         send_geometry(resource->handle, geometry.x(), geometry.y(), geometry.width(), geometry.height());
0393     }
0394 
0395     if (resource->version() >= ORG_KDE_PLASMA_WINDOW_INITIAL_STATE_SINCE_VERSION) {
0396         send_initial_state(resource->handle);
0397     }
0398     if (!m_resourceName.isEmpty()) {
0399         if (resource->version() >= ORG_KDE_PLASMA_WINDOW_RESOURCE_NAME_CHANGED_SINCE_VERSION) {
0400             send_resource_name_changed(resource->handle, m_resourceName);
0401         }
0402     }
0403 }
0404 
0405 void PlasmaWindowInterfacePrivate::setAppId(const QString &appId)
0406 {
0407     if (m_appId == appId) {
0408         return;
0409     }
0410 
0411     m_appId = appId;
0412     const auto clientResources = resourceMap();
0413 
0414     for (auto resource : clientResources) {
0415         send_app_id_changed(resource->handle, truncate(m_appId));
0416     }
0417 }
0418 
0419 void PlasmaWindowInterfacePrivate::setPid(quint32 pid)
0420 {
0421     if (m_pid == pid) {
0422         return;
0423     }
0424     m_pid = pid;
0425     const auto clientResources = resourceMap();
0426 
0427     for (auto resource : clientResources) {
0428         send_pid_changed(resource->handle, pid);
0429     }
0430 }
0431 
0432 void PlasmaWindowInterfacePrivate::setThemedIconName(const QString &iconName)
0433 {
0434     if (m_themedIconName == iconName) {
0435         return;
0436     }
0437     m_themedIconName = iconName;
0438     const auto clientResources = resourceMap();
0439 
0440     for (auto resource : clientResources) {
0441         send_themed_icon_name_changed(resource->handle, m_themedIconName);
0442     }
0443 }
0444 
0445 void PlasmaWindowInterfacePrivate::setIcon(const QIcon &icon)
0446 {
0447     m_icon = icon;
0448     setThemedIconName(m_icon.name());
0449 
0450     const auto clientResources = resourceMap();
0451     for (auto resource : clientResources) {
0452         if (resource->version() >= ORG_KDE_PLASMA_WINDOW_ICON_CHANGED_SINCE_VERSION) {
0453             send_icon_changed(resource->handle);
0454         }
0455     }
0456 }
0457 
0458 void PlasmaWindowInterfacePrivate::setResourceName(const QString &resourceName)
0459 {
0460     if (m_resourceName == resourceName) {
0461         return;
0462     }
0463     m_resourceName = resourceName;
0464 
0465     const auto clientResources = resourceMap();
0466     for (auto resource : clientResources) {
0467         if (resource->version() >= ORG_KDE_PLASMA_WINDOW_RESOURCE_NAME_CHANGED_SINCE_VERSION) {
0468             send_resource_name_changed(resource->handle, resourceName);
0469         }
0470     }
0471 }
0472 
0473 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_get_icon(Resource *resource, int32_t fd)
0474 {
0475     QThreadPool::globalInstance()->start([fd, icon = m_icon]() {
0476         QFile file;
0477         file.open(fd, QIODevice::WriteOnly, QFileDevice::AutoCloseHandle);
0478         QDataStream ds(&file);
0479         ds << icon;
0480         file.close();
0481     });
0482 }
0483 
0484 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_request_enter_virtual_desktop(Resource *resource, const QString &id)
0485 {
0486     Q_EMIT q->enterPlasmaVirtualDesktopRequested(id);
0487 }
0488 
0489 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_request_enter_new_virtual_desktop(Resource *resource)
0490 {
0491     Q_EMIT q->enterNewPlasmaVirtualDesktopRequested();
0492 }
0493 
0494 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_request_leave_virtual_desktop(Resource *resource, const QString &id)
0495 {
0496     Q_EMIT q->leavePlasmaVirtualDesktopRequested(id);
0497 }
0498 
0499 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_request_enter_activity(Resource *resource, const QString &id)
0500 {
0501     Q_EMIT q->enterPlasmaActivityRequested(id);
0502 }
0503 
0504 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_request_leave_activity(Resource *resource, const QString &id)
0505 {
0506     Q_EMIT q->leavePlasmaActivityRequested(id);
0507 }
0508 
0509 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_send_to_output(Resource *resource, struct wl_resource *output)
0510 {
0511     Q_EMIT q->sendToOutput(OutputInterface::get(output));
0512 }
0513 
0514 void PlasmaWindowInterfacePrivate::setTitle(const QString &title)
0515 {
0516     if (m_title == title) {
0517         return;
0518     }
0519     m_title = title;
0520     const auto clientResources = resourceMap();
0521 
0522     for (auto resource : clientResources) {
0523         send_title_changed(resource->handle, truncate(m_title));
0524     }
0525 }
0526 
0527 void PlasmaWindowInterfacePrivate::unmap()
0528 {
0529     if (unmapped) {
0530         return;
0531     }
0532     unmapped = true;
0533     const auto clientResources = resourceMap();
0534 
0535     for (auto resource : clientResources) {
0536         send_unmapped(resource->handle);
0537     }
0538 }
0539 
0540 void PlasmaWindowInterfacePrivate::setState(org_kde_plasma_window_management_state flag, bool set)
0541 {
0542     quint32 newState = m_state;
0543     if (set) {
0544         newState |= flag;
0545     } else {
0546         newState &= ~flag;
0547     }
0548     if (newState == m_state) {
0549         return;
0550     }
0551     m_state = newState;
0552     const auto clientResources = resourceMap();
0553 
0554     for (auto resource : clientResources) {
0555         send_state_changed(resource->handle, m_state);
0556     }
0557 }
0558 
0559 wl_resource *PlasmaWindowInterfacePrivate::resourceForParent(PlasmaWindowInterface *parent, Resource *child) const
0560 {
0561     if (!parent) {
0562         return nullptr;
0563     }
0564 
0565     const auto parentResource = parent->d->resourceMap();
0566 
0567     for (auto resource : parentResource) {
0568         if (static_cast<PlasmaWindowResource *>(child)->wmResource == static_cast<PlasmaWindowResource *>(resource)->wmResource) {
0569             return resource->handle;
0570         }
0571     }
0572     return nullptr;
0573 }
0574 
0575 void PlasmaWindowInterfacePrivate::setParentWindow(PlasmaWindowInterface *window)
0576 {
0577     if (parentWindow == window) {
0578         return;
0579     }
0580     QObject::disconnect(parentWindowDestroyConnection);
0581     parentWindowDestroyConnection = QMetaObject::Connection();
0582     parentWindow = window;
0583     if (parentWindow) {
0584         parentWindowDestroyConnection = QObject::connect(window, &QObject::destroyed, q, [this] {
0585             parentWindow = nullptr;
0586             parentWindowDestroyConnection = QMetaObject::Connection();
0587             const auto clientResources = resourceMap();
0588             for (auto resource : clientResources) {
0589                 send_parent_window(resource->handle, nullptr);
0590             }
0591         });
0592     }
0593     const auto clientResources = resourceMap();
0594     for (auto resource : clientResources) {
0595         send_parent_window(resource->handle, resourceForParent(window, resource));
0596     }
0597 }
0598 
0599 void PlasmaWindowInterfacePrivate::setGeometry(const QRect &geo)
0600 {
0601     if (geometry == geo) {
0602         return;
0603     }
0604     geometry = geo;
0605     if (!geometry.isValid()) {
0606         return;
0607     }
0608 
0609     const auto clientResources = resourceMap();
0610     for (auto resource : clientResources) {
0611         if (resource->version() < ORG_KDE_PLASMA_WINDOW_GEOMETRY_SINCE_VERSION) {
0612             continue;
0613         }
0614         send_geometry(resource->handle, geometry.x(), geometry.y(), geometry.width(), geometry.height());
0615     }
0616 }
0617 
0618 void PlasmaWindowInterfacePrivate::setApplicationMenuPaths(const QString &service, const QString &object)
0619 {
0620     if (m_appServiceName == service && m_appObjectPath == object) {
0621         return;
0622     }
0623     m_appServiceName = service;
0624     m_appObjectPath = object;
0625     const auto clientResources = resourceMap();
0626     for (auto resource : clientResources) {
0627         if (resource->version() < ORG_KDE_PLASMA_WINDOW_APPLICATION_MENU_SINCE_VERSION) {
0628             continue;
0629         }
0630         send_application_menu(resource->handle, service, object);
0631     }
0632 }
0633 
0634 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_close(Resource *resource)
0635 {
0636     Q_EMIT q->closeRequested();
0637 }
0638 
0639 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_request_move(Resource *resource)
0640 {
0641     Q_EMIT q->moveRequested();
0642 }
0643 
0644 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_request_resize(Resource *resource)
0645 {
0646     Q_EMIT q->resizeRequested();
0647 }
0648 
0649 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_set_virtual_desktop(Resource *resource, uint32_t number)
0650 {
0651     // This method is intentionally left blank.
0652 }
0653 
0654 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_set_state(Resource *resource, uint32_t flags, uint32_t state)
0655 {
0656     if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ACTIVE) {
0657         Q_EMIT q->activeRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ACTIVE);
0658     }
0659     if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED) {
0660         Q_EMIT q->minimizedRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED);
0661     }
0662     if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED) {
0663         Q_EMIT q->maximizedRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED);
0664     }
0665     if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN) {
0666         Q_EMIT q->fullscreenRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN);
0667     }
0668     if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE) {
0669         Q_EMIT q->keepAboveRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE);
0670     }
0671     if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW) {
0672         Q_EMIT q->keepBelowRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW);
0673     }
0674     if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_DEMANDS_ATTENTION) {
0675         Q_EMIT q->demandsAttentionRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_DEMANDS_ATTENTION);
0676     }
0677     if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_CLOSEABLE) {
0678         Q_EMIT q->closeableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_CLOSEABLE);
0679     }
0680     if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZABLE) {
0681         Q_EMIT q->minimizeableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZABLE);
0682     }
0683     if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZABLE) {
0684         Q_EMIT q->maximizeableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZABLE);
0685     }
0686     if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREENABLE) {
0687         Q_EMIT q->fullscreenableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREENABLE);
0688     }
0689     if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPTASKBAR) {
0690         Q_EMIT q->skipTaskbarRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPTASKBAR);
0691     }
0692     if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPSWITCHER) {
0693         Q_EMIT q->skipSwitcherRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPSWITCHER);
0694     }
0695     if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADEABLE) {
0696         Q_EMIT q->shadeableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADEABLE);
0697     }
0698     if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED) {
0699         Q_EMIT q->shadedRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED);
0700     }
0701     if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MOVABLE) {
0702         Q_EMIT q->movableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MOVABLE);
0703     }
0704     if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_RESIZABLE) {
0705         Q_EMIT q->resizableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_RESIZABLE);
0706     }
0707     if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_VIRTUAL_DESKTOP_CHANGEABLE) {
0708         Q_EMIT q->virtualDesktopChangeableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_VIRTUAL_DESKTOP_CHANGEABLE);
0709     }
0710 }
0711 
0712 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_set_minimized_geometry(Resource *resource,
0713                                                                                 wl_resource *panel,
0714                                                                                 uint32_t x,
0715                                                                                 uint32_t y,
0716                                                                                 uint32_t width,
0717                                                                                 uint32_t height)
0718 {
0719     SurfaceInterface *panelSurface = SurfaceInterface::get(panel);
0720 
0721     if (!panelSurface) {
0722         return;
0723     }
0724 
0725     if (minimizedGeometries.value(panelSurface) == QRect(x, y, width, height)) {
0726         return;
0727     }
0728 
0729     minimizedGeometries[panelSurface] = QRect(x, y, width, height);
0730     Q_EMIT q->minimizedGeometriesChanged();
0731     QObject::connect(panelSurface, &QObject::destroyed, q, [this, panelSurface]() {
0732         if (minimizedGeometries.remove(panelSurface)) {
0733             Q_EMIT q->minimizedGeometriesChanged();
0734         }
0735     });
0736 }
0737 
0738 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_unset_minimized_geometry(Resource *resource, wl_resource *panel)
0739 {
0740     SurfaceInterface *panelSurface = SurfaceInterface::get(panel);
0741 
0742     if (!panelSurface) {
0743         return;
0744     }
0745     if (!minimizedGeometries.contains(panelSurface)) {
0746         return;
0747     }
0748     minimizedGeometries.remove(panelSurface);
0749     Q_EMIT q->minimizedGeometriesChanged();
0750 }
0751 
0752 PlasmaWindowInterface::PlasmaWindowInterface(PlasmaWindowManagementInterface *wm, QObject *parent)
0753     : QObject(parent)
0754     , d(new PlasmaWindowInterfacePrivate(wm, this))
0755 {
0756 }
0757 
0758 PlasmaWindowInterface::~PlasmaWindowInterface() = default;
0759 
0760 void PlasmaWindowInterface::setAppId(const QString &appId)
0761 {
0762     d->setAppId(appId);
0763 }
0764 
0765 void PlasmaWindowInterface::setPid(quint32 pid)
0766 {
0767     d->setPid(pid);
0768 }
0769 
0770 void PlasmaWindowInterface::setTitle(const QString &title)
0771 {
0772     d->setTitle(title);
0773 }
0774 
0775 void PlasmaWindowInterface::unmap()
0776 {
0777     d->unmap();
0778 }
0779 
0780 QHash<SurfaceInterface *, QRect> PlasmaWindowInterface::minimizedGeometries() const
0781 {
0782     return d->minimizedGeometries;
0783 }
0784 
0785 void PlasmaWindowInterface::setActive(bool set)
0786 {
0787     d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ACTIVE, set);
0788 }
0789 
0790 void PlasmaWindowInterface::setFullscreen(bool set)
0791 {
0792     d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN, set);
0793 }
0794 
0795 void PlasmaWindowInterface::setKeepAbove(bool set)
0796 {
0797     d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE, set);
0798 }
0799 
0800 void PlasmaWindowInterface::setKeepBelow(bool set)
0801 {
0802     d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW, set);
0803 }
0804 
0805 void PlasmaWindowInterface::setMaximized(bool set)
0806 {
0807     d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED, set);
0808 }
0809 
0810 void PlasmaWindowInterface::setMinimized(bool set)
0811 {
0812     d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED, set);
0813 }
0814 
0815 void PlasmaWindowInterface::setOnAllDesktops(bool set)
0816 {
0817     // the deprecated vd management
0818     d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ON_ALL_DESKTOPS, set);
0819 
0820     if (!d->wm->plasmaVirtualDesktopManagementInterface()) {
0821         return;
0822     }
0823     const auto clientResources = d->resourceMap();
0824     // the current vd management
0825     if (set) {
0826         if (d->plasmaVirtualDesktops.isEmpty()) {
0827             return;
0828         }
0829         // leaving everything means on all desktops
0830         for (auto desk : plasmaVirtualDesktops()) {
0831             for (auto resource : clientResources) {
0832                 d->send_virtual_desktop_left(resource->handle, desk);
0833             }
0834         }
0835         d->plasmaVirtualDesktops.clear();
0836     } else {
0837         if (!d->plasmaVirtualDesktops.isEmpty()) {
0838             return;
0839         }
0840         // enters the desktops which are active (usually only one  but not a given)
0841         const auto desktops = d->wm->plasmaVirtualDesktopManagementInterface()->desktops();
0842         for (const auto desktop : desktops) {
0843             if (desktop->isActive() && !d->plasmaVirtualDesktops.contains(desktop->id())) {
0844                 d->plasmaVirtualDesktops << desktop->id();
0845                 for (auto resource : clientResources) {
0846                     d->send_virtual_desktop_entered(resource->handle, desktop->id());
0847                 }
0848             }
0849         }
0850     }
0851 }
0852 
0853 void PlasmaWindowInterface::setDemandsAttention(bool set)
0854 {
0855     d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_DEMANDS_ATTENTION, set);
0856 }
0857 
0858 void PlasmaWindowInterface::setCloseable(bool set)
0859 {
0860     d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_CLOSEABLE, set);
0861 }
0862 
0863 void PlasmaWindowInterface::setFullscreenable(bool set)
0864 {
0865     d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREENABLE, set);
0866 }
0867 
0868 void PlasmaWindowInterface::setMaximizeable(bool set)
0869 {
0870     d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZABLE, set);
0871 }
0872 
0873 void PlasmaWindowInterface::setMinimizeable(bool set)
0874 {
0875     d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZABLE, set);
0876 }
0877 
0878 void PlasmaWindowInterface::setSkipTaskbar(bool set)
0879 {
0880     d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPTASKBAR, set);
0881 }
0882 
0883 void PlasmaWindowInterface::setSkipSwitcher(bool skip)
0884 {
0885     d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPSWITCHER, skip);
0886 }
0887 
0888 void PlasmaWindowInterface::setIcon(const QIcon &icon)
0889 {
0890     d->setIcon(icon);
0891 }
0892 
0893 void PlasmaWindowInterface::setResourceName(const QString &resourceName)
0894 {
0895     d->setResourceName(resourceName);
0896 }
0897 
0898 void PlasmaWindowInterface::addPlasmaVirtualDesktop(const QString &id)
0899 {
0900     // don't add a desktop we're not sure it exists
0901     if (!d->wm->plasmaVirtualDesktopManagementInterface() || d->plasmaVirtualDesktops.contains(id)) {
0902         return;
0903     }
0904 
0905     PlasmaVirtualDesktopInterface *desktop = d->wm->plasmaVirtualDesktopManagementInterface()->desktop(id);
0906 
0907     if (!desktop) {
0908         return;
0909     }
0910 
0911     d->plasmaVirtualDesktops << id;
0912 
0913     // if the desktop dies, remove it from or list
0914     connect(desktop, &QObject::destroyed, this, [this, id]() {
0915         removePlasmaVirtualDesktop(id);
0916     });
0917 
0918     const auto clientResources = d->resourceMap();
0919     for (auto resource : clientResources) {
0920         d->send_virtual_desktop_entered(resource->handle, id);
0921     }
0922 }
0923 
0924 void PlasmaWindowInterface::removePlasmaVirtualDesktop(const QString &id)
0925 {
0926     if (!d->plasmaVirtualDesktops.contains(id)) {
0927         return;
0928     }
0929 
0930     d->plasmaVirtualDesktops.removeAll(id);
0931     const auto clientResources = d->resourceMap();
0932     for (auto resource : clientResources) {
0933         d->send_virtual_desktop_left(resource->handle, id);
0934     }
0935 
0936     // we went on all desktops
0937     if (d->plasmaVirtualDesktops.isEmpty()) {
0938         setOnAllDesktops(true);
0939     }
0940 }
0941 
0942 QStringList PlasmaWindowInterface::plasmaVirtualDesktops() const
0943 {
0944     return d->plasmaVirtualDesktops;
0945 }
0946 
0947 void PlasmaWindowInterface::addPlasmaActivity(const QString &id)
0948 {
0949     if (d->plasmaActivities.contains(id)) {
0950         return;
0951     }
0952 
0953     d->plasmaActivities << id;
0954 
0955     const auto clientResources = d->resourceMap();
0956     for (auto resource : clientResources) {
0957         if (resource->version() >= ORG_KDE_PLASMA_WINDOW_ACTIVITY_ENTERED_SINCE_VERSION) {
0958             d->send_activity_entered(resource->handle, id);
0959         }
0960     }
0961 }
0962 
0963 void PlasmaWindowInterface::removePlasmaActivity(const QString &id)
0964 {
0965     if (!d->plasmaActivities.removeOne(id)) {
0966         return;
0967     }
0968 
0969     const auto clientResources = d->resourceMap();
0970     for (auto resource : clientResources) {
0971         if (resource->version() >= ORG_KDE_PLASMA_WINDOW_ACTIVITY_LEFT_SINCE_VERSION) {
0972             d->send_activity_left(resource->handle, id);
0973         }
0974     }
0975 }
0976 
0977 QStringList PlasmaWindowInterface::plasmaActivities() const
0978 {
0979     return d->plasmaActivities;
0980 }
0981 
0982 void PlasmaWindowInterface::setShadeable(bool set)
0983 {
0984     d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADEABLE, set);
0985 }
0986 
0987 void PlasmaWindowInterface::setShaded(bool set)
0988 {
0989     d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED, set);
0990 }
0991 
0992 void PlasmaWindowInterface::setMovable(bool set)
0993 {
0994     d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MOVABLE, set);
0995 }
0996 
0997 void PlasmaWindowInterface::setResizable(bool set)
0998 {
0999     d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_RESIZABLE, set);
1000 }
1001 
1002 void PlasmaWindowInterface::setVirtualDesktopChangeable(bool set)
1003 {
1004     d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_VIRTUAL_DESKTOP_CHANGEABLE, set);
1005 }
1006 
1007 void PlasmaWindowInterface::setParentWindow(PlasmaWindowInterface *parentWindow)
1008 {
1009     d->setParentWindow(parentWindow);
1010 }
1011 
1012 void PlasmaWindowInterface::setGeometry(const QRect &geometry)
1013 {
1014     d->setGeometry(geometry);
1015 }
1016 
1017 void PlasmaWindowInterface::setApplicationMenuPaths(const QString &serviceName, const QString &objectPath)
1018 {
1019     d->setApplicationMenuPaths(serviceName, objectPath);
1020 }
1021 
1022 quint32 PlasmaWindowInterface::internalId() const
1023 {
1024     return d->windowId;
1025 }
1026 
1027 QString PlasmaWindowInterface::uuid() const
1028 {
1029     return d->uuid;
1030 }
1031 
1032 class PlasmaWindowActivationFeedbackInterfacePrivate : public QtWaylandServer::org_kde_plasma_activation_feedback
1033 {
1034 public:
1035     explicit PlasmaWindowActivationFeedbackInterfacePrivate(Display *display);
1036 
1037 protected:
1038     void org_kde_plasma_activation_feedback_destroy(Resource *resource) override;
1039 };
1040 
1041 class PlasmaWindowActivationInterfacePrivate : public QtWaylandServer::org_kde_plasma_activation
1042 {
1043 public:
1044     explicit PlasmaWindowActivationInterfacePrivate(PlasmaWindowActivationInterface *q)
1045         : QtWaylandServer::org_kde_plasma_activation()
1046         , q(q)
1047     {
1048     }
1049 
1050     PlasmaWindowActivationInterface *const q;
1051 };
1052 
1053 PlasmaWindowActivationFeedbackInterfacePrivate::PlasmaWindowActivationFeedbackInterfacePrivate(Display *display)
1054     : QtWaylandServer::org_kde_plasma_activation_feedback(*display, s_activationVersion)
1055 {
1056 }
1057 
1058 void PlasmaWindowActivationFeedbackInterfacePrivate::org_kde_plasma_activation_feedback_destroy(Resource *resource)
1059 {
1060     wl_resource_destroy(resource->handle);
1061 }
1062 
1063 PlasmaWindowActivationFeedbackInterface::PlasmaWindowActivationFeedbackInterface(Display *display, QObject *parent)
1064     : QObject(parent)
1065     , d(new PlasmaWindowActivationFeedbackInterfacePrivate(display))
1066 {
1067 }
1068 
1069 PlasmaWindowActivationFeedbackInterface::~PlasmaWindowActivationFeedbackInterface()
1070 {
1071 }
1072 
1073 std::unique_ptr<PlasmaWindowActivationInterface> PlasmaWindowActivationFeedbackInterface::createActivation(const QString &appid)
1074 {
1075     std::unique_ptr<PlasmaWindowActivationInterface> activation(new PlasmaWindowActivationInterface());
1076     const auto resources = d->resourceMap();
1077     for (auto resource : resources) {
1078         auto activationResource = activation->d->add(resource->client(), resource->version());
1079         d->send_activation(resource->handle, activationResource->handle);
1080     }
1081     activation->sendAppId(appid);
1082     return activation;
1083 }
1084 
1085 PlasmaWindowActivationInterface::PlasmaWindowActivationInterface()
1086     : d(new PlasmaWindowActivationInterfacePrivate(this))
1087 {
1088 }
1089 
1090 PlasmaWindowActivationInterface::~PlasmaWindowActivationInterface()
1091 {
1092     const auto clientResources = d->resourceMap();
1093     for (auto resource : clientResources) {
1094         d->send_finished(resource->handle);
1095     }
1096 }
1097 
1098 void PlasmaWindowActivationInterface::sendAppId(const QString &appid)
1099 {
1100     const auto clientResources = d->resourceMap();
1101     for (auto resource : clientResources) {
1102         d->send_app_id(resource->handle, appid);
1103     }
1104 }
1105 
1106 }
1107 
1108 #include "moc_plasmawindowmanagement.cpp"