KWayland

plasmawindowmanagement.cpp
1 /*
2  SPDX-FileCopyrightText: 2015 Martin Gräßlin <[email protected]>
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 
23 namespace KWayland
24 {
25 namespace Client
26 {
27 class Q_DECL_HIDDEN PlasmaWindowManagement::Private
28 {
29 public:
30  Private(PlasmaWindowManagement *q);
31  WaylandPointer<org_kde_plasma_window_management, org_kde_plasma_window_management_destroy> wm;
32  EventQueue *queue = nullptr;
33  bool showingDesktop = false;
34  QList<PlasmaWindow *> windows;
35  PlasmaWindow *activeWindow = nullptr;
36  QVector<quint32> stackingOrder;
37  QVector<QByteArray> stackingOrderUuids;
38 
39  void setup(org_kde_plasma_window_management *wm);
40 
41 private:
42  static void showDesktopCallback(void *data, org_kde_plasma_window_management *org_kde_plasma_window_management, uint32_t state);
43  static void windowCallback(void *data, org_kde_plasma_window_management *org_kde_plasma_window_management, uint32_t id);
44  static void windowWithUuidCallback(void *data, org_kde_plasma_window_management *org_kde_plasma_window_management, uint32_t id, const char *uuid);
45  static void stackingOrderCallback(void *data, org_kde_plasma_window_management *org_kde_plasma_window_management, wl_array *ids);
46  static void stackingOrderUuidsCallback(void *data, org_kde_plasma_window_management *org_kde_plasma_window_management, const char *uuids);
47  void setShowDesktop(bool set);
48  void windowCreated(org_kde_plasma_window *id, quint32 internalId, const char *uuid);
49  void setStackingOrder(const QVector<quint32> &ids);
50  void setStackingOrder(const QVector<QByteArray> &uuids);
51 
52  static struct org_kde_plasma_window_management_listener s_listener;
53  PlasmaWindowManagement *q;
54 };
55 
56 class Q_DECL_HIDDEN PlasmaWindow::Private
57 {
58 public:
59  Private(org_kde_plasma_window *window, quint32 internalId, const char *uuid, PlasmaWindow *q);
60  WaylandPointer<org_kde_plasma_window, org_kde_plasma_window_destroy> window;
61  quint32 internalId; ///< @deprecated
62  QByteArray uuid;
63  QString title;
64  QString appId;
65  quint32 desktop = 0;
66  bool active = false;
67  bool minimized = false;
68  bool maximized = false;
69  bool fullscreen = false;
70  bool keepAbove = false;
71  bool keepBelow = false;
72  bool onAllDesktops = false;
73  bool demandsAttention = false;
74  bool closeable = false;
75  bool minimizeable = false;
76  bool maximizeable = false;
77  bool fullscreenable = false;
78  bool skipTaskbar = false;
79  bool skipSwitcher = false;
80  bool shadeable = false;
81  bool shaded = false;
82  bool movable = false;
83  bool resizable = false;
84  bool virtualDesktopChangeable = false;
85  QIcon icon;
86  PlasmaWindowManagement *wm = nullptr;
87  bool unmapped = false;
88  QPointer<PlasmaWindow> parentWindow;
89  QMetaObject::Connection parentWindowUnmappedConnection;
90  QStringList plasmaVirtualDesktops;
91  QStringList plasmaActivities;
92  QRect geometry;
93  quint32 pid = 0;
94  QString resourceName;
95  QString applicationMenuServiceName;
96  QString applicationMenuObjectPath;
97 
98 private:
99  static void titleChangedCallback(void *data, org_kde_plasma_window *window, const char *title);
100  static void appIdChangedCallback(void *data, org_kde_plasma_window *window, const char *app_id);
101  static void pidChangedCallback(void *data, org_kde_plasma_window *window, uint32_t pid);
102  static void resourceNameChangedCallback(void *data, org_kde_plasma_window *window, const char *resourceName);
103  static void stateChangedCallback(void *data, org_kde_plasma_window *window, uint32_t state);
104  static void virtualDesktopChangedCallback(void *data, org_kde_plasma_window *window, int32_t number);
105  static void themedIconNameChangedCallback(void *data, org_kde_plasma_window *window, const char *name);
106  static void unmappedCallback(void *data, org_kde_plasma_window *window);
107  static void initialStateCallback(void *data, org_kde_plasma_window *window);
108  static void parentWindowCallback(void *data, org_kde_plasma_window *window, org_kde_plasma_window *parent);
109  static void windowGeometryCallback(void *data, org_kde_plasma_window *window, int32_t x, int32_t y, uint32_t width, uint32_t height);
110  static void iconChangedCallback(void *data, org_kde_plasma_window *org_kde_plasma_window);
111  static void virtualDesktopEnteredCallback(void *data, org_kde_plasma_window *org_kde_plasma_window, const char *id);
112  static void virtualDesktopLeftCallback(void *data, org_kde_plasma_window *org_kde_plasma_window, const char *id);
113  static void appmenuChangedCallback(void *data, org_kde_plasma_window *org_kde_plasma_window, const char *service_name, const char *object_path);
114  static void activityEnteredCallback(void *data, org_kde_plasma_window *org_kde_plasma_window, const char *id);
115  static void activityLeftCallback(void *data, org_kde_plasma_window *org_kde_plasma_window, const char *id);
116  void setActive(bool set);
117  void setMinimized(bool set);
118  void setMaximized(bool set);
119  void setFullscreen(bool set);
120  void setKeepAbove(bool set);
121  void setKeepBelow(bool set);
122  void setOnAllDesktops(bool set);
123  void setDemandsAttention(bool set);
124  void setCloseable(bool set);
125  void setMinimizeable(bool set);
126  void setMaximizeable(bool set);
127  void setFullscreenable(bool set);
128  void setSkipTaskbar(bool skip);
129  void setSkipSwitcher(bool skip);
130  void setShadeable(bool set);
131  void setShaded(bool set);
132  void setMovable(bool set);
133  void setResizable(bool set);
134  void setVirtualDesktopChangeable(bool set);
135  void setParentWindow(PlasmaWindow *parentWindow);
136  void setPid(const quint32 pid);
137 
138  static Private *cast(void *data)
139  {
140  return reinterpret_cast<Private *>(data);
141  }
142 
143  PlasmaWindow *q;
144 
145  static struct org_kde_plasma_window_listener s_listener;
146 };
147 
148 PlasmaWindowManagement::Private::Private(PlasmaWindowManagement *q)
149  : q(q)
150 {
151 }
152 
153 org_kde_plasma_window_management_listener PlasmaWindowManagement::Private::s_listener = {
154  showDesktopCallback,
155  windowCallback,
156  stackingOrderCallback,
157  stackingOrderUuidsCallback,
158  windowWithUuidCallback,
159 };
160 
161 void PlasmaWindowManagement::Private::setup(org_kde_plasma_window_management *windowManagement)
162 {
163  Q_ASSERT(!wm);
164  Q_ASSERT(windowManagement);
165  wm.setup(windowManagement);
166  org_kde_plasma_window_management_add_listener(windowManagement, &s_listener, this);
167 }
168 
169 void PlasmaWindowManagement::Private::showDesktopCallback(void *data, org_kde_plasma_window_management *org_kde_plasma_window_management, uint32_t state)
170 {
171  auto wm = reinterpret_cast<PlasmaWindowManagement::Private *>(data);
172  Q_ASSERT(wm->wm == org_kde_plasma_window_management);
173  switch (state) {
174  case ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_ENABLED:
175  wm->setShowDesktop(true);
176  break;
177  case ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_DISABLED:
178  wm->setShowDesktop(false);
179  break;
180  default:
181  Q_UNREACHABLE();
182  break;
183  }
184 }
185 
186 void PlasmaWindowManagement::Private::setShowDesktop(bool set)
187 {
188  if (showingDesktop == set) {
189  return;
190  }
191  showingDesktop = set;
192  Q_EMIT q->showingDesktopChanged(showingDesktop);
193 }
194 
195 void PlasmaWindowManagement::Private::windowCallback(void *data, org_kde_plasma_window_management *interface, uint32_t id)
196 {
197  auto wm = reinterpret_cast<PlasmaWindowManagement::Private *>(data);
198  Q_ASSERT(wm->wm == interface);
199  QTimer *timer = new QTimer();
200  timer->setSingleShot(true);
201  timer->setInterval(0);
203  timer,
205  wm->q,
206  [timer, wm, id] {
207  wm->windowCreated(org_kde_plasma_window_management_get_window(wm->wm, id), id, "unavailable");
208  timer->deleteLater();
209  },
211  timer->start();
212 }
213 
214 void PlasmaWindowManagement::Private::windowWithUuidCallback(void *data, org_kde_plasma_window_management *interface, uint32_t id, const char *_uuid)
215 {
216  QByteArray uuid(_uuid);
217  auto wm = reinterpret_cast<PlasmaWindowManagement::Private *>(data);
218  Q_ASSERT(wm->wm == interface);
219  QTimer *timer = new QTimer();
220  timer->setSingleShot(true);
221  timer->setInterval(0);
223  timer,
225  wm->q,
226  [timer, wm, id, uuid] {
227  wm->windowCreated(org_kde_plasma_window_management_get_window_by_uuid(wm->wm, uuid), id, uuid);
228  timer->deleteLater();
229  },
231  timer->start();
232 }
233 
234 void PlasmaWindowManagement::Private::windowCreated(org_kde_plasma_window *id, quint32 internalId, const char *uuid)
235 {
236  if (queue) {
237  queue->addProxy(id);
238  }
239  PlasmaWindow *window = new PlasmaWindow(q, id, internalId, uuid);
240  window->d->wm = q;
241  windows << window;
242 
243  const auto windowRemoved = [this, window] {
244  windows.removeAll(window);
245  if (activeWindow == window) {
246  activeWindow = nullptr;
247  Q_EMIT q->activeWindowChanged();
248  }
249  };
250 
251  QObject::connect(window, &QObject::destroyed, q, windowRemoved);
252  // 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
253  // PlasmaWindowManagement::windows().
254  QObject::connect(window, &PlasmaWindow::unmapped, q, windowRemoved);
255  QObject::connect(window, &PlasmaWindow::activeChanged, q, [this, window] {
256  if (window->d->unmapped) {
257  return;
258  }
259  if (window->isActive()) {
260  if (activeWindow == window) {
261  return;
262  }
263  activeWindow = window;
264  Q_EMIT q->activeWindowChanged();
265  } else {
266  if (activeWindow == window) {
267  activeWindow = nullptr;
268  Q_EMIT q->activeWindowChanged();
269  }
270  }
271  });
272 }
273 
274 void PlasmaWindowManagement::Private::stackingOrderCallback(void *data, org_kde_plasma_window_management *interface, wl_array *ids)
275 {
276  // This is no-op since setStackingOrder(const QVector<quint32> &ids) is deprecated since 5.73,
277  // but we can't remove this method because it's needed in
278  // PlasmaWindowManagement::Private::s_listener struct
279 }
280 
281 void PlasmaWindowManagement::Private::stackingOrderUuidsCallback(void *data, org_kde_plasma_window_management *interface, const char *uuids)
282 {
283  auto wm = reinterpret_cast<PlasmaWindowManagement::Private *>(data);
284  Q_ASSERT(wm->wm == interface);
285  wm->setStackingOrder(QByteArray(uuids).split(';').toVector());
286 }
287 
288 void PlasmaWindowManagement::Private::setStackingOrder(const QVector<QByteArray> &uuids)
289 {
290  if (stackingOrderUuids == uuids) {
291  return;
292  }
293  stackingOrderUuids = uuids;
294  Q_EMIT q->stackingOrderUuidsChanged();
295 }
296 
297 PlasmaWindowManagement::PlasmaWindowManagement(QObject *parent)
298  : QObject(parent)
299  , d(new Private(this))
300 {
301 }
302 
303 PlasmaWindowManagement::~PlasmaWindowManagement()
304 {
305  release();
306 }
307 
309 {
310  if (!d->wm) {
311  return;
312  }
314  d->wm.destroy();
315 }
316 
318 {
319  if (!d->wm) {
320  return;
321  }
323  d->wm.release();
324 }
325 
326 void PlasmaWindowManagement::setup(org_kde_plasma_window_management *wm)
327 {
328  d->setup(wm);
329 }
330 
332 {
333  d->queue = queue;
334 }
335 
337 {
338  return d->queue;
339 }
340 
342 {
343  return d->wm.isValid();
344 }
345 
346 PlasmaWindowManagement::operator org_kde_plasma_window_management *()
347 {
348  return d->wm;
349 }
350 
351 PlasmaWindowManagement::operator org_kde_plasma_window_management *() const
352 {
353  return d->wm;
354 }
355 
357 {
358  setShowingDesktop(false);
359 }
360 
362 {
363  setShowingDesktop(true);
364 }
365 
367 {
368  org_kde_plasma_window_management_show_desktop(d->wm,
369  show ? ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_ENABLED
370  : ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_DISABLED);
371 }
372 
374 {
375  return d->showingDesktop;
376 }
377 
379 {
380  return d->windows;
381 }
382 
384 {
385  return d->activeWindow;
386 }
387 
389 {
390  return new PlasmaWindowModel(this);
391 }
392 
394 {
395  return d->stackingOrderUuids;
396 }
397 
398 org_kde_plasma_window_listener PlasmaWindow::Private::s_listener = {
399  titleChangedCallback,
400  appIdChangedCallback,
401  stateChangedCallback,
402  virtualDesktopChangedCallback,
403  themedIconNameChangedCallback,
404  unmappedCallback,
405  initialStateCallback,
406  parentWindowCallback,
407  windowGeometryCallback,
408  iconChangedCallback,
409  pidChangedCallback,
410  virtualDesktopEnteredCallback,
411  virtualDesktopLeftCallback,
412  appmenuChangedCallback,
413  activityEnteredCallback,
414  activityLeftCallback,
415  resourceNameChangedCallback,
416 };
417 
418 void PlasmaWindow::Private::appmenuChangedCallback(void *data, org_kde_plasma_window *window, const char *service_name, const char *object_path)
419 {
420  Q_UNUSED(window)
421 
422  Private *p = cast(data);
423 
424  p->applicationMenuServiceName = QString::fromUtf8(service_name);
425  p->applicationMenuObjectPath = QString::fromUtf8(object_path);
426 
427  Q_EMIT p->q->applicationMenuChanged();
428 }
429 
430 void PlasmaWindow::Private::parentWindowCallback(void *data, org_kde_plasma_window *window, org_kde_plasma_window *parent)
431 {
432  Q_UNUSED(window)
433  Private *p = cast(data);
434  const auto windows = p->wm->windows();
435  auto it = std::find_if(windows.constBegin(), windows.constEnd(), [parent](const PlasmaWindow *w) {
436  return *w == parent;
437  });
438  p->setParentWindow(it != windows.constEnd() ? *it : nullptr);
439 }
440 
441 void PlasmaWindow::Private::windowGeometryCallback(void *data, org_kde_plasma_window *window, int32_t x, int32_t y, uint32_t width, uint32_t height)
442 {
443  Q_UNUSED(window)
444  Private *p = cast(data);
445  QRect geo(x, y, width, height);
446  if (geo == p->geometry) {
447  return;
448  }
449  p->geometry = geo;
450  Q_EMIT p->q->geometryChanged();
451 }
452 
453 void PlasmaWindow::Private::setParentWindow(PlasmaWindow *parent)
454 {
455  const auto old = parentWindow;
456  QObject::disconnect(parentWindowUnmappedConnection);
457  if (parent && !parent->d->unmapped) {
458  parentWindow = QPointer<PlasmaWindow>(parent);
459  parentWindowUnmappedConnection = QObject::connect(parent, &PlasmaWindow::unmapped, q, [this] {
460  setParentWindow(nullptr);
461  });
462  } else {
463  parentWindow = QPointer<PlasmaWindow>();
464  parentWindowUnmappedConnection = QMetaObject::Connection();
465  }
466  if (parentWindow.data() != old.data()) {
467  Q_EMIT q->parentWindowChanged();
468  }
469 }
470 
471 void PlasmaWindow::Private::initialStateCallback(void *data, org_kde_plasma_window *window)
472 {
473  Q_UNUSED(window)
474  Private *p = cast(data);
475  if (!p->unmapped) {
476  Q_EMIT p->wm->windowCreated(p->q);
477  }
478 }
479 
480 void PlasmaWindow::Private::titleChangedCallback(void *data, org_kde_plasma_window *window, const char *title)
481 {
482  Q_UNUSED(window)
483  Private *p = cast(data);
484  const QString t = QString::fromUtf8(title);
485  if (p->title == t) {
486  return;
487  }
488  p->title = t;
489  Q_EMIT p->q->titleChanged();
490 }
491 
492 void PlasmaWindow::Private::appIdChangedCallback(void *data, org_kde_plasma_window *window, const char *appId)
493 {
494  Q_UNUSED(window)
495  Private *p = cast(data);
496  const QString s = QString::fromUtf8(appId);
497  if (s == p->appId) {
498  return;
499  }
500  p->appId = s;
501  Q_EMIT p->q->appIdChanged();
502 }
503 
504 void PlasmaWindow::Private::pidChangedCallback(void *data, org_kde_plasma_window *window, uint32_t pid)
505 {
506  Q_UNUSED(window)
507  Private *p = cast(data);
508  if (p->pid == static_cast<quint32>(pid)) {
509  return;
510  }
511  p->pid = pid;
512 }
513 
514 void PlasmaWindow::Private::resourceNameChangedCallback(void *data, org_kde_plasma_window *window, const char *resourceName)
515 {
516  Q_UNUSED(window)
517  Private *p = cast(data);
518  const QString s = QString::fromUtf8(resourceName);
519  if (s == p->resourceName) {
520  return;
521  }
522  p->resourceName = s;
523  Q_EMIT p->q->resourceNameChanged();
524 }
525 
526 void PlasmaWindow::Private::virtualDesktopChangedCallback([[maybe_unused]] void *data,
527  [[maybe_unused]] org_kde_plasma_window *window,
528  [[maybe_unused]] int32_t number)
529 {
530  // Can't remove this method as it's used in PlasmaWindow::Private::s_listener struct
531 }
532 
533 void PlasmaWindow::Private::unmappedCallback(void *data, org_kde_plasma_window *window)
534 {
535  auto p = cast(data);
536  Q_UNUSED(window);
537  p->unmapped = true;
538  Q_EMIT p->q->unmapped();
539  p->q->deleteLater();
540 }
541 
542 void PlasmaWindow::Private::virtualDesktopEnteredCallback(void *data, org_kde_plasma_window *window, const char *id)
543 {
544  auto p = cast(data);
545  Q_UNUSED(window);
546  const QString stringId(QString::fromUtf8(id));
547  p->plasmaVirtualDesktops << stringId;
548  Q_EMIT p->q->plasmaVirtualDesktopEntered(stringId);
549  if (p->plasmaVirtualDesktops.count() == 1) {
550  Q_EMIT p->q->onAllDesktopsChanged();
551  }
552 }
553 
554 void PlasmaWindow::Private::virtualDesktopLeftCallback(void *data, org_kde_plasma_window *window, const char *id)
555 {
556  auto p = cast(data);
557  Q_UNUSED(window);
558  const QString stringId(QString::fromUtf8(id));
559  p->plasmaVirtualDesktops.removeAll(stringId);
560  Q_EMIT p->q->plasmaVirtualDesktopLeft(stringId);
561  if (p->plasmaVirtualDesktops.isEmpty()) {
562  Q_EMIT p->q->onAllDesktopsChanged();
563  }
564 }
565 
566 void PlasmaWindow::Private::activityEnteredCallback(void *data, org_kde_plasma_window *window, const char *id)
567 {
568  auto p = cast(data);
569  Q_UNUSED(window);
570  const QString stringId(QString::fromUtf8(id));
571  p->plasmaActivities << stringId;
572  Q_EMIT p->q->plasmaActivityEntered(stringId);
573 }
574 
575 void PlasmaWindow::Private::activityLeftCallback(void *data, org_kde_plasma_window *window, const char *id)
576 {
577  auto p = cast(data);
578  Q_UNUSED(window);
579  const QString stringId(QString::fromUtf8(id));
580  p->plasmaActivities.removeAll(stringId);
581  Q_EMIT p->q->plasmaActivityLeft(stringId);
582 }
583 
584 void PlasmaWindow::Private::stateChangedCallback(void *data, org_kde_plasma_window *window, uint32_t state)
585 {
586  auto p = cast(data);
587  Q_UNUSED(window);
588  p->setActive(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ACTIVE);
589  p->setMinimized(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED);
590  p->setMaximized(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED);
591  p->setFullscreen(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN);
592  p->setKeepAbove(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE);
593  p->setKeepBelow(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW);
594  p->setOnAllDesktops(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ON_ALL_DESKTOPS);
595  p->setDemandsAttention(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_DEMANDS_ATTENTION);
596  p->setCloseable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_CLOSEABLE);
597  p->setFullscreenable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREENABLE);
598  p->setMaximizeable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZABLE);
599  p->setMinimizeable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZABLE);
600  p->setSkipTaskbar(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPTASKBAR);
601  p->setSkipSwitcher(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPSWITCHER);
602  p->setShadeable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADEABLE);
603  p->setShaded(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED);
604  p->setMovable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MOVABLE);
605  p->setResizable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_RESIZABLE);
606  p->setVirtualDesktopChangeable(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_VIRTUAL_DESKTOP_CHANGEABLE);
607 }
608 
609 void PlasmaWindow::Private::themedIconNameChangedCallback(void *data, org_kde_plasma_window *window, const char *name)
610 {
611  auto p = cast(data);
612  Q_UNUSED(window);
613  const QString themedName = QString::fromUtf8(name);
614  if (!themedName.isEmpty()) {
615  QIcon icon = QIcon::fromTheme(themedName);
616  p->icon = icon;
617  } else {
618  p->icon = QIcon();
619  }
620  Q_EMIT p->q->iconChanged();
621 }
622 
623 static int readData(int fd, QByteArray &data)
624 {
625  // implementation based on QtWayland file qwaylanddataoffer.cpp
626  char buf[4096];
627  int retryCount = 0;
628  int n;
629  while (true) {
630  n = QT_READ(fd, buf, sizeof buf);
631  if (n > 0) {
632  data.append(buf, n);
633  } else if (n == -1 && (errno == EAGAIN) && ++retryCount < 1000) {
634  usleep(1000);
635  } else {
636  break;
637  }
638  }
639  return n;
640 }
641 
642 void PlasmaWindow::Private::iconChangedCallback(void *data, org_kde_plasma_window *window)
643 {
644  auto p = cast(data);
645  Q_UNUSED(window);
646  int pipeFds[2];
647  if (pipe2(pipeFds, O_CLOEXEC | O_NONBLOCK) != 0) {
648  return;
649  }
650  org_kde_plasma_window_get_icon(p->window, pipeFds[1]);
651  close(pipeFds[1]);
652  const int pipeFd = pipeFds[0];
653  auto readIcon = [pipeFd]() -> QIcon {
654  QByteArray content;
655  if (readData(pipeFd, content) != 0) {
656  close(pipeFd);
657  return QIcon();
658  }
659  close(pipeFd);
660  QDataStream ds(content);
661  QIcon icon;
662  ds >> icon;
663  return icon;
664  };
665  QFutureWatcher<QIcon> *watcher = new QFutureWatcher<QIcon>(p->q);
666  QObject::connect(watcher, &QFutureWatcher<QIcon>::finished, p->q, [p, watcher] {
667  watcher->deleteLater();
668  QIcon icon = watcher->result();
669  if (!icon.isNull()) {
670  p->icon = icon;
671  } else {
672  p->icon = QIcon::fromTheme(QStringLiteral("wayland"));
673  }
674  Q_EMIT p->q->iconChanged();
675  });
676  watcher->setFuture(QtConcurrent::run(readIcon));
677 }
678 
679 void PlasmaWindow::Private::setActive(bool set)
680 {
681  if (active == set) {
682  return;
683  }
684  active = set;
685  Q_EMIT q->activeChanged();
686 }
687 
688 void PlasmaWindow::Private::setFullscreen(bool set)
689 {
690  if (fullscreen == set) {
691  return;
692  }
693  fullscreen = set;
694  Q_EMIT q->fullscreenChanged();
695 }
696 
697 void PlasmaWindow::Private::setKeepAbove(bool set)
698 {
699  if (keepAbove == set) {
700  return;
701  }
702  keepAbove = set;
703  Q_EMIT q->keepAboveChanged();
704 }
705 
706 void PlasmaWindow::Private::setKeepBelow(bool set)
707 {
708  if (keepBelow == set) {
709  return;
710  }
711  keepBelow = set;
712  Q_EMIT q->keepBelowChanged();
713 }
714 
715 void PlasmaWindow::Private::setMaximized(bool set)
716 {
717  if (maximized == set) {
718  return;
719  }
720  maximized = set;
721  Q_EMIT q->maximizedChanged();
722 }
723 
724 void PlasmaWindow::Private::setMinimized(bool set)
725 {
726  if (minimized == set) {
727  return;
728  }
729  minimized = set;
730  Q_EMIT q->minimizedChanged();
731 }
732 
733 void PlasmaWindow::Private::setOnAllDesktops(bool set)
734 {
735  if (onAllDesktops == set) {
736  return;
737  }
738  onAllDesktops = set;
739  Q_EMIT q->onAllDesktopsChanged();
740 }
741 
742 void PlasmaWindow::Private::setDemandsAttention(bool set)
743 {
744  if (demandsAttention == set) {
745  return;
746  }
747  demandsAttention = set;
748  Q_EMIT q->demandsAttentionChanged();
749 }
750 
751 void PlasmaWindow::Private::setCloseable(bool set)
752 {
753  if (closeable == set) {
754  return;
755  }
756  closeable = set;
757  Q_EMIT q->closeableChanged();
758 }
759 
760 void PlasmaWindow::Private::setFullscreenable(bool set)
761 {
762  if (fullscreenable == set) {
763  return;
764  }
765  fullscreenable = set;
766  Q_EMIT q->fullscreenableChanged();
767 }
768 
769 void PlasmaWindow::Private::setMaximizeable(bool set)
770 {
771  if (maximizeable == set) {
772  return;
773  }
774  maximizeable = set;
775  Q_EMIT q->maximizeableChanged();
776 }
777 
778 void PlasmaWindow::Private::setMinimizeable(bool set)
779 {
780  if (minimizeable == set) {
781  return;
782  }
783  minimizeable = set;
784  Q_EMIT q->minimizeableChanged();
785 }
786 
787 void PlasmaWindow::Private::setSkipTaskbar(bool skip)
788 {
789  if (skipTaskbar == skip) {
790  return;
791  }
792  skipTaskbar = skip;
793  Q_EMIT q->skipTaskbarChanged();
794 }
795 
796 void PlasmaWindow::Private::setSkipSwitcher(bool skip)
797 {
798  if (skipSwitcher == skip) {
799  return;
800  }
801  skipSwitcher = skip;
802  Q_EMIT q->skipSwitcherChanged();
803 }
804 
805 void PlasmaWindow::Private::setShadeable(bool set)
806 {
807  if (shadeable == set) {
808  return;
809  }
810  shadeable = set;
811  Q_EMIT q->shadeableChanged();
812 }
813 
814 void PlasmaWindow::Private::setShaded(bool set)
815 {
816  if (shaded == set) {
817  return;
818  }
819  shaded = set;
820  Q_EMIT q->shadedChanged();
821 }
822 
823 void PlasmaWindow::Private::setMovable(bool set)
824 {
825  if (movable == set) {
826  return;
827  }
828  movable = set;
829  Q_EMIT q->movableChanged();
830 }
831 
832 void PlasmaWindow::Private::setResizable(bool set)
833 {
834  if (resizable == set) {
835  return;
836  }
837  resizable = set;
838  Q_EMIT q->resizableChanged();
839 }
840 
841 void PlasmaWindow::Private::setVirtualDesktopChangeable(bool set)
842 {
843  if (virtualDesktopChangeable == set) {
844  return;
845  }
846  virtualDesktopChangeable = set;
847  Q_EMIT q->virtualDesktopChangeableChanged();
848 }
849 
850 PlasmaWindow::Private::Private(org_kde_plasma_window *w, quint32 internalId, const char *uuid, PlasmaWindow *q)
851  : internalId(internalId)
852  , uuid(uuid)
853  , q(q)
854 {
855  Q_ASSERT(!this->uuid.isEmpty());
856  window.setup(w);
857  org_kde_plasma_window_add_listener(w, &s_listener, this);
858 }
859 
860 PlasmaWindow::PlasmaWindow(PlasmaWindowManagement *parent, org_kde_plasma_window *window, quint32 internalId, const char *uuid)
861  : QObject(parent)
862  , d(new Private(window, internalId, uuid, this))
863 {
864 }
865 
866 PlasmaWindow::~PlasmaWindow()
867 {
868  release();
869 }
870 
872 {
873  d->window.destroy();
874 }
875 
877 {
878  d->window.release();
879 }
880 
882 {
883  return d->window.isValid();
884 }
885 
886 PlasmaWindow::operator org_kde_plasma_window *() const
887 {
888  return d->window;
889 }
890 
891 PlasmaWindow::operator org_kde_plasma_window *()
892 {
893  return d->window;
894 }
895 
897 {
898  return d->appId;
899 }
900 
901 quint32 PlasmaWindow::pid() const
902 {
903  return d->pid;
904 }
905 
907 {
908  return d->resourceName;
909 }
910 
912 {
913  return d->title;
914 }
915 
917 {
918  return d->active;
919 }
920 
922 {
923  return d->fullscreen;
924 }
925 
927 {
928  return d->keepAbove;
929 }
930 
932 {
933  return d->keepBelow;
934 }
935 
937 {
938  return d->maximized;
939 }
940 
942 {
943  return d->minimized;
944 }
945 
947 {
948  // from protocol version 8 virtual desktops are managed by plasmaVirtualDesktops
949  if (org_kde_plasma_window_get_version(d->window) < 8) {
950  return d->onAllDesktops;
951  } else {
952  return d->plasmaVirtualDesktops.isEmpty();
953  }
954 }
955 
957 {
958  return d->demandsAttention;
959 }
960 
962 {
963  return d->closeable;
964 }
965 
967 {
968  return d->fullscreenable;
969 }
970 
972 {
973  return d->maximizeable;
974 }
975 
977 {
978  return d->minimizeable;
979 }
980 
982 {
983  return d->skipTaskbar;
984 }
985 
987 {
988  return d->skipSwitcher;
989 }
990 
992 {
993  return d->icon;
994 }
995 
997 {
998  return d->shadeable;
999 }
1000 
1002 {
1003  return d->shaded;
1004 }
1005 
1007 {
1008  return d->resizable;
1009 }
1010 
1012 {
1013  return d->movable;
1014 }
1015 
1017 {
1018  return d->virtualDesktopChangeable;
1019 }
1020 
1022 {
1023  return d->applicationMenuObjectPath;
1024 }
1025 
1027 {
1028  return d->applicationMenuServiceName;
1029 }
1030 
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 
1037 {
1038  org_kde_plasma_window_close(d->window);
1039 }
1040 
1042 {
1043  org_kde_plasma_window_request_move(d->window);
1044 }
1045 
1047 {
1048  org_kde_plasma_window_request_resize(d->window);
1049 }
1050 
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 
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 
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 
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 
1088 {
1089  org_kde_plasma_window_set_minimized_geometry(d->window, *panel, geom.x(), geom.y(), geom.width(), geom.height());
1090 }
1091 
1093 {
1094  org_kde_plasma_window_unset_minimized_geometry(d->window, *panel);
1095 }
1096 
1098 {
1099  if (d->shaded) {
1100  org_kde_plasma_window_set_state(d->window, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED, 0);
1101  } else {
1102  org_kde_plasma_window_set_state(d->window, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED);
1103  }
1104 }
1105 
1107 {
1108  return d->uuid;
1109 }
1110 
1112 {
1113  return d->parentWindow;
1114 }
1115 
1117 {
1118  return d->geometry;
1119 }
1120 
1122 {
1123  org_kde_plasma_window_request_enter_virtual_desktop(d->window, id.toUtf8());
1124 }
1125 
1127 {
1128  org_kde_plasma_window_request_enter_new_virtual_desktop(d->window);
1129 }
1130 
1132 {
1133  org_kde_plasma_window_request_leave_virtual_desktop(d->window, id.toUtf8());
1134 }
1135 
1137 {
1138  return d->plasmaVirtualDesktops;
1139 }
1140 
1142 {
1143  org_kde_plasma_window_request_enter_activity(d->window, id.toUtf8());
1144 }
1145 
1147 {
1148  org_kde_plasma_window_request_leave_activity(d->window, id.toUtf8());
1149 }
1150 
1152 {
1153  return d->plasmaActivities;
1154 }
1155 
1157 {
1158  if (org_kde_plasma_window_get_version(d->window) >= ORG_KDE_PLASMA_WINDOW_SEND_TO_OUTPUT_SINCE_VERSION) {
1159  org_kde_plasma_window_send_to_output(d->window, *output);
1160  }
1161 }
1162 
1163 class Q_DECL_HIDDEN PlasmaActivationFeedback::Private
1164 {
1165 public:
1166  Private(PlasmaActivationFeedback *q);
1167  WaylandPointer<org_kde_plasma_activation_feedback, org_kde_plasma_activation_feedback_destroy> feedback;
1168  EventQueue *queue = nullptr;
1169 
1170  void setup(org_kde_plasma_activation_feedback *feedback);
1171 
1172 private:
1173  static void activationCallback(void *data, struct org_kde_plasma_activation_feedback *feedback, struct org_kde_plasma_activation *id);
1174 
1175  static struct org_kde_plasma_activation_feedback_listener s_listener;
1177 };
1178 
1179 PlasmaActivationFeedback::Private::Private(PlasmaActivationFeedback *q)
1180  : q(q)
1181 {
1182 }
1183 
1184 org_kde_plasma_activation_feedback_listener PlasmaActivationFeedback::Private::s_listener = {
1185  activationCallback,
1186 };
1187 
1188 void PlasmaActivationFeedback::Private::activationCallback(void *data, org_kde_plasma_activation_feedback *interface, struct org_kde_plasma_activation *id)
1189 {
1190  auto feedbackPrivate = reinterpret_cast<PlasmaActivationFeedback::Private *>(data);
1191  Q_ASSERT(feedbackPrivate->feedback == interface);
1192  auto activation = new PlasmaActivation(feedbackPrivate->q, id);
1193  Q_EMIT feedbackPrivate->q->activation(activation);
1194 }
1195 
1196 void PlasmaActivationFeedback::Private::setup(org_kde_plasma_activation_feedback *m)
1197 {
1198  Q_ASSERT(!feedback);
1199  Q_ASSERT(m);
1200  feedback.setup(m);
1201  org_kde_plasma_activation_feedback_add_listener(m, &s_listener, this);
1202 }
1203 
1204 PlasmaActivationFeedback::PlasmaActivationFeedback(QObject *parent)
1205  : QObject(parent)
1206  , d(new Private(this))
1207 {
1208 }
1209 
1210 PlasmaActivationFeedback::~PlasmaActivationFeedback()
1211 {
1212  release();
1213 }
1214 
1216 {
1217  if (!d->feedback) {
1218  return;
1219  }
1221  d->feedback.destroy();
1222 }
1223 
1225 {
1226  if (!d->feedback) {
1227  return;
1228  }
1230  d->feedback.release();
1231 }
1232 
1233 void PlasmaActivationFeedback::setup(org_kde_plasma_activation_feedback *wm)
1234 {
1235  d->setup(wm);
1236 }
1237 
1239 {
1240  d->queue = queue;
1241 }
1242 
1244 {
1245  return d->queue;
1246 }
1247 
1249 {
1250  return d->feedback.isValid();
1251 }
1252 
1253 PlasmaActivationFeedback::operator org_kde_plasma_activation_feedback *()
1254 {
1255  return d->feedback;
1256 }
1257 
1258 PlasmaActivationFeedback::operator org_kde_plasma_activation_feedback *() const
1259 {
1260  return d->feedback;
1261 }
1262 
1263 class Q_DECL_HIDDEN PlasmaActivation::Private
1264 {
1265 public:
1266  Private(org_kde_plasma_activation *activation, PlasmaActivation *q)
1267  : activation(activation)
1268  {
1269  org_kde_plasma_activation_add_listener(activation, &s_listener, q);
1270  }
1271 
1272  static PlasmaActivation *cast(void *data)
1273  {
1274  return reinterpret_cast<PlasmaActivation *>(data);
1275  }
1276  WaylandPointer<org_kde_plasma_activation, org_kde_plasma_activation_destroy> activation;
1277 
1278  static org_kde_plasma_activation_listener s_listener;
1279  static void app_idCallback(void *data, struct org_kde_plasma_activation *org_kde_plasma_activation, const char *app_id);
1280  static void finishedCallback(void *data, struct org_kde_plasma_activation *org_kde_plasma_activation);
1281 };
1282 
1283 org_kde_plasma_activation_listener PlasmaActivation::Private::s_listener = {
1284  app_idCallback,
1285  finishedCallback,
1286 };
1287 
1288 void PlasmaActivation::Private::app_idCallback(void *data, org_kde_plasma_activation *activation, const char *appId)
1289 {
1290  Q_UNUSED(activation)
1291  Q_EMIT cast(data)->applicationId(QString::fromUtf8(appId));
1292 }
1293 
1294 void PlasmaActivation::Private::finishedCallback(void *data, org_kde_plasma_activation *)
1295 {
1296  auto q = cast(data);
1297  Q_EMIT q->finished();
1298  Q_EMIT q->deleteLater();
1299  q->d->activation.release();
1300 }
1301 
1302 PlasmaActivation::PlasmaActivation(PlasmaActivationFeedback *parent, org_kde_plasma_activation *activation)
1303  : QObject(parent)
1304  , d(new PlasmaActivation::Private(activation, this))
1305 {
1306 }
1307 
1308 PlasmaActivation::~PlasmaActivation() = default;
1309 }
1310 }
void setShowingDesktop(bool show)
Requests to change the showing desktop state to show.
void setEventQueue(EventQueue *queue)
Sets the queue to use for creating a PlasmaActivationFeedback.
void requestEnterNewVirtualDesktop()
Make the window enter a new virtual desktop.
QStringList plasmaVirtualDesktops() const
Return all the virtual desktop ids this window is associated to.
QFuture< T > run(Function function,...)
void requestClose()
Requests to close the window.
QPointer< PlasmaWindow > parentWindow() const
The parent window of this PlasmaWindow.
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
Wrapper for the wl_output interface.
Definition: output.h:54
QString fromUtf8(const char *str, int size)
void interfaceAboutToBeReleased()
This signal is emitted right before the interface is released.
void requestToggleKeepAbove()
Requests the window at this model row index have its keep above state toggled.
Q_EMITQ_EMIT
QByteArray & append(char ch)
Wrapper for the wl_surface interface.
Definition: surface.h:43
void setSingleShot(bool singleShot)
void sendToOutput(KWayland::Client::Output *output) const
Sends the current window to output.
void destroy()
Destroys the data held by this PlasmaActivationFeedback.
QIcon fromTheme(const QString &name)
int width() const const
PlasmaWindowModel * createWindowModel()
Factory method to create a PlasmaWindowModel.
int x() const const
int y() const const
Exposes the window list and window state as a Qt item model.
void setup(org_kde_plasma_window_management *shell)
Setup this Shell to manage the shell.
void requestLeaveVirtualDesktop(const QString &id)
Ask the server to make the window the window exit a virtual desktop.
const QList< QKeySequence > & close()
QString applicationMenuServiceName() const
Return the D-BUS service name for a window's application menu.
void requestEnterVirtualDesktop(const QString &id)
Ask the server to make the window enter a virtual desktop.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString applicationMenuObjectPath() const
Return the D-BUS object path to a windows's application menu.
void destroyed(QObject *obj)
void requestResize()
Requests to start an interactive resize operation.
void start(int msec)
Wrapper class for wl_event_queue interface.
Definition: event_queue.h:54
bool isShowingDesktop() const
Whether the system is currently showing the desktop.
QByteArray uuid() const
A unique identifier for the window.
void timeout()
bool isEmpty() const const
void setEventQueue(EventQueue *queue)
Sets the queue to use for creating a Surface.
void setup(org_kde_plasma_activation_feedback *manager)
Setup this PlasmaActivationFeedback to manage the manager.
QueuedConnection
void unsetMinimizedGeometry(Surface *panel)
Remove the task geometry information for a particular panel.
void destroy()
Destroys the data held by this PlasmaWindowManagement.
void interfaceAboutToBeDestroyed()
This signal is emitted right before the data is destroyed.
GeoCoordinates geo(const QVariant &location)
void requestEnterActivity(const QString &id)
Ask the server to make the window enter an activity.
void setMinimizedGeometry(Surface *panel, const QRect &geom)
Sets the geometry of the taskbar entry for this window relative to a panel in particular.
Wrapper for the org_kde_plasma_window interface.
void destroy()
Destroys the data held by this PlasmaWindow.
void interfaceAboutToBeDestroyed()
This signal is emitted right before the data is destroyed.
void setFuture(const QFuture< T > &future)
int height() const const
QStringList plasmaActivities() const
Return all the activity ids this window is associated to.
void showDesktop()
Same as calling setShowingDesktop with true.
void activeChanged()
The window became active or inactive.
void release()
Releases the org_kde_plasma_window_management interface.
void unmapped()
The window got unmapped and is no longer available to the Wayland server.
void release()
Releases the org_kde_plasma_window interface.
void requestToggleMinimized()
Requests the window at this model row index have its minimized state toggled.
void requestToggleShaded()
Requests the window at this model row index have its shaded state toggled.
void requestMove()
Requests to start an interactive window move operation.
KJOBWIDGETS_EXPORT QWidget * window(KJob *job)
void setInterval(int msec)
void interfaceAboutToBeReleased()
This signal is emitted right before the interface is released.
void requestToggleKeepBelow()
Requests the window at this model row index have its keep below state toggled.
void requestActivate()
Requests to activate the window.
void release()
Releases the org_kde_plasma_activation_feedback interface.
void hideDesktop()
Same as calling setShowingDesktop with false.
void requestToggleMaximized()
Requests the window at this model row index have its maximized state toggled.
QVector< QByteArray > stackingOrderUuids() const
void requestLeaveActivity(const QString &id)
Ask the server to make the window exit an activity.
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Jun 4 2023 03:50:51 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.