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 }