diff --git a/src/client/xdgshell_v6.cpp b/src/client/xdgshell_v6.cpp index d4e0ffd..0f376d2 100644 --- a/src/client/xdgshell_v6.cpp +++ b/src/client/xdgshell_v6.cpp @@ -1,576 +1,581 @@ /**************************************************************************** Copyright 2017 David Edmundson This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #include "xdgshell_p.h" #include "event_queue.h" #include "output.h" #include "seat.h" #include "surface.h" #include "wayland_pointer_p.h" #include #include namespace KWayland { namespace Client { class XdgShellUnstableV6::Private : public XdgShell::Private { public: void setupV6(zxdg_shell_v6 *shell) override; void release() override; void destroy() override; bool isValid() const override; XdgShellSurface *getXdgSurface(Surface *surface, QObject *parent) override; XdgShellPopup *getXdgPopup(Surface *surface, XdgShellSurface *parentSurface, const XdgPositioner &positioner, Seat *seat, quint32 serial, QObject *parent) override; XdgShellPopup *getXdgPopup(Surface *surface, XdgShellPopup *parentSurface, const XdgPositioner &positioner, Seat *seat, quint32 serial, QObject *parent) override; operator zxdg_shell_v6*() override { return xdgshellv6; } operator zxdg_shell_v6*() const override { return xdgshellv6; } private: - XdgShellPopup *getXdgPopup(Surface *surface, zxdg_surface_v6 *parentSurface, const XdgPositioner &positioner, Seat *seat, quint32 serial, QObject *parent); + XdgShellPopup *internalGetXdgPopup(Surface *surface, zxdg_surface_v6 *parentSurface, const XdgPositioner &positioner, Seat *seat, quint32 serial, QObject *parent); static void pingCallback(void *data, struct zxdg_shell_v6 *shell, uint32_t serial); WaylandPointer xdgshellv6; static const struct zxdg_shell_v6_listener s_shellListener; }; const struct zxdg_shell_v6_listener XdgShellUnstableV6::Private::s_shellListener = { pingCallback, }; void XdgShellUnstableV6::Private::pingCallback(void *data, struct zxdg_shell_v6 *shell, uint32_t serial) { Q_UNUSED(data) zxdg_shell_v6_pong(shell, serial); } void XdgShellUnstableV6::Private::setupV6(zxdg_shell_v6 *shell) { Q_ASSERT(shell); Q_ASSERT(!xdgshellv6); xdgshellv6.setup(shell); zxdg_shell_v6_add_listener(shell, &s_shellListener, this); } void XdgShellUnstableV6::Private::release() { xdgshellv6.release(); } void XdgShellUnstableV6::Private::destroy() { xdgshellv6.destroy(); } bool XdgShellUnstableV6::Private::isValid() const { return xdgshellv6.isValid(); } XdgShellSurface *XdgShellUnstableV6::Private::getXdgSurface(Surface *surface, QObject *parent) { Q_ASSERT(isValid()); auto ss = zxdg_shell_v6_get_xdg_surface(xdgshellv6, *surface); if (!ss) { return nullptr; } auto s = new XdgTopLevelUnstableV6(parent); auto toplevel = zxdg_surface_v6_get_toplevel(ss); if (queue) { queue->addProxy(ss); queue->addProxy(toplevel); } s->setup(ss, toplevel); return s; } XdgShellPopup *XdgShellUnstableV6::Private::getXdgPopup(Surface *surface, XdgShellSurface *parentSurface, const XdgPositioner &positioner, Seat *seat, quint32 serial, QObject *parent) { - return getXdgPopup(surface, *parentSurface, positioner, seat, serial, parent); + return internalGetXdgPopup(surface, *parentSurface, positioner, seat, serial, parent); } XdgShellPopup *XdgShellUnstableV6::Private::getXdgPopup(Surface *surface, XdgShellPopup *parentSurface, const XdgPositioner &positioner, Seat *seat, quint32 serial, QObject *parent) { - return getXdgPopup(surface, *parentSurface, positioner, seat, serial, parent); + return internalGetXdgPopup(surface, *parentSurface, positioner, seat, serial, parent); } -XdgShellPopup *XdgShellUnstableV6::Private::getXdgPopup(Surface *surface, zxdg_surface_v6 *parentSurface, const XdgPositioner &positioner, Seat *seat, quint32 serial, QObject *parent) +XdgShellPopup *XdgShellUnstableV6::Private::internalGetXdgPopup(Surface *surface, zxdg_surface_v6 *parentSurface, const XdgPositioner &positioner, Seat *seat, quint32 serial, QObject *parent) { Q_ASSERT(isValid()); auto ss = zxdg_shell_v6_get_xdg_surface(xdgshellv6, *surface); if (!ss) { return nullptr; } auto p = zxdg_shell_v6_create_positioner(xdgshellv6); auto anchorRect = positioner.anchor(); zxdg_positioner_v6_set_anchor_rect(p, anchorRect.x(), anchorRect.y(), anchorRect.width(), anchorRect.height()); QSize initialSize = positioner.initialSize(); zxdg_positioner_v6_set_size(p, initialSize.width(), initialSize.height()); QPoint anchorOffset = positioner.anchorOffset(); if (!anchorOffset.isNull()) { zxdg_positioner_v6_set_offset(p, anchorOffset.x(), anchorOffset.y()); } uint32_t anchor = 0; if (positioner.anchorEdge().testFlag(Qt::LeftEdge)) { anchor |= ZXDG_POSITIONER_V6_ANCHOR_LEFT; } if (positioner.anchorEdge().testFlag(Qt::TopEdge)) { anchor |= ZXDG_POSITIONER_V6_ANCHOR_TOP; } if (positioner.anchorEdge().testFlag(Qt::RightEdge)) { anchor |= ZXDG_POSITIONER_V6_ANCHOR_RIGHT; } if (positioner.anchorEdge().testFlag(Qt::BottomEdge)) { anchor |= ZXDG_POSITIONER_V6_ANCHOR_BOTTOM; } if (anchor != 0) { zxdg_positioner_v6_set_anchor(p, anchor); } uint32_t gravity = 0; if (positioner.anchorEdge().testFlag(Qt::LeftEdge)) { gravity |= ZXDG_POSITIONER_V6_GRAVITY_LEFT; } if (positioner.anchorEdge().testFlag(Qt::TopEdge)) { gravity |= ZXDG_POSITIONER_V6_GRAVITY_TOP; } if (positioner.anchorEdge().testFlag(Qt::RightEdge)) { gravity |= ZXDG_POSITIONER_V6_GRAVITY_RIGHT; } if (positioner.anchorEdge().testFlag(Qt::BottomEdge)) { gravity |= ZXDG_POSITIONER_V6_GRAVITY_BOTTOM; } zxdg_positioner_v6_set_anchor(p, anchor); if (gravity != 0) { zxdg_positioner_v6_set_gravity(p, gravity); } uint32_t constraint = 0; if (positioner.constraints().testFlag(XdgPositioner::Constraint::SlideX)) { constraint |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X; } if (positioner.constraints().testFlag(XdgPositioner::Constraint::SlideY)) { constraint |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y; } if (positioner.constraints().testFlag(XdgPositioner::Constraint::FlipX)) { constraint |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X; } if (positioner.constraints().testFlag(XdgPositioner::Constraint::FlipY)) { constraint |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y; } if (positioner.constraints().testFlag(XdgPositioner::Constraint::ResizeX)) { constraint |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y; } if (positioner.constraints().testFlag(XdgPositioner::Constraint::ResizeY)) { constraint |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y; } if (constraint != 0) { zxdg_positioner_v6_set_constraint_adjustment(p, constraint); } XdgShellPopup *s = new XdgShellPopupUnstableV6(parent); auto popup = zxdg_surface_v6_get_popup(ss, parentSurface, p); if (queue) { //deliberately not adding the positioner because the positioner has no events sent to it queue->addProxy(ss); queue->addProxy(popup); } s->setup(ss, popup); zxdg_positioner_v6_destroy(p); + zxdg_popup_v6_grab(popup, *seat, serial); + return s; } XdgShellUnstableV6::XdgShellUnstableV6(QObject *parent) : XdgShell(new Private, parent) { } XdgShellUnstableV6::~XdgShellUnstableV6() = default; //A top level wraps both xdg_surface_v6 and xdg_top_level into the public API XdgShelllSurface class XdgTopLevelUnstableV6::Private : public XdgShellSurface::Private { public: Private(XdgShellSurface *q); WaylandPointer xdgtoplevelv6; WaylandPointer xdgsurfacev6; void setupV6(zxdg_surface_v6 *surface, zxdg_toplevel_v6 *toplevel) override; void release() override; void destroy() override; bool isValid() const override; operator zxdg_surface_v6*() override { return xdgsurfacev6; } operator zxdg_surface_v6*() const override { return xdgsurfacev6; } operator zxdg_toplevel_v6*() override { return xdgtoplevelv6; } operator zxdg_toplevel_v6*() const override { return xdgtoplevelv6; } void setTransientFor(XdgShellSurface *parent) override; void setTitle(const QString &title) override; void setAppId(const QByteArray &appId) override; void showWindowMenu(Seat *seat, quint32 serial, qint32 x, qint32 y) override; void move(Seat *seat, quint32 serial) override; void resize(Seat *seat, quint32 serial, Qt::Edges edges) override; void ackConfigure(quint32 serial) override; void setMaximized() override; void unsetMaximized() override; void setFullscreen(Output *output) override; void unsetFullscreen() override; void setMinimized() override; void setMaxSize(const QSize &size) override; void setMinSize(const QSize &size) override; private: QSize pendingSize; States pendingState; static void configureCallback(void *data, struct zxdg_toplevel_v6 *xdg_toplevel, int32_t width, int32_t height, struct wl_array *state); static void closeCallback(void *data, zxdg_toplevel_v6 *xdg_toplevel); static void surfaceConfigureCallback(void *data, zxdg_surface_v6 *xdg_surface, uint32_t serial); static const struct zxdg_toplevel_v6_listener s_toplevelListener; static const struct zxdg_surface_v6_listener s_surfaceListener; }; const struct zxdg_toplevel_v6_listener XdgTopLevelUnstableV6::Private::s_toplevelListener = { configureCallback, closeCallback }; const struct zxdg_surface_v6_listener XdgTopLevelUnstableV6::Private::s_surfaceListener = { surfaceConfigureCallback }; void XdgTopLevelUnstableV6::Private::surfaceConfigureCallback(void *data, struct zxdg_surface_v6 *surface, uint32_t serial) { + Q_UNUSED(surface) auto s = reinterpret_cast(data); s->q->configureRequested(s->pendingSize, s->pendingState, serial); if (!s->pendingSize.isNull()) { s->q->setSize(s->pendingSize); s->pendingSize = QSize(); } s->pendingState = 0; } void XdgTopLevelUnstableV6::Private::configureCallback(void *data, struct zxdg_toplevel_v6 *xdg_toplevel, int32_t width, int32_t height, struct wl_array *state) { Q_UNUSED(xdg_toplevel) auto s = reinterpret_cast(data); States states; uint32_t *statePtr = reinterpret_cast(state->data); for (size_t i = 0; i < state->size / sizeof(uint32_t); i++) { switch (statePtr[i]) { case ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED: states = states | XdgShellSurface::State::Maximized; break; case ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN: states = states | XdgShellSurface::State::Fullscreen; break; case ZXDG_TOPLEVEL_V6_STATE_RESIZING: states = states | XdgShellSurface::State::Resizing; break; case ZXDG_TOPLEVEL_V6_STATE_ACTIVATED: states = states | XdgShellSurface::State::Activated; break; } } s->pendingSize = QSize(width, height); s->pendingState = states; } void XdgTopLevelUnstableV6::Private::closeCallback(void *data, zxdg_toplevel_v6 *xdg_toplevel) { auto s = reinterpret_cast(data); Q_ASSERT(s->xdgtoplevelv6 == xdg_toplevel); emit s->q->closeRequested(); } XdgTopLevelUnstableV6::Private::Private(XdgShellSurface *q) : XdgShellSurface::Private(q) { } void XdgTopLevelUnstableV6::Private::setupV6(zxdg_surface_v6 *surface, zxdg_toplevel_v6 *topLevel) { Q_ASSERT(surface); Q_ASSERT(!xdgtoplevelv6); xdgsurfacev6.setup(surface); xdgtoplevelv6.setup(topLevel); zxdg_surface_v6_add_listener(xdgsurfacev6, &s_surfaceListener, this); zxdg_toplevel_v6_add_listener(xdgtoplevelv6, &s_toplevelListener, this); } void XdgTopLevelUnstableV6::Private::release() { xdgtoplevelv6.release(); xdgsurfacev6.release(); } void XdgTopLevelUnstableV6::Private::destroy() { xdgtoplevelv6.destroy(); xdgsurfacev6.destroy(); } bool XdgTopLevelUnstableV6::Private::isValid() const { return xdgtoplevelv6.isValid() && xdgsurfacev6.isValid(); } void XdgTopLevelUnstableV6::Private::setTransientFor(XdgShellSurface *parent) { zxdg_toplevel_v6 *parentSurface = nullptr; if (parent) { parentSurface = *parent; } zxdg_toplevel_v6_set_parent(xdgtoplevelv6, parentSurface); } void XdgTopLevelUnstableV6::Private::setTitle(const QString & title) { zxdg_toplevel_v6_set_title(xdgtoplevelv6, title.toUtf8().constData()); } void XdgTopLevelUnstableV6::Private::setAppId(const QByteArray & appId) { zxdg_toplevel_v6_set_app_id(xdgtoplevelv6, appId.constData()); } void XdgTopLevelUnstableV6::Private::showWindowMenu(Seat *seat, quint32 serial, qint32 x, qint32 y) { zxdg_toplevel_v6_show_window_menu(xdgtoplevelv6, *seat, serial, x, y); } void XdgTopLevelUnstableV6::Private::move(Seat *seat, quint32 serial) { zxdg_toplevel_v6_move(xdgtoplevelv6, *seat, serial); } void XdgTopLevelUnstableV6::Private::resize(Seat *seat, quint32 serial, Qt::Edges edges) { uint wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_NONE; if (edges.testFlag(Qt::TopEdge)) { if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::TopEdge)) { wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_LEFT; } else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::TopEdge)) { wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_RIGHT; } else if ((edges & ~Qt::TopEdge) == Qt::Edges()) { wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP; } } else if (edges.testFlag(Qt::BottomEdge)) { if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::BottomEdge)) { wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_LEFT; } else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::BottomEdge)) { wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_RIGHT; } else if ((edges & ~Qt::BottomEdge) == Qt::Edges()) { wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM; } } else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::Edges())) { wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_RIGHT; } else if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::Edges())) { wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_LEFT; } zxdg_toplevel_v6_resize(xdgtoplevelv6, *seat, serial, wlEdge); } void XdgTopLevelUnstableV6::Private::ackConfigure(quint32 serial) { zxdg_surface_v6_ack_configure(xdgsurfacev6, serial); } void XdgTopLevelUnstableV6::Private::setMaximized() { zxdg_toplevel_v6_set_maximized(xdgtoplevelv6); } void XdgTopLevelUnstableV6::Private::unsetMaximized() { zxdg_toplevel_v6_unset_maximized(xdgtoplevelv6); } void XdgTopLevelUnstableV6::Private::setFullscreen(Output *output) { wl_output *o = nullptr; if (output) { o = *output; } zxdg_toplevel_v6_set_fullscreen(xdgtoplevelv6, o); } void XdgTopLevelUnstableV6::Private::unsetFullscreen() { zxdg_toplevel_v6_unset_fullscreen(xdgtoplevelv6); } void XdgTopLevelUnstableV6::Private::setMinimized() { zxdg_toplevel_v6_set_minimized(xdgtoplevelv6); } void XdgTopLevelUnstableV6::Private::setMaxSize(const QSize &size) { zxdg_toplevel_v6_set_max_size(xdgtoplevelv6, size.width(), size.height()); } void XdgTopLevelUnstableV6::Private::setMinSize(const QSize &size) { zxdg_toplevel_v6_set_min_size(xdgtoplevelv6, size.width(), size.height()); } XdgTopLevelUnstableV6::XdgTopLevelUnstableV6(QObject *parent) : XdgShellSurface(new Private(this), parent) { } XdgTopLevelUnstableV6::~XdgTopLevelUnstableV6() = default; class XdgShellPopupUnstableV6::Private : public XdgShellPopup::Private { public: Private(XdgShellPopup *q); void setupV6(zxdg_surface_v6 *s, zxdg_popup_v6 *p) override; void release() override; void destroy() override; bool isValid() const override; operator zxdg_surface_v6*() override { return xdgsurfacev6; } operator zxdg_surface_v6*() const override { return xdgsurfacev6; } operator zxdg_popup_v6*() override { return xdgpopupv6; } operator zxdg_popup_v6*() const override { return xdgpopupv6; } WaylandPointer xdgsurfacev6; WaylandPointer xdgpopupv6; QRect pendingRect; private: static void configureCallback(void *data, zxdg_popup_v6 *xdg_popup, int32_t x, int32_t y, int32_t width, int32_t height); static void popupDoneCallback(void *data, zxdg_popup_v6 *xdg_popup); static void surfaceConfigureCallback(void *data, zxdg_surface_v6 *xdg_surface, uint32_t serial); static const struct zxdg_popup_v6_listener s_popupListener; static const struct zxdg_surface_v6_listener s_surfaceListener; }; const struct zxdg_popup_v6_listener XdgShellPopupUnstableV6::Private::s_popupListener = { configureCallback, popupDoneCallback }; const struct zxdg_surface_v6_listener XdgShellPopupUnstableV6::Private::s_surfaceListener = { surfaceConfigureCallback, }; void XdgShellPopupUnstableV6::Private::configureCallback(void *data, zxdg_popup_v6 *xdg_popup, int32_t x, int32_t y, int32_t width, int32_t height) { + Q_UNUSED(xdg_popup); auto s = reinterpret_cast(data); s->pendingRect = QRect(x, y, width, height); } void XdgShellPopupUnstableV6::Private::surfaceConfigureCallback(void *data, struct zxdg_surface_v6 *surface, uint32_t serial) { + Q_UNUSED(surface); auto s = reinterpret_cast(data); s->q->configureRequested(s->pendingRect, serial); s->pendingRect = QRect(); } void XdgShellPopupUnstableV6::Private::popupDoneCallback(void *data, zxdg_popup_v6 *xdg_popup) { auto s = reinterpret_cast(data); Q_ASSERT(s->xdgpopupv6 == xdg_popup); emit s->q->popupDone(); } XdgShellPopupUnstableV6::Private::Private(XdgShellPopup *q) : XdgShellPopup::Private(q) { } void XdgShellPopupUnstableV6::Private::setupV6(zxdg_surface_v6 *s, zxdg_popup_v6 *p) { Q_ASSERT(p); Q_ASSERT(!xdgsurfacev6); Q_ASSERT(!xdgpopupv6); xdgsurfacev6.setup(s); xdgpopupv6.setup(p); zxdg_surface_v6_add_listener(xdgsurfacev6, &s_surfaceListener, this); zxdg_popup_v6_add_listener(xdgpopupv6, &s_popupListener, this); } void XdgShellPopupUnstableV6::Private::release() { xdgpopupv6.release(); } void XdgShellPopupUnstableV6::Private::destroy() { xdgpopupv6.destroy(); } bool XdgShellPopupUnstableV6::Private::isValid() const { return xdgpopupv6.isValid(); } XdgShellPopupUnstableV6::XdgShellPopupUnstableV6(QObject *parent) : XdgShellPopup(new Private(this), parent) { } XdgShellPopupUnstableV6::~XdgShellPopupUnstableV6() = default; } }