KWayland

plasmawindowmanagement_interface.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_interface.h"
7 #include "display.h"
8 #include "global_p.h"
9 #include "plasmavirtualdesktop_interface.h"
10 #include "resource_p.h"
11 #include "surface_interface.h"
12 
13 #include <QFile>
14 #include <QHash>
15 #include <QIcon>
16 #include <QList>
17 #include <QRect>
18 #include <QVector>
19 #include <QtConcurrentRun>
20 
21 #include <wayland-plasma-window-management-server-protocol.h>
22 #include <wayland-server.h>
23 
24 namespace KWayland
25 {
26 namespace Server
27 {
28 class PlasmaWindowManagementInterface::Private : public Global::Private
29 {
30 public:
31  Private(PlasmaWindowManagementInterface *q, Display *d);
32  void sendShowingDesktopState();
33  void sendStackingOrderChanged();
34 
35  ShowingDesktopState state = ShowingDesktopState::Disabled;
36  QVector<wl_resource *> resources;
39  quint32 windowIdCounter = 0;
40  QVector<quint32> stackingOrder;
41 
42 private:
43  static void unbind(wl_resource *resource);
44  static void showDesktopCallback(wl_client *client, wl_resource *resource, uint32_t state);
45  static void getWindowCallback(wl_client *client, wl_resource *resource, uint32_t id, uint32_t internalWindowId);
46  static void getWindowByUuidCallback(wl_client *client, wl_resource *resource, uint32_t id, const char *uuid);
47 
48  void bind(wl_client *client, uint32_t version, uint32_t id) override;
49  void sendShowingDesktopState(wl_resource *r);
50  void sendStackingOrderChanged(wl_resource *r);
51 
52  PlasmaWindowManagementInterface *q;
53  static const struct org_kde_plasma_window_management_interface s_interface;
54  static const quint32 s_version;
55 };
56 
57 class PlasmaWindowInterface::Private
58 {
59 public:
60  Private(PlasmaWindowManagementInterface *wm, PlasmaWindowInterface *q);
61  ~Private();
62 
63  void createResource(wl_resource *parent, uint32_t id);
64  void setTitle(const QString &title);
65  void setAppId(const QString &appId);
66  void setPid(quint32 pid);
67  void setThemedIconName(const QString &iconName);
68  void setIcon(const QIcon &icon);
69  void setVirtualDesktop(quint32 desktop);
70  void unmap();
71  void setState(org_kde_plasma_window_management_state flag, bool set);
72  void setParentWindow(PlasmaWindowInterface *parent);
73  void setGeometry(const QRect &geometry);
74  void setApplicationMenuPaths(const QString &service, const QString &object);
75  wl_resource *resourceForParent(PlasmaWindowInterface *parent, wl_resource *child) const;
76 
77  QVector<wl_resource *> resources;
78  quint32 windowId = 0;
79  QHash<SurfaceInterface *, QRect> minimizedGeometries;
80  PlasmaWindowManagementInterface *wm;
81 
82  bool unmapped = false;
83  PlasmaWindowInterface *parentWindow = nullptr;
84  QMetaObject::Connection parentWindowDestroyConnection;
85  QStringList plasmaVirtualDesktops;
86  QRect geometry;
87 
88 private:
89  static void unbind(wl_resource *resource);
90  static void setStateCallback(wl_client *client, wl_resource *resource, uint32_t flags, uint32_t state);
91  static void setVirtualDesktopCallback(wl_client *client, wl_resource *resource, uint32_t number);
92  static void closeCallback(wl_client *client, wl_resource *resource);
93  static void requestMoveCallback(wl_client *client, wl_resource *resource);
94  static void requestResizeCallback(wl_client *client, wl_resource *resource);
95  static void
96  setMinimizedGeometryCallback(wl_client *client, wl_resource *resource, wl_resource *panel, uint32_t x, uint32_t y, uint32_t width, uint32_t height);
97  static void unsetMinimizedGeometryCallback(wl_client *client, wl_resource *resource, wl_resource *panel);
98  static void destroyCallback(wl_client *client, wl_resource *resource);
99  static void getIconCallback(wl_client *client, wl_resource *resource, int32_t fd);
100  static void requestEnterVirtualDesktopCallback(wl_client *client, wl_resource *resource, const char *id);
101  static void requestEnterNewVirtualDesktopCallback(wl_client *client, wl_resource *resource);
102  static void requestLeaveVirtualDesktopCallback(wl_client *client, wl_resource *resource, const char *id);
103  static Private *cast(wl_resource *resource)
104  {
105  return reinterpret_cast<Private *>(wl_resource_get_user_data(resource));
106  }
107 
108  PlasmaWindowInterface *q;
109  QString m_title;
110  QString m_appId;
111  quint32 m_pid = 0;
112  QString m_themedIconName;
113  QString m_appServiceName;
114  QString m_appObjectPath;
115  QIcon m_icon;
116  quint32 m_virtualDesktop = 0;
117  quint32 m_state = 0;
118  static const struct org_kde_plasma_window_interface s_interface;
119 };
120 
121 const quint32 PlasmaWindowManagementInterface::Private::s_version = 11;
122 
123 PlasmaWindowManagementInterface::Private::Private(PlasmaWindowManagementInterface *q, Display *d)
124  : Global::Private(d, &org_kde_plasma_window_management_interface, s_version)
125  , q(q)
126 {
127 }
128 
129 #ifndef K_DOXYGEN
130 const struct org_kde_plasma_window_management_interface PlasmaWindowManagementInterface::Private::s_interface = {showDesktopCallback,
131  getWindowCallback,
132  getWindowByUuidCallback};
133 #endif
134 
135 void PlasmaWindowManagementInterface::Private::sendShowingDesktopState()
136 {
137  for (wl_resource *r : resources) {
138  sendShowingDesktopState(r);
139  }
140 }
141 
142 void PlasmaWindowManagementInterface::Private::sendShowingDesktopState(wl_resource *r)
143 {
144  uint32_t s = 0;
145  switch (state) {
146  case ShowingDesktopState::Enabled:
147  s = ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_ENABLED;
148  break;
149  case ShowingDesktopState::Disabled:
150  s = ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_DISABLED;
151  break;
152  default:
153  Q_UNREACHABLE();
154  break;
155  }
156  org_kde_plasma_window_management_send_show_desktop_changed(r, s);
157 }
158 
159 void PlasmaWindowManagementInterface::Private::sendStackingOrderChanged()
160 {
161  for (wl_resource *r : resources) {
162  sendStackingOrderChanged(r);
163  }
164 }
165 
166 void PlasmaWindowManagementInterface::Private::sendStackingOrderChanged(wl_resource *r)
167 {
168  if (wl_resource_get_version(r) < ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STACKING_ORDER_CHANGED_SINCE_VERSION) {
169  return;
170  }
171 
172  wl_array wlIds;
173  wl_array_init(&wlIds);
174  const size_t memLength = sizeof(uint32_t) * stackingOrder.size();
175  void *s = wl_array_add(&wlIds, memLength);
176  memcpy(s, stackingOrder.data(), memLength);
177 
178  org_kde_plasma_window_management_send_stacking_order_changed(r, &wlIds);
179 
180  wl_array_release(&wlIds);
181 }
182 
183 void PlasmaWindowManagementInterface::Private::showDesktopCallback(wl_client *client, wl_resource *resource, uint32_t state)
184 {
185  Q_UNUSED(client)
186  ShowingDesktopState s = ShowingDesktopState::Disabled;
187  switch (state) {
188  case ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_ENABLED:
189  s = ShowingDesktopState::Enabled;
190  break;
191  case ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_DISABLED:
192  default:
193  s = ShowingDesktopState::Disabled;
194  break;
195  }
196  Q_EMIT reinterpret_cast<Private *>(wl_resource_get_user_data(resource))->q->requestChangeShowingDesktop(s);
197 }
198 
199 void PlasmaWindowManagementInterface::Private::getWindowByUuidCallback(wl_client *client, wl_resource *resource, uint32_t id, const char *uuid)
200 {
201  Q_UNUSED(client);
202  Q_UNUSED(uuid);
203  qCritical() << "window_by_uuid is unsupported, port to KWaylandServer::PlasmaWindowManagementInterface";
204 
205  auto p = reinterpret_cast<Private *>(wl_resource_get_user_data(resource));
206  PlasmaWindowInterface *window = new PlasmaWindowInterface(p->q, p->q);
207  window->d->unmapped = true;
208  window->d->createResource(resource, id);
209  return;
210 }
211 
212 void PlasmaWindowManagementInterface::Private::getWindowCallback(wl_client *client, wl_resource *resource, uint32_t id, uint32_t internalWindowId)
213 {
214  Q_UNUSED(client)
215  auto p = reinterpret_cast<Private *>(wl_resource_get_user_data(resource));
216  auto it = std::find_if(p->windows.constBegin(), p->windows.constEnd(), [internalWindowId](PlasmaWindowInterface *window) {
217  return window->d->windowId == internalWindowId;
218  });
219  if (it == p->windows.constEnd()) {
220  // create a temp window just for the resource and directly send an unmapped
221  PlasmaWindowInterface *window = new PlasmaWindowInterface(p->q, p->q);
222  window->d->unmapped = true;
223  window->d->createResource(resource, id);
224  return;
225  }
226  (*it)->d->createResource(resource, id);
227 }
228 
229 PlasmaWindowManagementInterface::PlasmaWindowManagementInterface(Display *display, QObject *parent)
230  : Global(new Private(this, display), parent)
231 {
232 }
233 
234 PlasmaWindowManagementInterface::~PlasmaWindowManagementInterface() = default;
235 
236 void PlasmaWindowManagementInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id)
237 {
238  auto c = display->getConnection(client);
239  wl_resource *shell = c->createResource(&org_kde_plasma_window_management_interface, qMin(version, s_version), id);
240  if (!shell) {
241  wl_client_post_no_memory(client);
242  return;
243  }
244  wl_resource_set_implementation(shell, &s_interface, this, unbind);
245  resources << shell;
246  for (auto it = windows.constBegin(); it != windows.constEnd(); ++it) {
247  org_kde_plasma_window_management_send_window(shell, (*it)->d->windowId);
248  }
249  sendStackingOrderChanged();
250 }
251 
252 void PlasmaWindowManagementInterface::Private::unbind(wl_resource *resource)
253 {
254  auto wm = reinterpret_cast<Private *>(wl_resource_get_user_data(resource));
255  wm->resources.removeAll(resource);
256 }
257 
258 void PlasmaWindowManagementInterface::setShowingDesktopState(PlasmaWindowManagementInterface::ShowingDesktopState state)
259 {
260  Q_D();
261  if (d->state == state) {
262  return;
263  }
264  d->state = state;
265  d->sendShowingDesktopState();
266 }
267 
268 PlasmaWindowManagementInterface::Private *PlasmaWindowManagementInterface::d_func() const
269 {
270  return reinterpret_cast<Private *>(d.data());
271 }
272 
273 PlasmaWindowInterface *PlasmaWindowManagementInterface::createWindow(QObject *parent)
274 {
275  Q_D();
276  PlasmaWindowInterface *window = new PlasmaWindowInterface(this, parent);
277  // TODO: improve window ids so that it cannot wrap around
278  window->d->windowId = ++d->windowIdCounter;
279  for (auto it = d->resources.constBegin(); it != d->resources.constEnd(); ++it) {
280  org_kde_plasma_window_management_send_window(*it, window->d->windowId);
281  }
282  d->windows << window;
283  connect(window, &QObject::destroyed, this, [this, window] {
284  Q_D();
285  d->windows.removeAll(window);
286  });
287  return window;
288 }
289 
290 QList<PlasmaWindowInterface *> PlasmaWindowManagementInterface::windows() const
291 {
292  Q_D();
293  return d->windows;
294 }
295 
296 void PlasmaWindowManagementInterface::unmapWindow(PlasmaWindowInterface *window)
297 {
298  if (!window) {
299  return;
300  }
301  Q_D();
302  d->windows.removeOne(window);
303  Q_ASSERT(!d->windows.contains(window));
304  window->d->unmap();
305 }
306 
307 void PlasmaWindowManagementInterface::setStackingOrder(const QVector<quint32> &stackingOrder)
308 {
309  Q_D();
310  if (d->stackingOrder == stackingOrder) {
311  return;
312  }
313  d->stackingOrder = stackingOrder;
314  d->sendStackingOrderChanged();
315 }
316 
317 void PlasmaWindowManagementInterface::setPlasmaVirtualDesktopManagementInterface(PlasmaVirtualDesktopManagementInterface *manager)
318 {
319  Q_D();
320  if (d->plasmaVirtualDesktopManagementInterface == manager) {
321  return;
322  }
323  d->plasmaVirtualDesktopManagementInterface = manager;
324 }
325 
326 PlasmaVirtualDesktopManagementInterface *PlasmaWindowManagementInterface::plasmaVirtualDesktopManagementInterface() const
327 {
328  Q_D();
329  return d->plasmaVirtualDesktopManagementInterface;
330 }
331 
332 #ifndef K_DOXYGEN
333 const struct org_kde_plasma_window_interface PlasmaWindowInterface::Private::s_interface = {setStateCallback,
334  setVirtualDesktopCallback,
335  setMinimizedGeometryCallback,
336  unsetMinimizedGeometryCallback,
337  closeCallback,
338  requestMoveCallback,
339  requestResizeCallback,
340  destroyCallback,
341  getIconCallback,
342  requestEnterVirtualDesktopCallback,
343  requestEnterNewVirtualDesktopCallback,
344  requestLeaveVirtualDesktopCallback};
345 #endif
346 
347 PlasmaWindowInterface::Private::Private(PlasmaWindowManagementInterface *wm, PlasmaWindowInterface *q)
348  : wm(wm)
349  , q(q)
350 {
351 }
352 
353 PlasmaWindowInterface::Private::~Private()
354 {
355  // need to copy, as destroy goes through the destroy listener and modifies the list as we iterate
356  const auto c = resources;
357  for (const auto &r : c) {
358  auto client = wl_resource_get_client(r);
359  org_kde_plasma_window_send_unmapped(r);
360  wl_resource_destroy(r);
361  wl_client_flush(client);
362  }
363 }
364 
365 void PlasmaWindowInterface::Private::destroyCallback(wl_client *, wl_resource *r)
366 {
367  Private *p = cast(r);
368  p->resources.removeAll(r);
369  wl_resource_destroy(r);
370  if (p->unmapped && p->resources.isEmpty()) {
371  p->q->deleteLater();
372  }
373 }
374 
375 void PlasmaWindowInterface::Private::unbind(wl_resource *resource)
376 {
377  Private *p = reinterpret_cast<Private *>(wl_resource_get_user_data(resource));
378  p->resources.removeAll(resource);
379  if (p->unmapped && p->resources.isEmpty()) {
380  p->q->deleteLater();
381  }
382 }
383 
384 void PlasmaWindowInterface::Private::createResource(wl_resource *parent, uint32_t id)
385 {
386  ClientConnection *c = wm->display()->getConnection(wl_resource_get_client(parent));
387  wl_resource *resource = c->createResource(&org_kde_plasma_window_interface, wl_resource_get_version(parent), id);
388  if (!resource) {
389  return;
390  }
391  wl_resource_set_implementation(resource, &s_interface, this, unbind);
392  resources << resource;
393 
394  org_kde_plasma_window_send_virtual_desktop_changed(resource, m_virtualDesktop);
395  for (const auto &desk : plasmaVirtualDesktops) {
396  org_kde_plasma_window_send_virtual_desktop_entered(resource, desk.toUtf8().constData());
397  }
398  if (!m_appId.isEmpty()) {
399  org_kde_plasma_window_send_app_id_changed(resource, m_appId.toUtf8().constData());
400  }
401  if (m_pid != 0) {
402  org_kde_plasma_window_send_pid_changed(resource, m_pid);
403  }
404  if (!m_title.isEmpty()) {
405  org_kde_plasma_window_send_title_changed(resource, m_title.toUtf8().constData());
406  }
407  if (!m_appObjectPath.isEmpty() || !m_appServiceName.isEmpty()) {
408  org_kde_plasma_window_send_application_menu(resource, m_appServiceName.toUtf8().constData(), m_appObjectPath.toUtf8().constData());
409  }
410  org_kde_plasma_window_send_state_changed(resource, m_state);
411  if (!m_themedIconName.isEmpty()) {
412  org_kde_plasma_window_send_themed_icon_name_changed(resource, m_themedIconName.toUtf8().constData());
413  } else {
414  if (wl_resource_get_version(resource) >= ORG_KDE_PLASMA_WINDOW_ICON_CHANGED_SINCE_VERSION) {
415  org_kde_plasma_window_send_icon_changed(resource);
416  }
417  }
418 
419  org_kde_plasma_window_send_parent_window(resource, resourceForParent(parentWindow, resource));
420 
421  if (unmapped) {
422  org_kde_plasma_window_send_unmapped(resource);
423  }
424 
425  if (geometry.isValid() && wl_resource_get_version(resource) >= ORG_KDE_PLASMA_WINDOW_GEOMETRY_SINCE_VERSION) {
426  org_kde_plasma_window_send_geometry(resource, geometry.x(), geometry.y(), geometry.width(), geometry.height());
427  }
428 
429  if (wl_resource_get_version(resource) >= ORG_KDE_PLASMA_WINDOW_INITIAL_STATE_SINCE_VERSION) {
430  org_kde_plasma_window_send_initial_state(resource);
431  }
432  c->flush();
433 }
434 
435 void PlasmaWindowInterface::Private::setAppId(const QString &appId)
436 {
437  if (m_appId == appId) {
438  return;
439  }
440  m_appId = appId;
441  const QByteArray utf8 = m_appId.toUtf8();
442  for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
443  org_kde_plasma_window_send_app_id_changed(*it, utf8.constData());
444  }
445 }
446 
447 void PlasmaWindowInterface::Private::setPid(quint32 pid)
448 {
449  if (m_pid == pid) {
450  return;
451  }
452  m_pid = pid;
453  for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
454  org_kde_plasma_window_send_pid_changed(*it, pid);
455  }
456 }
457 
458 void PlasmaWindowInterface::Private::setThemedIconName(const QString &iconName)
459 {
460  if (m_themedIconName == iconName) {
461  return;
462  }
463  m_themedIconName = iconName;
464  const QByteArray utf8 = m_themedIconName.toUtf8();
465  for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
466  org_kde_plasma_window_send_themed_icon_name_changed(*it, utf8.constData());
467  }
468 }
469 
470 void PlasmaWindowInterface::Private::setIcon(const QIcon &icon)
471 {
472  m_icon = icon;
473  setThemedIconName(m_icon.name());
474  if (m_icon.name().isEmpty()) {
475  for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
476  if (wl_resource_get_version(*it) >= ORG_KDE_PLASMA_WINDOW_ICON_CHANGED_SINCE_VERSION) {
477  org_kde_plasma_window_send_icon_changed(*it);
478  }
479  }
480  }
481 }
482 
483 void PlasmaWindowInterface::Private::getIconCallback(wl_client *client, wl_resource *resource, int32_t fd)
484 {
485  Q_UNUSED(client)
486  Private *p = cast(resource);
488  [fd](const QIcon &icon) {
489  QFile file;
491  QDataStream ds(&file);
492  ds << icon;
493  file.close();
494  },
495  p->m_icon);
496 }
497 
498 void PlasmaWindowInterface::Private::requestEnterVirtualDesktopCallback(wl_client *client, wl_resource *resource, const char *id)
499 {
500  Q_UNUSED(client)
501  Private *p = cast(resource);
502  Q_EMIT p->q->enterPlasmaVirtualDesktopRequested(QString::fromUtf8(id));
503 }
504 
505 void PlasmaWindowInterface::Private::requestEnterNewVirtualDesktopCallback(wl_client *client, wl_resource *resource)
506 {
507  Q_UNUSED(client)
508  Private *p = cast(resource);
509  Q_EMIT p->q->enterNewPlasmaVirtualDesktopRequested();
510 }
511 
512 void PlasmaWindowInterface::Private::requestLeaveVirtualDesktopCallback(wl_client *client, wl_resource *resource, const char *id)
513 {
514  Q_UNUSED(client)
515  Private *p = cast(resource);
516  Q_EMIT p->q->leavePlasmaVirtualDesktopRequested(QString::fromUtf8(id));
517 }
518 
519 void PlasmaWindowInterface::Private::setTitle(const QString &title)
520 {
521  if (m_title == title) {
522  return;
523  }
524  m_title = title;
525  const QByteArray utf8 = m_title.toUtf8();
526  for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
527  org_kde_plasma_window_send_title_changed(*it, utf8.constData());
528  }
529 }
530 
531 void PlasmaWindowInterface::Private::setVirtualDesktop(quint32 desktop)
532 {
533  if (m_virtualDesktop == desktop) {
534  return;
535  }
536  m_virtualDesktop = desktop;
537  for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
538  org_kde_plasma_window_send_virtual_desktop_changed(*it, m_virtualDesktop);
539  }
540 }
541 
542 void PlasmaWindowInterface::Private::unmap()
543 {
544  unmapped = true;
545  for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
546  org_kde_plasma_window_send_unmapped(*it);
547  }
548  if (resources.isEmpty()) {
549  q->deleteLater();
550  }
551 }
552 
553 void PlasmaWindowInterface::Private::setState(org_kde_plasma_window_management_state flag, bool set)
554 {
555  quint32 newState = m_state;
556  if (set) {
557  newState |= flag;
558  } else {
559  newState &= ~flag;
560  }
561  if (newState == m_state) {
562  return;
563  }
564  m_state = newState;
565  for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
566  org_kde_plasma_window_send_state_changed(*it, m_state);
567  }
568 }
569 
570 wl_resource *PlasmaWindowInterface::Private::resourceForParent(PlasmaWindowInterface *parent, wl_resource *child) const
571 {
572  if (!parent) {
573  return nullptr;
574  }
575  auto it = std::find_if(parent->d->resources.begin(), parent->d->resources.end(), [child](wl_resource *parentResource) {
576  return wl_resource_get_client(child) == wl_resource_get_client(parentResource);
577  });
578  if (it != parent->d->resources.end()) {
579  return *it;
580  }
581  return nullptr;
582 }
583 
584 void PlasmaWindowInterface::Private::setParentWindow(PlasmaWindowInterface *window)
585 {
586  if (parentWindow == window) {
587  return;
588  }
589  QObject::disconnect(parentWindowDestroyConnection);
590  parentWindowDestroyConnection = QMetaObject::Connection();
591  parentWindow = window;
592  if (parentWindow) {
593  parentWindowDestroyConnection = QObject::connect(window, &QObject::destroyed, q, [this] {
594  parentWindow = nullptr;
595  parentWindowDestroyConnection = QMetaObject::Connection();
596  for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
597  org_kde_plasma_window_send_parent_window(*it, nullptr);
598  }
599  });
600  }
601  for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
602  org_kde_plasma_window_send_parent_window(*it, resourceForParent(window, *it));
603  }
604 }
605 
606 void PlasmaWindowInterface::Private::setGeometry(const QRect &geo)
607 {
608  if (geometry == geo) {
609  return;
610  }
611  geometry = geo;
612  if (!geometry.isValid()) {
613  return;
614  }
615  for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
616  auto resource = *it;
617  if (wl_resource_get_version(resource) < ORG_KDE_PLASMA_WINDOW_GEOMETRY_SINCE_VERSION) {
618  continue;
619  }
620  org_kde_plasma_window_send_geometry(resource, geometry.x(), geometry.y(), geometry.width(), geometry.height());
621  }
622 }
623 
624 void PlasmaWindowInterface::Private::setApplicationMenuPaths(const QString &service, const QString &object)
625 {
626  if (m_appServiceName == service && m_appObjectPath == object) {
627  return;
628  }
629  m_appServiceName = service;
630  m_appObjectPath = object;
631  for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
632  auto resource = *it;
633  if (wl_resource_get_version(resource) < ORG_KDE_PLASMA_WINDOW_APPLICATION_MENU_SINCE_VERSION) {
634  continue;
635  }
636  org_kde_plasma_window_send_application_menu(resource, qUtf8Printable(service), qUtf8Printable(object));
637  }
638 }
639 
640 void PlasmaWindowInterface::Private::closeCallback(wl_client *client, wl_resource *resource)
641 {
642  Q_UNUSED(client)
643  Private *p = cast(resource);
644  Q_EMIT p->q->closeRequested();
645 }
646 
647 void PlasmaWindowInterface::Private::requestMoveCallback(wl_client *client, wl_resource *resource)
648 {
649  Q_UNUSED(client)
650  Private *p = cast(resource);
651  Q_EMIT p->q->moveRequested();
652 }
653 
654 void PlasmaWindowInterface::Private::requestResizeCallback(wl_client *client, wl_resource *resource)
655 {
656  Q_UNUSED(client)
657  Private *p = cast(resource);
658  Q_EMIT p->q->resizeRequested();
659 }
660 
661 void PlasmaWindowInterface::Private::setVirtualDesktopCallback(wl_client *client, wl_resource *resource, uint32_t number)
662 {
663  Q_UNUSED(client)
664  Private *p = cast(resource);
665  Q_EMIT p->q->virtualDesktopRequested(number);
666 }
667 
668 void PlasmaWindowInterface::Private::setStateCallback(wl_client *client, wl_resource *resource, uint32_t flags, uint32_t state)
669 {
670  Q_UNUSED(client)
671  Private *p = cast(resource);
672  if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ACTIVE) {
673  Q_EMIT p->q->activeRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ACTIVE);
674  }
675  if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED) {
676  Q_EMIT p->q->minimizedRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED);
677  }
678  if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED) {
679  Q_EMIT p->q->maximizedRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED);
680  }
681  if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN) {
682  Q_EMIT p->q->fullscreenRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN);
683  }
684  if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE) {
685  Q_EMIT p->q->keepAboveRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE);
686  }
687  if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW) {
688  Q_EMIT p->q->keepBelowRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW);
689  }
690  if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_DEMANDS_ATTENTION) {
691  Q_EMIT p->q->demandsAttentionRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_DEMANDS_ATTENTION);
692  }
693  if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_CLOSEABLE) {
694  Q_EMIT p->q->closeableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_CLOSEABLE);
695  }
696  if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZABLE) {
697  Q_EMIT p->q->minimizeableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZABLE);
698  }
699  if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZABLE) {
700  Q_EMIT p->q->maximizeableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZABLE);
701  }
702  if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREENABLE) {
703  Q_EMIT p->q->fullscreenableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREENABLE);
704  }
705  if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPTASKBAR) {
706  Q_EMIT p->q->skipTaskbarRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPTASKBAR);
707  }
708  if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPSWITCHER) {
709  Q_EMIT p->q->skipSwitcherRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPSWITCHER);
710  }
711  if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADEABLE) {
712  Q_EMIT p->q->shadeableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADEABLE);
713  }
714  if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED) {
715  Q_EMIT p->q->shadedRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED);
716  }
717  if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MOVABLE) {
718  Q_EMIT p->q->movableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MOVABLE);
719  }
720  if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_RESIZABLE) {
721  Q_EMIT p->q->resizableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_RESIZABLE);
722  }
723  if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_VIRTUAL_DESKTOP_CHANGEABLE) {
724  Q_EMIT p->q->virtualDesktopChangeableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_VIRTUAL_DESKTOP_CHANGEABLE);
725  }
726 }
727 
728 void PlasmaWindowInterface::Private::setMinimizedGeometryCallback(wl_client *client,
729  wl_resource *resource,
730  wl_resource *panel,
731  uint32_t x,
732  uint32_t y,
733  uint32_t width,
734  uint32_t height)
735 {
736  Q_UNUSED(client)
737  Private *p = cast(resource);
738  SurfaceInterface *panelSurface = SurfaceInterface::get(panel);
739 
740  if (!panelSurface) {
741  return;
742  }
743 
744  if (p->minimizedGeometries.value(panelSurface) == QRect(x, y, width, height)) {
745  return;
746  }
747 
748  p->minimizedGeometries[panelSurface] = QRect(x, y, width, height);
749  Q_EMIT p->q->minimizedGeometriesChanged();
750  connect(panelSurface, &QObject::destroyed, p->q, [p, panelSurface]() {
751  if (p->minimizedGeometries.remove(panelSurface)) {
752  Q_EMIT p->q->minimizedGeometriesChanged();
753  }
754  });
755 }
756 
757 void PlasmaWindowInterface::Private::unsetMinimizedGeometryCallback(wl_client *client, wl_resource *resource, wl_resource *panel)
758 {
759  Q_UNUSED(client)
760  Private *p = cast(resource);
761  SurfaceInterface *panelSurface = SurfaceInterface::get(panel);
762 
763  if (!panelSurface) {
764  return;
765  }
766  if (!p->minimizedGeometries.contains(panelSurface)) {
767  return;
768  }
769  p->minimizedGeometries.remove(panelSurface);
770  Q_EMIT p->q->minimizedGeometriesChanged();
771 }
772 
773 PlasmaWindowInterface::PlasmaWindowInterface(PlasmaWindowManagementInterface *wm, QObject *parent)
774  : QObject(parent)
775  , d(new Private(wm, this))
776 {
777 }
778 
779 PlasmaWindowInterface::~PlasmaWindowInterface() = default;
780 
781 void PlasmaWindowInterface::setAppId(const QString &appId)
782 {
783  d->setAppId(appId);
784 }
785 
786 void PlasmaWindowInterface::setPid(quint32 pid)
787 {
788  d->setPid(pid);
789 }
790 
791 void PlasmaWindowInterface::setTitle(const QString &title)
792 {
793  d->setTitle(title);
794 }
795 
796 void PlasmaWindowInterface::setVirtualDesktop(quint32 desktop)
797 {
798  d->setVirtualDesktop(desktop);
799 }
800 
801 void PlasmaWindowInterface::unmap()
802 {
803  d->wm->unmapWindow(this);
804 }
805 
806 QHash<SurfaceInterface *, QRect> PlasmaWindowInterface::minimizedGeometries() const
807 {
808  return d->minimizedGeometries;
809 }
810 
811 void PlasmaWindowInterface::setActive(bool set)
812 {
813  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ACTIVE, set);
814 }
815 
816 void PlasmaWindowInterface::setFullscreen(bool set)
817 {
818  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN, set);
819 }
820 
821 void PlasmaWindowInterface::setKeepAbove(bool set)
822 {
823  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE, set);
824 }
825 
826 void PlasmaWindowInterface::setKeepBelow(bool set)
827 {
828  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW, set);
829 }
830 
831 void PlasmaWindowInterface::setMaximized(bool set)
832 {
833  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED, set);
834 }
835 
836 void PlasmaWindowInterface::setMinimized(bool set)
837 {
838  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED, set);
839 }
840 
841 void PlasmaWindowInterface::setOnAllDesktops(bool set)
842 {
843  // the deprecated vd management
844  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ON_ALL_DESKTOPS, set);
845 
846  if (!d->wm->plasmaVirtualDesktopManagementInterface()) {
847  return;
848  }
849 
850  // the current vd management
851  if (set) {
852  if (d->plasmaVirtualDesktops.isEmpty()) {
853  return;
854  }
855  // leaving everything means on all desktops
856  for (auto desk : plasmaVirtualDesktops()) {
857  for (auto it = d->resources.constBegin(); it != d->resources.constEnd(); ++it) {
858  org_kde_plasma_window_send_virtual_desktop_left(*it, desk.toUtf8().constData());
859  }
860  }
861  d->plasmaVirtualDesktops.clear();
862  } else {
863  if (!d->plasmaVirtualDesktops.isEmpty()) {
864  return;
865  }
866  // enters the desktops which are active (usually only one but not a given)
867  for (auto desk : d->wm->plasmaVirtualDesktopManagementInterface()->desktops()) {
868  if (desk->isActive() && !d->plasmaVirtualDesktops.contains(desk->id())) {
869  d->plasmaVirtualDesktops << desk->id();
870  for (auto it = d->resources.constBegin(); it != d->resources.constEnd(); ++it) {
871  org_kde_plasma_window_send_virtual_desktop_entered(*it, desk->id().toUtf8().constData());
872  }
873  }
874  }
875  }
876 }
877 
878 void PlasmaWindowInterface::setDemandsAttention(bool set)
879 {
880  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_DEMANDS_ATTENTION, set);
881 }
882 
883 void PlasmaWindowInterface::setCloseable(bool set)
884 {
885  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_CLOSEABLE, set);
886 }
887 
888 void PlasmaWindowInterface::setFullscreenable(bool set)
889 {
890  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREENABLE, set);
891 }
892 
893 void PlasmaWindowInterface::setMaximizeable(bool set)
894 {
895  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZABLE, set);
896 }
897 
898 void PlasmaWindowInterface::setMinimizeable(bool set)
899 {
900  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZABLE, set);
901 }
902 
903 void PlasmaWindowInterface::setSkipTaskbar(bool set)
904 {
905  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPTASKBAR, set);
906 }
907 
908 void PlasmaWindowInterface::setSkipSwitcher(bool skip)
909 {
910  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPSWITCHER, skip);
911 }
912 
913 void PlasmaWindowInterface::setThemedIconName(const QString &iconName)
914 {
915  d->setThemedIconName(iconName);
916 }
917 
918 void PlasmaWindowInterface::setIcon(const QIcon &icon)
919 {
920  d->setIcon(icon);
921 }
922 
923 void PlasmaWindowInterface::addPlasmaVirtualDesktop(const QString &id)
924 {
925  // don't add a desktop we're not sure it exists
926  if (!d->wm->plasmaVirtualDesktopManagementInterface() || d->plasmaVirtualDesktops.contains(id)) {
927  return;
928  }
929 
930  PlasmaVirtualDesktopInterface *desktop = d->wm->plasmaVirtualDesktopManagementInterface()->desktop(id);
931 
932  if (!desktop) {
933  return;
934  }
935 
936  d->plasmaVirtualDesktops << id;
937 
938  // if the desktop dies, remove it from or list
939  connect(desktop, &QObject::destroyed, this, [this, id]() {
940  removePlasmaVirtualDesktop(id);
941  });
942 
943  for (auto it = d->resources.constBegin(); it != d->resources.constEnd(); ++it) {
944  org_kde_plasma_window_send_virtual_desktop_entered(*it, id.toUtf8().constData());
945  }
946 }
947 
948 void PlasmaWindowInterface::removePlasmaVirtualDesktop(const QString &id)
949 {
950  if (!d->plasmaVirtualDesktops.contains(id)) {
951  return;
952  }
953 
954  d->plasmaVirtualDesktops.removeAll(id);
955  for (auto it = d->resources.constBegin(); it != d->resources.constEnd(); ++it) {
956  org_kde_plasma_window_send_virtual_desktop_left(*it, id.toUtf8().constData());
957  }
958 
959  // we went on all desktops
960  if (d->plasmaVirtualDesktops.isEmpty()) {
961  setOnAllDesktops(true);
962  }
963 }
964 
965 QStringList PlasmaWindowInterface::plasmaVirtualDesktops() const
966 {
967  return d->plasmaVirtualDesktops;
968 }
969 
970 void PlasmaWindowInterface::setShadeable(bool set)
971 {
972  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADEABLE, set);
973 }
974 
975 void PlasmaWindowInterface::setShaded(bool set)
976 {
977  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED, set);
978 }
979 
980 void PlasmaWindowInterface::setMovable(bool set)
981 {
982  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MOVABLE, set);
983 }
984 
985 void PlasmaWindowInterface::setResizable(bool set)
986 {
987  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_RESIZABLE, set);
988 }
989 
990 void PlasmaWindowInterface::setVirtualDesktopChangeable(bool set)
991 {
992  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_VIRTUAL_DESKTOP_CHANGEABLE, set);
993 }
994 
995 void PlasmaWindowInterface::setParentWindow(PlasmaWindowInterface *parentWindow)
996 {
997  d->setParentWindow(parentWindow);
998 }
999 
1000 void PlasmaWindowInterface::setGeometry(const QRect &geometry)
1001 {
1002  d->setGeometry(geometry);
1003 }
1004 
1005 void PlasmaWindowInterface::setApplicationMenuPaths(const QString &serviceName, const QString &objectPath)
1006 {
1007  d->setApplicationMenuPaths(serviceName, objectPath);
1008 }
1009 
1010 quint32 PlasmaWindowInterface::internalId() const
1011 {
1012  return d->windowId;
1013 }
1014 
1015 }
1016 }
ClientConnection * getConnection(wl_client *client)
Gets the ClientConnection for the given client.
Definition: display.cpp:673
KJOBWIDGETS_EXPORT QWidget * window(KJob *job)
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
QString fromUtf8(const char *str, int size)
Resource representing a wl_surface.
const char * constData() const const
void deleteLater()
virtual bool open(QIODevice::OpenMode mode) override
PlasmaVirtualDesktopManagementInterface * plasmaVirtualDesktopManagementInterface() const
void flush()
Flushes the connection to this client.
T * data() const const
void clear()
wl_resource * createResource(const wl_interface *interface, quint32 version, quint32 id)
Creates a new wl_resource for the provided interface.
Wrapper for the org_kde_plasma_virtual_desktop_management interface.
QObject(QObject *parent)
virtual void close() override
Convenient Class which represents a wl_client.
Display * display()
Definition: global.cpp:78
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
QFuture< T > run(Function function,...)
void destroyed(QObject *obj)
Q_EMITQ_EMIT
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Sep 27 2021 22:51:57 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.