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

KDE's Doxygen guidelines are available online.