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

KDE's Doxygen guidelines are available online.