KWayland

xdgshell_stable_interface.cpp
1 /*
2  SPDX-FileCopyrightText: 2017 David Edmundson <[email protected]>
3  SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <[email protected]>
4 
5  SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6 */
7 #include "display.h"
8 #include "generic_shell_surface_p.h"
9 #include "global.h"
10 #include "global_p.h"
11 #include "output_interface.h"
12 #include "resource_p.h"
13 #include "seat_interface.h"
14 #include "surface_interface.h"
15 #include "xdgshell_interface_p.h"
16 #include "xdgshell_stable_interface_p.h"
17 
18 #include <wayland-xdg-shell-server-protocol.h>
19 
20 namespace KWayland
21 {
22 namespace Server
23 {
24 class XdgShellStableInterface::Private : public XdgShellInterface::Private
25 {
26 public:
27  Private(XdgShellStableInterface *q, Display *d);
28 
31 
32 private:
33  void createSurface(wl_client *client, uint32_t version, uint32_t id, SurfaceInterface *surface, wl_resource *parentResource);
34  void createPositioner(wl_client *client, uint32_t version, uint32_t id, wl_resource *parentResource);
35 
36  void bind(wl_client *client, uint32_t version, uint32_t id) override;
37 
38  quint32 ping(XdgShellSurfaceInterface *surface) override;
39 
40  static void unbind(wl_resource *resource);
41  static Private *cast(wl_resource *r)
42  {
43  return static_cast<Private *>(wl_resource_get_user_data(r));
44  }
45 
46  static void destroyCallback(wl_client *client, wl_resource *resource);
47  static void createPositionerCallback(wl_client *client, wl_resource *resource, uint32_t id);
48  static void getXdgSurfaceCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface);
49  static void pongCallback(wl_client *client, wl_resource *resource, uint32_t serial);
50 
51  XdgShellStableInterface *q;
52  static const struct xdg_wm_base_interface s_interface;
53  static const quint32 s_version;
55 };
56 
57 class XdgPopupStableInterface::Private : public XdgShellPopupInterface::Private
58 {
59 public:
60  Private(XdgPopupStableInterface *q, XdgShellStableInterface *c, SurfaceInterface *surface, wl_resource *parentResource);
61  ~Private() override;
62 
63  QRect windowGeometry() const override;
64  void commit() override;
65 
66  void ackConfigure(quint32 serial)
67  {
68  if (!configureSerials.contains(serial)) {
69  return;
70  }
71  while (!configureSerials.isEmpty()) {
72  quint32 i = configureSerials.takeFirst();
73  Q_EMIT q_func()->configureAcknowledged(i);
74  if (i == serial) {
75  break;
76  }
77  }
78  }
79 
80  void popupDone() override;
81  quint32 configure(const QRect &rect) override;
82 
83  XdgPopupStableInterface *q_func()
84  {
85  return static_cast<XdgPopupStableInterface *>(q);
86  }
87 
88 private:
89  void setWindowGeometryCallback(const QRect &rect);
90 
91  static void grabCallback(wl_client *client, wl_resource *resource, wl_resource *seat, uint32_t serial);
92 
93  static const struct xdg_popup_interface s_interface;
94 
95  struct ShellSurfaceState {
96  QRect windowGeometry;
97 
98  bool windowGeometryIsSet = false;
99  };
100 
101  ShellSurfaceState m_currentState;
102  ShellSurfaceState m_pendingState;
103 
104  friend class XdgSurfaceStableInterface;
105 };
106 
107 class XdgSurfaceStableInterface::Private : public KWayland::Server::Resource::Private
108 {
109 public:
110  Private(XdgSurfaceStableInterface *q, XdgShellStableInterface *c, SurfaceInterface *surface, wl_resource *parentResource);
111 
112  ~Private() override;
113 
114  XdgSurfaceStableInterface *q_func()
115  {
116  return static_cast<XdgSurfaceStableInterface *>(q);
117  }
118 
119  void createTopLevel(wl_client *client, uint32_t version, uint32_t id, wl_resource *parentResource);
120  void createPopup(wl_client *client, uint32_t version, uint32_t id, wl_resource *parentResource, wl_resource *parentWindow, wl_resource *positioner);
121  XdgShellStableInterface *m_shell;
122  SurfaceInterface *m_surface;
123 
124  // effectively a union, only one of these should be populated.
125  // a surface cannot have two roles
128 
129 private:
130  static void destroyCallback(wl_client *client, wl_resource *resource);
131  static void getTopLevelCallback(wl_client *client, wl_resource *resource, uint32_t id);
132  static void getPopupCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *parent, wl_resource *positioner);
133  static void ackConfigureCallback(wl_client *client, wl_resource *resource, uint32_t serial);
134  static void setWindowGeometryCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height);
135  static const struct xdg_surface_interface s_interface;
136 };
137 
138 class XdgTopLevelStableInterface::Private : public XdgShellSurfaceInterface::Private
139 {
140 public:
141  Private(XdgTopLevelStableInterface *q, XdgShellStableInterface *c, SurfaceInterface *surface, wl_resource *parentResource);
142  ~Private() override;
143 
144  QRect windowGeometry() const override;
145  QSize minimumSize() const override;
146  QSize maximumSize() const override;
147  void close() override;
148  void commit() override;
149 
150  void ackConfigure(quint32 serial)
151  {
152  if (!configureSerials.contains(serial)) {
153  return;
154  }
155  while (!configureSerials.isEmpty()) {
156  quint32 i = configureSerials.takeFirst();
157  Q_EMIT q_func()->configureAcknowledged(i);
158  if (i == serial) {
159  break;
160  }
161  }
162  }
163 
164  quint32 configure(States states, const QSize &size) override
165  {
166  if (!resource) {
167  return 0;
168  }
169  const quint32 serial = global->display()->nextSerial();
170  wl_array configureStates;
171  wl_array_init(&configureStates);
172  if (states.testFlag(State::Maximized)) {
173  uint32_t *s = static_cast<uint32_t *>(wl_array_add(&configureStates, sizeof(uint32_t)));
174  *s = XDG_TOPLEVEL_STATE_MAXIMIZED;
175  }
176  if (states.testFlag(State::Fullscreen)) {
177  uint32_t *s = static_cast<uint32_t *>(wl_array_add(&configureStates, sizeof(uint32_t)));
178  *s = XDG_TOPLEVEL_STATE_FULLSCREEN;
179  }
180  if (states.testFlag(State::Resizing)) {
181  uint32_t *s = static_cast<uint32_t *>(wl_array_add(&configureStates, sizeof(uint32_t)));
182  *s = XDG_TOPLEVEL_STATE_RESIZING;
183  }
184  if (states.testFlag(State::Activated)) {
185  uint32_t *s = static_cast<uint32_t *>(wl_array_add(&configureStates, sizeof(uint32_t)));
186  *s = XDG_TOPLEVEL_STATE_ACTIVATED;
187  }
188  configureSerials << serial;
189  xdg_toplevel_send_configure(resource, size.width(), size.height(), &configureStates);
190 
191  xdg_surface_send_configure(parentResource, serial);
192 
193  client->flush();
194  wl_array_release(&configureStates);
195  return serial;
196  };
197 
198  XdgTopLevelStableInterface *q_func()
199  {
200  return static_cast<XdgTopLevelStableInterface *>(q);
201  }
202 
203 private:
204  void setWindowGeometryCallback(const QRect &rect);
205 
206  static void destroyCallback(wl_client *client, wl_resource *resource);
207  static void setParentCallback(struct wl_client *client, struct wl_resource *resource, wl_resource *parent);
208  static void showWindowMenuCallback(wl_client *client, wl_resource *resource, wl_resource *seat, uint32_t serial, int32_t x, int32_t y);
209  static void setMaxSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height);
210  static void setMinSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height);
211  static void setMaximizedCallback(wl_client *client, wl_resource *resource);
212  static void unsetMaximizedCallback(wl_client *client, wl_resource *resource);
213  static void setFullscreenCallback(wl_client *client, wl_resource *resource, wl_resource *output);
214  static void unsetFullscreenCallback(wl_client *client, wl_resource *resource);
215  static void setMinimizedCallback(wl_client *client, wl_resource *resource);
216 
217  static const struct xdg_toplevel_interface s_interface;
218 
219  struct ShellSurfaceState {
220  QRect windowGeometry;
221  QSize minimumSize = QSize(0, 0);
222  QSize maximiumSize = QSize(INT32_MAX, INT32_MAX);
223 
224  bool windowGeometryIsSet = false;
225  bool minimumSizeIsSet = false;
226  bool maximumSizeIsSet = false;
227  };
228 
229  ShellSurfaceState m_currentState;
230  ShellSurfaceState m_pendingState;
231 
232  friend class XdgSurfaceStableInterface;
233 };
234 
235 const quint32 XdgShellStableInterface::Private::s_version = 1;
236 
237 #ifndef K_DOXYGEN
238 const struct xdg_wm_base_interface XdgShellStableInterface::Private::s_interface = {destroyCallback,
239  createPositionerCallback,
240  getXdgSurfaceCallback,
241  pongCallback};
242 #endif
243 
244 void XdgShellStableInterface::Private::destroyCallback(wl_client *client, wl_resource *resource)
245 {
246  Q_UNUSED(client)
247  auto s = cast(resource);
248  if (!s->surfaces.isEmpty()) {
249  wl_resource_post_error(resource, XDG_WM_BASE_ERROR_DEFUNCT_SURFACES, "WMBase destroyed before surfaces");
250  }
251 
252  wl_resource_destroy(resource);
253 }
254 
255 void XdgShellStableInterface::Private::createPositionerCallback(wl_client *client, wl_resource *resource, uint32_t id)
256 {
257  auto s = cast(resource);
258  s->createPositioner(client, wl_resource_get_version(resource), id, resource);
259 }
260 
261 void XdgShellStableInterface::Private::getXdgSurfaceCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface)
262 {
263  auto s = cast(resource);
264  s->createSurface(client, wl_resource_get_version(resource), id, SurfaceInterface::get(surface), resource);
265 }
266 
267 void XdgShellStableInterface::Private::createSurface(wl_client *client, uint32_t version, uint32_t id, SurfaceInterface *surface, wl_resource *parentResource)
268 {
269  auto it = std::find_if(surfaces.constBegin(), surfaces.constEnd(), [surface](XdgSurfaceStableInterface *s) {
270  return surface == s->surface();
271  });
272  if (it != surfaces.constEnd()) {
273  wl_resource_post_error(surface->resource(), XDG_WM_BASE_ERROR_ROLE, "XDG Surface already created");
274  return;
275  }
276  XdgSurfaceStableInterface *shellSurface = new XdgSurfaceStableInterface(q, surface, parentResource);
277  surfaces << shellSurface;
278  QObject::connect(shellSurface, &XdgSurfaceStableInterface::destroyed, q, [this, shellSurface] {
279  surfaces.removeAll(shellSurface);
280  });
281 
282  shellSurface->d->create(display->getConnection(client), version, id);
283 }
284 
285 void XdgShellStableInterface::Private::createPositioner(wl_client *client, uint32_t version, uint32_t id, wl_resource *parentResource)
286 {
287  Q_UNUSED(client)
288 
289  XdgPositionerStableInterface *positioner = new XdgPositionerStableInterface(q, parentResource);
290  positioners << positioner;
291  QObject::connect(positioner, &Resource::destroyed, q, [this, positioner] {
292  positioners.removeAll(positioner);
293  });
294  positioner->d->create(display->getConnection(client), version, id);
295 }
296 
297 void XdgShellStableInterface::Private::pongCallback(wl_client *client, wl_resource *resource, uint32_t serial)
298 {
299  Q_UNUSED(client)
300  auto s = cast(resource);
301  auto timerIt = s->pingTimers.find(serial);
302  if (timerIt != s->pingTimers.end() && timerIt.value()->isActive()) {
303  delete timerIt.value();
304  s->pingTimers.erase(timerIt);
305  Q_EMIT s->q->pongReceived(serial);
306  }
307 }
308 
309 XdgShellStableInterface::Private::Private(XdgShellStableInterface *q, Display *d)
310  : XdgShellInterface::Private(XdgShellInterfaceVersion::Stable, q, d, &xdg_wm_base_interface, 1)
311  , q(q)
312 {
313 }
314 
315 void XdgShellStableInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id)
316 {
317  auto c = display->getConnection(client);
318  auto resource = c->createResource(&xdg_wm_base_interface, qMin(version, s_version), id);
319  if (!resource) {
320  wl_client_post_no_memory(client);
321  return;
322  }
323  resources[client] = resource;
324  wl_resource_set_implementation(resource, &s_interface, this, unbind);
325 }
326 
327 void XdgShellStableInterface::Private::unbind(wl_resource *resource)
328 {
329  auto s = cast(resource);
330  auto client = wl_resource_get_client(resource);
331  s->resources.remove(client);
332 }
333 
334 XdgTopLevelStableInterface *XdgShellStableInterface::getSurface(wl_resource *resource)
335 {
336  if (!resource) {
337  return nullptr;
338  }
339  Q_D();
340 
341  for (auto it = d->surfaces.constBegin(); it != d->surfaces.constEnd(); it++) {
342  auto topLevel = (*it)->topLevel();
343  if (topLevel && topLevel->resource() == resource) {
344  return topLevel;
345  }
346  }
347  return nullptr;
348 }
349 
350 XdgSurfaceStableInterface *XdgShellStableInterface::realGetSurface(wl_resource *resource)
351 {
352  if (!resource) {
353  return nullptr;
354  }
355  Q_D();
356 
357  for (auto it = d->surfaces.constBegin(); it != d->surfaces.constEnd(); it++) {
358  if ((*it)->resource() == resource) {
359  return (*it);
360  }
361  }
362  return nullptr;
363 }
364 
365 XdgPositionerStableInterface *XdgShellStableInterface::getPositioner(wl_resource *resource)
366 {
367  if (!resource) {
368  return nullptr;
369  }
370  Q_D();
371  for (auto it = d->positioners.constBegin(); it != d->positioners.constEnd(); it++) {
372  if ((*it)->resource() == resource) {
373  return *it;
374  }
375  }
376  return nullptr;
377 }
378 
379 quint32 XdgShellStableInterface::Private::ping(XdgShellSurfaceInterface *surface)
380 {
381  auto client = surface->client()->client();
382  // from here we can get the resource bound to our global.
383 
384  auto clientXdgShellResource = resources.value(client);
385  if (!clientXdgShellResource) {
386  return 0;
387  }
388 
389  const quint32 pingSerial = display->nextSerial();
390  xdg_wm_base_send_ping(clientXdgShellResource, pingSerial);
391 
392  setupTimer(pingSerial);
393  return pingSerial;
394 }
395 
396 XdgShellStableInterface::Private *XdgShellStableInterface::d_func() const
397 {
398  return static_cast<Private *>(d.data());
399 }
400 
401 namespace
402 {
403 template<>
404 Qt::Edges edgesToQtEdges(xdg_toplevel_resize_edge edges)
405 {
406  Qt::Edges qtEdges;
407  switch (edges) {
408  case XDG_TOPLEVEL_RESIZE_EDGE_TOP:
409  qtEdges = Qt::TopEdge;
410  break;
411  case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM:
412  qtEdges = Qt::BottomEdge;
413  break;
414  case XDG_TOPLEVEL_RESIZE_EDGE_LEFT:
415  qtEdges = Qt::LeftEdge;
416  break;
417  case XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT:
418  qtEdges = Qt::TopEdge | Qt::LeftEdge;
419  break;
420  case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT:
421  qtEdges = Qt::BottomEdge | Qt::LeftEdge;
422  break;
423  case XDG_TOPLEVEL_RESIZE_EDGE_RIGHT:
424  qtEdges = Qt::RightEdge;
425  break;
426  case XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT:
427  qtEdges = Qt::TopEdge | Qt::RightEdge;
428  break;
429  case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT:
430  qtEdges = Qt::BottomEdge | Qt::RightEdge;
431  break;
432  case XDG_TOPLEVEL_RESIZE_EDGE_NONE:
433  break;
434  default:
435  Q_UNREACHABLE();
436  break;
437  }
438  return qtEdges;
439 }
440 }
441 
442 #ifndef K_DOXYGEN
443 const struct xdg_surface_interface XdgSurfaceStableInterface::Private::s_interface = {destroyCallback,
444  getTopLevelCallback,
445  getPopupCallback,
446  setWindowGeometryCallback,
447  ackConfigureCallback};
448 #endif
449 
450 void XdgSurfaceStableInterface::Private::destroyCallback(wl_client *client, wl_resource *resource)
451 {
452  Q_UNUSED(client)
453  wl_resource_destroy(resource);
454 }
455 
456 void XdgSurfaceStableInterface::Private::getTopLevelCallback(wl_client *client, wl_resource *resource, uint32_t id)
457 {
458  auto s = cast<XdgSurfaceStableInterface::Private>(resource);
459  s->createTopLevel(client, wl_resource_get_version(resource), id, resource);
460 }
461 
462 void XdgSurfaceStableInterface::Private::createTopLevel(wl_client *client, uint32_t version, uint32_t id, wl_resource *parentResource)
463 {
464  // FIXME: That's incorrect! The client may have asked us to create an xdg-toplevel
465  // for a pointer surface or a subsurface. We have to post an error in that case.
466  if (m_topLevel) {
467  wl_resource_post_error(parentResource, XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED, "Toplevel already created on this surface");
468  return;
469  }
470  if (m_popup) {
471  wl_resource_post_error(parentResource, XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED, "Popup already created on this surface");
472  return;
473  }
474  m_topLevel = new XdgTopLevelStableInterface(m_shell, m_surface, parentResource);
475  m_topLevel->d->create(m_shell->display()->getConnection(client), version, id);
476 
477  Q_EMIT m_shell->surfaceCreated(m_topLevel);
478 }
479 
480 void XdgSurfaceStableInterface::Private::getPopupCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *parent, wl_resource *positioner)
481 {
482  auto s = cast<XdgSurfaceStableInterface::Private>(resource);
483  s->createPopup(client, wl_resource_get_version(resource), id, resource, parent, positioner);
484 }
485 
486 void XdgSurfaceStableInterface::Private::createPopup(wl_client *client,
487  uint32_t version,
488  uint32_t id,
489  wl_resource *parentResource,
490  wl_resource *parentSurface,
491  wl_resource *positioner)
492 {
493  // FIXME: That's incorrect! The client may have asked us to create an xdg-popup
494  // for a pointer surface or a subsurface. We have to post an error in that case.
495  if (m_topLevel) {
496  wl_resource_post_error(parentResource, XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED, "Toplevel already created on this surface");
497  return;
498  }
499  if (m_popup) {
500  wl_resource_post_error(parentResource, XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED, "Popup already created on this surface");
501  return;
502  }
503 
504  auto xdgPositioner = m_shell->getPositioner(positioner);
505  if (!xdgPositioner) {
506  wl_resource_post_error(parentResource, XDG_WM_BASE_ERROR_INVALID_POSITIONER, "Invalid positioner");
507  return;
508  }
509  m_popup = new XdgPopupStableInterface(m_shell, m_surface, parentResource);
510  auto pd = m_popup->d_func();
511 
512  pd->create(m_shell->display()->getConnection(client), version, id);
513 
514  auto parentXdgSurface = m_shell->realGetSurface(parentSurface);
515  if (!parentXdgSurface) {
516  wl_resource_post_error(parentResource, XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT, "Invalid popup parent");
517  return;
518  }
519  pd->parent = parentXdgSurface->surface();
520  pd->initialSize = xdgPositioner->initialSize();
521  pd->anchorRect = xdgPositioner->anchorRect();
522  pd->anchorEdge = xdgPositioner->anchorEdge();
523  pd->gravity = xdgPositioner->gravity();
524  pd->constraintAdjustments = xdgPositioner->constraintAdjustments();
525  pd->anchorOffset = xdgPositioner->anchorOffset();
526 
527  Q_EMIT m_shell->xdgPopupCreated(m_popup.data());
528 }
529 
530 void XdgSurfaceStableInterface::Private::ackConfigureCallback(wl_client *client, wl_resource *resource, uint32_t serial)
531 {
532  auto s = cast<Private>(resource);
533  Q_ASSERT(client == *s->client);
534 
535  if (s->m_topLevel) {
536  s->m_topLevel->d_func()->ackConfigure(serial);
537  } else if (s->m_popup) {
538  s->m_popup->d_func()->ackConfigure(serial);
539  }
540 }
541 
542 void XdgSurfaceStableInterface::Private::setWindowGeometryCallback(wl_client *client,
543  wl_resource *resource,
544  int32_t x,
545  int32_t y,
546  int32_t width,
547  int32_t height)
548 {
549  auto s = cast<Private>(resource);
550  Q_ASSERT(client == *s->client);
551 
552  if (width < 0 || height < 0) {
553  wl_resource_post_error(resource, XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, "Tried to set invalid xdg-surface geometry");
554  return;
555  }
556 
557  if (s->m_topLevel) {
558  s->m_topLevel->d_func()->setWindowGeometryCallback(QRect(x, y, width, height));
559  } else if (s->m_popup) {
560  s->m_popup->d_func()->setWindowGeometryCallback(QRect(x, y, width, height));
561  }
562 }
563 
564 XdgSurfaceStableInterface::Private::Private(XdgSurfaceStableInterface *q, XdgShellStableInterface *c, SurfaceInterface *surface, wl_resource *parentResource)
565  : KWayland::Server::Resource::Private(q, c, parentResource, &xdg_surface_interface, &s_interface)
566  , m_shell(c)
567  , m_surface(surface)
568 {
569 }
570 
571 XdgSurfaceStableInterface::Private::~Private() = default;
572 
573 class XdgPositionerStableInterface::Private : public KWayland::Server::Resource::Private
574 {
575 public:
576  Private(XdgPositionerStableInterface *q, XdgShellStableInterface *c, wl_resource *parentResource);
577 
578  QSize initialSize;
579  QRect anchorRect;
580  Qt::Edges anchorEdge;
581  Qt::Edges gravity;
582  PositionerConstraints constraintAdjustments;
583  QPoint anchorOffset;
584 
585 private:
586  static void setSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height);
587  static void setAnchorRectCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height);
588  static void setAnchorCallback(wl_client *client, wl_resource *resource, uint32_t anchor);
589  static void setGravityCallback(wl_client *client, wl_resource *resource, uint32_t gravity);
590  static void setConstraintAdjustmentCallback(wl_client *client, wl_resource *resource, uint32_t constraint_adjustment);
591  static void setOffsetCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y);
592 
593  static const struct xdg_positioner_interface s_interface;
594 };
595 
596 XdgPositionerStableInterface::Private::Private(XdgPositionerStableInterface *q, XdgShellStableInterface *c, wl_resource *parentResource)
597  : KWayland::Server::Resource::Private(q, c, parentResource, &xdg_positioner_interface, &s_interface)
598 {
599 }
600 
601 #ifndef K_DOXYGEN
602 const struct xdg_positioner_interface XdgPositionerStableInterface::Private::s_interface = {resourceDestroyedCallback,
603  setSizeCallback,
604  setAnchorRectCallback,
605  setAnchorCallback,
606  setGravityCallback,
607  setConstraintAdjustmentCallback,
608  setOffsetCallback};
609 #endif
610 
611 void XdgPositionerStableInterface::Private::setSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height)
612 {
613  Q_UNUSED(client)
614  auto s = cast<Private>(resource);
615  s->initialSize = QSize(width, height);
616 }
617 
618 void XdgPositionerStableInterface::Private::setAnchorRectCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
619 {
620  Q_UNUSED(client)
621  auto s = cast<Private>(resource);
622  s->anchorRect = QRect(x, y, width, height);
623 }
624 
625 void XdgPositionerStableInterface::Private::setAnchorCallback(wl_client *client, wl_resource *resource, uint32_t anchor)
626 {
627  Q_UNUSED(client)
628 
629  auto s = cast<Private>(resource);
630 
631  Qt::Edges qtEdges;
632  switch (anchor) {
633  case XDG_POSITIONER_ANCHOR_TOP:
634  qtEdges = Qt::TopEdge;
635  break;
636  case XDG_POSITIONER_ANCHOR_BOTTOM:
637  qtEdges = Qt::BottomEdge;
638  break;
639  case XDG_POSITIONER_ANCHOR_LEFT:
640  qtEdges = Qt::LeftEdge;
641  break;
642  case XDG_POSITIONER_ANCHOR_TOP_LEFT:
643  qtEdges = Qt::TopEdge | Qt::LeftEdge;
644  break;
645  case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT:
646  qtEdges = Qt::BottomEdge | Qt::LeftEdge;
647  break;
648  case XDG_POSITIONER_ANCHOR_RIGHT:
649  qtEdges = Qt::RightEdge;
650  break;
651  case XDG_POSITIONER_ANCHOR_TOP_RIGHT:
652  qtEdges = Qt::TopEdge | Qt::RightEdge;
653  break;
654  case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT:
655  qtEdges = Qt::BottomEdge | Qt::RightEdge;
656  break;
657  case XDG_POSITIONER_ANCHOR_NONE:
658  break;
659  default:
660  Q_UNREACHABLE();
661  break;
662  }
663 
664  s->anchorEdge = qtEdges;
665 }
666 
667 void XdgPositionerStableInterface::Private::setGravityCallback(wl_client *client, wl_resource *resource, uint32_t gravity)
668 {
669  Q_UNUSED(client)
670  auto s = cast<Private>(resource);
671 
672  Qt::Edges qtEdges;
673  switch (gravity) {
674  case XDG_POSITIONER_GRAVITY_TOP:
675  qtEdges = Qt::TopEdge;
676  break;
677  case XDG_POSITIONER_GRAVITY_BOTTOM:
678  qtEdges = Qt::BottomEdge;
679  break;
680  case XDG_POSITIONER_GRAVITY_LEFT:
681  qtEdges = Qt::LeftEdge;
682  break;
683  case XDG_POSITIONER_GRAVITY_TOP_LEFT:
684  qtEdges = Qt::TopEdge | Qt::LeftEdge;
685  break;
686  case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT:
687  qtEdges = Qt::BottomEdge | Qt::LeftEdge;
688  break;
689  case XDG_POSITIONER_GRAVITY_RIGHT:
690  qtEdges = Qt::RightEdge;
691  break;
692  case XDG_POSITIONER_GRAVITY_TOP_RIGHT:
693  qtEdges = Qt::TopEdge | Qt::RightEdge;
694  break;
695  case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT:
696  qtEdges = Qt::BottomEdge | Qt::RightEdge;
697  break;
698  case XDG_POSITIONER_GRAVITY_NONE:
699  break;
700  default:
701  Q_UNREACHABLE();
702  break;
703  }
704 
705  s->gravity = qtEdges;
706 }
707 
708 void XdgPositionerStableInterface::Private::setConstraintAdjustmentCallback(wl_client *client, wl_resource *resource, uint32_t constraint_adjustment)
709 {
710  Q_UNUSED(client)
711  auto s = cast<Private>(resource);
712  PositionerConstraints constraints;
713  if (constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X) {
714  constraints |= PositionerConstraint::SlideX;
715  }
716  if (constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y) {
717  constraints |= PositionerConstraint::SlideY;
718  }
719  if (constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X) {
720  constraints |= PositionerConstraint::FlipX;
721  }
722  if (constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y) {
723  constraints |= PositionerConstraint::FlipY;
724  }
725  if (constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X) {
726  constraints |= PositionerConstraint::ResizeX;
727  }
728  if (constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y) {
729  constraints |= PositionerConstraint::ResizeY;
730  }
731  s->constraintAdjustments = constraints;
732 }
733 
734 void XdgPositionerStableInterface::Private::setOffsetCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y)
735 {
736  Q_UNUSED(client)
737  auto s = cast<Private>(resource);
738  s->anchorOffset = QPoint(x, y);
739 }
740 
741 QRect XdgTopLevelStableInterface::Private::windowGeometry() const
742 {
743  return m_currentState.windowGeometry;
744 }
745 
746 QSize XdgTopLevelStableInterface::Private::minimumSize() const
747 {
748  return m_currentState.minimumSize;
749 }
750 
751 QSize XdgTopLevelStableInterface::Private::maximumSize() const
752 {
753  return m_currentState.maximiumSize;
754 }
755 
756 void XdgTopLevelStableInterface::Private::close()
757 {
758  xdg_toplevel_send_close(resource);
759  client->flush();
760 }
761 
762 void XdgTopLevelStableInterface::Private::commit()
763 {
764  const bool windowGeometryChanged = m_pendingState.windowGeometryIsSet;
765  const bool minimumSizeChanged = m_pendingState.minimumSizeIsSet;
766  const bool maximumSizeChanged = m_pendingState.maximumSizeIsSet;
767 
768  if (windowGeometryChanged) {
769  m_currentState.windowGeometry = m_pendingState.windowGeometry;
770  }
771  if (minimumSizeChanged) {
772  m_currentState.minimumSize = m_pendingState.minimumSize;
773  }
774  if (maximumSizeChanged) {
775  m_currentState.maximiumSize = m_pendingState.maximiumSize;
776  }
777 
778  m_pendingState = ShellSurfaceState{};
779 
780  if (windowGeometryChanged) {
781  Q_EMIT q_func()->windowGeometryChanged(m_currentState.windowGeometry);
782  }
783  if (minimumSizeChanged) {
784  Q_EMIT q_func()->minSizeChanged(m_currentState.minimumSize);
785  }
786  if (maximumSizeChanged) {
787  Q_EMIT q_func()->maxSizeChanged(m_currentState.maximiumSize);
788  }
789 }
790 
791 void XdgTopLevelStableInterface::Private::setMaxSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height)
792 {
793  if (width < 0 || height < 0) {
794  wl_resource_post_error(resource, XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, "Tried to set invalid xdg-toplevel maximum size");
795  return;
796  }
797  if (width == 0) {
798  width = INT32_MAX;
799  }
800  if (height == 0) {
801  height = INT32_MAX;
802  }
803  auto s = cast<Private>(resource);
804  Q_ASSERT(client == *s->client);
805  s->m_pendingState.maximiumSize = QSize(width, height);
806  s->m_pendingState.maximumSizeIsSet = true;
807 }
808 
809 void XdgTopLevelStableInterface::Private::setMinSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height)
810 {
811  if (width < 0 || height < 0) {
812  wl_resource_post_error(resource, XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, "Tried to set invalid xdg-toplevel minimum size");
813  return;
814  }
815  auto s = cast<Private>(resource);
816  Q_ASSERT(client == *s->client);
817  s->m_pendingState.minimumSize = QSize(width, height);
818  s->m_pendingState.minimumSizeIsSet = true;
819 }
820 
821 void XdgTopLevelStableInterface::Private::setWindowGeometryCallback(const QRect &rect)
822 {
823  m_pendingState.windowGeometry = rect;
824  m_pendingState.windowGeometryIsSet = true;
825 }
826 
827 const struct xdg_toplevel_interface XdgTopLevelStableInterface::Private::s_interface = {destroyCallback,
828  setParentCallback,
829  setTitleCallback,
830  setAppIdCallback,
831  showWindowMenuCallback,
832  moveCallback,
833  resizeCallback<xdg_toplevel_resize_edge>,
834  setMaxSizeCallback,
835  setMinSizeCallback,
836  setMaximizedCallback,
837  unsetMaximizedCallback,
838  setFullscreenCallback,
839  unsetFullscreenCallback,
840  setMinimizedCallback};
841 
842 void XdgTopLevelStableInterface::Private::destroyCallback(wl_client *client, wl_resource *resource)
843 {
844  Q_UNUSED(client)
845  wl_resource_destroy(resource);
846 }
847 
848 void XdgTopLevelStableInterface::Private::setParentCallback(wl_client *client, wl_resource *resource, wl_resource *parent)
849 {
850  auto s = cast<Private>(resource);
851  Q_ASSERT(client == *s->client);
852  if (!parent) {
853  // setting null is valid API. Clear
854  s->parent = nullptr;
855  Q_EMIT s->q_func()->transientForChanged();
856  } else {
857  auto parentSurface = static_cast<XdgShellStableInterface *>(s->q->global())->getSurface(parent);
858  if (s->parent.data() != parentSurface) {
859  s->parent = QPointer<XdgTopLevelStableInterface>(parentSurface);
860  Q_EMIT s->q_func()->transientForChanged();
861  }
862  }
863 }
864 
865 void XdgTopLevelStableInterface::Private::showWindowMenuCallback(wl_client *client,
866  wl_resource *resource,
867  wl_resource *seat,
868  uint32_t serial,
869  int32_t x,
870  int32_t y)
871 {
872  auto s = cast<Private>(resource);
873  Q_ASSERT(client == *s->client);
874  Q_EMIT s->q_func()->windowMenuRequested(SeatInterface::get(seat), serial, QPoint(x, y));
875 }
876 
877 XdgTopLevelStableInterface::Private::Private(XdgTopLevelStableInterface *q, XdgShellStableInterface *c, SurfaceInterface *surface, wl_resource *parentResource)
878  : XdgShellSurfaceInterface::Private(XdgShellInterfaceVersion::Stable, q, c, surface, parentResource, &xdg_toplevel_interface, &s_interface)
879 {
880 }
881 
882 void XdgTopLevelStableInterface::Private::setMaximizedCallback(wl_client *client, wl_resource *resource)
883 {
884  auto s = cast<Private>(resource);
885  Q_ASSERT(client == *s->client);
886  s->q_func()->maximizedChanged(true);
887 }
888 
889 void XdgTopLevelStableInterface::Private::unsetMaximizedCallback(wl_client *client, wl_resource *resource)
890 {
891  auto s = cast<Private>(resource);
892  Q_ASSERT(client == *s->client);
893  s->q_func()->maximizedChanged(false);
894 }
895 
896 void XdgTopLevelStableInterface::Private::setFullscreenCallback(wl_client *client, wl_resource *resource, wl_resource *output)
897 {
898  auto s = cast<Private>(resource);
899  Q_ASSERT(client == *s->client);
900  OutputInterface *o = nullptr;
901  if (output) {
902  o = OutputInterface::get(output);
903  }
904  s->q_func()->fullscreenChanged(true, o);
905 }
906 
907 void XdgTopLevelStableInterface::Private::unsetFullscreenCallback(wl_client *client, wl_resource *resource)
908 {
909  auto s = cast<Private>(resource);
910  Q_ASSERT(client == *s->client);
911  s->q_func()->fullscreenChanged(false, nullptr);
912 }
913 
914 void XdgTopLevelStableInterface::Private::setMinimizedCallback(wl_client *client, wl_resource *resource)
915 {
916  auto s = cast<Private>(resource);
917  Q_ASSERT(client == *s->client);
918  s->q_func()->minimizeRequested();
919 }
920 
921 XdgTopLevelStableInterface::Private::~Private() = default;
922 
923 #ifndef K_DOXYGEN
924 const struct xdg_popup_interface XdgPopupStableInterface::Private::s_interface = {resourceDestroyedCallback, grabCallback};
925 #endif
926 
927 XdgPopupStableInterface::Private::Private(XdgPopupStableInterface *q, XdgShellStableInterface *c, SurfaceInterface *surface, wl_resource *parentResource)
928  : XdgShellPopupInterface::Private(XdgShellInterfaceVersion::Stable, q, c, surface, parentResource, &xdg_popup_interface, &s_interface)
929 {
930 }
931 
932 QRect XdgPopupStableInterface::Private::windowGeometry() const
933 {
934  return m_currentState.windowGeometry;
935 }
936 
937 void XdgPopupStableInterface::Private::commit()
938 {
939  const bool windowGeometryChanged = m_pendingState.windowGeometryIsSet;
940 
941  if (windowGeometryChanged) {
942  m_currentState.windowGeometry = m_pendingState.windowGeometry;
943  }
944 
945  m_pendingState = ShellSurfaceState{};
946 
947  if (windowGeometryChanged) {
948  Q_EMIT q_func()->windowGeometryChanged(m_currentState.windowGeometry);
949  }
950 }
951 
952 void XdgPopupStableInterface::Private::setWindowGeometryCallback(const QRect &rect)
953 {
954  m_pendingState.windowGeometry = rect;
955  m_pendingState.windowGeometryIsSet = true;
956 }
957 
958 void XdgPopupStableInterface::Private::grabCallback(wl_client *client, wl_resource *resource, wl_resource *seat, uint32_t serial)
959 {
960  Q_UNUSED(client)
961  auto s = cast<Private>(resource);
962  auto seatInterface = SeatInterface::get(seat);
963  s->q_func()->grabRequested(seatInterface, serial);
964 }
965 
966 XdgPopupStableInterface::Private::~Private() = default;
967 
968 quint32 XdgPopupStableInterface::Private::configure(const QRect &rect)
969 {
970  if (!resource) {
971  return 0;
972  }
973  const quint32 serial = global->display()->nextSerial();
974  configureSerials << serial;
975  xdg_popup_send_configure(resource, rect.x(), rect.y(), rect.width(), rect.height());
976  xdg_surface_send_configure(parentResource, serial);
977  client->flush();
978 
979  return serial;
980 }
981 
982 void XdgPopupStableInterface::Private::popupDone()
983 {
984  if (!resource) {
985  return;
986  }
987  // TODO: dismiss all child popups
988  xdg_popup_send_popup_done(resource);
989  client->flush();
990 }
991 
992 XdgShellStableInterface::XdgShellStableInterface(Display *display, QObject *parent)
993  : XdgShellInterface(new Private(this, display), parent)
994 {
995 }
996 
997 Display *XdgShellStableInterface::display() const
998 {
999  return d->display;
1000 }
1001 
1002 XdgShellStableInterface::~XdgShellStableInterface() = default;
1003 
1004 XdgSurfaceStableInterface::XdgSurfaceStableInterface(XdgShellStableInterface *parent, SurfaceInterface *surface, wl_resource *parentResource)
1005  : KWayland::Server::Resource(new Private(this, parent, surface, parentResource))
1006 {
1007 }
1008 
1009 XdgSurfaceStableInterface::~XdgSurfaceStableInterface() = default;
1010 
1011 SurfaceInterface *XdgSurfaceStableInterface::surface() const
1012 {
1013  Q_D();
1014  return d->m_surface;
1015 }
1016 
1017 XdgPositionerStableInterface::XdgPositionerStableInterface(XdgShellStableInterface *parent, wl_resource *parentResource)
1018  : KWayland::Server::Resource(new Private(this, parent, parentResource))
1019 {
1020 }
1021 
1022 QSize XdgPositionerStableInterface::initialSize() const
1023 {
1024  Q_D();
1025  return d->initialSize;
1026 }
1027 
1028 QRect XdgPositionerStableInterface::anchorRect() const
1029 {
1030  Q_D();
1031  return d->anchorRect;
1032 }
1033 
1034 Qt::Edges XdgPositionerStableInterface::anchorEdge() const
1035 {
1036  Q_D();
1037  return d->anchorEdge;
1038 }
1039 
1040 Qt::Edges XdgPositionerStableInterface::gravity() const
1041 {
1042  Q_D();
1043  return d->gravity;
1044 }
1045 
1046 PositionerConstraints XdgPositionerStableInterface::constraintAdjustments() const
1047 {
1048  Q_D();
1049  return d->constraintAdjustments;
1050 }
1051 
1052 QPoint XdgPositionerStableInterface::anchorOffset() const
1053 {
1054  Q_D();
1055  return d->anchorOffset;
1056 }
1057 
1058 XdgPositionerStableInterface::Private *XdgPositionerStableInterface::d_func() const
1059 {
1060  return static_cast<Private *>(d.data());
1061 }
1062 
1063 XdgTopLevelStableInterface *XdgSurfaceStableInterface::topLevel() const
1064 {
1065  Q_D();
1066  return d->m_topLevel.data();
1067 }
1068 
1069 XdgPopupStableInterface *XdgSurfaceStableInterface::popup() const
1070 {
1071  Q_D();
1072  return d->m_popup.data();
1073 }
1074 
1075 XdgSurfaceStableInterface::Private *XdgSurfaceStableInterface::d_func() const
1076 {
1077  return static_cast<Private *>(d.data());
1078 }
1079 
1080 XdgTopLevelStableInterface::XdgTopLevelStableInterface(XdgShellStableInterface *parent, SurfaceInterface *surface, wl_resource *parentResource)
1081  : KWayland::Server::XdgShellSurfaceInterface(new Private(this, parent, surface, parentResource))
1082 {
1083 }
1084 
1085 XdgTopLevelStableInterface::~XdgTopLevelStableInterface() = default;
1086 
1087 XdgTopLevelStableInterface::Private *XdgTopLevelStableInterface::d_func() const
1088 {
1089  return static_cast<Private *>(d.data());
1090 }
1091 
1092 XdgPopupStableInterface::XdgPopupStableInterface(XdgShellStableInterface *parent, SurfaceInterface *surface, wl_resource *parentResource)
1093  : XdgShellPopupInterface(new Private(this, parent, surface, parentResource))
1094 {
1095 }
1096 
1097 XdgPopupStableInterface::~XdgPopupStableInterface() = default;
1098 
1099 XdgPopupStableInterface::Private *XdgPopupStableInterface::d_func() const
1100 {
1101  return static_cast<Private *>(d.data());
1102 }
1103 
1104 }
1105 }
XdgShellInterfaceVersion
Enum describing the different InterfaceVersion encapsulated in this implementation.
KGuiItem configure()
@ FlipX
Invert the anchor and gravity on the X axis.
@ ResizeY
Resize the popup in the Y axis.
int width() const const
int x() const const
int y() const const
int width() const const
const QList< QKeySequence > & close()
@ SlideX
Slide the popup on the X axis until there is room.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
static SurfaceInterface * get(wl_resource *native)
void destroyed(QObject *obj)
@ ResizeX
Resize the popup in the X axis.
int height() const const
@ SlideY
Slide the popup on the Y axis until there is room.
int height() const const
typedef Edges
Q_D(Todo)
@ FlipY
Invert the anchor and gravity on the Y axis.
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Feb 7 2023 03:56:22 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.