KWayland

xdgshell_v6_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_v6_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-v6-server-protocol.h>
19 
20 namespace KWayland
21 {
22 namespace Server
23 {
24 
25 class XdgShellV6Interface::Private : public XdgShellInterface::Private
26 {
27 public:
28  Private(XdgShellV6Interface *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 reinterpret_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  XdgShellV6Interface *q;
53  static const struct zxdg_shell_v6_interface s_interface;
54  static const quint32 s_version;
56 };
57 
58 class XdgPopupV6Interface::Private : public XdgShellPopupInterface::Private
59 {
60 public:
61  Private(XdgPopupV6Interface *q, XdgShellV6Interface *c, SurfaceInterface *surface, wl_resource *parentResource);
62  ~Private();
63 
64  QRect windowGeometry() const override;
65  void commit() override;
66 
67  void ackConfigure(quint32 serial) {
68  if (!configureSerials.contains(serial)) {
69  // TODO: send error?
70  return;
71  }
72  while (!configureSerials.isEmpty()) {
73  quint32 i = configureSerials.takeFirst();
74  emit q_func()->configureAcknowledged(i);
75  if (i == serial) {
76  break;
77  }
78  }
79  }
80 
81  void popupDone() override;
82  quint32 configure(const QRect &rect) override;
83 
84  XdgPopupV6Interface *q_func() {
85  return reinterpret_cast<XdgPopupV6Interface *>(q);
86  }
87 private:
88  void setWindowGeometryCallback(const QRect &rect);
89 
90  static void grabCallback(wl_client *client, wl_resource *resource, wl_resource *seat, uint32_t serial);
91 
92  static const struct zxdg_popup_v6_interface s_interface;
93 
94  struct ShellSurfaceState
95  {
96  QRect windowGeometry;
97 
98  bool windowGeometryIsSet = false;
99  };
100 
101  ShellSurfaceState m_currentState;
102  ShellSurfaceState m_pendingState;
103 
104  friend class XdgSurfaceV6Interface;
105 };
106 
107 class XdgSurfaceV6Interface::Private : public KWayland::Server::Resource::Private
108 {
109 public:
110  Private(XdgSurfaceV6Interface* q, XdgShellV6Interface* c, SurfaceInterface* surface, wl_resource* parentResource);
111 
112  ~Private();
113 
114  XdgSurfaceV6Interface *q_func() {
115  return reinterpret_cast<XdgSurfaceV6Interface *>(q);
116  }
117 
118  void createTopLevel(wl_client *client, uint32_t version, uint32_t id, wl_resource *parentResource);
119  void createPopup(wl_client *client, uint32_t version, uint32_t id, wl_resource *parentResource, wl_resource *parentWindow, wl_resource *positioner);
120  XdgShellV6Interface *m_shell;
121  SurfaceInterface *m_surface;
122 
123  //effectively a union, only one of these should be populated.
124  //a surface cannot have two roles
127 
128 private:
129  static void destroyCallback(wl_client *client, wl_resource *resource);
130  static void getTopLevelCallback(wl_client *client, wl_resource *resource, uint32_t id);
131  static void getPopupCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *parent, wl_resource *positioner);
132  static void ackConfigureCallback(wl_client *client, wl_resource *resource, uint32_t serial);
133  static void setWindowGeometryCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height);
134  static const struct zxdg_surface_v6_interface s_interface;
135 };
136 
137 class XdgTopLevelV6Interface::Private : public XdgShellSurfaceInterface::Private
138 {
139 public:
140  Private(XdgTopLevelV6Interface* q, XdgShellV6Interface* c, SurfaceInterface* surface, wl_resource* parentResource);
141  ~Private();
142 
143  QRect windowGeometry() const override;
144  QSize minimumSize() const override;
145  QSize maximumSize() const override;
146  void close() override;
147  void commit() override;
148 
149  void ackConfigure(quint32 serial) {
150  if (!configureSerials.contains(serial)) {
151  // TODO: send error?
152  return;
153  }
154  while (!configureSerials.isEmpty()) {
155  quint32 i = configureSerials.takeFirst();
156  emit q_func()->configureAcknowledged(i);
157  if (i == serial) {
158  break;
159  }
160  }
161  }
162 
163  quint32 configure(States states, const QSize &size) override {
164  if (!resource) {
165  return 0;
166  }
167  const quint32 serial = global->display()->nextSerial();
168  wl_array state;
169  wl_array_init(&state);
170  if (states.testFlag(State::Maximized)) {
171  uint32_t *s = reinterpret_cast<uint32_t*>(wl_array_add(&state, sizeof(uint32_t)));
172  *s = ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED;
173  }
174  if (states.testFlag(State::Fullscreen)) {
175  uint32_t *s = reinterpret_cast<uint32_t*>(wl_array_add(&state, sizeof(uint32_t)));
176  *s = ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN;
177  }
178  if (states.testFlag(State::Resizing)) {
179  uint32_t *s = reinterpret_cast<uint32_t*>(wl_array_add(&state, sizeof(uint32_t)));
180  *s = ZXDG_TOPLEVEL_V6_STATE_RESIZING;
181  }
182  if (states.testFlag(State::Activated)) {
183  uint32_t *s = reinterpret_cast<uint32_t*>(wl_array_add(&state, sizeof(uint32_t)));
184  *s = ZXDG_TOPLEVEL_V6_STATE_ACTIVATED;
185  }
186  configureSerials << serial;
187  zxdg_toplevel_v6_send_configure(resource, size.width(), size.height(), &state);
188 
189  zxdg_surface_v6_send_configure(parentResource, serial);
190 
191  client->flush();
192  wl_array_release(&state);
193  return serial;
194  };
195 
196  XdgTopLevelV6Interface *q_func() {
197  return reinterpret_cast<XdgTopLevelV6Interface*>(q);
198  }
199 
200 private:
201  void setWindowGeometryCallback(const QRect &rect);
202 
203  static void destroyCallback(wl_client *client, wl_resource *resource);
204  static void setParentCallback(struct wl_client *client, struct wl_resource *resource, wl_resource *parent);
205  static void showWindowMenuCallback(wl_client *client, wl_resource *resource, wl_resource *seat, uint32_t serial, int32_t x, int32_t y);
206  static void setMaxSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height);
207  static void setMinSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height);
208  static void setMaximizedCallback(wl_client *client, wl_resource *resource);
209  static void unsetMaximizedCallback(wl_client *client, wl_resource *resource);
210  static void setFullscreenCallback(wl_client *client, wl_resource *resource, wl_resource *output);
211  static void unsetFullscreenCallback(wl_client *client, wl_resource *resource);
212  static void setMinimizedCallback(wl_client *client, wl_resource *resource);
213 
214  static const struct zxdg_toplevel_v6_interface s_interface;
215 
216  struct ShellSurfaceState
217  {
218  QRect windowGeometry;
219  QSize minimumSize = QSize(0, 0);
220  QSize maximiumSize = QSize(INT32_MAX, INT32_MAX);
221 
222  bool windowGeometryIsSet = false;
223  bool minimumSizeIsSet = false;
224  bool maximumSizeIsSet = false;
225  };
226 
227  ShellSurfaceState m_currentState;
228  ShellSurfaceState m_pendingState;
229 
230  friend class XdgSurfaceV6Interface;
231 };
232 
233 
234 const quint32 XdgShellV6Interface::Private::s_version = 1;
235 
236 #ifndef K_DOXYGEN
237 const struct zxdg_shell_v6_interface XdgShellV6Interface::Private::s_interface = {
238  destroyCallback,
239  createPositionerCallback,
240  getXdgSurfaceCallback,
241  pongCallback
242 };
243 #endif
244 
245 void XdgShellV6Interface::Private::destroyCallback(wl_client *client, wl_resource *resource)
246 {
247  Q_UNUSED(client)
248  // TODO: send protocol error if there are still surfaces mapped
249  wl_resource_destroy(resource);
250 }
251 
252 void XdgShellV6Interface::Private::createPositionerCallback(wl_client *client, wl_resource *resource, uint32_t id)
253 {
254  auto s = cast(resource);
255  s->createPositioner(client, wl_resource_get_version(resource), id, resource);
256 }
257 
258 void XdgShellV6Interface::Private::getXdgSurfaceCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * surface)
259 {
260  auto s = cast(resource);
261  s->createSurface(client, wl_resource_get_version(resource), id, SurfaceInterface::get(surface), resource);
262 }
263 
264 void XdgShellV6Interface::Private::createSurface(wl_client *client, uint32_t version, uint32_t id, SurfaceInterface *surface, wl_resource *parentResource)
265 {
266  auto it = std::find_if(surfaces.constBegin(), surfaces.constEnd(),
267  [surface](XdgSurfaceV6Interface *s) {
268  return false;
269  return surface == s->surface();
270  }
271  );
272  if (it != surfaces.constEnd()) {
273  wl_resource_post_error(surface->resource(), ZXDG_SHELL_V6_ERROR_ROLE, "ShellSurface already created");
274  return;
275  }
276  XdgSurfaceV6Interface *shellSurface = new XdgSurfaceV6Interface(q, surface, parentResource);
277  surfaces << shellSurface;
278  QObject::connect(shellSurface, &XdgSurfaceV6Interface::destroyed, q,
279  [this, shellSurface] {
280  surfaces.removeAll(shellSurface);
281  }
282  );
283 
284  shellSurface->d->create(display->getConnection(client), version, id);
285 }
286 
287 void XdgShellV6Interface::Private::createPositioner(wl_client *client, uint32_t version, uint32_t id, wl_resource *parentResource)
288 {
289  Q_UNUSED(client)
290 
291  XdgPositionerV6Interface *positioner = new XdgPositionerV6Interface(q, parentResource);
292  positioners << positioner;
293  QObject::connect(positioner, &Resource::destroyed, q,
294  [this, positioner] {
295  positioners.removeAll(positioner);
296  }
297  );
298  positioner->d->create(display->getConnection(client), version, id);
299 }
300 
301 void XdgShellV6Interface::Private::pongCallback(wl_client *client, wl_resource *resource, uint32_t serial)
302 {
303  Q_UNUSED(client)
304  auto s = cast(resource);
305  auto timerIt = s->pingTimers.find(serial);
306  if (timerIt != s->pingTimers.end() && timerIt.value()->isActive()) {
307  delete timerIt.value();
308  s->pingTimers.erase(timerIt);
309  emit s->q->pongReceived(serial);
310  }
311 }
312 
313 XdgShellV6Interface::Private::Private(XdgShellV6Interface *q, Display *d)
314  : XdgShellInterface::Private(XdgShellInterfaceVersion::UnstableV6, q, d, &zxdg_shell_v6_interface, 1)
315  , q(q)
316 {
317 }
318 
319 void XdgShellV6Interface::Private::bind(wl_client *client, uint32_t version, uint32_t id)
320 {
321  auto c = display->getConnection(client);
322  auto resource = c->createResource(&zxdg_shell_v6_interface, qMin(version, s_version), id);
323  if (!resource) {
324  wl_client_post_no_memory(client);
325  return;
326  }
327  resources[client] = resource;
328  wl_resource_set_implementation(resource, &s_interface, this, unbind);
329 }
330 
331 void XdgShellV6Interface::Private::unbind(wl_resource *resource)
332 {
333  auto s = cast(resource);
334  auto client = wl_resource_get_client(resource);
335  s->resources.remove(client);
336 }
337 
338 XdgTopLevelV6Interface *XdgShellV6Interface::getSurface(wl_resource *resource)
339 {
340  if (!resource) {
341  return nullptr;
342  }
343  Q_D();
344 
345  for (auto it = d->surfaces.constBegin(); it != d->surfaces.constEnd() ; it++) {
346  auto topLevel = (*it)->topLevel();
347  if (topLevel && topLevel->resource() == resource) {
348  return topLevel;
349  }
350  }
351  return nullptr;
352 }
353 
354 XdgSurfaceV6Interface *XdgShellV6Interface::realGetSurface(wl_resource *resource)
355 {
356  if (!resource) {
357  return nullptr;
358  }
359  Q_D();
360 
361  for (auto it = d->surfaces.constBegin(); it != d->surfaces.constEnd() ; it++) {
362  if ((*it)->resource() == resource) {
363  return (*it);
364  }
365  }
366  return nullptr;
367 }
368 
369 XdgPositionerV6Interface *XdgShellV6Interface::getPositioner(wl_resource *resource)
370 {
371  if (!resource) {
372  return nullptr;
373  }
374  Q_D();
375  for (auto it = d->positioners.constBegin(); it != d->positioners.constEnd() ; it++) {
376  if ((*it)->resource() == resource) {
377  return *it;
378  }
379  }
380  return nullptr;
381 }
382 
383 quint32 XdgShellV6Interface::Private::ping(XdgShellSurfaceInterface *surface)
384 {
385  auto client = surface->client()->client();
386  //from here we can get the resource bound to our global.
387 
388  auto clientXdgShellResource = resources.value(client);
389  if (!clientXdgShellResource) {
390  return 0;
391  }
392 
393  const quint32 pingSerial = display->nextSerial();
394  zxdg_shell_v6_send_ping(clientXdgShellResource, pingSerial);
395 
396  setupTimer(pingSerial);
397  return pingSerial;
398 }
399 
400 XdgShellV6Interface::Private *XdgShellV6Interface::d_func() const
401 {
402  return reinterpret_cast<Private*>(d.data());
403 }
404 
405 namespace {
406 template <>
407 Qt::Edges edgesToQtEdges(zxdg_toplevel_v6_resize_edge edges)
408 {
409  Qt::Edges qtEdges;
410  switch (edges) {
411  case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP:
412  qtEdges = Qt::TopEdge;
413  break;
414  case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM:
415  qtEdges = Qt::BottomEdge;
416  break;
417  case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_LEFT:
418  qtEdges = Qt::LeftEdge;
419  break;
420  case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_LEFT:
421  qtEdges = Qt::TopEdge | Qt::LeftEdge;
422  break;
423  case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_LEFT:
424  qtEdges = Qt::BottomEdge | Qt::LeftEdge;
425  break;
426  case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_RIGHT:
427  qtEdges = Qt::RightEdge;
428  break;
429  case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_RIGHT:
430  qtEdges = Qt::TopEdge | Qt::RightEdge;
431  break;
432  case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_RIGHT:
433  qtEdges = Qt::BottomEdge | Qt::RightEdge;
434  break;
435  case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_NONE:
436  break;
437  default:
438  Q_UNREACHABLE();
439  break;
440  }
441  return qtEdges;
442 }
443 }
444 
445 #ifndef K_DOXYGEN
446 const struct zxdg_surface_v6_interface XdgSurfaceV6Interface::Private::s_interface = {
447  destroyCallback,
448  getTopLevelCallback,
449  getPopupCallback,
450  setWindowGeometryCallback,
451  ackConfigureCallback
452 };
453 #endif
454 
455 void XdgSurfaceV6Interface::Private::destroyCallback(wl_client *client, wl_resource *resource)
456 {
457  Q_UNUSED(client)
458  //FIXME check if we have attached toplevels first and throw an error
459  wl_resource_destroy(resource);
460 }
461 
462 void XdgSurfaceV6Interface::Private::getTopLevelCallback(wl_client *client, wl_resource *resource, uint32_t id)
463 {
464  auto s = cast<XdgSurfaceV6Interface::Private>(resource);
465  s->createTopLevel(client, wl_resource_get_version(resource), id, resource);
466 }
467 
468 void XdgSurfaceV6Interface::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, ZXDG_SHELL_V6_ERROR_ROLE, "Toplevel already created on this surface");
474  return;
475  }
476  if (m_popup) {
477  wl_resource_post_error(parentResource, ZXDG_SHELL_V6_ERROR_ROLE, "Popup already created on this surface");
478  return;
479  }
480  m_topLevel = new XdgTopLevelV6Interface (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 XdgSurfaceV6Interface::Private::getPopupCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *parent, wl_resource *positioner)
488 {
489  auto s = cast<XdgSurfaceV6Interface::Private>(resource);
490  s->createPopup(client, wl_resource_get_version(resource), id, resource, parent, positioner);
491 }
492 
493 void XdgSurfaceV6Interface::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, ZXDG_SHELL_V6_ERROR_ROLE, "Toplevel already created on this surface");
499  return;
500  }
501  if (m_popup) {
502  wl_resource_post_error(parentResource, ZXDG_SHELL_V6_ERROR_ROLE, "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, ZXDG_SHELL_V6_ERROR_INVALID_POSITIONER, "Invalid positioner");
509  return;
510  }
511  m_popup = new XdgPopupV6Interface(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  pd->parent = parentXdgSurface->surface();
519  } else {
520  wl_resource_post_error(parentResource, ZXDG_SHELL_V6_ERROR_INVALID_POPUP_PARENT, "Invalid popup parent");
521  return;
522  }
523 
524  pd->initialSize = xdgPositioner->initialSize();
525  pd->anchorRect = xdgPositioner->anchorRect();
526  pd->anchorEdge = xdgPositioner->anchorEdge();
527  pd->gravity = xdgPositioner->gravity();
528  pd->constraintAdjustments = xdgPositioner->constraintAdjustments();
529  pd->anchorOffset = xdgPositioner->anchorOffset();
530 
531  emit m_shell->xdgPopupCreated(m_popup.data());
532 }
533 
534 
535 void XdgSurfaceV6Interface::Private::ackConfigureCallback(wl_client *client, wl_resource *resource, uint32_t serial)
536 {
537  auto s = cast<Private>(resource);
538  Q_ASSERT(client == *s->client);
539 
540  if (s->m_topLevel) {
541  s->m_topLevel->d_func()->ackConfigure(serial);
542  } else if (s->m_popup) {
543  s->m_popup->d_func()->ackConfigure(serial);
544  }
545 }
546 
547 void XdgSurfaceV6Interface::Private::setWindowGeometryCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, 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, ZXDG_SHELL_V6_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 XdgSurfaceV6Interface::Private::Private(XdgSurfaceV6Interface *q, XdgShellV6Interface *c, SurfaceInterface *surface, wl_resource *parentResource)
565  : KWayland::Server::Resource::Private(q, c, parentResource, &zxdg_surface_v6_interface, &s_interface),
566  m_shell(c),
567  m_surface(surface)
568 {
569 }
570 
571 XdgSurfaceV6Interface::Private::~Private() = default;
572 
573 
574 class XdgPositionerV6Interface::Private : public KWayland::Server::Resource::Private
575 {
576 public:
577  Private(XdgPositionerV6Interface *q, XdgShellV6Interface *c, wl_resource* parentResource);
578 
583  PositionerConstraints constraintAdjustments;
585 
586 private:
587  static void setSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height);
588  static void setAnchorRectCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height);
589  static void setAnchorCallback(wl_client *client, wl_resource *resource, uint32_t anchor);
590  static void setGravityCallback(wl_client *client, wl_resource *resource, uint32_t gravity);
591  static void setConstraintAdjustmentCallback(wl_client *client, wl_resource *resource, uint32_t constraint_adjustment);
592  static void setOffsetCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y);
593 
594  static const struct zxdg_positioner_v6_interface s_interface;
595 };
596 
597 XdgPositionerV6Interface::Private::Private(XdgPositionerV6Interface *q, XdgShellV6Interface *c, wl_resource *parentResource)
598  : KWayland::Server::Resource::Private(q, c, parentResource, &zxdg_positioner_v6_interface, &s_interface)
599 {
600 }
601 
602 #ifndef K_DOXYGEN
603 const struct zxdg_positioner_v6_interface XdgPositionerV6Interface::Private::s_interface = {
604  resourceDestroyedCallback,
605  setSizeCallback,
606  setAnchorRectCallback,
607  setAnchorCallback,
608  setGravityCallback,
609  setConstraintAdjustmentCallback,
610  setOffsetCallback
611 };
612 #endif
613 
614 
615 void XdgPositionerV6Interface::Private::setSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height) {
616  Q_UNUSED(client)
617  auto s = cast<Private>(resource);
618  s->initialSize = QSize(width, height);
619 }
620 
621 void XdgPositionerV6Interface::Private::setAnchorRectCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
622 {
623  Q_UNUSED(client)
624  auto s = cast<Private>(resource);
625  s->anchorRect = QRect(x, y, width, height);
626 }
627 
628 void XdgPositionerV6Interface::Private::setAnchorCallback(wl_client *client, wl_resource *resource, uint32_t anchor) {
629  Q_UNUSED(client)
630 
631  auto s = cast<Private>(resource);
632  //Note - see David E's email to wayland-devel about this being bad API
633  if ((anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT) &&
634  (anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT)) {
635  wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, "Invalid arguments");
636  return;
637  }
638  if ((anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP) &&
639  (anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM)) {
640  wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, "Invalid arguments");
641  return;
642  }
643 
644  Qt::Edges edges;
645  if (anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT) {
646  edges |= Qt::LeftEdge;
647  }
648  if (anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP) {
649  edges |= Qt::TopEdge;
650  }
651  if (anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT) {
652  edges |= Qt::RightEdge;
653  }
654  if (anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM) {
655  edges |= Qt::BottomEdge;
656  }
657 
658  s->anchorEdge = edges;
659 }
660 
661 void XdgPositionerV6Interface::Private::setGravityCallback(wl_client *client, wl_resource *resource, uint32_t gravity) {
662  Q_UNUSED(client)
663  auto s = cast<Private>(resource);
664  if ((gravity & ZXDG_POSITIONER_V6_GRAVITY_LEFT) &&
665  (gravity & ZXDG_POSITIONER_V6_GRAVITY_RIGHT)) {
666  wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, "Invalid arguments");
667  return;
668  }
669  if ((gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP) &&
670  (gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM)) {
671  wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, "Invalid arguments");
672  return;
673  }
674 
675  Qt::Edges edges;
676  if (gravity & ZXDG_POSITIONER_V6_ANCHOR_LEFT) {
677  edges |= Qt::LeftEdge;
678  }
679  if (gravity & ZXDG_POSITIONER_V6_ANCHOR_TOP) {
680  edges |= Qt::TopEdge;
681  }
682  if (gravity & ZXDG_POSITIONER_V6_ANCHOR_RIGHT) {
683  edges |= Qt::RightEdge;
684  }
685  if (gravity & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM) {
686  edges |= Qt::BottomEdge;
687  }
688 
689  s->gravity = edges;
690 }
691 
692 void XdgPositionerV6Interface::Private::setConstraintAdjustmentCallback(wl_client *client, wl_resource *resource, uint32_t constraint_adjustment) {
693  Q_UNUSED(client)
694  auto s = cast<Private>(resource);
695  PositionerConstraints constraints;
696  if (constraint_adjustment & ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X) {
697  constraints |= PositionerConstraint::SlideX;
698  }
699  if (constraint_adjustment & ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y) {
700  constraints |= PositionerConstraint::SlideY;
701  }
702  if (constraint_adjustment & ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X) {
703  constraints |= PositionerConstraint::FlipX;
704  }
705  if (constraint_adjustment & ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y) {
706  constraints |= PositionerConstraint::FlipY;
707  }
708  if (constraint_adjustment & ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X) {
709  constraints |= PositionerConstraint::ResizeX;
710  }
711  if (constraint_adjustment & ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y) {
712  constraints |= PositionerConstraint::ResizeY;
713  }
714  s->constraintAdjustments = constraints;
715 }
716 
717 void XdgPositionerV6Interface::Private::setOffsetCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y)
718 {
719  Q_UNUSED(client)
720  auto s = cast<Private>(resource);
721  s->anchorOffset = QPoint(x,y);
722 }
723 
724 QRect XdgTopLevelV6Interface::Private::windowGeometry() const
725 {
726  return m_currentState.windowGeometry;
727 }
728 
729 QSize XdgTopLevelV6Interface::Private::minimumSize() const
730 {
731  return m_currentState.minimumSize;
732 }
733 
734 QSize XdgTopLevelV6Interface::Private::maximumSize() const
735 {
736  return m_currentState.maximiumSize;
737 }
738 
739 void XdgTopLevelV6Interface::Private::close()
740 {
741  zxdg_toplevel_v6_send_close(resource);
742  client->flush();
743 }
744 
745 void XdgTopLevelV6Interface::Private::setMaxSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height)
746 {
747  if (width < 0 || height < 0) {
748  wl_resource_post_error(resource, ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE, "Tried to set invalid xdg-toplevel maximum size");
749  return;
750  }
751  if (width == 0) {
752  width = INT32_MAX;
753  }
754  if (height == 0) {
755  height = INT32_MAX;
756  }
757  auto s = cast<Private>(resource);
758  Q_ASSERT(client == *s->client);
759  s->m_pendingState.maximiumSize = QSize(width, height);
760  s->m_pendingState.maximumSizeIsSet = true;
761 }
762 
763 void XdgTopLevelV6Interface::Private::setMinSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height)
764 {
765  if (width < 0 || height < 0) {
766  wl_resource_post_error(resource, ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE, "Tried to set invalid xdg-toplevel minimum size");
767  return;
768  }
769  auto s = cast<Private>(resource);
770  Q_ASSERT(client == *s->client);
771  s->m_pendingState.minimumSize = QSize(width, height);
772  s->m_pendingState.minimumSizeIsSet = true;
773 }
774 
775 void XdgTopLevelV6Interface::Private::setWindowGeometryCallback(const QRect &rect)
776 {
777  m_pendingState.windowGeometry = rect;
778  m_pendingState.windowGeometryIsSet = true;
779 }
780 
781 const struct zxdg_toplevel_v6_interface XdgTopLevelV6Interface::Private::s_interface = {
782  destroyCallback,
783  setParentCallback,
784  setTitleCallback,
785  setAppIdCallback,
786  showWindowMenuCallback,
787  moveCallback,
788  resizeCallback<zxdg_toplevel_v6_resize_edge>,
789  setMaxSizeCallback,
790  setMinSizeCallback,
791  setMaximizedCallback,
792  unsetMaximizedCallback,
793  setFullscreenCallback,
794  unsetFullscreenCallback,
795  setMinimizedCallback
796 };
797 
798 void XdgTopLevelV6Interface::Private::destroyCallback(wl_client *client, wl_resource *resource)
799 {
800  Q_UNUSED(client)
801  wl_resource_destroy(resource);
802 }
803 
804 void XdgTopLevelV6Interface::Private::setParentCallback(wl_client *client, wl_resource *resource, wl_resource *parent)
805 {
806  auto s = cast<Private>(resource);
807  Q_ASSERT(client == *s->client);
808  if (!parent) {
809  //setting null is valid API. Clear
810  s->parent = nullptr;
811  emit s->q_func()->transientForChanged();
812  } else {
813  auto parentSurface = static_cast<XdgShellV6Interface*>(s->q->global())->getSurface(parent);
814  if (s->parent.data() != parentSurface) {
815  s->parent = QPointer<XdgTopLevelV6Interface>(parentSurface);
816  emit s->q_func()->transientForChanged();
817  }
818  }
819 }
820 
821 void XdgTopLevelV6Interface::Private::showWindowMenuCallback(wl_client *client, wl_resource *resource, wl_resource *seat, uint32_t serial, int32_t x, int32_t y)
822 {
823  auto s = cast<Private>(resource);
824  Q_ASSERT(client == *s->client);
825  emit s->q_func()->windowMenuRequested(SeatInterface::get(seat), serial, QPoint(x, y));
826 }
827 
828 XdgTopLevelV6Interface::Private::Private(XdgTopLevelV6Interface *q, XdgShellV6Interface *c, SurfaceInterface *surface, wl_resource *parentResource)
829  : XdgShellSurfaceInterface::Private(XdgShellInterfaceVersion::UnstableV6, q, c, surface, parentResource, &zxdg_toplevel_v6_interface, &s_interface)
830 {
831 }
832 
833 void XdgTopLevelV6Interface::Private::commit()
834 {
835  const bool windowGeometryChanged = m_pendingState.windowGeometryIsSet;
836  const bool minimumSizeChanged = m_pendingState.minimumSizeIsSet;
837  const bool maximumSizeChanged = m_pendingState.maximumSizeIsSet;
838 
839  if (windowGeometryChanged) {
840  m_currentState.windowGeometry = m_pendingState.windowGeometry;
841  }
842  if (minimumSizeChanged) {
843  m_currentState.minimumSize = m_pendingState.minimumSize;
844  }
845  if (maximumSizeChanged) {
846  m_currentState.maximiumSize = m_pendingState.maximiumSize;
847  }
848 
849  m_pendingState = ShellSurfaceState{};
850 
851  if (windowGeometryChanged) {
852  emit q_func()->windowGeometryChanged(m_currentState.windowGeometry);
853  }
854  if (minimumSizeChanged) {
855  emit q_func()->minSizeChanged(m_currentState.minimumSize);
856  }
857  if (maximumSizeChanged) {
858  emit q_func()->maxSizeChanged(m_currentState.maximiumSize);
859  }
860 }
861 
862 void XdgTopLevelV6Interface::Private::setMaximizedCallback(wl_client *client, wl_resource *resource)
863 {
864  auto s = cast<Private>(resource);
865  Q_ASSERT(client == *s->client);
866  s->q_func()->maximizedChanged(true);
867 }
868 
869 void XdgTopLevelV6Interface::Private::unsetMaximizedCallback(wl_client *client, wl_resource *resource)
870 {
871  auto s = cast<Private>(resource);
872  Q_ASSERT(client == *s->client);
873  s->q_func()->maximizedChanged(false);
874 }
875 
876 void XdgTopLevelV6Interface::Private::setFullscreenCallback(wl_client *client, wl_resource *resource, wl_resource *output)
877 {
878  auto s = cast<Private>(resource);
879  Q_ASSERT(client == *s->client);
880  OutputInterface *o = nullptr;
881  if (output) {
882  o = OutputInterface::get(output);
883  }
884  s->q_func()->fullscreenChanged(true, o);
885 }
886 
887 void XdgTopLevelV6Interface::Private::unsetFullscreenCallback(wl_client *client, wl_resource *resource)
888 {
889  auto s = cast<Private>(resource);
890  Q_ASSERT(client == *s->client);
891  s->q_func()->fullscreenChanged(false, nullptr);
892 }
893 
894 void XdgTopLevelV6Interface::Private::setMinimizedCallback(wl_client *client, wl_resource *resource)
895 {
896  auto s = cast<Private>(resource);
897  Q_ASSERT(client == *s->client);
898  s->q_func()->minimizeRequested();
899 }
900 
901 XdgTopLevelV6Interface::Private::~Private() = default;
902 
903 #ifndef K_DOXYGEN
904 const struct zxdg_popup_v6_interface XdgPopupV6Interface::Private::s_interface = {
905  resourceDestroyedCallback,
906  grabCallback
907 };
908 #endif
909 
910 XdgPopupV6Interface::Private::Private(XdgPopupV6Interface *q, XdgShellV6Interface *c, SurfaceInterface *surface, wl_resource *parentResource)
911  : XdgShellPopupInterface::Private(XdgShellInterfaceVersion::UnstableV6, q, c, surface, parentResource, &zxdg_popup_v6_interface, &s_interface)
912 {
913 }
914 
915 void XdgPopupV6Interface::Private::grabCallback(wl_client *client, wl_resource *resource, wl_resource *seat, uint32_t serial)
916 {
917  Q_UNUSED(client)
918  auto s = cast<Private>(resource);
919  auto seatInterface = SeatInterface::get(seat);
920  s->q_func()->grabRequested(seatInterface, serial);
921 }
922 
923 XdgPopupV6Interface::Private::~Private() = default;
924 
925 QRect XdgPopupV6Interface::Private::windowGeometry() const
926 {
927  return m_currentState.windowGeometry;
928 }
929 
930 void XdgPopupV6Interface::Private::commit()
931 {
932  const bool windowGeometryChanged = m_pendingState.windowGeometryIsSet;
933 
934  if (windowGeometryChanged) {
935  m_currentState.windowGeometry = m_pendingState.windowGeometry;
936  }
937 
938  m_pendingState = ShellSurfaceState{};
939 
940  if (windowGeometryChanged) {
941  emit q_func()->windowGeometryChanged(m_currentState.windowGeometry);
942  }
943 }
944 
945 void XdgPopupV6Interface::Private::setWindowGeometryCallback(const QRect &rect)
946 {
947  m_pendingState.windowGeometry = rect;
948  m_pendingState.windowGeometryIsSet = true;
949 }
950 
951 quint32 XdgPopupV6Interface::Private::configure(const QRect &rect)
952 {
953  if (!resource) {
954  return 0;
955  }
956  const quint32 serial = global->display()->nextSerial();
957  configureSerials << serial;
958  zxdg_popup_v6_send_configure(resource, rect.x(), rect.y(), rect.width(), rect.height());
959  zxdg_surface_v6_send_configure(parentResource, serial);
960  client->flush();
961 
962  return serial;
963 }
964 
965 void XdgPopupV6Interface::Private::popupDone()
966 {
967  if (!resource) {
968  return;
969  }
970  // TODO: dismiss all child popups
971  zxdg_popup_v6_send_popup_done(resource);
972  client->flush();
973 }
974 
975 XdgShellV6Interface::XdgShellV6Interface(Display *display, QObject *parent)
976  : XdgShellInterface(new Private(this, display), parent)
977 {
978 }
979 
980 Display* XdgShellV6Interface::display() const
981 {
982  return d->display;
983 }
984 
985 XdgShellV6Interface::~XdgShellV6Interface() = default;
986 
987 XdgSurfaceV6Interface::XdgSurfaceV6Interface(XdgShellV6Interface *parent, SurfaceInterface *surface, wl_resource *parentResource)
988  : KWayland::Server::Resource(new Private(this, parent, surface, parentResource))
989 {
990 }
991 
992 XdgSurfaceV6Interface::~XdgSurfaceV6Interface() = default;
993 
994 SurfaceInterface* XdgSurfaceV6Interface::surface() const
995 {
996  Q_D();
997  return d->m_surface;
998 }
999 
1000 XdgPositionerV6Interface::XdgPositionerV6Interface(XdgShellV6Interface *parent, wl_resource *parentResource)
1001  : KWayland::Server::Resource(new Private(this, parent, parentResource))
1002 {
1003 }
1004 
1005 QSize XdgPositionerV6Interface::initialSize() const
1006 {
1007  Q_D();
1008  return d->initialSize;
1009 }
1010 
1011 QRect XdgPositionerV6Interface::anchorRect() const
1012 {
1013  Q_D();
1014  return d->anchorRect;
1015 }
1016 
1017 Qt::Edges XdgPositionerV6Interface::anchorEdge() const
1018 {
1019  Q_D();
1020  return d->anchorEdge;
1021 }
1022 
1023 Qt::Edges XdgPositionerV6Interface::gravity() const
1024 {
1025  Q_D();
1026  return d->gravity;
1027 }
1028 
1029 PositionerConstraints XdgPositionerV6Interface::constraintAdjustments() const
1030 {
1031  Q_D();
1032  return d->constraintAdjustments;
1033 }
1034 
1035 QPoint XdgPositionerV6Interface::anchorOffset() const
1036 {
1037  Q_D();
1038  return d->anchorOffset;
1039 }
1040 
1041 
1042 XdgPositionerV6Interface::Private *XdgPositionerV6Interface::d_func() const
1043 {
1044  return reinterpret_cast<Private*>(d.data());
1045 }
1046 
1047 
1048 XdgTopLevelV6Interface* XdgSurfaceV6Interface::topLevel() const
1049 {
1050  Q_D();
1051  return d->m_topLevel.data();
1052 }
1053 
1054 XdgPopupV6Interface* XdgSurfaceV6Interface::popup() const
1055 {
1056  Q_D();
1057  return d->m_popup.data();
1058 }
1059 
1060 XdgSurfaceV6Interface::Private *XdgSurfaceV6Interface::d_func() const
1061 {
1062  return reinterpret_cast<Private*>(d.data());
1063 }
1064 
1065 
1066 XdgTopLevelV6Interface::XdgTopLevelV6Interface(XdgShellV6Interface *parent, SurfaceInterface *surface, wl_resource *parentResource)
1067  : KWayland::Server::XdgShellSurfaceInterface(new Private(this, parent, surface, parentResource))
1068 {
1069 }
1070 
1071 XdgTopLevelV6Interface::~XdgTopLevelV6Interface() = default;
1072 
1073 XdgTopLevelV6Interface::Private *XdgTopLevelV6Interface::d_func() const
1074 {
1075  return reinterpret_cast<Private*>(d.data());
1076 }
1077 
1078 XdgPopupV6Interface::XdgPopupV6Interface(XdgShellV6Interface *parent, SurfaceInterface *surface, wl_resource *parentResource)
1079  : XdgShellPopupInterface(new Private(this, parent, surface, parentResource))
1080 {
1081 }
1082 
1083 XdgPopupV6Interface::~XdgPopupV6Interface() = default;
1084 
1085 XdgPopupV6Interface::Private *XdgPopupV6Interface::d_func() const
1086 {
1087  return reinterpret_cast<Private*>(d.data());
1088 }
1089 
1090 }
1091 }
1092 
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.
int height() const const
int x() const const
int y() const const
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 width() const const
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.