File indexing completed on 2024-12-22 05:09:21

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 "event_queue.h"
0008 #include "output.h"
0009 #include "plasmavirtualdesktop.h"
0010 #include "plasmawindowmodel.h"
0011 #include "surface.h"
0012 #include "wayland_pointer_p.h"
0013 // Wayland
0014 #include <wayland-plasma-window-management-client-protocol.h>
0015 
0016 #include <QFutureWatcher>
0017 #include <QTimer>
0018 #include <QtConcurrentRun>
0019 #include <qplatformdefs.h>
0020 
0021 #include <cerrno>
0022 
0023 namespace KWayland
0024 {
0025 namespace Client
0026 {
0027 class Q_DECL_HIDDEN PlasmaWindowManagement::Private
0028 {
0029 public:
0030     Private(PlasmaWindowManagement *q);
0031     WaylandPointer<org_kde_plasma_window_management, org_kde_plasma_window_management_destroy> wm;
0032     EventQueue *queue = nullptr;
0033     bool showingDesktop = false;
0034     QList<PlasmaWindow *> windows;
0035     PlasmaWindow *activeWindow = nullptr;
0036     QList<quint32> stackingOrder;
0037     QList<QByteArray> stackingOrderUuids;
0038 
0039     void setup(org_kde_plasma_window_management *wm);
0040 
0041 private:
0042     static void showDesktopCallback(void *data, org_kde_plasma_window_management *org_kde_plasma_window_management, uint32_t state);
0043     static void windowCallback(void *data, org_kde_plasma_window_management *org_kde_plasma_window_management, uint32_t id);
0044     static void windowWithUuidCallback(void *data, org_kde_plasma_window_management *org_kde_plasma_window_management, uint32_t id, const char *uuid);
0045     static void stackingOrderCallback(void *data, org_kde_plasma_window_management *org_kde_plasma_window_management, wl_array *ids);
0046     static void stackingOrderUuidsCallback(void *data, org_kde_plasma_window_management *org_kde_plasma_window_management, const char *uuids);
0047     void setShowDesktop(bool set);
0048     void windowCreated(org_kde_plasma_window *id, quint32 internalId, const char *uuid);
0049     void setStackingOrder(const QList<quint32> &ids);
0050     void setStackingOrder(const QList<QByteArray> &uuids);
0051 
0052     static struct org_kde_plasma_window_management_listener s_listener;
0053     PlasmaWindowManagement *q;
0054 };
0055 
0056 class Q_DECL_HIDDEN PlasmaWindow::Private
0057 {
0058 public:
0059     Private(org_kde_plasma_window *window, quint32 internalId, const char *uuid, PlasmaWindow *q);
0060     WaylandPointer<org_kde_plasma_window, org_kde_plasma_window_destroy> window;
0061     quint32 internalId; ///< @deprecated
0062     QByteArray uuid;
0063     QString title;
0064     QString appId;
0065     quint32 desktop = 0;
0066     bool active = false;
0067     bool minimized = false;
0068     bool maximized = false;
0069     bool fullscreen = false;
0070     bool keepAbove = false;
0071     bool keepBelow = false;
0072     bool onAllDesktops = false;
0073     bool demandsAttention = false;
0074     bool closeable = false;
0075     bool minimizeable = false;
0076     bool maximizeable = false;
0077     bool fullscreenable = false;
0078     bool skipTaskbar = false;
0079     bool skipSwitcher = false;
0080     bool shadeable = false;
0081     bool shaded = false;
0082     bool movable = false;
0083     bool resizable = false;
0084     bool virtualDesktopChangeable = false;
0085     QIcon icon;
0086     PlasmaWindowManagement *wm = nullptr;
0087     bool unmapped = false;
0088     QPointer<PlasmaWindow> parentWindow;
0089     QMetaObject::Connection parentWindowUnmappedConnection;
0090     QStringList plasmaVirtualDesktops;
0091     QStringList plasmaActivities;
0092     QRect geometry;
0093     quint32 pid = 0;
0094     QString resourceName;
0095     QString applicationMenuServiceName;
0096     QString applicationMenuObjectPath;
0097 
0098 private:
0099     static void titleChangedCallback(void *data, org_kde_plasma_window *window, const char *title);
0100     static void appIdChangedCallback(void *data, org_kde_plasma_window *window, const char *app_id);
0101     static void pidChangedCallback(void *data, org_kde_plasma_window *window, uint32_t pid);
0102     static void resourceNameChangedCallback(void *data, org_kde_plasma_window *window, const char *resourceName);
0103     static void stateChangedCallback(void *data, org_kde_plasma_window *window, uint32_t state);
0104     static void virtualDesktopChangedCallback(void *data, org_kde_plasma_window *window, int32_t number);
0105     static void themedIconNameChangedCallback(void *data, org_kde_plasma_window *window, const char *name);
0106     static void unmappedCallback(void *data, org_kde_plasma_window *window);
0107     static void initialStateCallback(void *data, org_kde_plasma_window *window);
0108     static void parentWindowCallback(void *data, org_kde_plasma_window *window, org_kde_plasma_window *parent);
0109     static void windowGeometryCallback(void *data, org_kde_plasma_window *window, int32_t x, int32_t y, uint32_t width, uint32_t height);
0110     static void iconChangedCallback(void *data, org_kde_plasma_window *org_kde_plasma_window);
0111     static void virtualDesktopEnteredCallback(void *data, org_kde_plasma_window *org_kde_plasma_window, const char *id);
0112     static void virtualDesktopLeftCallback(void *data, org_kde_plasma_window *org_kde_plasma_window, const char *id);
0113     static void appmenuChangedCallback(void *data, org_kde_plasma_window *org_kde_plasma_window, const char *service_name, const char *object_path);
0114     static void activityEnteredCallback(void *data, org_kde_plasma_window *org_kde_plasma_window, const char *id);
0115     static void activityLeftCallback(void *data, org_kde_plasma_window *org_kde_plasma_window, const char *id);
0116     void setActive(bool set);
0117     void setMinimized(bool set);
0118     void setMaximized(bool set);
0119     void setFullscreen(bool set);
0120     void setKeepAbove(bool set);
0121     void setKeepBelow(bool set);
0122     void setOnAllDesktops(bool set);
0123     void setDemandsAttention(bool set);
0124     void setCloseable(bool set);
0125     void setMinimizeable(bool set);
0126     void setMaximizeable(bool set);
0127     void setFullscreenable(bool set);
0128     void setSkipTaskbar(bool skip);
0129     void setSkipSwitcher(bool skip);
0130     void setShadeable(bool set);
0131     void setShaded(bool set);
0132     void setMovable(bool set);
0133     void setResizable(bool set);
0134     void setVirtualDesktopChangeable(bool set);
0135     void setParentWindow(PlasmaWindow *parentWindow);
0136     void setPid(const quint32 pid);
0137 
0138     static Private *cast(void *data)
0139     {
0140         return reinterpret_cast<Private *>(data);
0141     }
0142 
0143     PlasmaWindow *q;
0144 
0145     static struct org_kde_plasma_window_listener s_listener;
0146 };
0147 
0148 PlasmaWindowManagement::Private::Private(PlasmaWindowManagement *q)
0149     : q(q)
0150 {
0151 }
0152 
0153 org_kde_plasma_window_management_listener PlasmaWindowManagement::Private::s_listener = {
0154     showDesktopCallback,
0155     windowCallback,
0156     stackingOrderCallback,
0157     stackingOrderUuidsCallback,
0158     windowWithUuidCallback,
0159 };
0160 
0161 void PlasmaWindowManagement::Private::setup(org_kde_plasma_window_management *windowManagement)
0162 {
0163     Q_ASSERT(!wm);
0164     Q_ASSERT(windowManagement);
0165     wm.setup(windowManagement);
0166     org_kde_plasma_window_management_add_listener(windowManagement, &s_listener, this);
0167 }
0168 
0169 void PlasmaWindowManagement::Private::showDesktopCallback(void *data, org_kde_plasma_window_management *org_kde_plasma_window_management, uint32_t state)
0170 {
0171     auto wm = reinterpret_cast<PlasmaWindowManagement::Private *>(data);
0172     Q_ASSERT(wm->wm == org_kde_plasma_window_management);
0173     switch (state) {
0174     case ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_ENABLED:
0175         wm->setShowDesktop(true);
0176         break;
0177     case ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_DISABLED:
0178         wm->setShowDesktop(false);
0179         break;
0180     default:
0181         Q_UNREACHABLE();
0182         break;
0183     }
0184 }
0185 
0186 void PlasmaWindowManagement::Private::setShowDesktop(bool set)
0187 {
0188     if (showingDesktop == set) {
0189         return;
0190     }
0191     showingDesktop = set;
0192     Q_EMIT q->showingDesktopChanged(showingDesktop);
0193 }
0194 
0195 void PlasmaWindowManagement::Private::windowCallback(void *data, org_kde_plasma_window_management *interface, uint32_t id)
0196 {
0197     auto wm = reinterpret_cast<PlasmaWindowManagement::Private *>(data);
0198     Q_ASSERT(wm->wm == interface);
0199     QTimer *timer = new QTimer();
0200     timer->setSingleShot(true);
0201     timer->setInterval(0);
0202     QObject::connect(
0203         timer,
0204         &QTimer::timeout,
0205         wm->q,
0206         [timer, wm, id] {
0207             wm->windowCreated(org_kde_plasma_window_management_get_window(wm->wm, id), id, "unavailable");
0208             timer->deleteLater();
0209         },
0210         Qt::QueuedConnection);
0211     timer->start();
0212 }
0213 
0214 void PlasmaWindowManagement::Private::windowWithUuidCallback(void *data, org_kde_plasma_window_management *interface, uint32_t id, const char *_uuid)
0215 {
0216     QByteArray uuid(_uuid);
0217     auto wm = reinterpret_cast<PlasmaWindowManagement::Private *>(data);
0218     Q_ASSERT(wm->wm == interface);
0219     QTimer *timer = new QTimer();
0220     timer->setSingleShot(true);
0221     timer->setInterval(0);
0222     QObject::connect(
0223         timer,
0224         &QTimer::timeout,
0225         wm->q,
0226         [timer, wm, id, uuid] {
0227             wm->windowCreated(org_kde_plasma_window_management_get_window_by_uuid(wm->wm, uuid), id, uuid);
0228             timer->deleteLater();
0229         },
0230         Qt::QueuedConnection);
0231     timer->start();
0232 }
0233 
0234 void PlasmaWindowManagement::Private::windowCreated(org_kde_plasma_window *id, quint32 internalId, const char *uuid)
0235 {
0236     if (queue) {
0237         queue->addProxy(id);
0238     }
0239     PlasmaWindow *window = new PlasmaWindow(q, id, internalId, uuid);
0240     window->d->wm = q;
0241     windows << window;
0242 
0243     const auto windowRemoved = [this, window] {
0244         windows.removeAll(window);
0245         if (activeWindow == window) {
0246             activeWindow = nullptr;
0247             Q_EMIT q->activeWindowChanged();
0248         }
0249     };
0250 
0251     QObject::connect(window, &QObject::destroyed, q, windowRemoved);
0252     // unmapped is emitted earlier than QObject::destroyed. We want to update windows earlier to ensure other slot will see the up to date value of
0253     // PlasmaWindowManagement::windows().
0254     QObject::connect(window, &PlasmaWindow::unmapped, q, windowRemoved);
0255     QObject::connect(window, &PlasmaWindow::activeChanged, q, [this, window] {
0256         if (window->d->unmapped) {
0257             return;
0258         }
0259         if (window->isActive()) {
0260             if (activeWindow == window) {
0261                 return;
0262             }
0263             activeWindow = window;
0264             Q_EMIT q->activeWindowChanged();
0265         } else {
0266             if (activeWindow == window) {
0267                 activeWindow = nullptr;
0268                 Q_EMIT q->activeWindowChanged();
0269             }
0270         }
0271     });
0272 }
0273 
0274 void PlasmaWindowManagement::Private::stackingOrderCallback(void *data, org_kde_plasma_window_management *interface, wl_array *ids)
0275 {
0276     // This is no-op since setStackingOrder(const QList<quint32> &ids) is deprecated since 5.73,
0277     // but we can't remove this method because it's needed in
0278     // PlasmaWindowManagement::Private::s_listener struct
0279 }
0280 
0281 void PlasmaWindowManagement::Private::stackingOrderUuidsCallback(void *data, org_kde_plasma_window_management *interface, const char *uuids)
0282 {
0283     auto wm = reinterpret_cast<PlasmaWindowManagement::Private *>(data);
0284     Q_ASSERT(wm->wm == interface);
0285     wm->setStackingOrder(QByteArray(uuids).split(';').toVector());
0286 }
0287 
0288 void PlasmaWindowManagement::Private::setStackingOrder(const QList<QByteArray> &uuids)
0289 {
0290     if (stackingOrderUuids == uuids) {
0291         return;
0292     }
0293     stackingOrderUuids = uuids;
0294     Q_EMIT q->stackingOrderUuidsChanged();
0295 }
0296 
0297 PlasmaWindowManagement::PlasmaWindowManagement(QObject *parent)
0298     : QObject(parent)
0299     , d(new Private(this))
0300 {
0301 }
0302 
0303 PlasmaWindowManagement::~PlasmaWindowManagement()
0304 {
0305     release();
0306 }
0307 
0308 void PlasmaWindowManagement::destroy()
0309 {
0310     if (!d->wm) {
0311         return;
0312     }
0313     Q_EMIT interfaceAboutToBeDestroyed();
0314     d->wm.destroy();
0315 }
0316 
0317 void PlasmaWindowManagement::release()
0318 {
0319     if (!d->wm) {
0320         return;
0321     }
0322     Q_EMIT interfaceAboutToBeReleased();
0323     d->wm.release();
0324 }
0325 
0326 void PlasmaWindowManagement::setup(org_kde_plasma_window_management *wm)
0327 {
0328     d->setup(wm);
0329 }
0330 
0331 void PlasmaWindowManagement::setEventQueue(EventQueue *queue)
0332 {
0333     d->queue = queue;
0334 }
0335 
0336 EventQueue *PlasmaWindowManagement::eventQueue()
0337 {
0338     return d->queue;
0339 }
0340 
0341 bool PlasmaWindowManagement::isValid() const
0342 {
0343     return d->wm.isValid();
0344 }
0345 
0346 PlasmaWindowManagement::operator org_kde_plasma_window_management *()
0347 {
0348     return d->wm;
0349 }
0350 
0351 PlasmaWindowManagement::operator org_kde_plasma_window_management *() const
0352 {
0353     return d->wm;
0354 }
0355 
0356 void PlasmaWindowManagement::hideDesktop()
0357 {
0358     setShowingDesktop(false);
0359 }
0360 
0361 void PlasmaWindowManagement::showDesktop()
0362 {
0363     setShowingDesktop(true);
0364 }
0365 
0366 void PlasmaWindowManagement::setShowingDesktop(bool show)
0367 {
0368     org_kde_plasma_window_management_show_desktop(d->wm,
0369                                                   show ? ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_ENABLED
0370                                                        : ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_DISABLED);
0371 }
0372 
0373 bool PlasmaWindowManagement::isShowingDesktop() const
0374 {
0375     return d->showingDesktop;
0376 }
0377 
0378 QList<PlasmaWindow *> PlasmaWindowManagement::windows() const
0379 {
0380     return d->windows;
0381 }
0382 
0383 PlasmaWindow *PlasmaWindowManagement::activeWindow() const
0384 {
0385     return d->activeWindow;
0386 }
0387 
0388 PlasmaWindowModel *PlasmaWindowManagement::createWindowModel()
0389 {
0390     return new PlasmaWindowModel(this);
0391 }
0392 
0393 QList<QByteArray> PlasmaWindowManagement::stackingOrderUuids() const
0394 {
0395     return d->stackingOrderUuids;
0396 }
0397 
0398 org_kde_plasma_window_listener PlasmaWindow::Private::s_listener = {
0399     titleChangedCallback,
0400     appIdChangedCallback,
0401     stateChangedCallback,
0402     virtualDesktopChangedCallback,
0403     themedIconNameChangedCallback,
0404     unmappedCallback,
0405     initialStateCallback,
0406     parentWindowCallback,
0407     windowGeometryCallback,
0408     iconChangedCallback,
0409     pidChangedCallback,
0410     virtualDesktopEnteredCallback,
0411     virtualDesktopLeftCallback,
0412     appmenuChangedCallback,
0413     activityEnteredCallback,
0414     activityLeftCallback,
0415     resourceNameChangedCallback,
0416 };
0417 
0418 void PlasmaWindow::Private::appmenuChangedCallback(void *data, org_kde_plasma_window *window, const char *service_name, const char *object_path)
0419 {
0420     Q_UNUSED(window)
0421 
0422     Private *p = cast(data);
0423 
0424     p->applicationMenuServiceName = QString::fromUtf8(service_name);
0425     p->applicationMenuObjectPath = QString::fromUtf8(object_path);
0426 
0427     Q_EMIT p->q->applicationMenuChanged();
0428 }
0429 
0430 void PlasmaWindow::Private::parentWindowCallback(void *data, org_kde_plasma_window *window, org_kde_plasma_window *parent)
0431 {
0432     Q_UNUSED(window)
0433     Private *p = cast(data);
0434     const auto windows = p->wm->windows();
0435     auto it = std::find_if(windows.constBegin(), windows.constEnd(), [parent](const PlasmaWindow *w) {
0436         return *w == parent;
0437     });
0438     p->setParentWindow(it != windows.constEnd() ? *it : nullptr);
0439 }
0440 
0441 void PlasmaWindow::Private::windowGeometryCallback(void *data, org_kde_plasma_window *window, int32_t x, int32_t y, uint32_t width, uint32_t height)
0442 {
0443     Q_UNUSED(window)
0444     Private *p = cast(data);
0445     QRect geo(x, y, width, height);
0446     if (geo == p->geometry) {
0447         return;
0448     }
0449     p->geometry = geo;
0450     Q_EMIT p->q->geometryChanged();
0451 }
0452 
0453 void PlasmaWindow::Private::setParentWindow(PlasmaWindow *parent)
0454 {
0455     const auto old = parentWindow;
0456     QObject::disconnect(parentWindowUnmappedConnection);
0457     if (parent && !parent->d->unmapped) {
0458         parentWindow = QPointer<PlasmaWindow>(parent);
0459         parentWindowUnmappedConnection = QObject::connect(parent, &PlasmaWindow::unmapped, q, [this] {
0460             setParentWindow(nullptr);
0461         });
0462     } else {
0463         parentWindow = QPointer<PlasmaWindow>();
0464         parentWindowUnmappedConnection = QMetaObject::Connection();
0465     }
0466     if (parentWindow.data() != old.data()) {
0467         Q_EMIT q->parentWindowChanged();
0468     }
0469 }
0470 
0471 void PlasmaWindow::Private::initialStateCallback(void *data, org_kde_plasma_window *window)
0472 {
0473     Q_UNUSED(window)
0474     Private *p = cast(data);
0475     if (!p->unmapped) {
0476         Q_EMIT p->wm->windowCreated(p->q);
0477     }
0478 }
0479 
0480 void PlasmaWindow::Private::titleChangedCallback(void *data, org_kde_plasma_window *window, const char *title)
0481 {
0482     Q_UNUSED(window)
0483     Private *p = cast(data);
0484     const QString t = QString::fromUtf8(title);
0485     if (p->title == t) {
0486         return;
0487     }
0488     p->title = t;
0489     Q_EMIT p->q->titleChanged();
0490 }
0491 
0492 void PlasmaWindow::Private::appIdChangedCallback(void *data, org_kde_plasma_window *window, const char *appId)
0493 {
0494     Q_UNUSED(window)
0495     Private *p = cast(data);
0496     const QString s = QString::fromUtf8(appId);
0497     if (s == p->appId) {
0498         return;
0499     }
0500     p->appId = s;
0501     Q_EMIT p->q->appIdChanged();
0502 }
0503 
0504 void PlasmaWindow::Private::pidChangedCallback(void *data, org_kde_plasma_window *window, uint32_t pid)
0505 {
0506     Q_UNUSED(window)
0507     Private *p = cast(data);
0508     if (p->pid == static_cast<quint32>(pid)) {
0509         return;
0510     }
0511     p->pid = pid;
0512 }
0513 
0514 void PlasmaWindow::Private::resourceNameChangedCallback(void *data, org_kde_plasma_window *window, const char *resourceName)
0515 {
0516     Q_UNUSED(window)
0517     Private *p = cast(data);
0518     const QString s = QString::fromUtf8(resourceName);
0519     if (s == p->resourceName) {
0520         return;
0521     }
0522     p->resourceName = s;
0523     Q_EMIT p->q->resourceNameChanged();
0524 }
0525 
0526 void PlasmaWindow::Private::virtualDesktopChangedCallback([[maybe_unused]] void *data,
0527                                                           [[maybe_unused]] org_kde_plasma_window *window,
0528                                                           [[maybe_unused]] int32_t number)
0529 {
0530     // Can't remove this method as it's used in PlasmaWindow::Private::s_listener struct
0531 }
0532 
0533 void PlasmaWindow::Private::unmappedCallback(void *data, org_kde_plasma_window *window)
0534 {
0535     auto p = cast(data);
0536     Q_UNUSED(window);
0537     p->unmapped = true;
0538     Q_EMIT p->q->unmapped();
0539     p->q->deleteLater();
0540 }
0541 
0542 void PlasmaWindow::Private::virtualDesktopEnteredCallback(void *data, org_kde_plasma_window *window, const char *id)
0543 {
0544     auto p = cast(data);
0545     Q_UNUSED(window);
0546     const QString stringId(QString::fromUtf8(id));
0547     p->plasmaVirtualDesktops << stringId;
0548     Q_EMIT p->q->plasmaVirtualDesktopEntered(stringId);
0549     if (p->plasmaVirtualDesktops.count() == 1) {
0550         Q_EMIT p->q->onAllDesktopsChanged();
0551     }
0552 }
0553 
0554 void PlasmaWindow::Private::virtualDesktopLeftCallback(void *data, org_kde_plasma_window *window, const char *id)
0555 {
0556     auto p = cast(data);
0557     Q_UNUSED(window);
0558     const QString stringId(QString::fromUtf8(id));
0559     p->plasmaVirtualDesktops.removeAll(stringId);
0560     Q_EMIT p->q->plasmaVirtualDesktopLeft(stringId);
0561     if (p->plasmaVirtualDesktops.isEmpty()) {
0562         Q_EMIT p->q->onAllDesktopsChanged();
0563     }
0564 }
0565 
0566 void PlasmaWindow::Private::activityEnteredCallback(void *data, org_kde_plasma_window *window, const char *id)
0567 {
0568     auto p = cast(data);
0569     Q_UNUSED(window);
0570     const QString stringId(QString::fromUtf8(id));
0571     p->plasmaActivities << stringId;
0572     Q_EMIT p->q->plasmaActivityEntered(stringId);
0573 }
0574 
0575 void PlasmaWindow::Private::activityLeftCallback(void *data, org_kde_plasma_window *window, const char *id)
0576 {
0577     auto p = cast(data);
0578     Q_UNUSED(window);
0579     const QString stringId(QString::fromUtf8(id));
0580     p->plasmaActivities.removeAll(stringId);
0581     Q_EMIT p->q->plasmaActivityLeft(stringId);
0582 }
0583 
0584 void PlasmaWindow::Private::stateChangedCallback(void *data, org_kde_plasma_window *window, uint32_t state)
0585 {
0586     auto p = cast(data);
0587     Q_UNUSED(window);
0588     p->setActive(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ACTIVE);
0589     p->setMinimized(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED);
0590     p->setMaximized(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED);
0591     p->setFullscreen(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN);
0592     p->setKeepAbove(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE);
0593     p->setKeepBelow(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW);
0594     p->setOnAllDesktops(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ON_ALL_DESKTOPS);
0595     p->setDemandsAttention(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_DEMANDS_ATTENTION);
0596     p->setCloseable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_CLOSEABLE);
0597     p->setFullscreenable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREENABLE);
0598     p->setMaximizeable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZABLE);
0599     p->setMinimizeable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZABLE);
0600     p->setSkipTaskbar(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPTASKBAR);
0601     p->setSkipSwitcher(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPSWITCHER);
0602     p->setShadeable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADEABLE);
0603     p->setShaded(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED);
0604     p->setMovable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MOVABLE);
0605     p->setResizable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_RESIZABLE);
0606     p->setVirtualDesktopChangeable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_VIRTUAL_DESKTOP_CHANGEABLE);
0607 }
0608 
0609 void PlasmaWindow::Private::themedIconNameChangedCallback(void *data, org_kde_plasma_window *window, const char *name)
0610 {
0611     auto p = cast(data);
0612     Q_UNUSED(window);
0613     const QString themedName = QString::fromUtf8(name);
0614     if (!themedName.isEmpty()) {
0615         QIcon icon = QIcon::fromTheme(themedName);
0616         p->icon = icon;
0617     } else {
0618         p->icon = QIcon();
0619     }
0620     Q_EMIT p->q->iconChanged();
0621 }
0622 
0623 static int readData(int fd, QByteArray &data)
0624 {
0625     // implementation based on QtWayland file qwaylanddataoffer.cpp
0626     char buf[4096];
0627     int retryCount = 0;
0628     int n;
0629     while (true) {
0630         n = QT_READ(fd, buf, sizeof buf);
0631         if (n > 0) {
0632             data.append(buf, n);
0633         } else if (n == -1 && (errno == EAGAIN) && ++retryCount < 1000) {
0634             usleep(1000);
0635         } else {
0636             break;
0637         }
0638     }
0639     return n;
0640 }
0641 
0642 void PlasmaWindow::Private::iconChangedCallback(void *data, org_kde_plasma_window *window)
0643 {
0644     auto p = cast(data);
0645     Q_UNUSED(window);
0646     int pipeFds[2];
0647     if (pipe2(pipeFds, O_CLOEXEC | O_NONBLOCK) != 0) {
0648         return;
0649     }
0650     org_kde_plasma_window_get_icon(p->window, pipeFds[1]);
0651     close(pipeFds[1]);
0652     const int pipeFd = pipeFds[0];
0653     auto readIcon = [pipeFd]() -> QIcon {
0654         QByteArray content;
0655         if (readData(pipeFd, content) != 0) {
0656             close(pipeFd);
0657             return QIcon();
0658         }
0659         close(pipeFd);
0660         QDataStream ds(content);
0661         QIcon icon;
0662         ds >> icon;
0663         return icon;
0664     };
0665     QFutureWatcher<QIcon> *watcher = new QFutureWatcher<QIcon>(p->q);
0666     QObject::connect(watcher, &QFutureWatcher<QIcon>::finished, p->q, [p, watcher] {
0667         watcher->deleteLater();
0668         QIcon icon = watcher->result();
0669         if (!icon.isNull()) {
0670             p->icon = icon;
0671         } else {
0672             p->icon = QIcon::fromTheme(QStringLiteral("wayland"));
0673         }
0674         Q_EMIT p->q->iconChanged();
0675     });
0676     watcher->setFuture(QtConcurrent::run(readIcon));
0677 }
0678 
0679 void PlasmaWindow::Private::setActive(bool set)
0680 {
0681     if (active == set) {
0682         return;
0683     }
0684     active = set;
0685     Q_EMIT q->activeChanged();
0686 }
0687 
0688 void PlasmaWindow::Private::setFullscreen(bool set)
0689 {
0690     if (fullscreen == set) {
0691         return;
0692     }
0693     fullscreen = set;
0694     Q_EMIT q->fullscreenChanged();
0695 }
0696 
0697 void PlasmaWindow::Private::setKeepAbove(bool set)
0698 {
0699     if (keepAbove == set) {
0700         return;
0701     }
0702     keepAbove = set;
0703     Q_EMIT q->keepAboveChanged();
0704 }
0705 
0706 void PlasmaWindow::Private::setKeepBelow(bool set)
0707 {
0708     if (keepBelow == set) {
0709         return;
0710     }
0711     keepBelow = set;
0712     Q_EMIT q->keepBelowChanged();
0713 }
0714 
0715 void PlasmaWindow::Private::setMaximized(bool set)
0716 {
0717     if (maximized == set) {
0718         return;
0719     }
0720     maximized = set;
0721     Q_EMIT q->maximizedChanged();
0722 }
0723 
0724 void PlasmaWindow::Private::setMinimized(bool set)
0725 {
0726     if (minimized == set) {
0727         return;
0728     }
0729     minimized = set;
0730     Q_EMIT q->minimizedChanged();
0731 }
0732 
0733 void PlasmaWindow::Private::setOnAllDesktops(bool set)
0734 {
0735     if (onAllDesktops == set) {
0736         return;
0737     }
0738     onAllDesktops = set;
0739     Q_EMIT q->onAllDesktopsChanged();
0740 }
0741 
0742 void PlasmaWindow::Private::setDemandsAttention(bool set)
0743 {
0744     if (demandsAttention == set) {
0745         return;
0746     }
0747     demandsAttention = set;
0748     Q_EMIT q->demandsAttentionChanged();
0749 }
0750 
0751 void PlasmaWindow::Private::setCloseable(bool set)
0752 {
0753     if (closeable == set) {
0754         return;
0755     }
0756     closeable = set;
0757     Q_EMIT q->closeableChanged();
0758 }
0759 
0760 void PlasmaWindow::Private::setFullscreenable(bool set)
0761 {
0762     if (fullscreenable == set) {
0763         return;
0764     }
0765     fullscreenable = set;
0766     Q_EMIT q->fullscreenableChanged();
0767 }
0768 
0769 void PlasmaWindow::Private::setMaximizeable(bool set)
0770 {
0771     if (maximizeable == set) {
0772         return;
0773     }
0774     maximizeable = set;
0775     Q_EMIT q->maximizeableChanged();
0776 }
0777 
0778 void PlasmaWindow::Private::setMinimizeable(bool set)
0779 {
0780     if (minimizeable == set) {
0781         return;
0782     }
0783     minimizeable = set;
0784     Q_EMIT q->minimizeableChanged();
0785 }
0786 
0787 void PlasmaWindow::Private::setSkipTaskbar(bool skip)
0788 {
0789     if (skipTaskbar == skip) {
0790         return;
0791     }
0792     skipTaskbar = skip;
0793     Q_EMIT q->skipTaskbarChanged();
0794 }
0795 
0796 void PlasmaWindow::Private::setSkipSwitcher(bool skip)
0797 {
0798     if (skipSwitcher == skip) {
0799         return;
0800     }
0801     skipSwitcher = skip;
0802     Q_EMIT q->skipSwitcherChanged();
0803 }
0804 
0805 void PlasmaWindow::Private::setShadeable(bool set)
0806 {
0807     if (shadeable == set) {
0808         return;
0809     }
0810     shadeable = set;
0811     Q_EMIT q->shadeableChanged();
0812 }
0813 
0814 void PlasmaWindow::Private::setShaded(bool set)
0815 {
0816     if (shaded == set) {
0817         return;
0818     }
0819     shaded = set;
0820     Q_EMIT q->shadedChanged();
0821 }
0822 
0823 void PlasmaWindow::Private::setMovable(bool set)
0824 {
0825     if (movable == set) {
0826         return;
0827     }
0828     movable = set;
0829     Q_EMIT q->movableChanged();
0830 }
0831 
0832 void PlasmaWindow::Private::setResizable(bool set)
0833 {
0834     if (resizable == set) {
0835         return;
0836     }
0837     resizable = set;
0838     Q_EMIT q->resizableChanged();
0839 }
0840 
0841 void PlasmaWindow::Private::setVirtualDesktopChangeable(bool set)
0842 {
0843     if (virtualDesktopChangeable == set) {
0844         return;
0845     }
0846     virtualDesktopChangeable = set;
0847     Q_EMIT q->virtualDesktopChangeableChanged();
0848 }
0849 
0850 PlasmaWindow::Private::Private(org_kde_plasma_window *w, quint32 internalId, const char *uuid, PlasmaWindow *q)
0851     : internalId(internalId)
0852     , uuid(uuid)
0853     , q(q)
0854 {
0855     Q_ASSERT(!this->uuid.isEmpty());
0856     window.setup(w);
0857     org_kde_plasma_window_add_listener(w, &s_listener, this);
0858 }
0859 
0860 PlasmaWindow::PlasmaWindow(PlasmaWindowManagement *parent, org_kde_plasma_window *window, quint32 internalId, const char *uuid)
0861     : QObject(parent)
0862     , d(new Private(window, internalId, uuid, this))
0863 {
0864 }
0865 
0866 PlasmaWindow::~PlasmaWindow()
0867 {
0868     release();
0869 }
0870 
0871 void PlasmaWindow::destroy()
0872 {
0873     d->window.destroy();
0874 }
0875 
0876 void PlasmaWindow::release()
0877 {
0878     d->window.release();
0879 }
0880 
0881 bool PlasmaWindow::isValid() const
0882 {
0883     return d->window.isValid();
0884 }
0885 
0886 PlasmaWindow::operator org_kde_plasma_window *() const
0887 {
0888     return d->window;
0889 }
0890 
0891 PlasmaWindow::operator org_kde_plasma_window *()
0892 {
0893     return d->window;
0894 }
0895 
0896 QString PlasmaWindow::appId() const
0897 {
0898     return d->appId;
0899 }
0900 
0901 quint32 PlasmaWindow::pid() const
0902 {
0903     return d->pid;
0904 }
0905 
0906 QString PlasmaWindow::resourceName() const
0907 {
0908     return d->resourceName;
0909 }
0910 
0911 QString PlasmaWindow::title() const
0912 {
0913     return d->title;
0914 }
0915 
0916 bool PlasmaWindow::isActive() const
0917 {
0918     return d->active;
0919 }
0920 
0921 bool PlasmaWindow::isFullscreen() const
0922 {
0923     return d->fullscreen;
0924 }
0925 
0926 bool PlasmaWindow::isKeepAbove() const
0927 {
0928     return d->keepAbove;
0929 }
0930 
0931 bool PlasmaWindow::isKeepBelow() const
0932 {
0933     return d->keepBelow;
0934 }
0935 
0936 bool PlasmaWindow::isMaximized() const
0937 {
0938     return d->maximized;
0939 }
0940 
0941 bool PlasmaWindow::isMinimized() const
0942 {
0943     return d->minimized;
0944 }
0945 
0946 bool PlasmaWindow::isOnAllDesktops() const
0947 {
0948     // from protocol version 8 virtual desktops are managed by plasmaVirtualDesktops
0949     if (org_kde_plasma_window_get_version(d->window) < 8) {
0950         return d->onAllDesktops;
0951     } else {
0952         return d->plasmaVirtualDesktops.isEmpty();
0953     }
0954 }
0955 
0956 bool PlasmaWindow::isDemandingAttention() const
0957 {
0958     return d->demandsAttention;
0959 }
0960 
0961 bool PlasmaWindow::isCloseable() const
0962 {
0963     return d->closeable;
0964 }
0965 
0966 bool PlasmaWindow::isFullscreenable() const
0967 {
0968     return d->fullscreenable;
0969 }
0970 
0971 bool PlasmaWindow::isMaximizeable() const
0972 {
0973     return d->maximizeable;
0974 }
0975 
0976 bool PlasmaWindow::isMinimizeable() const
0977 {
0978     return d->minimizeable;
0979 }
0980 
0981 bool PlasmaWindow::skipTaskbar() const
0982 {
0983     return d->skipTaskbar;
0984 }
0985 
0986 bool PlasmaWindow::skipSwitcher() const
0987 {
0988     return d->skipSwitcher;
0989 }
0990 
0991 QIcon PlasmaWindow::icon() const
0992 {
0993     return d->icon;
0994 }
0995 
0996 bool PlasmaWindow::isShadeable() const
0997 {
0998     return d->shadeable;
0999 }
1000 
1001 bool PlasmaWindow::isShaded() const
1002 {
1003     return d->shaded;
1004 }
1005 
1006 bool PlasmaWindow::isResizable() const
1007 {
1008     return d->resizable;
1009 }
1010 
1011 bool PlasmaWindow::isMovable() const
1012 {
1013     return d->movable;
1014 }
1015 
1016 bool PlasmaWindow::isVirtualDesktopChangeable() const
1017 {
1018     return d->virtualDesktopChangeable;
1019 }
1020 
1021 QString PlasmaWindow::applicationMenuObjectPath() const
1022 {
1023     return d->applicationMenuObjectPath;
1024 }
1025 
1026 QString PlasmaWindow::applicationMenuServiceName() const
1027 {
1028     return d->applicationMenuServiceName;
1029 }
1030 
1031 void PlasmaWindow::requestActivate()
1032 {
1033     org_kde_plasma_window_set_state(d->window, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ACTIVE, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ACTIVE);
1034 }
1035 
1036 void PlasmaWindow::requestClose()
1037 {
1038     org_kde_plasma_window_close(d->window);
1039 }
1040 
1041 void PlasmaWindow::requestMove()
1042 {
1043     org_kde_plasma_window_request_move(d->window);
1044 }
1045 
1046 void PlasmaWindow::requestResize()
1047 {
1048     org_kde_plasma_window_request_resize(d->window);
1049 }
1050 
1051 void PlasmaWindow::requestToggleKeepAbove()
1052 {
1053     if (d->keepAbove) {
1054         org_kde_plasma_window_set_state(d->window, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE, 0);
1055     } else {
1056         org_kde_plasma_window_set_state(d->window, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE);
1057     }
1058 }
1059 
1060 void PlasmaWindow::requestToggleKeepBelow()
1061 {
1062     if (d->keepBelow) {
1063         org_kde_plasma_window_set_state(d->window, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW, 0);
1064     } else {
1065         org_kde_plasma_window_set_state(d->window, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW);
1066     }
1067 }
1068 
1069 void PlasmaWindow::requestToggleMinimized()
1070 {
1071     if (d->minimized) {
1072         org_kde_plasma_window_set_state(d->window, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED, 0);
1073     } else {
1074         org_kde_plasma_window_set_state(d->window, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED);
1075     }
1076 }
1077 
1078 void PlasmaWindow::requestToggleMaximized()
1079 {
1080     if (d->maximized) {
1081         org_kde_plasma_window_set_state(d->window, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED, 0);
1082     } else {
1083         org_kde_plasma_window_set_state(d->window, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED);
1084     }
1085 }
1086 
1087 void PlasmaWindow::requestToggleFullscreen()
1088 {
1089     if (d->fullscreen) {
1090         org_kde_plasma_window_set_state(d->window, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN, 0);
1091     } else {
1092         org_kde_plasma_window_set_state(d->window, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN);
1093     }
1094 }
1095 
1096 void PlasmaWindow::setMinimizedGeometry(Surface *panel, const QRect &geom)
1097 {
1098     org_kde_plasma_window_set_minimized_geometry(d->window, *panel, geom.x(), geom.y(), geom.width(), geom.height());
1099 }
1100 
1101 void PlasmaWindow::unsetMinimizedGeometry(Surface *panel)
1102 {
1103     org_kde_plasma_window_unset_minimized_geometry(d->window, *panel);
1104 }
1105 
1106 void PlasmaWindow::requestToggleShaded()
1107 {
1108     if (d->shaded) {
1109         org_kde_plasma_window_set_state(d->window, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED, 0);
1110     } else {
1111         org_kde_plasma_window_set_state(d->window, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED);
1112     }
1113 }
1114 
1115 QByteArray PlasmaWindow::uuid() const
1116 {
1117     return d->uuid;
1118 }
1119 
1120 QPointer<PlasmaWindow> PlasmaWindow::parentWindow() const
1121 {
1122     return d->parentWindow;
1123 }
1124 
1125 QRect PlasmaWindow::geometry() const
1126 {
1127     return d->geometry;
1128 }
1129 
1130 void PlasmaWindow::requestEnterVirtualDesktop(const QString &id)
1131 {
1132     org_kde_plasma_window_request_enter_virtual_desktop(d->window, id.toUtf8());
1133 }
1134 
1135 void PlasmaWindow::requestEnterNewVirtualDesktop()
1136 {
1137     org_kde_plasma_window_request_enter_new_virtual_desktop(d->window);
1138 }
1139 
1140 void PlasmaWindow::requestLeaveVirtualDesktop(const QString &id)
1141 {
1142     org_kde_plasma_window_request_leave_virtual_desktop(d->window, id.toUtf8());
1143 }
1144 
1145 QStringList PlasmaWindow::plasmaVirtualDesktops() const
1146 {
1147     return d->plasmaVirtualDesktops;
1148 }
1149 
1150 void PlasmaWindow::requestEnterActivity(const QString &id)
1151 {
1152     org_kde_plasma_window_request_enter_activity(d->window, id.toUtf8());
1153 }
1154 
1155 void PlasmaWindow::requestLeaveActivity(const QString &id)
1156 {
1157     org_kde_plasma_window_request_leave_activity(d->window, id.toUtf8());
1158 }
1159 
1160 QStringList PlasmaWindow::plasmaActivities() const
1161 {
1162     return d->plasmaActivities;
1163 }
1164 
1165 void PlasmaWindow::sendToOutput(KWayland::Client::Output *output) const
1166 {
1167     if (org_kde_plasma_window_get_version(d->window) >= ORG_KDE_PLASMA_WINDOW_SEND_TO_OUTPUT_SINCE_VERSION) {
1168         org_kde_plasma_window_send_to_output(d->window, *output);
1169     }
1170 }
1171 
1172 class Q_DECL_HIDDEN PlasmaActivationFeedback::Private
1173 {
1174 public:
1175     Private(PlasmaActivationFeedback *q);
1176     WaylandPointer<org_kde_plasma_activation_feedback, org_kde_plasma_activation_feedback_destroy> feedback;
1177     EventQueue *queue = nullptr;
1178 
1179     void setup(org_kde_plasma_activation_feedback *feedback);
1180 
1181 private:
1182     static void activationCallback(void *data, struct org_kde_plasma_activation_feedback *feedback, struct org_kde_plasma_activation *id);
1183 
1184     static struct org_kde_plasma_activation_feedback_listener s_listener;
1185     PlasmaActivationFeedback *q;
1186 };
1187 
1188 PlasmaActivationFeedback::Private::Private(PlasmaActivationFeedback *q)
1189     : q(q)
1190 {
1191 }
1192 
1193 org_kde_plasma_activation_feedback_listener PlasmaActivationFeedback::Private::s_listener = {
1194     activationCallback,
1195 };
1196 
1197 void PlasmaActivationFeedback::Private::activationCallback(void *data, org_kde_plasma_activation_feedback *interface, struct org_kde_plasma_activation *id)
1198 {
1199     auto feedbackPrivate = reinterpret_cast<PlasmaActivationFeedback::Private *>(data);
1200     Q_ASSERT(feedbackPrivate->feedback == interface);
1201     auto activation = new PlasmaActivation(feedbackPrivate->q, id);
1202     Q_EMIT feedbackPrivate->q->activation(activation);
1203 }
1204 
1205 void PlasmaActivationFeedback::Private::setup(org_kde_plasma_activation_feedback *m)
1206 {
1207     Q_ASSERT(!feedback);
1208     Q_ASSERT(m);
1209     feedback.setup(m);
1210     org_kde_plasma_activation_feedback_add_listener(m, &s_listener, this);
1211 }
1212 
1213 PlasmaActivationFeedback::PlasmaActivationFeedback(QObject *parent)
1214     : QObject(parent)
1215     , d(new Private(this))
1216 {
1217 }
1218 
1219 PlasmaActivationFeedback::~PlasmaActivationFeedback()
1220 {
1221     release();
1222 }
1223 
1224 void PlasmaActivationFeedback::destroy()
1225 {
1226     if (!d->feedback) {
1227         return;
1228     }
1229     Q_EMIT interfaceAboutToBeDestroyed();
1230     d->feedback.destroy();
1231 }
1232 
1233 void PlasmaActivationFeedback::release()
1234 {
1235     if (!d->feedback) {
1236         return;
1237     }
1238     Q_EMIT interfaceAboutToBeReleased();
1239     d->feedback.release();
1240 }
1241 
1242 void PlasmaActivationFeedback::setup(org_kde_plasma_activation_feedback *wm)
1243 {
1244     d->setup(wm);
1245 }
1246 
1247 void PlasmaActivationFeedback::setEventQueue(EventQueue *queue)
1248 {
1249     d->queue = queue;
1250 }
1251 
1252 EventQueue *PlasmaActivationFeedback::eventQueue()
1253 {
1254     return d->queue;
1255 }
1256 
1257 bool PlasmaActivationFeedback::isValid() const
1258 {
1259     return d->feedback.isValid();
1260 }
1261 
1262 PlasmaActivationFeedback::operator org_kde_plasma_activation_feedback *()
1263 {
1264     return d->feedback;
1265 }
1266 
1267 PlasmaActivationFeedback::operator org_kde_plasma_activation_feedback *() const
1268 {
1269     return d->feedback;
1270 }
1271 
1272 class Q_DECL_HIDDEN PlasmaActivation::Private
1273 {
1274 public:
1275     Private(org_kde_plasma_activation *activation, PlasmaActivation *q)
1276         : activation(activation)
1277     {
1278         org_kde_plasma_activation_add_listener(activation, &s_listener, q);
1279     }
1280 
1281     static PlasmaActivation *cast(void *data)
1282     {
1283         return reinterpret_cast<PlasmaActivation *>(data);
1284     }
1285     WaylandPointer<org_kde_plasma_activation, org_kde_plasma_activation_destroy> activation;
1286 
1287     static org_kde_plasma_activation_listener s_listener;
1288     static void app_idCallback(void *data, struct org_kde_plasma_activation *org_kde_plasma_activation, const char *app_id);
1289     static void finishedCallback(void *data, struct org_kde_plasma_activation *org_kde_plasma_activation);
1290 };
1291 
1292 org_kde_plasma_activation_listener PlasmaActivation::Private::s_listener = {
1293     app_idCallback,
1294     finishedCallback,
1295 };
1296 
1297 void PlasmaActivation::Private::app_idCallback(void *data, org_kde_plasma_activation *activation, const char *appId)
1298 {
1299     Q_UNUSED(activation)
1300     Q_EMIT cast(data)->applicationId(QString::fromUtf8(appId));
1301 }
1302 
1303 void PlasmaActivation::Private::finishedCallback(void *data, org_kde_plasma_activation *)
1304 {
1305     auto q = cast(data);
1306     Q_EMIT q->finished();
1307     Q_EMIT q->deleteLater();
1308     q->d->activation.release();
1309 }
1310 
1311 PlasmaActivation::PlasmaActivation(PlasmaActivationFeedback *parent, org_kde_plasma_activation *activation)
1312     : QObject(parent)
1313     , d(new PlasmaActivation::Private(activation, this))
1314 {
1315 }
1316 
1317 PlasmaActivation::~PlasmaActivation() = default;
1318 }
1319 }
1320 
1321 #include "moc_plasmawindowmanagement.cpp"