File indexing completed on 2024-12-22 05:09:26

0001 /*
0002     SPDX-FileCopyrightText: 2017 David Edmundson <davidedmundson@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 #include "event_queue.h"
0007 #include "output.h"
0008 #include "seat.h"
0009 #include "surface.h"
0010 #include "wayland_pointer_p.h"
0011 #include "xdgshell_p.h"
0012 #include <wayland-xdg-shell-client-protocol.h>
0013 
0014 namespace KWayland
0015 {
0016 namespace Client
0017 {
0018 class XdgShellStable::Private : public XdgShell::Private
0019 {
0020 public:
0021     void setup(xdg_wm_base *shell) override;
0022     void release() override;
0023     void destroy() override;
0024     bool isValid() const override;
0025     XdgShellSurface *getXdgSurface(Surface *surface, QObject *parent) override;
0026 
0027     XdgShellPopup *getXdgPopup(Surface *surface, XdgShellSurface *parentSurface, const XdgPositioner &positioner, QObject *parent) override;
0028     XdgShellPopup *getXdgPopup(Surface *surface, XdgShellPopup *parentSurface, const XdgPositioner &positioner, QObject *parent) override;
0029 
0030     using XdgShell::Private::operator xdg_shell *;
0031     using XdgShell::Private::operator zxdg_shell_v6 *;
0032     operator xdg_wm_base *() override
0033     {
0034         return xdg_shell_base;
0035     }
0036     operator xdg_wm_base *() const override
0037     {
0038         return xdg_shell_base;
0039     }
0040 
0041 private:
0042     XdgShellPopup *internalGetXdgPopup(Surface *surface, xdg_surface *parentSurface, const XdgPositioner &positioner, QObject *parent);
0043     static void pingCallback(void *data, struct xdg_wm_base *shell, uint32_t serial);
0044 
0045     WaylandPointer<xdg_wm_base, xdg_wm_base_destroy> xdg_shell_base;
0046     static const struct xdg_wm_base_listener s_shellListener;
0047 };
0048 
0049 const struct xdg_wm_base_listener XdgShellStable::Private::s_shellListener = {
0050     pingCallback,
0051 };
0052 
0053 void XdgShellStable::Private::pingCallback(void *data, struct xdg_wm_base *shell, uint32_t serial)
0054 {
0055     Q_UNUSED(data)
0056     xdg_wm_base_pong(shell, serial);
0057 }
0058 
0059 void XdgShellStable::Private::setup(xdg_wm_base *shell)
0060 {
0061     Q_ASSERT(shell);
0062     Q_ASSERT(!xdg_shell_base);
0063     xdg_shell_base.setup(shell);
0064     xdg_wm_base_add_listener(shell, &s_shellListener, this);
0065 }
0066 
0067 void XdgShellStable::Private::release()
0068 {
0069     xdg_shell_base.release();
0070 }
0071 
0072 void XdgShellStable::Private::destroy()
0073 {
0074     xdg_shell_base.destroy();
0075 }
0076 
0077 bool XdgShellStable::Private::isValid() const
0078 {
0079     return xdg_shell_base.isValid();
0080 }
0081 
0082 XdgShellSurface *XdgShellStable::Private::getXdgSurface(Surface *surface, QObject *parent)
0083 {
0084     Q_ASSERT(isValid());
0085     auto ss = xdg_wm_base_get_xdg_surface(xdg_shell_base, *surface);
0086 
0087     if (!ss) {
0088         return nullptr;
0089     }
0090 
0091     auto s = new XdgTopLevelStable(parent);
0092     auto toplevel = xdg_surface_get_toplevel(ss);
0093     if (queue) {
0094         queue->addProxy(ss);
0095         queue->addProxy(toplevel);
0096     }
0097     s->setup(ss, toplevel);
0098     return s;
0099 }
0100 
0101 XdgShellPopup *XdgShellStable::Private::getXdgPopup(Surface *surface, XdgShellSurface *parentSurface, const XdgPositioner &positioner, QObject *parent)
0102 {
0103     return internalGetXdgPopup(surface, *parentSurface, positioner, parent);
0104 }
0105 
0106 XdgShellPopup *XdgShellStable::Private::getXdgPopup(Surface *surface, XdgShellPopup *parentSurface, const XdgPositioner &positioner, QObject *parent)
0107 {
0108     return internalGetXdgPopup(surface, *parentSurface, positioner, parent);
0109 }
0110 
0111 XdgShellPopup *XdgShellStable::Private::internalGetXdgPopup(Surface *surface, xdg_surface *parentSurface, const XdgPositioner &positioner, QObject *parent)
0112 {
0113     Q_ASSERT(isValid());
0114     auto ss = xdg_wm_base_get_xdg_surface(xdg_shell_base, *surface);
0115     if (!ss) {
0116         return nullptr;
0117     }
0118 
0119     auto p = xdg_wm_base_create_positioner(xdg_shell_base);
0120 
0121     auto anchorRect = positioner.anchorRect();
0122     xdg_positioner_set_anchor_rect(p, anchorRect.x(), anchorRect.y(), anchorRect.width(), anchorRect.height());
0123 
0124     QSize initialSize = positioner.initialSize();
0125     xdg_positioner_set_size(p, initialSize.width(), initialSize.height());
0126 
0127     QPoint anchorOffset = positioner.anchorOffset();
0128     if (!anchorOffset.isNull()) {
0129         xdg_positioner_set_offset(p, anchorOffset.x(), anchorOffset.y());
0130     }
0131 
0132     uint32_t anchor = XDG_POSITIONER_ANCHOR_NONE;
0133     if (positioner.anchorEdge().testFlag(Qt::TopEdge)) {
0134         if (positioner.anchorEdge().testFlag(Qt::LeftEdge) && ((positioner.anchorEdge() & ~Qt::LeftEdge) == Qt::TopEdge)) {
0135             anchor = XDG_POSITIONER_ANCHOR_TOP_LEFT;
0136         } else if (positioner.anchorEdge().testFlag(Qt::RightEdge) && ((positioner.anchorEdge() & ~Qt::RightEdge) == Qt::TopEdge)) {
0137             anchor = XDG_POSITIONER_ANCHOR_TOP_RIGHT;
0138         } else if ((positioner.anchorEdge() & ~Qt::TopEdge) == Qt::Edges()) {
0139             anchor = XDG_POSITIONER_ANCHOR_TOP;
0140         }
0141     } else if (positioner.anchorEdge().testFlag(Qt::BottomEdge)) {
0142         if (positioner.anchorEdge().testFlag(Qt::LeftEdge) && ((positioner.anchorEdge() & ~Qt::LeftEdge) == Qt::BottomEdge)) {
0143             anchor = XDG_POSITIONER_ANCHOR_BOTTOM_LEFT;
0144         } else if (positioner.anchorEdge().testFlag(Qt::RightEdge) && ((positioner.anchorEdge() & ~Qt::RightEdge) == Qt::BottomEdge)) {
0145             anchor = XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT;
0146         } else if ((positioner.anchorEdge() & ~Qt::BottomEdge) == Qt::Edges()) {
0147             anchor = XDG_POSITIONER_ANCHOR_BOTTOM;
0148         }
0149     } else if (positioner.anchorEdge().testFlag(Qt::RightEdge) && ((positioner.anchorEdge() & ~Qt::RightEdge) == Qt::Edges())) {
0150         anchor = XDG_POSITIONER_ANCHOR_RIGHT;
0151     } else if (positioner.anchorEdge().testFlag(Qt::LeftEdge) && ((positioner.anchorEdge() & ~Qt::LeftEdge) == Qt::Edges())) {
0152         anchor = XDG_POSITIONER_ANCHOR_LEFT;
0153     }
0154     if (anchor != 0) {
0155         xdg_positioner_set_anchor(p, anchor);
0156     }
0157 
0158     uint32_t gravity = XDG_POSITIONER_GRAVITY_NONE;
0159     if (positioner.gravity().testFlag(Qt::TopEdge)) {
0160         if (positioner.gravity().testFlag(Qt::LeftEdge) && ((positioner.gravity() & ~Qt::LeftEdge) == Qt::TopEdge)) {
0161             gravity = XDG_POSITIONER_GRAVITY_TOP_LEFT;
0162         } else if (positioner.gravity().testFlag(Qt::RightEdge) && ((positioner.gravity() & ~Qt::RightEdge) == Qt::TopEdge)) {
0163             gravity = XDG_POSITIONER_GRAVITY_TOP_RIGHT;
0164         } else if ((positioner.gravity() & ~Qt::TopEdge) == Qt::Edges()) {
0165             gravity = XDG_POSITIONER_GRAVITY_TOP;
0166         }
0167     } else if (positioner.gravity().testFlag(Qt::BottomEdge)) {
0168         if (positioner.gravity().testFlag(Qt::LeftEdge) && ((positioner.gravity() & ~Qt::LeftEdge) == Qt::BottomEdge)) {
0169             gravity = XDG_POSITIONER_GRAVITY_BOTTOM_LEFT;
0170         } else if (positioner.gravity().testFlag(Qt::RightEdge) && ((positioner.gravity() & ~Qt::RightEdge) == Qt::BottomEdge)) {
0171             gravity = XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT;
0172         } else if ((positioner.gravity() & ~Qt::BottomEdge) == Qt::Edges()) {
0173             gravity = XDG_POSITIONER_GRAVITY_BOTTOM;
0174         }
0175     } else if (positioner.gravity().testFlag(Qt::RightEdge) && ((positioner.gravity() & ~Qt::RightEdge) == Qt::Edges())) {
0176         gravity = XDG_POSITIONER_GRAVITY_RIGHT;
0177     } else if (positioner.gravity().testFlag(Qt::LeftEdge) && ((positioner.gravity() & ~Qt::LeftEdge) == Qt::Edges())) {
0178         gravity = XDG_POSITIONER_GRAVITY_LEFT;
0179     }
0180     if (gravity != 0) {
0181         xdg_positioner_set_gravity(p, gravity);
0182     }
0183 
0184     uint32_t constraint = XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE;
0185     if (positioner.constraints().testFlag(XdgPositioner::Constraint::SlideX)) {
0186         constraint |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X;
0187     }
0188     if (positioner.constraints().testFlag(XdgPositioner::Constraint::SlideY)) {
0189         constraint |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y;
0190     }
0191     if (positioner.constraints().testFlag(XdgPositioner::Constraint::FlipX)) {
0192         constraint |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X;
0193     }
0194     if (positioner.constraints().testFlag(XdgPositioner::Constraint::FlipY)) {
0195         constraint |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y;
0196     }
0197     if (positioner.constraints().testFlag(XdgPositioner::Constraint::ResizeX)) {
0198         constraint |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X;
0199     }
0200     if (positioner.constraints().testFlag(XdgPositioner::Constraint::ResizeY)) {
0201         constraint |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y;
0202     }
0203     if (constraint != 0) {
0204         xdg_positioner_set_constraint_adjustment(p, constraint);
0205     }
0206 
0207     XdgShellPopup *s = new XdgShellPopupStable(parent);
0208     auto popup = xdg_surface_get_popup(ss, parentSurface, p);
0209     if (queue) {
0210         // deliberately not adding the positioner because the positioner has no events sent to it
0211         queue->addProxy(ss);
0212         queue->addProxy(popup);
0213     }
0214     s->setup(ss, popup);
0215 
0216     xdg_positioner_destroy(p);
0217 
0218     return s;
0219 }
0220 
0221 XdgShellStable::XdgShellStable(QObject *parent)
0222     : XdgShell(new Private, parent)
0223 {
0224 }
0225 
0226 XdgShellStable::~XdgShellStable() = default;
0227 
0228 // A top level wraps both xdg_surface and xdg_top_level into the public API XdgShelllSurface
0229 class XdgTopLevelStable::Private : public XdgShellSurface::Private
0230 {
0231 public:
0232     Private(XdgShellSurface *q);
0233     WaylandPointer<xdg_toplevel, xdg_toplevel_destroy> xdgtoplevel;
0234     WaylandPointer<xdg_surface, xdg_surface_destroy> xdgsurface;
0235 
0236     void setup(xdg_surface *surface, xdg_toplevel *toplevel) override;
0237     void release() override;
0238     void destroy() override;
0239     bool isValid() const override;
0240 
0241     using XdgShellSurface::Private::operator zxdg_toplevel_v6 *;
0242     using XdgShellSurface::Private::operator zxdg_surface_v6 *;
0243     operator xdg_surface *() override
0244     {
0245         return xdgsurface;
0246     }
0247     operator xdg_surface *() const override
0248     {
0249         return xdgsurface;
0250     }
0251     operator xdg_toplevel *() override
0252     {
0253         return xdgtoplevel;
0254     }
0255     operator xdg_toplevel *() const override
0256     {
0257         return xdgtoplevel;
0258     }
0259 
0260     void setTransientFor(XdgShellSurface *parent) override;
0261     void setTitle(const QString &title) override;
0262     void setAppId(const QByteArray &appId) override;
0263     void showWindowMenu(Seat *seat, quint32 serial, qint32 x, qint32 y) override;
0264     void move(Seat *seat, quint32 serial) override;
0265     void resize(Seat *seat, quint32 serial, Qt::Edges edges) override;
0266     void ackConfigure(quint32 serial) override;
0267     void setMaximized() override;
0268     void unsetMaximized() override;
0269     void setFullscreen(Output *output) override;
0270     void unsetFullscreen() override;
0271     void setMinimized() override;
0272     void setMaxSize(const QSize &size) override;
0273     void setMinSize(const QSize &size) override;
0274     void setWindowGeometry(const QRect &windowGeometry) override;
0275 
0276 private:
0277     QSize pendingSize;
0278     States pendingState;
0279 
0280     static void configureCallback(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *state);
0281     static void closeCallback(void *data, xdg_toplevel *xdg_toplevel);
0282     static void surfaceConfigureCallback(void *data, xdg_surface *xdg_surface, uint32_t serial);
0283 
0284     static const struct xdg_toplevel_listener s_toplevelListener;
0285     static const struct xdg_surface_listener s_surfaceListener;
0286 };
0287 
0288 const struct xdg_toplevel_listener XdgTopLevelStable::Private::s_toplevelListener = {configureCallback, closeCallback};
0289 
0290 const struct xdg_surface_listener XdgTopLevelStable::Private::s_surfaceListener = {surfaceConfigureCallback};
0291 
0292 void XdgTopLevelStable::Private::surfaceConfigureCallback(void *data, struct xdg_surface *surface, uint32_t serial)
0293 {
0294     Q_UNUSED(surface)
0295     auto s = static_cast<Private *>(data);
0296     s->q->configureRequested(s->pendingSize, s->pendingState, serial);
0297     if (!s->pendingSize.isNull()) {
0298         s->q->setSize(s->pendingSize);
0299         s->pendingSize = QSize();
0300     }
0301     s->pendingState = {};
0302 }
0303 
0304 void XdgTopLevelStable::Private::configureCallback(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *state)
0305 {
0306     Q_UNUSED(xdg_toplevel)
0307     auto s = static_cast<Private *>(data);
0308     States states;
0309 
0310     uint32_t *statePtr = static_cast<uint32_t *>(state->data);
0311     for (size_t i = 0; i < state->size / sizeof(uint32_t); i++) {
0312         switch (statePtr[i]) {
0313         case XDG_TOPLEVEL_STATE_MAXIMIZED:
0314             states = states | XdgShellSurface::State::Maximized;
0315             break;
0316         case XDG_TOPLEVEL_STATE_FULLSCREEN:
0317             states = states | XdgShellSurface::State::Fullscreen;
0318             break;
0319         case XDG_TOPLEVEL_STATE_RESIZING:
0320             states = states | XdgShellSurface::State::Resizing;
0321             break;
0322         case XDG_TOPLEVEL_STATE_ACTIVATED:
0323             states = states | XdgShellSurface::State::Activated;
0324             break;
0325         }
0326     }
0327     s->pendingSize = QSize(width, height);
0328     s->pendingState = states;
0329 }
0330 
0331 void XdgTopLevelStable::Private::closeCallback(void *data, xdg_toplevel *xdg_toplevel)
0332 {
0333     auto s = static_cast<XdgTopLevelStable::Private *>(data);
0334     Q_ASSERT(s->xdgtoplevel == xdg_toplevel);
0335     Q_EMIT s->q->closeRequested();
0336 }
0337 
0338 XdgTopLevelStable::Private::Private(XdgShellSurface *q)
0339     : XdgShellSurface::Private(q)
0340 {
0341 }
0342 
0343 void XdgTopLevelStable::Private::setup(xdg_surface *surface, xdg_toplevel *topLevel)
0344 {
0345     Q_ASSERT(surface);
0346     Q_ASSERT(!xdgtoplevel);
0347     xdgsurface.setup(surface);
0348     xdgtoplevel.setup(topLevel);
0349     xdg_surface_add_listener(xdgsurface, &s_surfaceListener, this);
0350     xdg_toplevel_add_listener(xdgtoplevel, &s_toplevelListener, this);
0351 }
0352 
0353 void XdgTopLevelStable::Private::release()
0354 {
0355     xdgtoplevel.release();
0356     xdgsurface.release();
0357 }
0358 
0359 void XdgTopLevelStable::Private::destroy()
0360 {
0361     xdgtoplevel.destroy();
0362     xdgsurface.destroy();
0363 }
0364 
0365 bool XdgTopLevelStable::Private::isValid() const
0366 {
0367     return xdgtoplevel.isValid() && xdgsurface.isValid();
0368 }
0369 
0370 void XdgTopLevelStable::Private::setTransientFor(XdgShellSurface *parent)
0371 {
0372     xdg_toplevel *parentSurface = nullptr;
0373     if (parent) {
0374         parentSurface = *parent;
0375     }
0376     xdg_toplevel_set_parent(xdgtoplevel, parentSurface);
0377 }
0378 
0379 void XdgTopLevelStable::Private::setTitle(const QString &title)
0380 {
0381     xdg_toplevel_set_title(xdgtoplevel, title.toUtf8().constData());
0382 }
0383 
0384 void XdgTopLevelStable::Private::setAppId(const QByteArray &appId)
0385 {
0386     xdg_toplevel_set_app_id(xdgtoplevel, appId.constData());
0387 }
0388 
0389 void XdgTopLevelStable::Private::showWindowMenu(Seat *seat, quint32 serial, qint32 x, qint32 y)
0390 {
0391     xdg_toplevel_show_window_menu(xdgtoplevel, *seat, serial, x, y);
0392 }
0393 
0394 void XdgTopLevelStable::Private::move(Seat *seat, quint32 serial)
0395 {
0396     xdg_toplevel_move(xdgtoplevel, *seat, serial);
0397 }
0398 
0399 void XdgTopLevelStable::Private::resize(Seat *seat, quint32 serial, Qt::Edges edges)
0400 {
0401     uint wlEdge = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
0402     if (edges.testFlag(Qt::TopEdge)) {
0403         if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::TopEdge)) {
0404             wlEdge = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
0405         } else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::TopEdge)) {
0406             wlEdge = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
0407         } else if ((edges & ~Qt::TopEdge) == Qt::Edges()) {
0408             wlEdge = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
0409         }
0410     } else if (edges.testFlag(Qt::BottomEdge)) {
0411         if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::BottomEdge)) {
0412             wlEdge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
0413         } else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::BottomEdge)) {
0414             wlEdge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
0415         } else if ((edges & ~Qt::BottomEdge) == Qt::Edges()) {
0416             wlEdge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
0417         }
0418     } else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::Edges())) {
0419         wlEdge = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
0420     } else if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::Edges())) {
0421         wlEdge = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
0422     }
0423     xdg_toplevel_resize(xdgtoplevel, *seat, serial, wlEdge);
0424 }
0425 
0426 void XdgTopLevelStable::Private::ackConfigure(quint32 serial)
0427 {
0428     xdg_surface_ack_configure(xdgsurface, serial);
0429 }
0430 
0431 void XdgTopLevelStable::Private::setMaximized()
0432 {
0433     xdg_toplevel_set_maximized(xdgtoplevel);
0434 }
0435 
0436 void XdgTopLevelStable::Private::unsetMaximized()
0437 {
0438     xdg_toplevel_unset_maximized(xdgtoplevel);
0439 }
0440 
0441 void XdgTopLevelStable::Private::setFullscreen(Output *output)
0442 {
0443     wl_output *o = nullptr;
0444     if (output) {
0445         o = *output;
0446     }
0447     xdg_toplevel_set_fullscreen(xdgtoplevel, o);
0448 }
0449 
0450 void XdgTopLevelStable::Private::unsetFullscreen()
0451 {
0452     xdg_toplevel_unset_fullscreen(xdgtoplevel);
0453 }
0454 
0455 void XdgTopLevelStable::Private::setMinimized()
0456 {
0457     xdg_toplevel_set_minimized(xdgtoplevel);
0458 }
0459 
0460 void XdgTopLevelStable::Private::setMaxSize(const QSize &size)
0461 {
0462     xdg_toplevel_set_max_size(xdgtoplevel, size.width(), size.height());
0463 }
0464 
0465 void XdgTopLevelStable::Private::setMinSize(const QSize &size)
0466 {
0467     xdg_toplevel_set_min_size(xdgtoplevel, size.width(), size.height());
0468 }
0469 
0470 void XdgTopLevelStable::Private::setWindowGeometry(const QRect &windowGeometry)
0471 {
0472     xdg_surface_set_window_geometry(xdgsurface, windowGeometry.x(), windowGeometry.y(), windowGeometry.width(), windowGeometry.height());
0473 }
0474 
0475 XdgTopLevelStable::XdgTopLevelStable(QObject *parent)
0476     : XdgShellSurface(new Private(this), parent)
0477 {
0478 }
0479 
0480 XdgTopLevelStable::~XdgTopLevelStable() = default;
0481 
0482 class XdgShellPopupStable::Private : public XdgShellPopup::Private
0483 {
0484 public:
0485     Private(XdgShellPopup *q);
0486 
0487     void setup(xdg_surface *s, xdg_popup *p) override;
0488     void release() override;
0489     void destroy() override;
0490     bool isValid() const override;
0491     void requestGrab(Seat *seat, quint32 serial) override;
0492     void ackConfigure(quint32 serial) override;
0493     void setWindowGeometry(const QRect &windowGeometry) override;
0494 
0495     using XdgShellPopup::Private::operator zxdg_popup_v6 *;
0496     using XdgShellPopup::Private::operator zxdg_surface_v6 *;
0497     operator xdg_surface *() override
0498     {
0499         return xdgsurface;
0500     }
0501     operator xdg_surface *() const override
0502     {
0503         return xdgsurface;
0504     }
0505     operator xdg_popup *() override
0506     {
0507         return xdgpopup;
0508     }
0509     operator xdg_popup *() const override
0510     {
0511         return xdgpopup;
0512     }
0513     WaylandPointer<xdg_surface, xdg_surface_destroy> xdgsurface;
0514     WaylandPointer<xdg_popup, xdg_popup_destroy> xdgpopup;
0515 
0516     QRect pendingRect;
0517 
0518 private:
0519     static void configureCallback(void *data, xdg_popup *xdg_popup, int32_t x, int32_t y, int32_t width, int32_t height);
0520     static void popupDoneCallback(void *data, xdg_popup *xdg_popup);
0521     static void surfaceConfigureCallback(void *data, xdg_surface *xdg_surface, uint32_t serial);
0522 
0523     static const struct xdg_popup_listener s_popupListener;
0524     static const struct xdg_surface_listener s_surfaceListener;
0525 };
0526 
0527 const struct xdg_popup_listener XdgShellPopupStable::Private::s_popupListener = {configureCallback, popupDoneCallback};
0528 
0529 const struct xdg_surface_listener XdgShellPopupStable::Private::s_surfaceListener = {
0530     surfaceConfigureCallback,
0531 };
0532 
0533 void XdgShellPopupStable::Private::configureCallback(void *data, xdg_popup *xdg_popup, int32_t x, int32_t y, int32_t width, int32_t height)
0534 {
0535     Q_UNUSED(xdg_popup)
0536     auto s = static_cast<Private *>(data);
0537     s->pendingRect = QRect(x, y, width, height);
0538 }
0539 
0540 void XdgShellPopupStable::Private::surfaceConfigureCallback(void *data, struct xdg_surface *surface, uint32_t serial)
0541 {
0542     Q_UNUSED(surface)
0543     auto s = static_cast<Private *>(data);
0544     s->q->configureRequested(s->pendingRect, serial);
0545     s->pendingRect = QRect();
0546 }
0547 
0548 void XdgShellPopupStable::Private::popupDoneCallback(void *data, xdg_popup *xdg_popup)
0549 {
0550     auto s = static_cast<XdgShellPopupStable::Private *>(data);
0551     Q_ASSERT(s->xdgpopup == xdg_popup);
0552     Q_EMIT s->q->popupDone();
0553 }
0554 
0555 XdgShellPopupStable::Private::Private(XdgShellPopup *q)
0556     : XdgShellPopup::Private(q)
0557 {
0558 }
0559 
0560 void XdgShellPopupStable::Private::setup(xdg_surface *s, xdg_popup *p)
0561 {
0562     Q_ASSERT(p);
0563     Q_ASSERT(!xdgsurface);
0564     Q_ASSERT(!xdgpopup);
0565 
0566     xdgsurface.setup(s);
0567     xdgpopup.setup(p);
0568     xdg_surface_add_listener(xdgsurface, &s_surfaceListener, this);
0569     xdg_popup_add_listener(xdgpopup, &s_popupListener, this);
0570 }
0571 
0572 void XdgShellPopupStable::Private::release()
0573 {
0574     xdgpopup.release();
0575 }
0576 
0577 void XdgShellPopupStable::Private::destroy()
0578 {
0579     xdgpopup.destroy();
0580 }
0581 
0582 bool XdgShellPopupStable::Private::isValid() const
0583 {
0584     return xdgpopup.isValid();
0585 }
0586 
0587 void XdgShellPopupStable::Private::requestGrab(Seat *seat, quint32 serial)
0588 {
0589     xdg_popup_grab(xdgpopup, *seat, serial);
0590 }
0591 
0592 void XdgShellPopupStable::Private::ackConfigure(quint32 serial)
0593 {
0594     xdg_surface_ack_configure(xdgsurface, serial);
0595 }
0596 
0597 void XdgShellPopupStable::Private::setWindowGeometry(const QRect &windowGeometry)
0598 {
0599     xdg_surface_set_window_geometry(xdgsurface, windowGeometry.x(), windowGeometry.y(), windowGeometry.width(), windowGeometry.height());
0600 }
0601 
0602 XdgShellPopupStable::XdgShellPopupStable(QObject *parent)
0603     : XdgShellPopup(new Private(this), parent)
0604 {
0605 }
0606 
0607 XdgShellPopupStable::~XdgShellPopupStable() = default;
0608 
0609 }
0610 }