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;
80  PlasmaWindowManagementInterface *wm;
81 
82  bool unmapped = false;
83  PlasmaWindowInterface *parentWindow = nullptr;
84  QMetaObject::Connection parentWindowDestroyConnection;
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 
797 {
798  d->setVirtualDesktop(desktop);
799 }
800 
802 {
803  d->wm->unmapWindow(this);
804 }
805 
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 
914 {
915  d->setThemedIconName(iconName);
916 }
917 
919 {
920  d->setIcon(icon);
921 }
922 
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]() {
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 
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 
966 {
967  return d->plasmaVirtualDesktops;
968 }
969 
971 {
972  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADEABLE, set);
973 }
974 
976 {
977  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED, set);
978 }
979 
981 {
982  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MOVABLE, set);
983 }
984 
986 {
987  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_RESIZABLE, set);
988 }
989 
991 {
992  d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_VIRTUAL_DESKTOP_CHANGEABLE, set);
993 }
994 
996 {
997  d->setParentWindow(parentWindow);
998 }
999 
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 
1011 {
1012  return d->windowId;
1013 }
1014 
1015 }
1016 }
Wrapper for the org_kde_plasma_virtual_desktop_management interface.
QFuture< T > run(Function function,...)
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
QString fromUtf8(const char *str, int size)
void setIcon(const QIcon &icon)
Set the icon of the PlasmaWindowInterface.
virtual bool open(QIODevice::OpenMode mode) override
void unmap()
This method removes the Window and the Client is supposed to release the resource bound for this Wind...
quint32 internalId() const
Return the window internal id.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void removePlasmaVirtualDesktop(const QString &id)
Removes a visrtual desktop from a window.
static SurfaceInterface * get(wl_resource *native)
void destroyed(QObject *obj)
QHash< SurfaceInterface *, QRect > minimizedGeometries() const
QStringList plasmaVirtualDesktops() const
The ids of all the desktops currently associated with this window.
void setGeometry(const QRect &geometry)
Sets the window geometry of this PlasmaWindow.
void addPlasmaVirtualDesktop(const QString &id)
Adds a new desktop to this window: a window can be on an arbitrary subset of virtual desktops.
PlasmaVirtualDesktopManagementInterface * plasmaVirtualDesktopManagementInterface() const
void setParentWindow(PlasmaWindowInterface *parentWindow)
Sets this PlasmaWindowInterface as a transient window to parentWindow.
GeoCoordinates geo(const QVariant &location)
virtual void close() override
const char * constData() const const
void setApplicationMenuPaths(const QString &serviceName, const QString &objectPath)
Set the application menu D-BUS service name and object path for the window.
KJOBWIDGETS_EXPORT QWidget * window(KJob *job)
QObject * parent() const const
Q_D(Todo)
virtual QVariant get(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName)
void setVirtualDesktopChangeable(bool set)
FIXME: still relevant with new desktops?
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Feb 7 2023 03:56:21 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.