KWaylandServer

xdgshell_interface.cpp
1 /*
2  SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6 
7 #include "xdgshell_interface.h"
8 #include "xdgshell_interface_p.h"
9 
10 #include "display.h"
11 #include "output_interface.h"
12 #include "seat_interface.h"
13 #include "utils.h"
14 
15 #include <QTimer>
16 
17 namespace KWaylandServer
18 {
19 static const int s_version = 3;
20 
21 XdgShellInterfacePrivate::XdgShellInterfacePrivate(XdgShellInterface *shell)
22  : q(shell)
23 {
24 }
25 
26 static wl_client *clientFromXdgSurface(XdgSurfaceInterface *surface)
27 {
28  return XdgSurfaceInterfacePrivate::get(surface)->resource()->client();
29 }
30 
31 XdgShellInterfacePrivate::Resource *XdgShellInterfacePrivate::resourceForXdgSurface(XdgSurfaceInterface *surface) const
32 {
33  return resourceMap().value(clientFromXdgSurface(surface));
34 }
35 
36 void XdgShellInterfacePrivate::registerXdgSurface(XdgSurfaceInterface *surface)
37 {
38  xdgSurfaces.insert(clientFromXdgSurface(surface), surface);
39 }
40 
41 void XdgShellInterfacePrivate::unregisterXdgSurface(XdgSurfaceInterface *surface)
42 {
43  xdgSurfaces.remove(clientFromXdgSurface(surface), surface);
44 }
45 
46 /**
47  * @todo Whether the ping is delayed or has timed out is out of domain of the XdgShellInterface.
48  * Such matter must be handled somewhere else, e.g. XdgToplevelClient, not here!
49  */
50 void XdgShellInterfacePrivate::registerPing(quint32 serial)
51 {
52  QTimer *timer = new QTimer(q);
53  timer->setInterval(1000);
54  QObject::connect(timer, &QTimer::timeout, q, [this, serial, attempt = 0]() mutable {
55  ++attempt;
56  if (attempt == 1) {
57  Q_EMIT q->pingDelayed(serial);
58  return;
59  }
60  Q_EMIT q->pingTimeout(serial);
61  delete pings.take(serial);
62  });
63  pings.insert(serial, timer);
64  timer->start();
65 }
66 
67 XdgShellInterfacePrivate *XdgShellInterfacePrivate::get(XdgShellInterface *shell)
68 {
69  return shell->d.data();
70 }
71 
72 void XdgShellInterfacePrivate::xdg_wm_base_destroy(Resource *resource)
73 {
74  if (xdgSurfaces.contains(resource->client())) {
75  wl_resource_post_error(resource->handle, error_defunct_surfaces, "xdg_wm_base was destroyed before children");
76  return;
77  }
78  wl_resource_destroy(resource->handle);
79 }
80 
81 void XdgShellInterfacePrivate::xdg_wm_base_create_positioner(Resource *resource, uint32_t id)
82 {
83  wl_resource *positionerResource = wl_resource_create(resource->client(), &xdg_positioner_interface, resource->version(), id);
84  new XdgPositionerPrivate(positionerResource);
85 }
86 
87 void XdgShellInterfacePrivate::xdg_wm_base_get_xdg_surface(Resource *resource, uint32_t id, ::wl_resource *surfaceResource)
88 {
89  SurfaceInterface *surface = SurfaceInterface::get(surfaceResource);
90 
91  if (surface->buffer()) {
92  wl_resource_post_error(resource->handle, XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER, "xdg_surface must not have a buffer at creation");
93  return;
94  }
95 
96  wl_resource *xdgSurfaceResource = wl_resource_create(resource->client(), &xdg_surface_interface, resource->version(), id);
97 
98  XdgSurfaceInterface *xdgSurface = new XdgSurfaceInterface(q, surface, xdgSurfaceResource);
99  registerXdgSurface(xdgSurface);
100 }
101 
102 void XdgShellInterfacePrivate::xdg_wm_base_pong(Resource *resource, uint32_t serial)
103 {
104  Q_UNUSED(resource)
105  if (QTimer *timer = pings.take(serial)) {
106  delete timer;
107  }
108  Q_EMIT q->pongReceived(serial);
109 }
110 
112  : QObject(parent)
113  , d(new XdgShellInterfacePrivate(this))
114 {
115  d->display = display;
116  d->init(*display, s_version);
117 }
118 
120 {
121 }
122 
124 {
125  return d->display;
126 }
127 
129 {
130  XdgShellInterfacePrivate::Resource *clientResource = d->resourceForXdgSurface(surface);
131  if (!clientResource)
132  return 0;
133 
134  quint32 serial = d->display->nextSerial();
135  d->send_ping(clientResource->handle, serial);
136  d->registerPing(serial);
137 
138  return serial;
139 }
140 
141 XdgSurfaceInterfacePrivate::XdgSurfaceInterfacePrivate(XdgSurfaceInterface *xdgSurface)
142  : q(xdgSurface)
143 {
144 }
145 
146 void XdgSurfaceInterfacePrivate::commit()
147 {
148  if (next.acknowledgedConfigureIsSet) {
149  current.acknowledgedConfigure = next.acknowledgedConfigure;
150  next.acknowledgedConfigureIsSet = false;
151  Q_EMIT q->configureAcknowledged(current.acknowledgedConfigure);
152  }
153 
154  if (next.windowGeometryIsSet) {
155  current.windowGeometry = next.windowGeometry;
156  next.windowGeometryIsSet = false;
157  Q_EMIT q->windowGeometryChanged(current.windowGeometry);
158  }
159 
160  isMapped = surface->buffer();
161 }
162 
163 void XdgSurfaceInterfacePrivate::reset()
164 {
165  isConfigured = false;
166  current = XdgSurfaceState{};
167  next = XdgSurfaceState{};
168  Q_EMIT q->resetOccurred();
169 }
170 
171 XdgSurfaceInterfacePrivate *XdgSurfaceInterfacePrivate::get(XdgSurfaceInterface *surface)
172 {
173  return surface->d.data();
174 }
175 
176 void XdgSurfaceInterfacePrivate::xdg_surface_destroy_resource(Resource *resource)
177 {
178  Q_UNUSED(resource)
179  Q_EMIT q->aboutToBeDestroyed();
180  XdgShellInterfacePrivate::get(shell)->unregisterXdgSurface(q);
181  delete q;
182 }
183 
184 void XdgSurfaceInterfacePrivate::xdg_surface_destroy(Resource *resource)
185 {
186  if (toplevel || popup) {
187  qWarning() << "Tried to destroy xdg_surface before its role object";
188  }
189  wl_resource_destroy(resource->handle);
190 }
191 
192 void XdgSurfaceInterfacePrivate::xdg_surface_get_toplevel(Resource *resource, uint32_t id)
193 {
194  const SurfaceRole *surfaceRole = SurfaceRole::get(surface);
195  if (surfaceRole) {
196  wl_resource_post_error(resource->handle, error_already_constructed, "the surface already has a role assigned %s", surfaceRole->name().constData());
197  return;
198  }
199 
200  wl_resource *toplevelResource = wl_resource_create(resource->client(), &xdg_toplevel_interface, resource->version(), id);
201 
202  toplevel = new XdgToplevelInterface(q, toplevelResource);
203  Q_EMIT shell->toplevelCreated(toplevel);
204 }
205 
206 void XdgSurfaceInterfacePrivate::xdg_surface_get_popup(Resource *resource, uint32_t id, ::wl_resource *parentResource, ::wl_resource *positionerResource)
207 {
208  const SurfaceRole *surfaceRole = SurfaceRole::get(surface);
209  if (surfaceRole) {
210  wl_resource_post_error(resource->handle, error_already_constructed, "the surface already has a role assigned %s", surfaceRole->name().constData());
211  return;
212  }
213 
214  XdgPositioner positioner = XdgPositioner::get(positionerResource);
215  if (!positioner.isComplete()) {
216  auto shellPrivate = XdgShellInterfacePrivate::get(shell);
217  wl_resource_post_error(shellPrivate->resourceForXdgSurface(q)->handle,
218  QtWaylandServer::xdg_wm_base::error_invalid_positioner,
219  "xdg_positioner is incomplete");
220  return;
221  }
222 
223  XdgSurfaceInterface *parentXdgSurface = XdgSurfaceInterface::get(parentResource);
224  SurfaceInterface *parentSurface = nullptr;
225  if (parentXdgSurface) {
226  parentSurface = parentXdgSurface->surface();
227  }
228 
229  wl_resource *popupResource = wl_resource_create(resource->client(), &xdg_popup_interface, resource->version(), id);
230 
231  popup = new XdgPopupInterface(q, parentSurface, positioner, popupResource);
232  Q_EMIT shell->popupCreated(popup);
233 }
234 
235 void XdgSurfaceInterfacePrivate::xdg_surface_set_window_geometry(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
236 {
237  if (!toplevel && !popup) {
238  wl_resource_post_error(resource->handle, error_not_constructed, "xdg_surface must have a role");
239  return;
240  }
241 
242  if (width < 1 || height < 1) {
243  wl_resource_post_error(resource->handle, -1, "invalid window geometry size (%dx%d)", width, height);
244  return;
245  }
246 
247  next.windowGeometry = QRect(x, y, width, height);
248  next.windowGeometryIsSet = true;
249 }
250 
251 void XdgSurfaceInterfacePrivate::xdg_surface_ack_configure(Resource *resource, uint32_t serial)
252 {
253  Q_UNUSED(resource)
254  next.acknowledgedConfigure = serial;
255  next.acknowledgedConfigureIsSet = true;
256 }
257 
259  : d(new XdgSurfaceInterfacePrivate(this))
260 {
261  d->shell = shell;
262  d->surface = surface;
263  d->init(resource);
264 }
265 
267 {
268 }
269 
271 {
272  return d->toplevel;
273 }
274 
276 {
277  return d->popup;
278 }
279 
281 {
282  return d->shell;
283 }
284 
286 {
287  return d->surface;
288 }
289 
291 {
292  return d->isConfigured;
293 }
294 
296 {
297  return d->current.windowGeometry;
298 }
299 
301 {
302  if (auto surfacePrivate = resource_cast<XdgSurfaceInterfacePrivate *>(resource)) {
303  return surfacePrivate->q;
304  }
305  return nullptr;
306 }
307 
308 XdgToplevelInterfacePrivate::XdgToplevelInterfacePrivate(XdgToplevelInterface *toplevel, XdgSurfaceInterface *surface)
309  : SurfaceRole(surface->surface(), QByteArrayLiteral("xdg_toplevel"))
310  , q(toplevel)
311  , xdgSurface(surface)
312 {
313 }
314 
315 void XdgToplevelInterfacePrivate::commit()
316 {
317  auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface);
318 
319  bool isResettable = xdgSurfacePrivate->isConfigured && xdgSurfacePrivate->isMapped;
320 
321  if (xdgSurfacePrivate->isConfigured) {
322  xdgSurfacePrivate->commit();
323  } else {
324  Q_EMIT q->initializeRequested();
325  return;
326  }
327 
328  if (isResettable && !xdgSurfacePrivate->isMapped) {
329  reset();
330  return;
331  }
332 
333  if (current.minimumSize != next.minimumSize) {
334  current.minimumSize = next.minimumSize;
335  Q_EMIT q->minimumSizeChanged(current.minimumSize);
336  }
337  if (current.maximumSize != next.maximumSize) {
338  current.maximumSize = next.maximumSize;
339  Q_EMIT q->maximumSizeChanged(current.maximumSize);
340  }
341 }
342 
343 void XdgToplevelInterfacePrivate::reset()
344 {
345  auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface);
346  xdgSurfacePrivate->reset();
347 
348  windowTitle = QString();
349  windowClass = QString();
350  current = next = State();
351 
352  Q_EMIT q->resetOccurred();
353 }
354 
355 void XdgToplevelInterfacePrivate::xdg_toplevel_destroy_resource(Resource *resource)
356 {
357  Q_UNUSED(resource)
358  Q_EMIT q->aboutToBeDestroyed();
359  delete q;
360 }
361 
362 void XdgToplevelInterfacePrivate::xdg_toplevel_destroy(Resource *resource)
363 {
364  wl_resource_destroy(resource->handle);
365 }
366 
367 void XdgToplevelInterfacePrivate::xdg_toplevel_set_parent(Resource *resource, ::wl_resource *parentResource)
368 {
369  Q_UNUSED(resource)
371  if (parentXdgToplevel == parent) {
372  return;
373  }
374  parentXdgToplevel = parent;
375  Q_EMIT q->parentXdgToplevelChanged();
376 }
377 
378 void XdgToplevelInterfacePrivate::xdg_toplevel_set_title(Resource *resource, const QString &title)
379 {
380  Q_UNUSED(resource)
381  if (windowTitle == title) {
382  return;
383  }
384  windowTitle = title;
385  Q_EMIT q->windowTitleChanged(title);
386 }
387 
388 void XdgToplevelInterfacePrivate::xdg_toplevel_set_app_id(Resource *resource, const QString &app_id)
389 {
390  Q_UNUSED(resource)
391  if (windowClass == app_id) {
392  return;
393  }
394  windowClass = app_id;
395  Q_EMIT q->windowClassChanged(app_id);
396 }
397 
398 void XdgToplevelInterfacePrivate::xdg_toplevel_show_window_menu(Resource *resource, ::wl_resource *seatResource, uint32_t serial, int32_t x, int32_t y)
399 {
400  auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface);
401 
402  if (!xdgSurfacePrivate->isConfigured) {
403  wl_resource_post_error(resource->handle, QtWaylandServer::xdg_surface::error_not_constructed, "surface has not been configured yet");
404  return;
405  }
406 
407  SeatInterface *seat = SeatInterface::get(seatResource);
408  Q_EMIT q->windowMenuRequested(seat, QPoint(x, y), serial);
409 }
410 
411 void XdgToplevelInterfacePrivate::xdg_toplevel_move(Resource *resource, ::wl_resource *seatResource, uint32_t serial)
412 {
413  auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface);
414 
415  if (!xdgSurfacePrivate->isConfigured) {
416  wl_resource_post_error(resource->handle, QtWaylandServer::xdg_surface::error_not_constructed, "surface has not been configured yet");
417  return;
418  }
419 
420  SeatInterface *seat = SeatInterface::get(seatResource);
421  Q_EMIT q->moveRequested(seat, serial);
422 }
423 
424 void XdgToplevelInterfacePrivate::xdg_toplevel_resize(Resource *resource, ::wl_resource *seatResource, uint32_t serial, uint32_t xdgEdges)
425 {
426  auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface);
427 
428  if (!xdgSurfacePrivate->isConfigured) {
429  wl_resource_post_error(resource->handle, QtWaylandServer::xdg_surface::error_not_constructed, "surface has not been configured yet");
430  return;
431  }
432 
433  SeatInterface *seat = SeatInterface::get(seatResource);
434 
435  Qt::Edges edges;
436  if (xdgEdges & XDG_TOPLEVEL_RESIZE_EDGE_TOP) {
437  edges |= Qt::TopEdge;
438  }
439  if (xdgEdges & XDG_TOPLEVEL_RESIZE_EDGE_RIGHT) {
440  edges |= Qt::RightEdge;
441  }
442  if (xdgEdges & XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM) {
443  edges |= Qt::BottomEdge;
444  }
445  if (xdgEdges & XDG_TOPLEVEL_RESIZE_EDGE_LEFT) {
446  edges |= Qt::LeftEdge;
447  }
448 
449  Q_EMIT q->resizeRequested(seat, edges, serial);
450 }
451 
452 void XdgToplevelInterfacePrivate::xdg_toplevel_set_max_size(Resource *resource, int32_t width, int32_t height)
453 {
454  if (width < 0 || height < 0) {
455  wl_resource_post_error(resource->handle, -1, "width and height must be positive or zero");
456  return;
457  }
458  next.maximumSize = QSize(width, height);
459 }
460 
461 void XdgToplevelInterfacePrivate::xdg_toplevel_set_min_size(Resource *resource, int32_t width, int32_t height)
462 {
463  if (width < 0 || height < 0) {
464  wl_resource_post_error(resource->handle, -1, "width and height must be positive or zero");
465  return;
466  }
467  next.minimumSize = QSize(width, height);
468 }
469 
470 void XdgToplevelInterfacePrivate::xdg_toplevel_set_maximized(Resource *resource)
471 {
472  Q_UNUSED(resource)
473  Q_EMIT q->maximizeRequested();
474 }
475 
476 void XdgToplevelInterfacePrivate::xdg_toplevel_unset_maximized(Resource *resource)
477 {
478  Q_UNUSED(resource)
479  Q_EMIT q->unmaximizeRequested();
480 }
481 
482 void XdgToplevelInterfacePrivate::xdg_toplevel_set_fullscreen(Resource *resource, ::wl_resource *outputResource)
483 {
484  Q_UNUSED(resource)
485  OutputInterface *output = OutputInterface::get(outputResource);
486  Q_EMIT q->fullscreenRequested(output);
487 }
488 
489 void XdgToplevelInterfacePrivate::xdg_toplevel_unset_fullscreen(Resource *resource)
490 {
491  Q_UNUSED(resource)
492  Q_EMIT q->unfullscreenRequested();
493 }
494 
495 void XdgToplevelInterfacePrivate::xdg_toplevel_set_minimized(Resource *resource)
496 {
497  Q_UNUSED(resource)
498  Q_EMIT q->minimizeRequested();
499 }
500 
501 XdgToplevelInterfacePrivate *XdgToplevelInterfacePrivate::get(XdgToplevelInterface *toplevel)
502 {
503  return toplevel->d.data();
504 }
505 
506 XdgToplevelInterfacePrivate *XdgToplevelInterfacePrivate::get(wl_resource *resource)
507 {
508  return resource_cast<XdgToplevelInterfacePrivate *>(resource);
509 }
510 
512  : d(new XdgToplevelInterfacePrivate(this, surface))
513 {
514  d->init(resource);
515 }
516 
518 {
519 }
520 
522 {
523  return d->xdgSurface->shell();
524 }
525 
527 {
528  return d->xdgSurface;
529 }
530 
532 {
533  return d->xdgSurface->surface();
534 }
535 
537 {
538  return d->xdgSurface->isConfigured();
539 }
540 
542 {
543  return d->parentXdgToplevel;
544 }
545 
547 {
548  return d->windowTitle;
549 }
550 
552 {
553  return d->windowClass;
554 }
555 
557 {
558  return d->current.minimumSize.isEmpty() ? QSize(0, 0) : d->current.minimumSize;
559 }
560 
562 {
563  return d->current.maximumSize.isEmpty() ? QSize(INT_MAX, INT_MAX) : d->current.maximumSize;
564 }
565 
566 quint32 XdgToplevelInterface::sendConfigure(const QSize &size, const States &states)
567 {
568  // Note that the states listed in the configure event must be an array of uint32_t.
569 
570  uint32_t statesData[8] = {0};
571  int i = 0;
572 
573  if (states & State::MaximizedHorizontal && states & State::MaximizedVertical) {
574  statesData[i++] = QtWaylandServer::xdg_toplevel::state_maximized;
575  }
576  if (states & State::FullScreen) {
577  statesData[i++] = QtWaylandServer::xdg_toplevel::state_fullscreen;
578  }
579  if (states & State::Resizing) {
580  statesData[i++] = QtWaylandServer::xdg_toplevel::state_resizing;
581  }
582  if (states & State::Activated) {
583  statesData[i++] = QtWaylandServer::xdg_toplevel::state_activated;
584  }
585 
586  if (d->resource()->version() >= XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION) {
587  if (states & State::TiledLeft) {
588  statesData[i++] = QtWaylandServer::xdg_toplevel::state_tiled_left;
589  }
590  if (states & State::TiledTop) {
591  statesData[i++] = QtWaylandServer::xdg_toplevel::state_tiled_top;
592  }
593  if (states & State::TiledRight) {
594  statesData[i++] = QtWaylandServer::xdg_toplevel::state_tiled_right;
595  }
596  if (states & State::TiledBottom) {
597  statesData[i++] = QtWaylandServer::xdg_toplevel::state_tiled_bottom;
598  }
599  }
600 
601  const QByteArray xdgStates = QByteArray::fromRawData(reinterpret_cast<char *>(statesData), sizeof(uint32_t) * i);
602  const quint32 serial = xdgSurface()->shell()->display()->nextSerial();
603 
604  d->send_configure(size.width(), size.height(), xdgStates);
605 
606  auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface());
607  xdgSurfacePrivate->send_configure(serial);
608  xdgSurfacePrivate->isConfigured = true;
609 
610  return serial;
611 }
612 
614 {
615  d->send_close();
616 }
617 
619 {
620  if (auto toplevelPrivate = resource_cast<XdgToplevelInterfacePrivate *>(resource)) {
621  return toplevelPrivate->q;
622  }
623  return nullptr;
624 }
625 
626 XdgPopupInterfacePrivate *XdgPopupInterfacePrivate::get(XdgPopupInterface *popup)
627 {
628  return popup->d.data();
629 }
630 
631 XdgPopupInterfacePrivate::XdgPopupInterfacePrivate(XdgPopupInterface *popup, XdgSurfaceInterface *surface)
632  : SurfaceRole(surface->surface(), QByteArrayLiteral("xdg_popup"))
633  , q(popup)
634  , xdgSurface(surface)
635 {
636 }
637 
638 void XdgPopupInterfacePrivate::commit()
639 {
640  if (!parentSurface) {
641  auto shellPrivate = XdgShellInterfacePrivate::get(xdgSurface->shell());
642  wl_resource_post_error(shellPrivate->resourceForXdgSurface(xdgSurface)->handle,
643  QtWaylandServer::xdg_wm_base::error_invalid_popup_parent,
644  "no xdg_popup parent surface has been specified");
645  return;
646  }
647 
648  auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface);
649  bool isResettable = xdgSurfacePrivate->isConfigured && xdgSurfacePrivate->isMapped;
650 
651  if (xdgSurfacePrivate->isConfigured) {
652  xdgSurfacePrivate->commit();
653  } else {
654  Q_EMIT q->initializeRequested();
655  return;
656  }
657 
658  if (isResettable && !xdgSurfacePrivate->isMapped) {
659  reset();
660  }
661 }
662 
663 void XdgPopupInterfacePrivate::reset()
664 {
665  auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface);
666  xdgSurfacePrivate->reset();
667 }
668 
669 void XdgPopupInterfacePrivate::xdg_popup_destroy_resource(Resource *resource)
670 {
671  Q_UNUSED(resource)
672  Q_EMIT q->aboutToBeDestroyed();
673  delete q;
674 }
675 
676 void XdgPopupInterfacePrivate::xdg_popup_destroy(Resource *resource)
677 {
678  // TODO: We need to post an error with the code XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP if
679  // this popup is not the topmost grabbing popup. We most likely need a grab abstraction or
680  // something to determine whether the given popup has an explicit grab.
681  wl_resource_destroy(resource->handle);
682 }
683 
684 void XdgPopupInterfacePrivate::xdg_popup_grab(Resource *resource, ::wl_resource *seatHandle, uint32_t serial)
685 {
686  if (xdgSurface->surface()->buffer()) {
687  wl_resource_post_error(resource->handle, error_invalid_grab, "xdg_surface is already mapped");
688  return;
689  }
690  SeatInterface *seat = SeatInterface::get(seatHandle);
691  Q_EMIT q->grabRequested(seat, serial);
692 }
693 
694 void XdgPopupInterfacePrivate::xdg_popup_reposition(Resource *resource, ::wl_resource *positionerResource, uint32_t token)
695 {
696  Q_UNUSED(resource)
697  positioner = XdgPositioner::get(positionerResource);
698  Q_EMIT q->repositionRequested(token);
699 }
700 
701 XdgPopupInterface::XdgPopupInterface(XdgSurfaceInterface *surface, SurfaceInterface *parentSurface, const XdgPositioner &positioner, ::wl_resource *resource)
702  : d(new XdgPopupInterfacePrivate(this, surface))
703 {
704  d->parentSurface = parentSurface;
705  d->positioner = positioner;
706  d->init(resource);
707 }
708 
710 {
711 }
712 
714 {
715  return d->parentSurface;
716 }
717 
719 {
720  return d->xdgSurface;
721 }
722 
724 {
725  return d->xdgSurface->surface();
726 }
727 
729 {
730  return d->xdgSurface->isConfigured();
731 }
732 
734 {
735  return d->positioner;
736 }
737 
739 {
740  const quint32 serial = xdgSurface()->shell()->display()->nextSerial();
741 
742  d->send_configure(rect.x(), rect.y(), rect.width(), rect.height());
743 
744  auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface());
745  xdgSurfacePrivate->send_configure(serial);
746  xdgSurfacePrivate->isConfigured = true;
747 
748  return serial;
749 }
750 
752 {
753  d->send_popup_done();
754 }
755 
757 {
758  Q_ASSERT(d->resource()->version() >= XDG_POPUP_REPOSITIONED_SINCE_VERSION);
759  d->send_repositioned(token);
760 }
761 
762 XdgPopupInterface *XdgPopupInterface::get(::wl_resource *resource)
763 {
764  if (auto popupPrivate = resource_cast<XdgPopupInterfacePrivate *>(resource)) {
765  return popupPrivate->q;
766  }
767  return nullptr;
768 }
769 
770 XdgPositionerPrivate::XdgPositionerPrivate(::wl_resource *resource)
771  : data(new XdgPositionerData)
772 {
773  init(resource);
774 }
775 
776 XdgPositionerPrivate *XdgPositionerPrivate::get(wl_resource *resource)
777 {
778  return resource_cast<XdgPositionerPrivate *>(resource);
779 }
780 
781 void XdgPositionerPrivate::xdg_positioner_destroy_resource(Resource *resource)
782 {
783  Q_UNUSED(resource)
784  delete this;
785 }
786 
787 void XdgPositionerPrivate::xdg_positioner_destroy(Resource *resource)
788 {
789  wl_resource_destroy(resource->handle);
790 }
791 
792 void XdgPositionerPrivate::xdg_positioner_set_size(Resource *resource, int32_t width, int32_t height)
793 {
794  if (width < 1 || height < 1) {
795  wl_resource_post_error(resource->handle, error_invalid_input, "width and height must be positive and non-zero");
796  return;
797  }
798  data->size = QSize(width, height);
799 }
800 
801 void XdgPositionerPrivate::xdg_positioner_set_anchor_rect(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
802 {
803  if (width < 1 || height < 1) {
804  wl_resource_post_error(resource->handle, error_invalid_input, "width and height must be positive and non-zero");
805  return;
806  }
807  data->anchorRect = QRect(x, y, width, height);
808 }
809 
810 void XdgPositionerPrivate::xdg_positioner_set_anchor(Resource *resource, uint32_t anchor)
811 {
812  if (anchor > anchor_bottom_right) {
813  wl_resource_post_error(resource->handle, error_invalid_input, "unknown anchor point");
814  return;
815  }
816 
817  switch (anchor) {
818  case anchor_top:
819  data->anchorEdges = Qt::TopEdge;
820  break;
821  case anchor_top_right:
822  data->anchorEdges = Qt::TopEdge | Qt::RightEdge;
823  break;
824  case anchor_right:
825  data->anchorEdges = Qt::RightEdge;
826  break;
827  case anchor_bottom_right:
828  data->anchorEdges = Qt::BottomEdge | Qt::RightEdge;
829  break;
830  case anchor_bottom:
831  data->anchorEdges = Qt::BottomEdge;
832  break;
833  case anchor_bottom_left:
834  data->anchorEdges = Qt::BottomEdge | Qt::LeftEdge;
835  break;
836  case anchor_left:
837  data->anchorEdges = Qt::LeftEdge;
838  break;
839  case anchor_top_left:
840  data->anchorEdges = Qt::TopEdge | Qt::LeftEdge;
841  break;
842  default:
843  data->anchorEdges = Qt::Edges();
844  break;
845  }
846 }
847 
848 void XdgPositionerPrivate::xdg_positioner_set_parent_size(Resource *resource, int32_t width, int32_t height)
849 {
850  Q_UNUSED(resource)
851  data->parentSize = QSize(width, height);
852 }
853 
854 void XdgPositionerPrivate::xdg_positioner_set_reactive(Resource *resource)
855 {
856  Q_UNUSED(resource)
857  data->isReactive = true;
858 }
859 
860 void XdgPositionerPrivate::xdg_positioner_set_parent_configure(Resource *resource, uint32_t serial)
861 {
862  Q_UNUSED(resource)
863  data->parentConfigure = serial;
864 }
865 
866 void XdgPositionerPrivate::xdg_positioner_set_gravity(Resource *resource, uint32_t gravity)
867 {
868  if (gravity > gravity_bottom_right) {
869  wl_resource_post_error(resource->handle, error_invalid_input, "unknown gravity direction");
870  return;
871  }
872 
873  switch (gravity) {
874  case gravity_top:
875  data->gravityEdges = Qt::TopEdge;
876  break;
877  case gravity_top_right:
878  data->gravityEdges = Qt::TopEdge | Qt::RightEdge;
879  break;
880  case gravity_right:
881  data->gravityEdges = Qt::RightEdge;
882  break;
883  case gravity_bottom_right:
884  data->gravityEdges = Qt::BottomEdge | Qt::RightEdge;
885  break;
886  case gravity_bottom:
887  data->gravityEdges = Qt::BottomEdge;
888  break;
889  case gravity_bottom_left:
890  data->gravityEdges = Qt::BottomEdge | Qt::LeftEdge;
891  break;
892  case gravity_left:
893  data->gravityEdges = Qt::LeftEdge;
894  break;
895  case gravity_top_left:
896  data->gravityEdges = Qt::TopEdge | Qt::LeftEdge;
897  break;
898  default:
899  data->gravityEdges = Qt::Edges();
900  break;
901  }
902 }
903 
904 void XdgPositionerPrivate::xdg_positioner_set_constraint_adjustment(Resource *resource, uint32_t constraint_adjustment)
905 {
906  Q_UNUSED(resource)
907 
908  if (constraint_adjustment & constraint_adjustment_flip_x) {
909  data->flipConstraintAdjustments |= Qt::Horizontal;
910  } else {
911  data->flipConstraintAdjustments &= ~Qt::Horizontal;
912  }
913 
914  if (constraint_adjustment & constraint_adjustment_flip_y) {
915  data->flipConstraintAdjustments |= Qt::Vertical;
916  } else {
917  data->flipConstraintAdjustments &= ~Qt::Vertical;
918  }
919 
920  if (constraint_adjustment & constraint_adjustment_slide_x) {
921  data->slideConstraintAdjustments |= Qt::Horizontal;
922  } else {
923  data->slideConstraintAdjustments &= ~Qt::Horizontal;
924  }
925 
926  if (constraint_adjustment & constraint_adjustment_slide_y) {
927  data->slideConstraintAdjustments |= Qt::Vertical;
928  } else {
929  data->slideConstraintAdjustments &= ~Qt::Vertical;
930  }
931 
932  if (constraint_adjustment & constraint_adjustment_resize_x) {
933  data->resizeConstraintAdjustments |= Qt::Horizontal;
934  } else {
935  data->resizeConstraintAdjustments &= ~Qt::Horizontal;
936  }
937 
938  if (constraint_adjustment & constraint_adjustment_resize_y) {
939  data->resizeConstraintAdjustments |= Qt::Vertical;
940  } else {
941  data->resizeConstraintAdjustments &= ~Qt::Vertical;
942  }
943 }
944 
945 void XdgPositionerPrivate::xdg_positioner_set_offset(Resource *resource, int32_t x, int32_t y)
946 {
947  Q_UNUSED(resource)
948  data->offset = QPoint(x, y);
949 }
950 
952  : d(new XdgPositionerData)
953 {
954 }
955 
957  : d(other.d)
958 {
959 }
960 
962 {
963 }
964 
966 {
967  d = other.d;
968  return *this;
969 }
970 
972 {
973  return d->size.isValid() && d->anchorRect.isValid();
974 }
975 
977 {
978  return d->slideConstraintAdjustments;
979 }
980 
982 {
983  return d->flipConstraintAdjustments;
984 }
985 
987 {
988  return d->resizeConstraintAdjustments;
989 }
990 
992 {
993  return d->anchorEdges;
994 }
995 
997 {
998  return d->gravityEdges;
999 }
1000 
1002 {
1003  return d->size;
1004 }
1005 
1007 {
1008  return d->anchorRect;
1009 }
1010 
1012 {
1013  return d->offset;
1014 }
1015 
1017 {
1018  return d->parentSize;
1019 }
1020 
1022 {
1023  return d->isReactive;
1024 }
1025 
1027 {
1028  return d->parentConfigure;
1029 }
1030 
1031 XdgPositioner XdgPositioner::get(::wl_resource *resource)
1032 {
1033  XdgPositionerPrivate *xdgPositionerPrivate = XdgPositionerPrivate::get(resource);
1034  if (xdgPositionerPrivate)
1035  return XdgPositioner(xdgPositionerPrivate->data);
1036  return XdgPositioner();
1037 }
1038 
1040  : d(data)
1041 {
1042 }
1043 
1044 } // namespace KWaylandServer
void setInterval(int msec)
quint32 ping(XdgSurfaceInterface *surface)
Sends a ping event to the client with the given xdg-surface surface.
bool isConfigured() const
Returns true if the toplevel has been configured; otherwise returns false.
quint32 sendConfigure(const QSize &size, const States &states)
Sends a configure event to the client.
void sendClose()
Sends a close event to the client.
Represents a Seat on the Wayland Display.
SurfaceInterface * surface() const
Returns the SurfaceInterface associated with the XdgPopupInterface.
int width() const const
The OutputInterface class represents a screen.
XdgShellInterface(Display *display, QObject *parent=nullptr)
Constructs an XdgShellInterface object with the given wayland display display.
static XdgPopupInterface * get(::wl_resource *resource)
Returns the XdgPopupInterface for the specified wayland resource object resource. ...
Qt::Orientations slideConstraintAdjustments() const
Returns the set of orientations along which the compositor may slide the popup to ensure that it is e...
typedef Edges
XdgPositioner()
Constructs an incomplete XdgPositioner object.
Class holding the Wayland server display loop.
Definition: display.h:47
The XdgPopupInterface class represents a surface that can be used to implement context menus...
The XdgPositioner class provides a collection of rules for the placement of a popup surface...
quint32 sendConfigure(const QRect &rect)
Sends a configure event to the client and returns the serial number of the event. ...
static XdgPositioner get(::wl_resource *resource)
Returns the current state of the xdg positioner object identified by resource.
Display * display() const
Returns the wayland display of the XdgShellInterface.
static XdgSurfaceInterface * get(::wl_resource *resource)
Returns the XdgSurfaceInterface for the specified wayland resource object resource.
QByteArray fromRawData(const char *data, int size)
int height() const const
int x() const const
int y() const const
static XdgToplevelInterface * get(::wl_resource *resource)
Returns the XdgToplevelInterface for the specified wayland resource object resource.
XdgPositioner positioner() const
Returns the XdgPositioner assigned to this XdgPopupInterface.
Qt::Edges anchorEdges() const
Returns the set of edges on the anchor rectangle that the surface should be positioned around...
XdgSurfaceInterface * xdgSurface() const
Returns the XdgSurfaceInterface associated with the XdgPopupInterface.
XdgPopupInterface * popup() const
Returns the XdgPopupInterface associated with this XdgSurfaceInterface.
XdgShellInterface * shell() const
Returns the XdgShellInterface associated with this XdgSurfaceInterface.
QSize minimumSize() const
Returns the minimum window geometry size of the toplevel surface.
The XdgShellInterface class represents an extension for destrop-style user interfaces.
void timeout()
~XdgToplevelInterface() override
Destructs the XdgToplevelInterface object.
The XdgToplevelInterface class represents a surface with window-like functionality such as maximize...
void sendRepositioned(quint32 token)
Sends a popup repositioned event to the client.
bool isReactive() const
Returns whether the surface should respond to movements in its parent window.
QRect anchorRect() const
Returns the anchor rectangle relative to the upper left corner of the window geometry of the parent s...
static SurfaceInterface * get(wl_resource *native)
QRect windowGeometry() const
Returns the window geometry of the XdgSurfaceInterface.
SurfaceInterface * surface() const
Returns the SurfaceInterface associated with the XdgToplevelInterface.
XdgToplevelInterface * toplevel() const
Returns the XdgToplevelInterface associated with this XdgSurfaceInterface.
XdgToplevelInterface(XdgSurfaceInterface *surface,::wl_resource *resource)
Constructs an XdgToplevelInterface for the given xdg-surface surface.
~XdgSurfaceInterface() override
Destructs the XdgSurfaceInterface object.
Qt::Orientations resizeConstraintAdjustments() const
Returns the set of orientations along which the compositor can resize the popup to ensure that it is ...
XdgShellInterface * shell() const
Returns the XdgShellInterface for this XdgToplevelInterface.
QString windowClass() const
Returns the window class of the toplevel surface.
T * data() const const
bool isConfigured() const
Returns true if the popup has been configured; otherwise returns false.
XdgSurfaceInterface * xdgSurface() const
Returns the XdgSurfaceInterface associated with the XdgToplevelInterface.
Qt::Edges gravityEdges() const
Returns the direction in which the surface should be positioned, relative to the anchor point of the ...
QCA_EXPORT void init()
int width() const const
quint32 parentConfigure() const
Returns the serial of the configure event for the parent window.
SurfaceInterface * parentSurface() const
Returns the parent surface for this popup surface.
~XdgPopupInterface() override
Destructs the XdgPopupInterface object.
SurfaceInterface * surface() const
Returns the SurfaceInterface assigned to this XdgSurfaceInterface.
int height() const const
bool isConfigured() const
Returns true if the surface has been configured; otherwise returns false.
bool isComplete() const
Returns true if the positioner object is complete; otherwise returns false.
void start(int msec)
QSize maximumSize() const
Returns the maximum window geometry size of the toplevel surface.
Qt::Orientations flipConstraintAdjustments() const
Returns the set of orientations along which the compositor may flip the popup to ensure that it is en...
Resource representing a wl_surface.
Horizontal
XdgSurfaceInterface(XdgShellInterface *shell, SurfaceInterface *surface,::wl_resource *resource)
Constructs an XdgSurfaceInterface for the given shell and surface.
QSize parentSize() const
Returns the parent size to use when positioning the popup.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void sendPopupDone()
Sends a popup done event to the client.
QObject * parent() const const
QPoint offset() const
Returns the surface position offset relative to the position of the anchor on the anchor rectangle an...
State
QString windowTitle() const
Returns the window title of the toplevel surface.
~XdgShellInterface() override
Destructs the XdgShellInterface object.
XdgPositioner & operator=(const XdgPositioner &other)
Assigns the value of other to this XdgPositioner object.
~XdgPositioner()
Destructs the XdgPositioner object.
Q_EMITQ_EMIT
The XdgSurfaceInterface class provides a base set of functionality required to construct user interfa...
XdgToplevelInterface * parentXdgToplevel() const
Returns the parent XdgToplevelInterface above which this toplevel is stacked.
QSize size() const
Returns the window geometry size of the surface that is to be positioned.
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Oct 23 2021 23:08:28 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.