1/*
2 SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6#include "plasmawindowmanagement.h"
7#include "event_queue.h"
8#include "output.h"
9#include "plasmavirtualdesktop.h"
10#include "plasmawindowmodel.h"
11#include "surface.h"
12#include "wayland_pointer_p.h"
13// Wayland
14#include <wayland-plasma-window-management-client-protocol.h>
15
16#include <QFutureWatcher>
17#include <QTimer>
18#include <QtConcurrentRun>
19#include <qplatformdefs.h>
20
21#include <cerrno>
22
23namespace KWayland
24{
25namespace Client
26{
27class Q_DECL_HIDDEN PlasmaWindowManagement::Private : public QObject
28{
29 Q_OBJECT
30public:
31 Private(PlasmaWindowManagement *q);
32 WaylandPointer<org_kde_plasma_window_management, org_kde_plasma_window_management_destroy> wm;
33 EventQueue *queue = nullptr;
34 bool showingDesktop = false;
35 QList<PlasmaWindow *> windows;
36 PlasmaWindow *activeWindow = nullptr;
37 QList<quint32> stackingOrder;
38 QList<QByteArray> stackingOrderUuids;
39
40 void setup(org_kde_plasma_window_management *wm);
41
42private:
43 static void showDesktopCallback(void *data, org_kde_plasma_window_management *org_kde_plasma_window_management, uint32_t state);
44 static void windowCallback(void *data, org_kde_plasma_window_management *org_kde_plasma_window_management, uint32_t id);
45 static void windowWithUuidCallback(void *data, org_kde_plasma_window_management *org_kde_plasma_window_management, uint32_t id, const char *uuid);
46 static void stackingOrderCallback(void *data, org_kde_plasma_window_management *org_kde_plasma_window_management, wl_array *ids);
47 static void stackingOrderUuidsCallback(void *data, org_kde_plasma_window_management *org_kde_plasma_window_management, const char *uuids);
48 static void stackingOrder2Callback(void *data, org_kde_plasma_window_management *interface);
49 void setShowDesktop(bool set);
50 void windowCreated(org_kde_plasma_window *id, quint32 internalId, const char *uuid);
51 void setStackingOrder(const QList<quint32> &ids);
52 void setStackingOrder(const QList<QByteArray> &uuids);
53
54 static void stackingOrderWindow(void *data, struct org_kde_plasma_stacking_order *org_kde_plasma_stacking_order, const char *uuid);
55 static void stackingOrderDone(void *data, struct org_kde_plasma_stacking_order *org_kde_plasma_stacking_order);
56
57 static struct org_kde_plasma_window_management_listener s_listener;
58 static const org_kde_plasma_stacking_order_listener s_stackingOrderListener;
59 PlasmaWindowManagement *q;
60};
61
62class Q_DECL_HIDDEN PlasmaWindow::Private
63{
64public:
65 Private(org_kde_plasma_window *window, quint32 internalId, const char *uuid, PlasmaWindow *q);
66 WaylandPointer<org_kde_plasma_window, org_kde_plasma_window_destroy> window;
67 quint32 internalId; ///< @deprecated
68 QByteArray uuid;
69 QString title;
70 QString appId;
71 quint32 desktop = 0;
72 bool active = false;
73 bool minimized = false;
74 bool maximized = false;
75 bool fullscreen = false;
76 bool keepAbove = false;
77 bool keepBelow = false;
78 bool onAllDesktops = false;
79 bool demandsAttention = false;
80 bool closeable = false;
81 bool minimizeable = false;
82 bool maximizeable = false;
83 bool fullscreenable = false;
84 bool skipTaskbar = false;
85 bool skipSwitcher = false;
86 bool shadeable = false;
87 bool shaded = false;
88 bool movable = false;
89 bool resizable = false;
90 bool virtualDesktopChangeable = false;
91 QIcon icon;
92 PlasmaWindowManagement *wm = nullptr;
93 bool unmapped = false;
94 QPointer<PlasmaWindow> parentWindow;
95 QMetaObject::Connection parentWindowUnmappedConnection;
96 QStringList plasmaVirtualDesktops;
97 QStringList plasmaActivities;
98 QRect geometry;
99 quint32 pid = 0;
100 QString resourceName;
101 QString applicationMenuServiceName;
102 QString applicationMenuObjectPath;
103 QRect clientGeometry;
104
105private:
106 static void titleChangedCallback(void *data, org_kde_plasma_window *window, const char *title);
107 static void appIdChangedCallback(void *data, org_kde_plasma_window *window, const char *app_id);
108 static void pidChangedCallback(void *data, org_kde_plasma_window *window, uint32_t pid);
109 static void resourceNameChangedCallback(void *data, org_kde_plasma_window *window, const char *resourceName);
110 static void stateChangedCallback(void *data, org_kde_plasma_window *window, uint32_t state);
111 static void virtualDesktopChangedCallback(void *data, org_kde_plasma_window *window, int32_t number);
112 static void themedIconNameChangedCallback(void *data, org_kde_plasma_window *window, const char *name);
113 static void unmappedCallback(void *data, org_kde_plasma_window *window);
114 static void initialStateCallback(void *data, org_kde_plasma_window *window);
115 static void parentWindowCallback(void *data, org_kde_plasma_window *window, org_kde_plasma_window *parent);
116 static void windowGeometryCallback(void *data, org_kde_plasma_window *window, int32_t x, int32_t y, uint32_t width, uint32_t height);
117 static void iconChangedCallback(void *data, org_kde_plasma_window *org_kde_plasma_window);
118 static void virtualDesktopEnteredCallback(void *data, org_kde_plasma_window *org_kde_plasma_window, const char *id);
119 static void virtualDesktopLeftCallback(void *data, org_kde_plasma_window *org_kde_plasma_window, const char *id);
120 static void appmenuChangedCallback(void *data, org_kde_plasma_window *org_kde_plasma_window, const char *service_name, const char *object_path);
121 static void activityEnteredCallback(void *data, org_kde_plasma_window *org_kde_plasma_window, const char *id);
122 static void activityLeftCallback(void *data, org_kde_plasma_window *org_kde_plasma_window, const char *id);
123 static void clientGeometryCallback(void *data, org_kde_plasma_window *window, int32_t x, int32_t y, uint32_t width, uint32_t height);
124 void setActive(bool set);
125 void setMinimized(bool set);
126 void setMaximized(bool set);
127 void setFullscreen(bool set);
128 void setKeepAbove(bool set);
129 void setKeepBelow(bool set);
130 void setOnAllDesktops(bool set);
131 void setDemandsAttention(bool set);
132 void setCloseable(bool set);
133 void setMinimizeable(bool set);
134 void setMaximizeable(bool set);
135 void setFullscreenable(bool set);
136 void setSkipTaskbar(bool skip);
137 void setSkipSwitcher(bool skip);
138 void setShadeable(bool set);
139 void setShaded(bool set);
140 void setMovable(bool set);
141 void setResizable(bool set);
142 void setVirtualDesktopChangeable(bool set);
143 void setParentWindow(PlasmaWindow *parentWindow);
144 void setPid(const quint32 pid);
145
146 static Private *cast(void *data)
147 {
148 return reinterpret_cast<Private *>(data);
149 }
150
151 PlasmaWindow *q;
152
153 static struct org_kde_plasma_window_listener s_listener;
154};
155
156struct StackingOrderData {
157 QPointer<PlasmaWindowManagement::Private> wm;
158 QList<QByteArray> list;
159};
160
161PlasmaWindowManagement::Private::Private(PlasmaWindowManagement *q)
162 : q(q)
163{
164}
165
166org_kde_plasma_window_management_listener PlasmaWindowManagement::Private::s_listener = {
167 .show_desktop_changed: showDesktopCallback,
168 .window: windowCallback,
169 .stacking_order_changed: stackingOrderCallback,
170 .stacking_order_uuid_changed: stackingOrderUuidsCallback,
171 .window_with_uuid: windowWithUuidCallback,
172 .stacking_order_changed_2: stackingOrder2Callback,
173};
174
175void PlasmaWindowManagement::Private::setup(org_kde_plasma_window_management *windowManagement)
176{
177 Q_ASSERT(!wm);
178 Q_ASSERT(windowManagement);
179 wm.setup(pointer: windowManagement);
180 org_kde_plasma_window_management_add_listener(org_kde_plasma_window_management: windowManagement, listener: &s_listener, data: this);
181
182 if (org_kde_plasma_window_management_get_version(org_kde_plasma_window_management: windowManagement) >= ORG_KDE_PLASMA_WINDOW_MANAGEMENT_GET_STACKING_ORDER_SINCE_VERSION) {
183 auto object = org_kde_plasma_window_management_get_stacking_order(org_kde_plasma_window_management: wm);
184 org_kde_plasma_stacking_order_add_listener(org_kde_plasma_stacking_order: object,
185 listener: &s_stackingOrderListener,
186 data: new StackingOrderData{
187 .wm = this,
188 .list = {},
189 });
190 }
191}
192
193void PlasmaWindowManagement::Private::showDesktopCallback(void *data, org_kde_plasma_window_management *org_kde_plasma_window_management, uint32_t state)
194{
195 auto wm = reinterpret_cast<PlasmaWindowManagement::Private *>(data);
196 Q_ASSERT(wm->wm == org_kde_plasma_window_management);
197 switch (state) {
198 case ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_ENABLED:
199 wm->setShowDesktop(true);
200 break;
201 case ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_DISABLED:
202 wm->setShowDesktop(false);
203 break;
204 default:
205 Q_UNREACHABLE();
206 break;
207 }
208}
209
210void PlasmaWindowManagement::Private::setShowDesktop(bool set)
211{
212 if (showingDesktop == set) {
213 return;
214 }
215 showingDesktop = set;
216 Q_EMIT q->showingDesktopChanged(showingDesktop);
217}
218
219void PlasmaWindowManagement::Private::windowCallback(void *data, org_kde_plasma_window_management *interface, uint32_t id)
220{
221 auto wm = reinterpret_cast<PlasmaWindowManagement::Private *>(data);
222 Q_ASSERT(wm->wm == interface);
223 QTimer *timer = new QTimer();
224 timer->setSingleShot(true);
225 timer->setInterval(0);
226 QObject::connect(
227 sender: timer,
228 signal: &QTimer::timeout,
229 context: wm->q,
230 slot: [timer, wm, id] {
231 wm->windowCreated(id: org_kde_plasma_window_management_get_window(org_kde_plasma_window_management: wm->wm, internal_window_id: id), internalId: id, uuid: "unavailable");
232 timer->deleteLater();
233 },
234 type: Qt::QueuedConnection);
235 timer->start();
236}
237
238void PlasmaWindowManagement::Private::windowWithUuidCallback(void *data, org_kde_plasma_window_management *interface, uint32_t id, const char *_uuid)
239{
240 QByteArray uuid(_uuid);
241 auto wm = reinterpret_cast<PlasmaWindowManagement::Private *>(data);
242 Q_ASSERT(wm->wm == interface);
243 QTimer *timer = new QTimer();
244 timer->setSingleShot(true);
245 timer->setInterval(0);
246 QObject::connect(
247 sender: timer,
248 signal: &QTimer::timeout,
249 context: wm->q,
250 slot: [timer, wm, id, uuid] {
251 wm->windowCreated(id: org_kde_plasma_window_management_get_window_by_uuid(org_kde_plasma_window_management: wm->wm, internal_window_uuid: uuid), internalId: id, uuid);
252 timer->deleteLater();
253 },
254 type: Qt::QueuedConnection);
255 timer->start();
256}
257
258void PlasmaWindowManagement::Private::windowCreated(org_kde_plasma_window *id, quint32 internalId, const char *uuid)
259{
260 if (queue) {
261 queue->addProxy(proxy: id);
262 }
263 PlasmaWindow *window = new PlasmaWindow(q, id, internalId, uuid);
264 window->d->wm = q;
265 windows << window;
266
267 const auto windowRemoved = [this, window] {
268 windows.removeAll(t: window);
269 if (activeWindow == window) {
270 activeWindow = nullptr;
271 Q_EMIT q->activeWindowChanged();
272 }
273 };
274
275 QObject::connect(sender: window, signal: &QObject::destroyed, context: q, slot: windowRemoved);
276 // 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
277 // PlasmaWindowManagement::windows().
278 QObject::connect(sender: window, signal: &PlasmaWindow::unmapped, context: q, slot: windowRemoved);
279 QObject::connect(sender: window, signal: &PlasmaWindow::activeChanged, context: q, slot: [this, window] {
280 if (window->d->unmapped) {
281 return;
282 }
283 if (window->isActive()) {
284 if (activeWindow == window) {
285 return;
286 }
287 activeWindow = window;
288 Q_EMIT q->activeWindowChanged();
289 } else {
290 if (activeWindow == window) {
291 activeWindow = nullptr;
292 Q_EMIT q->activeWindowChanged();
293 }
294 }
295 });
296}
297
298void PlasmaWindowManagement::Private::stackingOrderCallback(void *data, org_kde_plasma_window_management *interface, wl_array *ids)
299{
300 // This is no-op since setStackingOrder(const QList<quint32> &ids) is deprecated since 5.73,
301 // but we can't remove this method because it's needed in
302 // PlasmaWindowManagement::Private::s_listener struct
303}
304
305void PlasmaWindowManagement::Private::stackingOrderUuidsCallback(void *data, org_kde_plasma_window_management *interface, const char *uuids)
306{
307 auto wm = reinterpret_cast<PlasmaWindowManagement::Private *>(data);
308 Q_ASSERT(wm->wm == interface);
309 wm->setStackingOrder(QByteArray(uuids).split(sep: ';').toVector());
310}
311
312void PlasmaWindowManagement::Private::stackingOrderWindow(void *data, org_kde_plasma_stacking_order *org_kde_plasma_stacking_order, const char *uuid)
313{
314 Q_UNUSED(org_kde_plasma_stacking_order);
315 auto order = static_cast<StackingOrderData *>(data);
316 order->list.push_back(t: uuid);
317}
318
319void PlasmaWindowManagement::Private::stackingOrderDone(void *data, org_kde_plasma_stacking_order *org_kde_plasma_stacking_order)
320{
321 auto order = static_cast<StackingOrderData *>(data);
322 if (order->wm) {
323 order->wm->setStackingOrder(order->list);
324 }
325 delete order;
326 org_kde_plasma_stacking_order_destroy(org_kde_plasma_stacking_order);
327}
328
329const org_kde_plasma_stacking_order_listener PlasmaWindowManagement::Private::s_stackingOrderListener = {
330 .window = stackingOrderWindow,
331 .done = stackingOrderDone,
332};
333
334void PlasmaWindowManagement::Private::stackingOrder2Callback(void *data, org_kde_plasma_window_management *interface)
335{
336 auto wm = reinterpret_cast<PlasmaWindowManagement::Private *>(data);
337 Q_ASSERT(wm->wm == interface);
338 auto object = org_kde_plasma_window_management_get_stacking_order(org_kde_plasma_window_management: wm->wm);
339 org_kde_plasma_stacking_order_add_listener(org_kde_plasma_stacking_order: object,
340 listener: &s_stackingOrderListener,
341 data: new StackingOrderData{
342 .wm = wm,
343 .list = {},
344 });
345}
346
347void PlasmaWindowManagement::Private::setStackingOrder(const QList<QByteArray> &uuids)
348{
349 if (stackingOrderUuids == uuids) {
350 return;
351 }
352 stackingOrderUuids = uuids;
353 Q_EMIT q->stackingOrderUuidsChanged();
354}
355
356PlasmaWindowManagement::PlasmaWindowManagement(QObject *parent)
357 : QObject(parent)
358 , d(new Private(this))
359{
360}
361
362PlasmaWindowManagement::~PlasmaWindowManagement()
363{
364 release();
365}
366
367void PlasmaWindowManagement::destroy()
368{
369 if (!d->wm) {
370 return;
371 }
372 Q_EMIT interfaceAboutToBeDestroyed();
373 d->wm.destroy();
374}
375
376void PlasmaWindowManagement::release()
377{
378 if (!d->wm) {
379 return;
380 }
381 Q_EMIT interfaceAboutToBeReleased();
382 d->wm.release();
383}
384
385void PlasmaWindowManagement::setup(org_kde_plasma_window_management *wm)
386{
387 d->setup(wm);
388}
389
390void PlasmaWindowManagement::setEventQueue(EventQueue *queue)
391{
392 d->queue = queue;
393}
394
395EventQueue *PlasmaWindowManagement::eventQueue()
396{
397 return d->queue;
398}
399
400bool PlasmaWindowManagement::isValid() const
401{
402 return d->wm.isValid();
403}
404
405PlasmaWindowManagement::operator org_kde_plasma_window_management *()
406{
407 return d->wm;
408}
409
410PlasmaWindowManagement::operator org_kde_plasma_window_management *() const
411{
412 return d->wm;
413}
414
415void PlasmaWindowManagement::hideDesktop()
416{
417 setShowingDesktop(false);
418}
419
420void PlasmaWindowManagement::showDesktop()
421{
422 setShowingDesktop(true);
423}
424
425void PlasmaWindowManagement::setShowingDesktop(bool show)
426{
427 org_kde_plasma_window_management_show_desktop(org_kde_plasma_window_management: d->wm,
428 state: show ? ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_ENABLED
429 : ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_DISABLED);
430}
431
432bool PlasmaWindowManagement::isShowingDesktop() const
433{
434 return d->showingDesktop;
435}
436
437QList<PlasmaWindow *> PlasmaWindowManagement::windows() const
438{
439 return d->windows;
440}
441
442PlasmaWindow *PlasmaWindowManagement::activeWindow() const
443{
444 return d->activeWindow;
445}
446
447PlasmaWindowModel *PlasmaWindowManagement::createWindowModel()
448{
449 return new PlasmaWindowModel(this);
450}
451
452QList<QByteArray> PlasmaWindowManagement::stackingOrderUuids() const
453{
454 return d->stackingOrderUuids;
455}
456
457org_kde_plasma_window_listener PlasmaWindow::Private::s_listener = {
458 .title_changed: titleChangedCallback,
459 .app_id_changed: appIdChangedCallback,
460 .state_changed: stateChangedCallback,
461 .virtual_desktop_changed: virtualDesktopChangedCallback,
462 .themed_icon_name_changed: themedIconNameChangedCallback,
463 .unmapped: unmappedCallback,
464 .initial_state: initialStateCallback,
465 .parent_window: parentWindowCallback,
466 .geometry: windowGeometryCallback,
467 .icon_changed: iconChangedCallback,
468 .pid_changed: pidChangedCallback,
469 .virtual_desktop_entered: virtualDesktopEnteredCallback,
470 .virtual_desktop_left: virtualDesktopLeftCallback,
471 .application_menu: appmenuChangedCallback,
472 .activity_entered: activityEnteredCallback,
473 .activity_left: activityLeftCallback,
474 .resource_name_changed: resourceNameChangedCallback,
475 .client_geometry: clientGeometryCallback,
476};
477
478void PlasmaWindow::Private::appmenuChangedCallback(void *data, org_kde_plasma_window *window, const char *service_name, const char *object_path)
479{
480 Q_UNUSED(window)
481
482 Private *p = cast(data);
483
484 p->applicationMenuServiceName = QString::fromUtf8(utf8: service_name);
485 p->applicationMenuObjectPath = QString::fromUtf8(utf8: object_path);
486
487 Q_EMIT p->q->applicationMenuChanged();
488}
489
490void PlasmaWindow::Private::parentWindowCallback(void *data, org_kde_plasma_window *window, org_kde_plasma_window *parent)
491{
492 Q_UNUSED(window)
493 Private *p = cast(data);
494 const auto windows = p->wm->windows();
495 auto it = std::find_if(first: windows.constBegin(), last: windows.constEnd(), pred: [parent](const PlasmaWindow *w) {
496 return *w == parent;
497 });
498 p->setParentWindow(it != windows.constEnd() ? *it : nullptr);
499}
500
501void PlasmaWindow::Private::windowGeometryCallback(void *data, org_kde_plasma_window *window, int32_t x, int32_t y, uint32_t width, uint32_t height)
502{
503 Q_UNUSED(window)
504 Private *p = cast(data);
505 QRect geo(x, y, width, height);
506 if (geo == p->geometry) {
507 return;
508 }
509 p->geometry = geo;
510 Q_EMIT p->q->geometryChanged();
511}
512
513void PlasmaWindow::Private::setParentWindow(PlasmaWindow *parent)
514{
515 const auto old = parentWindow;
516 QObject::disconnect(parentWindowUnmappedConnection);
517 if (parent && !parent->d->unmapped) {
518 parentWindow = QPointer<PlasmaWindow>(parent);
519 parentWindowUnmappedConnection = QObject::connect(sender: parent, signal: &PlasmaWindow::unmapped, context: q, slot: [this] {
520 setParentWindow(nullptr);
521 });
522 } else {
523 parentWindow = QPointer<PlasmaWindow>();
524 parentWindowUnmappedConnection = QMetaObject::Connection();
525 }
526 if (parentWindow.data() != old.data()) {
527 Q_EMIT q->parentWindowChanged();
528 }
529}
530
531void PlasmaWindow::Private::initialStateCallback(void *data, org_kde_plasma_window *window)
532{
533 Q_UNUSED(window)
534 Private *p = cast(data);
535 if (!p->unmapped) {
536 Q_EMIT p->wm->windowCreated(window: p->q);
537 }
538}
539
540void PlasmaWindow::Private::titleChangedCallback(void *data, org_kde_plasma_window *window, const char *title)
541{
542 Q_UNUSED(window)
543 Private *p = cast(data);
544 const QString t = QString::fromUtf8(utf8: title);
545 if (p->title == t) {
546 return;
547 }
548 p->title = t;
549 Q_EMIT p->q->titleChanged();
550}
551
552void PlasmaWindow::Private::appIdChangedCallback(void *data, org_kde_plasma_window *window, const char *appId)
553{
554 Q_UNUSED(window)
555 Private *p = cast(data);
556 const QString s = QString::fromUtf8(utf8: appId);
557 if (s == p->appId) {
558 return;
559 }
560 p->appId = s;
561 Q_EMIT p->q->appIdChanged();
562}
563
564void PlasmaWindow::Private::pidChangedCallback(void *data, org_kde_plasma_window *window, uint32_t pid)
565{
566 Q_UNUSED(window)
567 Private *p = cast(data);
568 if (p->pid == static_cast<quint32>(pid)) {
569 return;
570 }
571 p->pid = pid;
572}
573
574void PlasmaWindow::Private::resourceNameChangedCallback(void *data, org_kde_plasma_window *window, const char *resourceName)
575{
576 Q_UNUSED(window)
577 Private *p = cast(data);
578 const QString s = QString::fromUtf8(utf8: resourceName);
579 if (s == p->resourceName) {
580 return;
581 }
582 p->resourceName = s;
583 Q_EMIT p->q->resourceNameChanged();
584}
585
586void PlasmaWindow::Private::virtualDesktopChangedCallback([[maybe_unused]] void *data,
587 [[maybe_unused]] org_kde_plasma_window *window,
588 [[maybe_unused]] int32_t number)
589{
590 // Can't remove this method as it's used in PlasmaWindow::Private::s_listener struct
591}
592
593void PlasmaWindow::Private::unmappedCallback(void *data, org_kde_plasma_window *window)
594{
595 auto p = cast(data);
596 Q_UNUSED(window);
597 p->unmapped = true;
598 Q_EMIT p->q->unmapped();
599 p->q->deleteLater();
600}
601
602void PlasmaWindow::Private::virtualDesktopEnteredCallback(void *data, org_kde_plasma_window *window, const char *id)
603{
604 auto p = cast(data);
605 Q_UNUSED(window);
606 const QString stringId(QString::fromUtf8(utf8: id));
607 p->plasmaVirtualDesktops << stringId;
608 Q_EMIT p->q->plasmaVirtualDesktopEntered(id: stringId);
609 if (p->plasmaVirtualDesktops.count() == 1) {
610 Q_EMIT p->q->onAllDesktopsChanged();
611 }
612}
613
614void PlasmaWindow::Private::virtualDesktopLeftCallback(void *data, org_kde_plasma_window *window, const char *id)
615{
616 auto p = cast(data);
617 Q_UNUSED(window);
618 const QString stringId(QString::fromUtf8(utf8: id));
619 p->plasmaVirtualDesktops.removeAll(t: stringId);
620 Q_EMIT p->q->plasmaVirtualDesktopLeft(id: stringId);
621 if (p->plasmaVirtualDesktops.isEmpty()) {
622 Q_EMIT p->q->onAllDesktopsChanged();
623 }
624}
625
626void PlasmaWindow::Private::activityEnteredCallback(void *data, org_kde_plasma_window *window, const char *id)
627{
628 auto p = cast(data);
629 Q_UNUSED(window);
630 const QString stringId(QString::fromUtf8(utf8: id));
631 p->plasmaActivities << stringId;
632 Q_EMIT p->q->plasmaActivityEntered(id: stringId);
633}
634
635void PlasmaWindow::Private::activityLeftCallback(void *data, org_kde_plasma_window *window, const char *id)
636{
637 auto p = cast(data);
638 Q_UNUSED(window);
639 const QString stringId(QString::fromUtf8(utf8: id));
640 p->plasmaActivities.removeAll(t: stringId);
641 Q_EMIT p->q->plasmaActivityLeft(id: stringId);
642}
643
644void PlasmaWindow::Private::stateChangedCallback(void *data, org_kde_plasma_window *window, uint32_t state)
645{
646 auto p = cast(data);
647 Q_UNUSED(window);
648 p->setActive(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ACTIVE);
649 p->setMinimized(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED);
650 p->setMaximized(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED);
651 p->setFullscreen(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN);
652 p->setKeepAbove(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE);
653 p->setKeepBelow(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW);
654 p->setOnAllDesktops(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ON_ALL_DESKTOPS);
655 p->setDemandsAttention(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_DEMANDS_ATTENTION);
656 p->setCloseable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_CLOSEABLE);
657 p->setFullscreenable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREENABLE);
658 p->setMaximizeable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZABLE);
659 p->setMinimizeable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZABLE);
660 p->setSkipTaskbar(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPTASKBAR);
661 p->setSkipSwitcher(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPSWITCHER);
662 p->setShadeable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADEABLE);
663 p->setShaded(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED);
664 p->setMovable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MOVABLE);
665 p->setResizable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_RESIZABLE);
666 p->setVirtualDesktopChangeable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_VIRTUAL_DESKTOP_CHANGEABLE);
667}
668
669void PlasmaWindow::Private::themedIconNameChangedCallback(void *data, org_kde_plasma_window *window, const char *name)
670{
671 auto p = cast(data);
672 Q_UNUSED(window);
673 const QString themedName = QString::fromUtf8(utf8: name);
674 if (!themedName.isEmpty()) {
675 QIcon icon = QIcon::fromTheme(name: themedName);
676 p->icon = icon;
677 } else {
678 p->icon = QIcon();
679 }
680 Q_EMIT p->q->iconChanged();
681}
682
683static int readData(int fd, QByteArray &data)
684{
685 // implementation based on QtWayland file qwaylanddataoffer.cpp
686 char buf[4096];
687 int retryCount = 0;
688 int n;
689 while (true) {
690 n = QT_READ(fd: fd, buf: buf, nbytes: sizeof buf);
691 if (n > 0) {
692 data.append(s: buf, len: n);
693 } else if (n == -1 && (errno == EAGAIN) && ++retryCount < 1000) {
694 usleep(useconds: 1000);
695 } else {
696 break;
697 }
698 }
699 return n;
700}
701
702void PlasmaWindow::Private::iconChangedCallback(void *data, org_kde_plasma_window *window)
703{
704 auto p = cast(data);
705 Q_UNUSED(window);
706 int pipeFds[2];
707 if (pipe2(pipedes: pipeFds, O_CLOEXEC | O_NONBLOCK) != 0) {
708 return;
709 }
710 org_kde_plasma_window_get_icon(org_kde_plasma_window: p->window, fd: pipeFds[1]);
711 close(fd: pipeFds[1]);
712 const int pipeFd = pipeFds[0];
713 auto readIcon = [pipeFd]() -> QIcon {
714 QByteArray content;
715 if (readData(fd: pipeFd, data&: content) != 0) {
716 close(fd: pipeFd);
717 return QIcon();
718 }
719 close(fd: pipeFd);
720 QDataStream ds(content);
721 QIcon icon;
722 ds >> icon;
723 return icon;
724 };
725 QFutureWatcher<QIcon> *watcher = new QFutureWatcher<QIcon>(p->q);
726 QObject::connect(sender: watcher, signal: &QFutureWatcher<QIcon>::finished, context: p->q, slot: [p, watcher] {
727 watcher->deleteLater();
728 QIcon icon = watcher->result();
729 if (!icon.isNull()) {
730 p->icon = icon;
731 } else {
732 p->icon = QIcon::fromTheme(QStringLiteral("wayland"));
733 }
734 Q_EMIT p->q->iconChanged();
735 });
736 watcher->setFuture(QtConcurrent::run(f&: readIcon));
737}
738
739void PlasmaWindow::Private::setActive(bool set)
740{
741 if (active == set) {
742 return;
743 }
744 active = set;
745 Q_EMIT q->activeChanged();
746}
747
748void PlasmaWindow::Private::setFullscreen(bool set)
749{
750 if (fullscreen == set) {
751 return;
752 }
753 fullscreen = set;
754 Q_EMIT q->fullscreenChanged();
755}
756
757void PlasmaWindow::Private::setKeepAbove(bool set)
758{
759 if (keepAbove == set) {
760 return;
761 }
762 keepAbove = set;
763 Q_EMIT q->keepAboveChanged();
764}
765
766void PlasmaWindow::Private::setKeepBelow(bool set)
767{
768 if (keepBelow == set) {
769 return;
770 }
771 keepBelow = set;
772 Q_EMIT q->keepBelowChanged();
773}
774
775void PlasmaWindow::Private::setMaximized(bool set)
776{
777 if (maximized == set) {
778 return;
779 }
780 maximized = set;
781 Q_EMIT q->maximizedChanged();
782}
783
784void PlasmaWindow::Private::setMinimized(bool set)
785{
786 if (minimized == set) {
787 return;
788 }
789 minimized = set;
790 Q_EMIT q->minimizedChanged();
791}
792
793void PlasmaWindow::Private::setOnAllDesktops(bool set)
794{
795 if (onAllDesktops == set) {
796 return;
797 }
798 onAllDesktops = set;
799 Q_EMIT q->onAllDesktopsChanged();
800}
801
802void PlasmaWindow::Private::setDemandsAttention(bool set)
803{
804 if (demandsAttention == set) {
805 return;
806 }
807 demandsAttention = set;
808 Q_EMIT q->demandsAttentionChanged();
809}
810
811void PlasmaWindow::Private::setCloseable(bool set)
812{
813 if (closeable == set) {
814 return;
815 }
816 closeable = set;
817 Q_EMIT q->closeableChanged();
818}
819
820void PlasmaWindow::Private::setFullscreenable(bool set)
821{
822 if (fullscreenable == set) {
823 return;
824 }
825 fullscreenable = set;
826 Q_EMIT q->fullscreenableChanged();
827}
828
829void PlasmaWindow::Private::setMaximizeable(bool set)
830{
831 if (maximizeable == set) {
832 return;
833 }
834 maximizeable = set;
835 Q_EMIT q->maximizeableChanged();
836}
837
838void PlasmaWindow::Private::setMinimizeable(bool set)
839{
840 if (minimizeable == set) {
841 return;
842 }
843 minimizeable = set;
844 Q_EMIT q->minimizeableChanged();
845}
846
847void PlasmaWindow::Private::setSkipTaskbar(bool skip)
848{
849 if (skipTaskbar == skip) {
850 return;
851 }
852 skipTaskbar = skip;
853 Q_EMIT q->skipTaskbarChanged();
854}
855
856void PlasmaWindow::Private::setSkipSwitcher(bool skip)
857{
858 if (skipSwitcher == skip) {
859 return;
860 }
861 skipSwitcher = skip;
862 Q_EMIT q->skipSwitcherChanged();
863}
864
865void PlasmaWindow::Private::setShadeable(bool set)
866{
867 if (shadeable == set) {
868 return;
869 }
870 shadeable = set;
871 Q_EMIT q->shadeableChanged();
872}
873
874void PlasmaWindow::Private::setShaded(bool set)
875{
876 if (shaded == set) {
877 return;
878 }
879 shaded = set;
880 Q_EMIT q->shadedChanged();
881}
882
883void PlasmaWindow::Private::setMovable(bool set)
884{
885 if (movable == set) {
886 return;
887 }
888 movable = set;
889 Q_EMIT q->movableChanged();
890}
891
892void PlasmaWindow::Private::setResizable(bool set)
893{
894 if (resizable == set) {
895 return;
896 }
897 resizable = set;
898 Q_EMIT q->resizableChanged();
899}
900
901void PlasmaWindow::Private::setVirtualDesktopChangeable(bool set)
902{
903 if (virtualDesktopChangeable == set) {
904 return;
905 }
906 virtualDesktopChangeable = set;
907 Q_EMIT q->virtualDesktopChangeableChanged();
908}
909
910PlasmaWindow::Private::Private(org_kde_plasma_window *w, quint32 internalId, const char *uuid, PlasmaWindow *q)
911 : internalId(internalId)
912 , uuid(uuid)
913 , q(q)
914{
915 Q_ASSERT(!this->uuid.isEmpty());
916 window.setup(pointer: w);
917 org_kde_plasma_window_add_listener(org_kde_plasma_window: w, listener: &s_listener, data: this);
918}
919
920PlasmaWindow::PlasmaWindow(PlasmaWindowManagement *parent, org_kde_plasma_window *window, quint32 internalId, const char *uuid)
921 : QObject(parent)
922 , d(new Private(window, internalId, uuid, this))
923{
924}
925
926PlasmaWindow::~PlasmaWindow()
927{
928 release();
929}
930
931void PlasmaWindow::destroy()
932{
933 d->window.destroy();
934}
935
936void PlasmaWindow::release()
937{
938 d->window.release();
939}
940
941bool PlasmaWindow::isValid() const
942{
943 return d->window.isValid();
944}
945
946PlasmaWindow::operator org_kde_plasma_window *() const
947{
948 return d->window;
949}
950
951PlasmaWindow::operator org_kde_plasma_window *()
952{
953 return d->window;
954}
955
956QString PlasmaWindow::appId() const
957{
958 return d->appId;
959}
960
961quint32 PlasmaWindow::pid() const
962{
963 return d->pid;
964}
965
966QString PlasmaWindow::resourceName() const
967{
968 return d->resourceName;
969}
970
971QString PlasmaWindow::title() const
972{
973 return d->title;
974}
975
976bool PlasmaWindow::isActive() const
977{
978 return d->active;
979}
980
981bool PlasmaWindow::isFullscreen() const
982{
983 return d->fullscreen;
984}
985
986bool PlasmaWindow::isKeepAbove() const
987{
988 return d->keepAbove;
989}
990
991bool PlasmaWindow::isKeepBelow() const
992{
993 return d->keepBelow;
994}
995
996bool PlasmaWindow::isMaximized() const
997{
998 return d->maximized;
999}
1000
1001bool PlasmaWindow::isMinimized() const
1002{
1003 return d->minimized;
1004}
1005
1006bool PlasmaWindow::isOnAllDesktops() const
1007{
1008 // from protocol version 8 virtual desktops are managed by plasmaVirtualDesktops
1009 if (org_kde_plasma_window_get_version(org_kde_plasma_window: d->window) < 8) {
1010 return d->onAllDesktops;
1011 } else {
1012 return d->plasmaVirtualDesktops.isEmpty();
1013 }
1014}
1015
1016bool PlasmaWindow::isDemandingAttention() const
1017{
1018 return d->demandsAttention;
1019}
1020
1021bool PlasmaWindow::isCloseable() const
1022{
1023 return d->closeable;
1024}
1025
1026bool PlasmaWindow::isFullscreenable() const
1027{
1028 return d->fullscreenable;
1029}
1030
1031bool PlasmaWindow::isMaximizeable() const
1032{
1033 return d->maximizeable;
1034}
1035
1036bool PlasmaWindow::isMinimizeable() const
1037{
1038 return d->minimizeable;
1039}
1040
1041bool PlasmaWindow::skipTaskbar() const
1042{
1043 return d->skipTaskbar;
1044}
1045
1046bool PlasmaWindow::skipSwitcher() const
1047{
1048 return d->skipSwitcher;
1049}
1050
1051QIcon PlasmaWindow::icon() const
1052{
1053 return d->icon;
1054}
1055
1056bool PlasmaWindow::isShadeable() const
1057{
1058 return d->shadeable;
1059}
1060
1061bool PlasmaWindow::isShaded() const
1062{
1063 return d->shaded;
1064}
1065
1066bool PlasmaWindow::isResizable() const
1067{
1068 return d->resizable;
1069}
1070
1071bool PlasmaWindow::isMovable() const
1072{
1073 return d->movable;
1074}
1075
1076bool PlasmaWindow::isVirtualDesktopChangeable() const
1077{
1078 return d->virtualDesktopChangeable;
1079}
1080
1081QString PlasmaWindow::applicationMenuObjectPath() const
1082{
1083 return d->applicationMenuObjectPath;
1084}
1085
1086QString PlasmaWindow::applicationMenuServiceName() const
1087{
1088 return d->applicationMenuServiceName;
1089}
1090
1091void PlasmaWindow::requestActivate()
1092{
1093 org_kde_plasma_window_set_state(org_kde_plasma_window: d->window, flags: ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ACTIVE, state: ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ACTIVE);
1094}
1095
1096void PlasmaWindow::requestClose()
1097{
1098 org_kde_plasma_window_close(org_kde_plasma_window: d->window);
1099}
1100
1101void PlasmaWindow::requestMove()
1102{
1103 org_kde_plasma_window_request_move(org_kde_plasma_window: d->window);
1104}
1105
1106void PlasmaWindow::requestResize()
1107{
1108 org_kde_plasma_window_request_resize(org_kde_plasma_window: d->window);
1109}
1110
1111void PlasmaWindow::requestToggleKeepAbove()
1112{
1113 if (d->keepAbove) {
1114 org_kde_plasma_window_set_state(org_kde_plasma_window: d->window, flags: ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE, state: 0);
1115 } else {
1116 org_kde_plasma_window_set_state(org_kde_plasma_window: d->window, flags: ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE, state: ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE);
1117 }
1118}
1119
1120void PlasmaWindow::requestToggleKeepBelow()
1121{
1122 if (d->keepBelow) {
1123 org_kde_plasma_window_set_state(org_kde_plasma_window: d->window, flags: ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW, state: 0);
1124 } else {
1125 org_kde_plasma_window_set_state(org_kde_plasma_window: d->window, flags: ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW, state: ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW);
1126 }
1127}
1128
1129void PlasmaWindow::requestToggleMinimized()
1130{
1131 if (d->minimized) {
1132 org_kde_plasma_window_set_state(org_kde_plasma_window: d->window, flags: ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED, state: 0);
1133 } else {
1134 org_kde_plasma_window_set_state(org_kde_plasma_window: d->window, flags: ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED, state: ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED);
1135 }
1136}
1137
1138void PlasmaWindow::requestToggleMaximized()
1139{
1140 if (d->maximized) {
1141 org_kde_plasma_window_set_state(org_kde_plasma_window: d->window, flags: ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED, state: 0);
1142 } else {
1143 org_kde_plasma_window_set_state(org_kde_plasma_window: d->window, flags: ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED, state: ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED);
1144 }
1145}
1146
1147void PlasmaWindow::requestToggleFullscreen()
1148{
1149 if (d->fullscreen) {
1150 org_kde_plasma_window_set_state(org_kde_plasma_window: d->window, flags: ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN, state: 0);
1151 } else {
1152 org_kde_plasma_window_set_state(org_kde_plasma_window: d->window, flags: ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN, state: ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN);
1153 }
1154}
1155
1156void PlasmaWindow::setMinimizedGeometry(Surface *panel, const QRect &geom)
1157{
1158 org_kde_plasma_window_set_minimized_geometry(org_kde_plasma_window: d->window, panel: *panel, x: geom.x(), y: geom.y(), width: geom.width(), height: geom.height());
1159}
1160
1161void PlasmaWindow::unsetMinimizedGeometry(Surface *panel)
1162{
1163 org_kde_plasma_window_unset_minimized_geometry(org_kde_plasma_window: d->window, panel: *panel);
1164}
1165
1166void PlasmaWindow::requestToggleShaded()
1167{
1168 if (d->shaded) {
1169 org_kde_plasma_window_set_state(org_kde_plasma_window: d->window, flags: ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED, state: 0);
1170 } else {
1171 org_kde_plasma_window_set_state(org_kde_plasma_window: d->window, flags: ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED, state: ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED);
1172 }
1173}
1174
1175QByteArray PlasmaWindow::uuid() const
1176{
1177 return d->uuid;
1178}
1179
1180QPointer<PlasmaWindow> PlasmaWindow::parentWindow() const
1181{
1182 return d->parentWindow;
1183}
1184
1185QRect PlasmaWindow::geometry() const
1186{
1187 return d->geometry;
1188}
1189
1190void PlasmaWindow::requestEnterVirtualDesktop(const QString &id)
1191{
1192 org_kde_plasma_window_request_enter_virtual_desktop(org_kde_plasma_window: d->window, id: id.toUtf8());
1193}
1194
1195void PlasmaWindow::requestEnterNewVirtualDesktop()
1196{
1197 org_kde_plasma_window_request_enter_new_virtual_desktop(org_kde_plasma_window: d->window);
1198}
1199
1200void PlasmaWindow::requestLeaveVirtualDesktop(const QString &id)
1201{
1202 org_kde_plasma_window_request_leave_virtual_desktop(org_kde_plasma_window: d->window, id: id.toUtf8());
1203}
1204
1205QStringList PlasmaWindow::plasmaVirtualDesktops() const
1206{
1207 return d->plasmaVirtualDesktops;
1208}
1209
1210void PlasmaWindow::requestEnterActivity(const QString &id)
1211{
1212 org_kde_plasma_window_request_enter_activity(org_kde_plasma_window: d->window, id: id.toUtf8());
1213}
1214
1215void PlasmaWindow::requestLeaveActivity(const QString &id)
1216{
1217 org_kde_plasma_window_request_leave_activity(org_kde_plasma_window: d->window, id: id.toUtf8());
1218}
1219
1220QStringList PlasmaWindow::plasmaActivities() const
1221{
1222 return d->plasmaActivities;
1223}
1224
1225void PlasmaWindow::sendToOutput(KWayland::Client::Output *output) const
1226{
1227 if (org_kde_plasma_window_get_version(org_kde_plasma_window: d->window) >= ORG_KDE_PLASMA_WINDOW_SEND_TO_OUTPUT_SINCE_VERSION) {
1228 org_kde_plasma_window_send_to_output(org_kde_plasma_window: d->window, output: *output);
1229 }
1230}
1231
1232class Q_DECL_HIDDEN PlasmaActivationFeedback::Private
1233{
1234public:
1235 Private(PlasmaActivationFeedback *q);
1236 WaylandPointer<org_kde_plasma_activation_feedback, org_kde_plasma_activation_feedback_destroy> feedback;
1237 EventQueue *queue = nullptr;
1238
1239 void setup(org_kde_plasma_activation_feedback *feedback);
1240
1241private:
1242 static void activationCallback(void *data, struct org_kde_plasma_activation_feedback *feedback, struct org_kde_plasma_activation *id);
1243
1244 static struct org_kde_plasma_activation_feedback_listener s_listener;
1245 PlasmaActivationFeedback *q;
1246};
1247
1248PlasmaActivationFeedback::Private::Private(PlasmaActivationFeedback *q)
1249 : q(q)
1250{
1251}
1252
1253org_kde_plasma_activation_feedback_listener PlasmaActivationFeedback::Private::s_listener = {
1254 .activation: activationCallback,
1255};
1256
1257void PlasmaActivationFeedback::Private::activationCallback(void *data, org_kde_plasma_activation_feedback *interface, struct org_kde_plasma_activation *id)
1258{
1259 auto feedbackPrivate = reinterpret_cast<PlasmaActivationFeedback::Private *>(data);
1260 Q_ASSERT(feedbackPrivate->feedback == interface);
1261 auto activation = new PlasmaActivation(feedbackPrivate->q, id);
1262 Q_EMIT feedbackPrivate->q->activation(activation);
1263}
1264
1265void PlasmaActivationFeedback::Private::setup(org_kde_plasma_activation_feedback *m)
1266{
1267 Q_ASSERT(!feedback);
1268 Q_ASSERT(m);
1269 feedback.setup(pointer: m);
1270 org_kde_plasma_activation_feedback_add_listener(org_kde_plasma_activation_feedback: m, listener: &s_listener, data: this);
1271}
1272
1273PlasmaActivationFeedback::PlasmaActivationFeedback(QObject *parent)
1274 : QObject(parent)
1275 , d(new Private(this))
1276{
1277}
1278
1279PlasmaActivationFeedback::~PlasmaActivationFeedback()
1280{
1281 release();
1282}
1283
1284void PlasmaActivationFeedback::destroy()
1285{
1286 if (!d->feedback) {
1287 return;
1288 }
1289 Q_EMIT interfaceAboutToBeDestroyed();
1290 d->feedback.destroy();
1291}
1292
1293void PlasmaActivationFeedback::release()
1294{
1295 if (!d->feedback) {
1296 return;
1297 }
1298 Q_EMIT interfaceAboutToBeReleased();
1299 d->feedback.release();
1300}
1301
1302void PlasmaActivationFeedback::setup(org_kde_plasma_activation_feedback *wm)
1303{
1304 d->setup(wm);
1305}
1306
1307void PlasmaActivationFeedback::setEventQueue(EventQueue *queue)
1308{
1309 d->queue = queue;
1310}
1311
1312EventQueue *PlasmaActivationFeedback::eventQueue()
1313{
1314 return d->queue;
1315}
1316
1317bool PlasmaActivationFeedback::isValid() const
1318{
1319 return d->feedback.isValid();
1320}
1321
1322PlasmaActivationFeedback::operator org_kde_plasma_activation_feedback *()
1323{
1324 return d->feedback;
1325}
1326
1327PlasmaActivationFeedback::operator org_kde_plasma_activation_feedback *() const
1328{
1329 return d->feedback;
1330}
1331
1332class Q_DECL_HIDDEN PlasmaActivation::Private
1333{
1334public:
1335 Private(org_kde_plasma_activation *activation, PlasmaActivation *q)
1336 : activation(activation)
1337 {
1338 org_kde_plasma_activation_add_listener(org_kde_plasma_activation: activation, listener: &s_listener, data: q);
1339 }
1340
1341 static PlasmaActivation *cast(void *data)
1342 {
1343 return reinterpret_cast<PlasmaActivation *>(data);
1344 }
1345 WaylandPointer<org_kde_plasma_activation, org_kde_plasma_activation_destroy> activation;
1346
1347 static org_kde_plasma_activation_listener s_listener;
1348 static void app_idCallback(void *data, struct org_kde_plasma_activation *org_kde_plasma_activation, const char *app_id);
1349 static void finishedCallback(void *data, struct org_kde_plasma_activation *org_kde_plasma_activation);
1350};
1351
1352org_kde_plasma_activation_listener PlasmaActivation::Private::s_listener = {
1353 .app_id: app_idCallback,
1354 .finished: finishedCallback,
1355};
1356
1357void PlasmaActivation::Private::app_idCallback(void *data, org_kde_plasma_activation *activation, const char *appId)
1358{
1359 Q_UNUSED(activation)
1360 Q_EMIT cast(data)->applicationId(appId: QString::fromUtf8(utf8: appId));
1361}
1362
1363void PlasmaActivation::Private::finishedCallback(void *data, org_kde_plasma_activation *)
1364{
1365 auto q = cast(data);
1366 Q_EMIT q->finished();
1367 Q_EMIT q->deleteLater();
1368 q->d->activation.release();
1369}
1370
1371PlasmaActivation::PlasmaActivation(PlasmaActivationFeedback *parent, org_kde_plasma_activation *activation)
1372 : QObject(parent)
1373 , d(new PlasmaActivation::Private(activation, this))
1374{
1375}
1376
1377PlasmaActivation::~PlasmaActivation() = default;
1378
1379QRect PlasmaWindow::clientGeometry() const
1380{
1381 return d->clientGeometry;
1382}
1383
1384void PlasmaWindow::Private::clientGeometryCallback(void *data, org_kde_plasma_window *window, int32_t x, int32_t y, uint32_t width, uint32_t height)
1385{
1386 Q_UNUSED(window)
1387 Private *p = cast(data);
1388 const QRect geo(x, y, width, height);
1389 if (p->clientGeometry == geo) {
1390 return;
1391 }
1392 p->clientGeometry = geo;
1393 Q_EMIT p->q->clientGeometryChanged();
1394}
1395
1396}
1397}
1398
1399#include "plasmawindowmanagement.moc"
1400

source code of kwayland/src/client/plasmawindowmanagement.cpp