diff --git a/src/wayland/CMakeLists.txt b/src/wayland/CMakeLists.txt index d95bf7391f..cd0a2a753e 100644 --- a/src/wayland/CMakeLists.txt +++ b/src/wayland/CMakeLists.txt @@ -55,6 +55,7 @@ set(SERVER_LIB_SRCS xdgforeign_interface.cpp xdgshell_v5_interface.cpp xdgshell_v6_interface.cpp + xdgshell_stable_interface.cpp xdgoutput_interface.cpp ../compat/wayland-xdg-shell-v5-protocol.c ) @@ -138,11 +139,6 @@ ecm_add_wayland_server_protocol(SERVER_LIB_SRCS BASENAME text-input-unstable-v2 ) -ecm_add_wayland_server_protocol(SERVER_LIB_SRCS - PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/xdg-shell-unstable-v5.xml - BASENAME xdg-shell-v5 -) - ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/xdg-shell-unstable-v6.xml BASENAME xdg-shell-v6 @@ -188,6 +184,11 @@ ecm_add_wayland_server_protocol(SERVER_LIB_SRCS BASENAME xdg-output ) +ecm_add_wayland_server_protocol(SERVER_LIB_SRCS + PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/xdg-shell.xml + BASENAME xdg-shell +) + set(SERVER_GENERATED_SRCS ${CMAKE_CURRENT_BINARY_DIR}/wayland-output-management-client-protocol.h ${CMAKE_CURRENT_BINARY_DIR}/wayland-output-management-server-protocol.h @@ -225,6 +226,8 @@ set(SERVER_GENERATED_SRCS ${CMAKE_CURRENT_BINARY_DIR}/wayland-text-input-unstable-v2-server-protocol.h ${CMAKE_CURRENT_BINARY_DIR}/wayland-xdg-shell-v6-client-protocol.h ${CMAKE_CURRENT_BINARY_DIR}/wayland-xdg-shell-v6-server-protocol.h + ${CMAKE_CURRENT_BINARY_DIR}/wayland-xdg-shell-client-protocol.h + ${CMAKE_CURRENT_BINARY_DIR}/wayland-xdg-shell-server-protocol.h ${CMAKE_CURRENT_BINARY_DIR}/wayland-pointer-gestures-unstable-v1-client-protocol.h ${CMAKE_CURRENT_BINARY_DIR}/wayland-pointer-gestures-unstable-v1-server-protocol.h ${CMAKE_CURRENT_BINARY_DIR}/wayland-pointer-constraints-unstable-v1-client-protocol.h diff --git a/src/wayland/autotests/client/CMakeLists.txt b/src/wayland/autotests/client/CMakeLists.txt index 25ca557c79..8e89199f26 100644 --- a/src/wayland/autotests/client/CMakeLists.txt +++ b/src/wayland/autotests/client/CMakeLists.txt @@ -376,6 +376,17 @@ add_executable(testXdgShellV6 ${testXdgShellV6_SRCS}) target_link_libraries( testXdgShellV6 Qt5::Test Qt5::Gui KF5::WaylandServer KF5::WaylandClient Wayland::Client) add_test(NAME kwayland-testXdgShellV6 COMMAND testXdgShellV6) ecm_mark_as_test(testXdgShellV6) +######################################################## +# Test XdgShellStable +######################################################## +set( testXdgShellStable_SRCS + test_xdg_shell.cpp + test_xdg_shell_stable.cpp + ) +add_executable(testXdgShellStable ${testXdgShellStable_SRCS}) +target_link_libraries( testXdgShellStable Qt5::Test Qt5::Gui KF5::WaylandServer KF5::WaylandClient Wayland::Client) +add_test(NAME kwayland-testXdgShellStable COMMAND testXdgShellStable) +ecm_mark_as_test(testXdgShellStable) ######################################################## # Test Pointer Constraints diff --git a/src/wayland/autotests/client/test_xdg_shell.cpp b/src/wayland/autotests/client/test_xdg_shell.cpp index ccecbd9356..fd29b0af4c 100644 --- a/src/wayland/autotests/client/test_xdg_shell.cpp +++ b/src/wayland/autotests/client/test_xdg_shell.cpp @@ -76,8 +76,9 @@ void XdgShellTest::init() QSignalSpy outputAnnouncedSpy(®istry, &Registry::outputAnnounced); QVERIFY(outputAnnouncedSpy.isValid()); - auto shellAnnouncedSignal = m_version == XdgShellInterfaceVersion::UnstableV5 ? - &Registry::xdgShellUnstableV5Announced : &Registry::xdgShellUnstableV6Announced; + auto shellAnnouncedSignal = m_version == XdgShellInterfaceVersion::UnstableV5 ? &Registry::xdgShellUnstableV5Announced : + m_version == XdgShellInterfaceVersion::UnstableV6 ? &Registry::xdgShellUnstableV6Announced : + &Registry::xdgShellStableAnnounced; QSignalSpy xdgShellAnnouncedSpy(®istry, shellAnnouncedSignal); QVERIFY(xdgShellAnnouncedSpy.isValid()); @@ -105,7 +106,18 @@ void XdgShellTest::init() QCOMPARE(xdgShellAnnouncedSpy.count(), 1); - Registry::Interface iface = m_version == XdgShellInterfaceVersion::UnstableV5 ? Registry::Interface::XdgShellUnstableV5 : Registry::Interface::XdgShellUnstableV6; + Registry::Interface iface; + switch (m_version) { + case XdgShellInterfaceVersion::UnstableV5: + iface = Registry::Interface::XdgShellUnstableV5; + break; + case XdgShellInterfaceVersion::UnstableV6: + iface = Registry::Interface::XdgShellUnstableV6; + break; + case XdgShellInterfaceVersion::Stable: + iface = Registry::Interface::XdgShellStable; + break; + } m_xdgShell = registry.createXdgShell(registry.interface(iface).name, registry.interface(iface).version, diff --git a/src/wayland/autotests/client/test_xdg_shell_stable.cpp b/src/wayland/autotests/client/test_xdg_shell_stable.cpp new file mode 100644 index 0000000000..e3f0617169 --- /dev/null +++ b/src/wayland/autotests/client/test_xdg_shell_stable.cpp @@ -0,0 +1,224 @@ +/******************************************************************** +Copyright 2016 Martin Gräßlin +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 "test_xdg_shell.h" +#include + +class XdgShellTestStable : public XdgShellTest { + Q_OBJECT +public: + XdgShellTestStable() : + XdgShellTest(KWayland::Server::XdgShellInterfaceVersion::Stable) {} + +private Q_SLOTS: + void testMaxSize(); + void testMinSize(); + + void testPopup_data(); + void testPopup(); + + void testMultipleRoles1(); + void testMultipleRoles2(); +}; + +void XdgShellTestStable::testMaxSize() +{ + qRegisterMetaType(); + // this test verifies changing the window maxSize + QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated); + QVERIFY(xdgSurfaceCreatedSpy.isValid()); + QScopedPointer surface(m_compositor->createSurface()); + QScopedPointer xdgSurface(m_xdgShell->createSurface(surface.data())); + QVERIFY(xdgSurfaceCreatedSpy.wait()); + auto serverXdgSurface = xdgSurfaceCreatedSpy.first().first().value(); + QVERIFY(serverXdgSurface); + + QSignalSpy maxSizeSpy(serverXdgSurface, &XdgShellSurfaceInterface::maxSizeChanged); + QVERIFY(maxSizeSpy.isValid()); + + xdgSurface->setMaxSize(QSize(100, 100)); + QVERIFY(maxSizeSpy.wait()); + QCOMPARE(maxSizeSpy.count(), 1); + QCOMPARE(maxSizeSpy.last().at(0).value(), QSize(100,100)); + + xdgSurface->setMaxSize(QSize(200, 200)); + QVERIFY(maxSizeSpy.wait()); + QCOMPARE(maxSizeSpy.count(), 2); + QCOMPARE(maxSizeSpy.last().at(0).value(), QSize(200,200)); +} + + +void XdgShellTestStable::testPopup_data() +{ + QTest::addColumn("positioner"); + XdgPositioner positioner(QSize(10,10), QRect(100,100,50,50)); + QTest::newRow("default") << positioner; + + XdgPositioner positioner2(QSize(20,20), QRect(101,102,51,52)); + QTest::newRow("sizeAndAnchorRect") << positioner2; + + positioner.setAnchorEdge(Qt::TopEdge | Qt::RightEdge); + QTest::newRow("anchorEdge") << positioner; + + positioner.setGravity(Qt::BottomEdge); + QTest::newRow("gravity") << positioner; + + positioner.setGravity(Qt::TopEdge | Qt::RightEdge); + QTest::newRow("gravity2") << positioner; + + positioner.setConstraints(XdgPositioner::Constraint::SlideX | XdgPositioner::Constraint::FlipY); + QTest::newRow("constraints") << positioner; + + positioner.setConstraints(XdgPositioner::Constraint::SlideX | XdgPositioner::Constraint::SlideY | XdgPositioner::Constraint::FlipX | XdgPositioner::Constraint::FlipY | XdgPositioner::Constraint::ResizeX | XdgPositioner::Constraint::ResizeY); + QTest::newRow("constraints2") << positioner; + + positioner.setAnchorOffset(QPoint(4,5)); + QTest::newRow("offset") << positioner; +} + +void XdgShellTestStable::testPopup() +{ + QSignalSpy xdgTopLevelCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated); + QSignalSpy xdgPopupCreatedSpy(m_xdgShellInterface, &XdgShellInterface::xdgPopupCreated); + + QScopedPointer parentSurface(m_compositor->createSurface()); + QScopedPointer xdgParentSurface(m_xdgShell->createSurface(parentSurface.data())); + + QVERIFY(xdgTopLevelCreatedSpy.wait()); + auto serverXdgTopLevel = xdgTopLevelCreatedSpy.first().first().value(); + + QFETCH(XdgPositioner, positioner); + + QScopedPointer surface(m_compositor->createSurface()); + QScopedPointer xdgSurface(m_xdgShell->createPopup(surface.data(), xdgParentSurface.data(), positioner)); + QVERIFY(xdgPopupCreatedSpy.wait()); + auto serverXdgPopup = xdgPopupCreatedSpy.first().first().value(); + QVERIFY(serverXdgPopup); + + QCOMPARE(serverXdgPopup->initialSize(), positioner.initialSize()); + QCOMPARE(serverXdgPopup->anchorRect(), positioner.anchorRect()); + QCOMPARE(serverXdgPopup->anchorEdge(), positioner.anchorEdge()); + QCOMPARE(serverXdgPopup->gravity(), positioner.gravity()); + QCOMPARE(serverXdgPopup->anchorOffset(), positioner.anchorOffset()); + //we have different enums for client server, but they share the same values + QCOMPARE((int)serverXdgPopup->constraintAdjustments(), (int)positioner.constraints()); + QCOMPARE(serverXdgPopup->transientFor().data(), serverXdgTopLevel->surface()); +} + +void XdgShellTestStable::testMinSize() +{ + qRegisterMetaType(); + // this test verifies changing the window minSize + QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated); + QVERIFY(xdgSurfaceCreatedSpy.isValid()); + QScopedPointer surface(m_compositor->createSurface()); + QScopedPointer xdgSurface(m_xdgShell->createSurface(surface.data())); + QVERIFY(xdgSurfaceCreatedSpy.wait()); + auto serverXdgSurface = xdgSurfaceCreatedSpy.first().first().value(); + QVERIFY(serverXdgSurface); + + QSignalSpy minSizeSpy(serverXdgSurface, &XdgShellSurfaceInterface::minSizeChanged); + QVERIFY(minSizeSpy.isValid()); + + xdgSurface->setMinSize(QSize(200, 200)); + QVERIFY(minSizeSpy.wait()); + QCOMPARE(minSizeSpy.count(), 1); + QCOMPARE(minSizeSpy.last().at(0).value(), QSize(200,200)); + + xdgSurface->setMinSize(QSize(100, 100)); + QVERIFY(minSizeSpy.wait()); + QCOMPARE(minSizeSpy.count(), 2); + QCOMPARE(minSizeSpy.last().at(0).value(), QSize(100,100)); +} + +//top level then toplevel +void XdgShellTestStable::testMultipleRoles1() +{ + //setting multiple roles on an xdg surface should fail + QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated); + QSignalSpy xdgPopupCreatedSpy(m_xdgShellInterface, &XdgShellInterface::xdgPopupCreated); + + QVERIFY(xdgSurfaceCreatedSpy.isValid()); + QVERIFY(xdgPopupCreatedSpy.isValid()); + + QScopedPointer surface(m_compositor->createSurface()); + //This is testing we work when a client does something stupid + //we can't use KWayland API here because by design that stops you from doing anything stupid + + qDebug() << (xdg_wm_base*)*m_xdgShell; + auto xdgSurface = xdg_wm_base_get_xdg_surface(*m_xdgShell, *surface.data()); + + //create a top level + auto xdgTopLevel1 = xdg_surface_get_toplevel(xdgSurface); + QVERIFY(xdgSurfaceCreatedSpy.wait()); + + //now try to create another top level for the same xdg surface. It should fail + auto xdgTopLevel2 = xdg_surface_get_toplevel(xdgSurface); + QVERIFY(!xdgSurfaceCreatedSpy.wait(10)); + + xdg_toplevel_destroy(xdgTopLevel1); + xdg_toplevel_destroy(xdgTopLevel2); + xdg_surface_destroy(xdgSurface); +} + +//toplevel then popup +void XdgShellTestStable::testMultipleRoles2() +{ + QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated); + QSignalSpy xdgPopupCreatedSpy(m_xdgShellInterface, &XdgShellInterface::xdgPopupCreated); + + QVERIFY(xdgSurfaceCreatedSpy.isValid()); + QVERIFY(xdgPopupCreatedSpy.isValid()); + + QScopedPointer surface(m_compositor->createSurface()); + QScopedPointer parentSurface(m_compositor->createSurface()); + + auto parentXdgSurface = xdg_wm_base_get_xdg_surface(*m_xdgShell, *parentSurface.data()); + auto xdgTopLevelParent = xdg_surface_get_toplevel(parentXdgSurface); + QVERIFY(xdgSurfaceCreatedSpy.wait()); + + + auto xdgSurface = xdg_wm_base_get_xdg_surface(*m_xdgShell, *surface.data()); + //create a top level + auto xdgTopLevel1 = xdg_surface_get_toplevel(xdgSurface); + QVERIFY(xdgSurfaceCreatedSpy.wait()); + + //now try to create a popup on the same xdg surface. It should fail + + auto positioner = xdg_wm_base_create_positioner(*m_xdgShell); + xdg_positioner_set_anchor_rect(positioner,10, 10, 10, 10); + xdg_positioner_set_size(positioner,10, 100); + + auto xdgPopup2 = xdg_surface_get_popup(xdgSurface, parentXdgSurface, positioner); + QVERIFY(!xdgPopupCreatedSpy.wait(10)); + + xdg_positioner_destroy(positioner); + xdg_toplevel_destroy(xdgTopLevel1); + xdg_toplevel_destroy(xdgTopLevelParent); + xdg_popup_destroy(xdgPopup2); + xdg_surface_destroy(xdgSurface); +} + + +QTEST_GUILESS_MAIN(XdgShellTestStable) + +#include "test_xdg_shell_stable.moc" + diff --git a/src/wayland/display.cpp b/src/wayland/display.cpp index 2bb1e60b33..79575ae31f 100644 --- a/src/wayland/display.cpp +++ b/src/wayland/display.cpp @@ -48,6 +48,7 @@ License along with this library. If not, see . #include "xdgshell_v5_interface_p.h" #include "xdgforeign_interface.h" #include "xdgshell_v6_interface_p.h" +#include "xdgshell_stable_interface_p.h" #include "appmenu_interface.h" #include "server_decoration_palette_interface.h" #include "xdgoutput_interface.h" @@ -384,6 +385,9 @@ XdgShellInterface *Display::createXdgShell(const XdgShellInterfaceVersion &versi case XdgShellInterfaceVersion::UnstableV6: x = new XdgShellV6Interface(this, parent); break; + case XdgShellInterfaceVersion::Stable: + x = new XdgShellStableInterface(this, parent); + break; } connect(this, &Display::aboutToTerminate, x, [x] { delete x; }); return x; diff --git a/src/wayland/server/xdgshell_stable_interface.cpp b/src/wayland/server/xdgshell_stable_interface.cpp new file mode 100644 index 0000000000..c41517b464 --- /dev/null +++ b/src/wayland/server/xdgshell_stable_interface.cpp @@ -0,0 +1,980 @@ +/**************************************************************************** +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_stable_interface_p.h" +#include "xdgshell_interface_p.h" +#include "generic_shell_surface_p.h" +#include "display.h" +#include "global_p.h" +#include "global.h" +#include "resource_p.h" +#include "output_interface.h" +#include "seat_interface.h" +#include "surface_interface.h" + +#include + +namespace KWayland +{ +namespace Server +{ + +class XdgShellStableInterface::Private : public XdgShellInterface::Private +{ +public: + Private(XdgShellStableInterface *q, Display *d); + + QVector surfaces; + QVector positioners; + +private: + + void createSurface(wl_client *client, uint32_t version, uint32_t id, SurfaceInterface *surface, wl_resource *parentResource); + void createPositioner(wl_client *client, uint32_t version, uint32_t id, wl_resource *parentResource); + + void bind(wl_client *client, uint32_t version, uint32_t id) override; + + quint32 ping(XdgShellSurfaceInterface * surface) override; + + static void unbind(wl_resource *resource); + static Private *cast(wl_resource *r) { + return static_cast(wl_resource_get_user_data(r)); + } + + static void destroyCallback(wl_client *client, wl_resource *resource); + static void createPositionerCallback(wl_client *client, wl_resource *resource, uint32_t id); + static void getXdgSurfaceCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * surface); + static void pongCallback(wl_client *client, wl_resource *resource, uint32_t serial); + + XdgShellStableInterface *q; + static const struct xdg_wm_base_interface s_interface; + static const quint32 s_version; + QHash resources; +}; + +class XdgPopupStableInterface::Private : public XdgShellPopupInterface::Private +{ +public: + Private(XdgPopupStableInterface *q, XdgShellStableInterface *c, SurfaceInterface *surface, wl_resource *parentResource); + ~Private() override; + + void ackConfigure(quint32 serial) { + if (!configureSerials.contains(serial)) { + return; + } + while (!configureSerials.isEmpty()) { + quint32 i = configureSerials.takeFirst(); + emit q_func()->configureAcknowledged(i); + if (i == serial) { + break; + } + } + } + + void popupDone() override; + quint32 configure(const QRect &rect) override; + + XdgPopupStableInterface *q_func() { + return static_cast(q); + } +private: + static void grabCallback(wl_client *client, wl_resource *resource, wl_resource *seat, uint32_t serial); + + static const struct xdg_popup_interface s_interface; +}; + +class XdgSurfaceStableInterface::Private : public KWayland::Server::Resource::Private +{ +public: + Private(XdgSurfaceStableInterface* q, XdgShellStableInterface* c, SurfaceInterface* surface, wl_resource* parentResource); + + ~Private() override; + + XdgSurfaceStableInterface *q_func() { + return static_cast(q); + } + + void createTopLevel(wl_client *client, uint32_t version, uint32_t id, wl_resource *parentResource); + void createPopup(wl_client *client, uint32_t version, uint32_t id, wl_resource *parentResource, wl_resource *parentWindow, wl_resource *positioner); + XdgShellStableInterface *m_shell; + SurfaceInterface *m_surface; + + //effectively a union, only one of these should be populated. + //a surface cannot have two roles + QPointer m_topLevel; + QPointer m_popup; + +private: + static void destroyCallback(wl_client *client, wl_resource *resource); + static void getTopLevelCallback(wl_client *client, wl_resource *resource, uint32_t id); + static void getPopupCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *parent, wl_resource *positioner); + static void ackConfigureCallback(wl_client *client, wl_resource *resource, uint32_t serial); + static void setWindowGeometryCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height); + static const struct xdg_surface_interface s_interface; +}; + +class XdgTopLevelStableInterface::Private : public XdgShellSurfaceInterface::Private +{ +public: + Private(XdgTopLevelStableInterface* q, XdgShellStableInterface* c, SurfaceInterface* surface, wl_resource* parentResource); + ~Private() override; + + void close() override; + + void ackConfigure(quint32 serial) { + if (!configureSerials.contains(serial)) { + return; + } + while (!configureSerials.isEmpty()) { + quint32 i = configureSerials.takeFirst(); + emit q_func()->configureAcknowledged(i); + if (i == serial) { + break; + } + } + } + + quint32 configure(States states, const QSize &size) override { + if (!resource) { + return 0; + } + const quint32 serial = global->display()->nextSerial(); + wl_array configureStates; + wl_array_init(&configureStates); + if (states.testFlag(State::Maximized)) { + uint32_t *s = static_cast(wl_array_add(&configureStates, sizeof(uint32_t))); + *s = XDG_TOPLEVEL_STATE_MAXIMIZED; + } + if (states.testFlag(State::Fullscreen)) { + uint32_t *s = static_cast(wl_array_add(&configureStates, sizeof(uint32_t))); + *s = XDG_TOPLEVEL_STATE_FULLSCREEN; + } + if (states.testFlag(State::Resizing)) { + uint32_t *s = static_cast(wl_array_add(&configureStates, sizeof(uint32_t))); + *s = XDG_TOPLEVEL_STATE_RESIZING; + } + if (states.testFlag(State::Activated)) { + uint32_t *s = static_cast(wl_array_add(&configureStates, sizeof(uint32_t))); + *s = XDG_TOPLEVEL_STATE_ACTIVATED; + } + configureSerials << serial; + xdg_toplevel_send_configure(resource, size.width(), size.height(), &configureStates); + + xdg_surface_send_configure(parentResource, serial); + + client->flush(); + wl_array_release(&configureStates); + return serial; + }; + + XdgTopLevelStableInterface *q_func() { + return static_cast(q); + } + +private: + static void destroyCallback(wl_client *client, wl_resource *resource); + static void setParentCallback(struct wl_client *client, struct wl_resource *resource, wl_resource *parent); + static void showWindowMenuCallback(wl_client *client, wl_resource *resource, wl_resource *seat, uint32_t serial, int32_t x, int32_t y); + static void setMaxSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height); + static void setMinSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height); + static void setMaximizedCallback(wl_client *client, wl_resource *resource); + static void unsetMaximizedCallback(wl_client *client, wl_resource *resource); + static void setFullscreenCallback(wl_client *client, wl_resource *resource, wl_resource *output); + static void unsetFullscreenCallback(wl_client *client, wl_resource *resource); + static void setMinimizedCallback(wl_client *client, wl_resource *resource); + + static const struct xdg_toplevel_interface s_interface; +}; + + +const quint32 XdgShellStableInterface::Private::s_version = 1; + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +const struct xdg_wm_base_interface XdgShellStableInterface::Private::s_interface = { + destroyCallback, + createPositionerCallback, + getXdgSurfaceCallback, + pongCallback +}; +#endif + +void XdgShellStableInterface::Private::destroyCallback(wl_client *client, wl_resource *resource) +{ + Q_UNUSED(client) + auto s = cast(resource); + if (!s->surfaces.isEmpty()) { + wl_resource_post_error(resource, XDG_WM_BASE_ERROR_DEFUNCT_SURFACES, "WMBase destroyed before surfaces"); + } + + wl_resource_destroy(resource); +} + +void XdgShellStableInterface::Private::createPositionerCallback(wl_client *client, wl_resource *resource, uint32_t id) +{ + auto s = cast(resource); + s->createPositioner(client, wl_resource_get_version(resource), id, resource); +} + +void XdgShellStableInterface::Private::getXdgSurfaceCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * surface) +{ + auto s = cast(resource); + s->createSurface(client, wl_resource_get_version(resource), id, SurfaceInterface::get(surface), resource); +} + +void XdgShellStableInterface::Private::createSurface(wl_client *client, uint32_t version, uint32_t id, SurfaceInterface *surface, wl_resource *parentResource) +{ + auto it = std::find_if(surfaces.constBegin(), surfaces.constEnd(), + [surface](XdgSurfaceStableInterface *s) { + return surface == s->surface(); + } + ); + if (it != surfaces.constEnd()) { + wl_resource_post_error(surface->resource(), XDG_WM_BASE_ERROR_ROLE, "XDG Surface already created"); + return; + } + XdgSurfaceStableInterface *shellSurface = new XdgSurfaceStableInterface(q, surface, parentResource); + surfaces << shellSurface; + QObject::connect(shellSurface, &XdgSurfaceStableInterface::destroyed, q, + [this, shellSurface] { + surfaces.removeAll(shellSurface); + } + ); + + shellSurface->d->create(display->getConnection(client), version, id); +} + +void XdgShellStableInterface::Private::createPositioner(wl_client *client, uint32_t version, uint32_t id, wl_resource *parentResource) +{ + Q_UNUSED(client) + + XdgPositionerStableInterface *positioner = new XdgPositionerStableInterface(q, parentResource); + positioners << positioner; + QObject::connect(positioner, &Resource::destroyed, q, + [this, positioner] { + positioners.removeAll(positioner); + } + ); + positioner->d->create(display->getConnection(client), version, id); +} + +void XdgShellStableInterface::Private::pongCallback(wl_client *client, wl_resource *resource, uint32_t serial) +{ + Q_UNUSED(client) + auto s = cast(resource); + auto timerIt = s->pingTimers.find(serial); + if (timerIt != s->pingTimers.end() && timerIt.value()->isActive()) { + delete timerIt.value(); + s->pingTimers.erase(timerIt); + emit s->q->pongReceived(serial); + } +} + +XdgShellStableInterface::Private::Private(XdgShellStableInterface *q, Display *d) + : XdgShellInterface::Private(XdgShellInterfaceVersion::Stable, q, d, &xdg_wm_base_interface, 1) + , q(q) +{ +} + +void XdgShellStableInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id) +{ + auto c = display->getConnection(client); + auto resource = c->createResource(&xdg_wm_base_interface, qMin(version, s_version), id); + if (!resource) { + wl_client_post_no_memory(client); + return; + } + resources[client] = resource; + wl_resource_set_implementation(resource, &s_interface, this, unbind); +} + +void XdgShellStableInterface::Private::unbind(wl_resource *resource) +{ + auto s = cast(resource); + auto client = wl_resource_get_client(resource); + s->resources.remove(client); +} + +XdgTopLevelStableInterface *XdgShellStableInterface::getSurface(wl_resource *resource) +{ + if (!resource) { + return nullptr; + } + Q_D(); + + for (auto it = d->surfaces.constBegin(); it != d->surfaces.constEnd() ; it++) { + auto topLevel = (*it)->topLevel(); + if (topLevel && topLevel->resource() == resource) { + return topLevel; + } + } + return nullptr; +} + +XdgSurfaceStableInterface *XdgShellStableInterface::realGetSurface(wl_resource *resource) +{ + if (!resource) { + return nullptr; + } + Q_D(); + + for (auto it = d->surfaces.constBegin(); it != d->surfaces.constEnd() ; it++) { + if ((*it)->resource() == resource) { + return (*it); + } + } + return nullptr; +} + +XdgPositionerStableInterface *XdgShellStableInterface::getPositioner(wl_resource *resource) +{ + if (!resource) { + return nullptr; + } + Q_D(); + for (auto it = d->positioners.constBegin(); it != d->positioners.constEnd() ; it++) { + if ((*it)->resource() == resource) { + return *it; + } + } + return nullptr; +} + +quint32 XdgShellStableInterface::Private::ping(XdgShellSurfaceInterface *surface) +{ + auto client = surface->client()->client(); + //from here we can get the resource bound to our global. + + auto clientXdgShellResource = resources.value(client); + if (!clientXdgShellResource) { + return 0; + } + + const quint32 pingSerial = display->nextSerial(); + xdg_wm_base_send_ping(clientXdgShellResource, pingSerial); + + setupTimer(pingSerial); + return pingSerial; +} + +XdgShellStableInterface::Private *XdgShellStableInterface::d_func() const +{ + return static_cast(d.data()); +} + +namespace { +template <> +Qt::Edges edgesToQtEdges(xdg_toplevel_resize_edge edges) +{ + Qt::Edges qtEdges; + switch (edges) { + case XDG_TOPLEVEL_RESIZE_EDGE_TOP: + qtEdges = Qt::TopEdge; + break; + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM: + qtEdges = Qt::BottomEdge; + break; + case XDG_TOPLEVEL_RESIZE_EDGE_LEFT: + qtEdges = Qt::LeftEdge; + break; + case XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT: + qtEdges = Qt::TopEdge | Qt::LeftEdge; + break; + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT: + qtEdges = Qt::BottomEdge | Qt::LeftEdge; + break; + case XDG_TOPLEVEL_RESIZE_EDGE_RIGHT: + qtEdges = Qt::RightEdge; + break; + case XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT: + qtEdges = Qt::TopEdge | Qt::RightEdge; + break; + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT: + qtEdges = Qt::BottomEdge | Qt::RightEdge; + break; + case XDG_TOPLEVEL_RESIZE_EDGE_NONE: + break; + default: + Q_UNREACHABLE(); + break; + } + return qtEdges; +} +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +const struct xdg_surface_interface XdgSurfaceStableInterface::Private::s_interface = { + destroyCallback, + getTopLevelCallback, + getPopupCallback, + setWindowGeometryCallback, + ackConfigureCallback +}; +#endif + +void XdgSurfaceStableInterface::Private::destroyCallback(wl_client *client, wl_resource *resource) +{ + Q_UNUSED(client) + wl_resource_destroy(resource); +} + +void XdgSurfaceStableInterface::Private::getTopLevelCallback(wl_client *client, wl_resource *resource, uint32_t id) +{ + auto s = cast(resource); + s->createTopLevel(client, wl_resource_get_version(resource), id, resource); +} + +void XdgSurfaceStableInterface::Private::createTopLevel(wl_client *client, uint32_t version, uint32_t id, wl_resource *parentResource) +{ + if (m_topLevel) { + wl_resource_post_error(parentResource, XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED, "Toplevel already created on this surface"); + return; + } + if (m_popup) { + wl_resource_post_error(parentResource, XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED, "Popup already created on this surface"); + return; + } + m_topLevel = new XdgTopLevelStableInterface (m_shell, m_surface, parentResource); + m_topLevel->d->create(m_shell->display()->getConnection(client), version, id); + + emit m_shell->surfaceCreated(m_topLevel); +} + + +void XdgSurfaceStableInterface::Private::getPopupCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *parent, wl_resource *positioner) +{ + auto s = cast(resource); + s->createPopup(client, wl_resource_get_version(resource), id, resource, parent, positioner); +} + +void XdgSurfaceStableInterface::Private::createPopup(wl_client *client, uint32_t version, uint32_t id, wl_resource *parentResource, wl_resource *parentSurface, wl_resource *positioner) +{ + + if (m_topLevel) { + wl_resource_post_error(parentResource, XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED, "Toplevel already created on this surface"); + return; + } + if (m_popup) { + wl_resource_post_error(parentResource, XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED, "Popup already created on this surface"); + return; + } + + auto xdgPositioner = m_shell->getPositioner(positioner); + if (!xdgPositioner) { + wl_resource_post_error(parentResource, XDG_WM_BASE_ERROR_INVALID_POSITIONER, "Invalid positioner"); + return; + } + m_popup = new XdgPopupStableInterface(m_shell, m_surface, parentResource); + auto pd = m_popup->d_func(); + + pd->create(m_shell->display()->getConnection(client), version, id); + + auto parentXdgSurface = m_shell->realGetSurface(parentSurface); + if (!parentXdgSurface) { + wl_resource_post_error(parentResource, XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT, "Invalid popup parent"); + return; + } + pd->parent = parentXdgSurface->surface(); + pd->initialSize = xdgPositioner->initialSize(); + pd->anchorRect = xdgPositioner->anchorRect(); + pd->anchorEdge = xdgPositioner->anchorEdge(); + pd->gravity = xdgPositioner->gravity(); + pd->constraintAdjustments = xdgPositioner->constraintAdjustments(); + pd->anchorOffset = xdgPositioner->anchorOffset(); + + emit m_shell->xdgPopupCreated(m_popup.data()); +} + + +void XdgSurfaceStableInterface::Private::ackConfigureCallback(wl_client *client, wl_resource *resource, uint32_t serial) +{ + auto s = cast(resource); + Q_ASSERT(client == *s->client); + + if (s->m_topLevel) { + s->m_topLevel->d_func()->ackConfigure(serial); + } else if (s->m_popup) { + s->m_popup->d_func()->ackConfigure(serial); + } +} + +void XdgSurfaceStableInterface::Private::setWindowGeometryCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) +{ + // TODO: implement - not done for v5 either + Q_UNUSED(client) + Q_UNUSED(resource) + Q_UNUSED(x) + Q_UNUSED(y) + Q_UNUSED(width) + Q_UNUSED(height) +} + +XdgSurfaceStableInterface::Private::Private(XdgSurfaceStableInterface *q, XdgShellStableInterface *c, SurfaceInterface *surface, wl_resource *parentResource) + : KWayland::Server::Resource::Private(q, c, parentResource, &xdg_surface_interface, &s_interface), + m_shell(c), + m_surface(surface) +{ +} + +XdgSurfaceStableInterface::Private::~Private() = default; + + +class XdgPositionerStableInterface::Private : public KWayland::Server::Resource::Private +{ +public: + Private(XdgPositionerStableInterface *q, XdgShellStableInterface *c, wl_resource* parentResource); + + QSize initialSize; + QRect anchorRect; + Qt::Edges anchorEdge; + Qt::Edges gravity; + PositionerConstraints constraintAdjustments; + QPoint anchorOffset; + +private: + static void setSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height); + static void setAnchorRectCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height); + static void setAnchorCallback(wl_client *client, wl_resource *resource, uint32_t anchor); + static void setGravityCallback(wl_client *client, wl_resource *resource, uint32_t gravity); + static void setConstraintAdjustmentCallback(wl_client *client, wl_resource *resource, uint32_t constraint_adjustment); + static void setOffsetCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y); + + static const struct xdg_positioner_interface s_interface; +}; + +XdgPositionerStableInterface::Private::Private(XdgPositionerStableInterface *q, XdgShellStableInterface *c, wl_resource *parentResource) + : KWayland::Server::Resource::Private(q, c, parentResource, &xdg_positioner_interface, &s_interface) +{ +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +const struct xdg_positioner_interface XdgPositionerStableInterface::Private::s_interface = { + resourceDestroyedCallback, + setSizeCallback, + setAnchorRectCallback, + setAnchorCallback, + setGravityCallback, + setConstraintAdjustmentCallback, + setOffsetCallback +}; +#endif + + +void XdgPositionerStableInterface::Private::setSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height) { + Q_UNUSED(client) + auto s = cast(resource); + s->initialSize = QSize(width, height); +} + +void XdgPositionerStableInterface::Private::setAnchorRectCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) +{ + Q_UNUSED(client) + auto s = cast(resource); + s->anchorRect = QRect(x, y, width, height); +} + +void XdgPositionerStableInterface::Private::setAnchorCallback(wl_client *client, wl_resource *resource, uint32_t anchor) { + Q_UNUSED(client) + + auto s = cast(resource); + + Qt::Edges qtEdges; + switch (anchor) { + case XDG_POSITIONER_ANCHOR_TOP: + qtEdges = Qt::TopEdge; + break; + case XDG_POSITIONER_ANCHOR_BOTTOM: + qtEdges = Qt::BottomEdge; + break; + case XDG_POSITIONER_ANCHOR_LEFT: + qtEdges = Qt::LeftEdge; + break; + case XDG_POSITIONER_ANCHOR_TOP_LEFT: + qtEdges = Qt::TopEdge | Qt::LeftEdge; + break; + case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: + qtEdges = Qt::BottomEdge | Qt::LeftEdge; + break; + case XDG_POSITIONER_ANCHOR_RIGHT: + qtEdges = Qt::RightEdge; + break; + case XDG_POSITIONER_ANCHOR_TOP_RIGHT: + qtEdges = Qt::TopEdge | Qt::RightEdge; + break; + case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: + qtEdges = Qt::BottomEdge | Qt::RightEdge; + break; + case XDG_POSITIONER_ANCHOR_NONE: + break; + default: + Q_UNREACHABLE(); + break; + } + + s->anchorEdge = qtEdges; +} + +void XdgPositionerStableInterface::Private::setGravityCallback(wl_client *client, wl_resource *resource, uint32_t gravity) { + Q_UNUSED(client) + auto s = cast(resource); + + Qt::Edges qtEdges; + switch (gravity) { + case XDG_POSITIONER_GRAVITY_TOP: + qtEdges = Qt::TopEdge; + break; + case XDG_POSITIONER_GRAVITY_BOTTOM: + qtEdges = Qt::BottomEdge; + break; + case XDG_POSITIONER_GRAVITY_LEFT: + qtEdges = Qt::LeftEdge; + break; + case XDG_POSITIONER_GRAVITY_TOP_LEFT: + qtEdges = Qt::TopEdge | Qt::LeftEdge; + break; + case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT: + qtEdges = Qt::BottomEdge | Qt::LeftEdge; + break; + case XDG_POSITIONER_GRAVITY_RIGHT: + qtEdges = Qt::RightEdge; + break; + case XDG_POSITIONER_GRAVITY_TOP_RIGHT: + qtEdges = Qt::TopEdge | Qt::RightEdge; + break; + case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT: + qtEdges = Qt::BottomEdge | Qt::RightEdge; + break; + case XDG_POSITIONER_GRAVITY_NONE: + break; + default: + Q_UNREACHABLE(); + break; + } + + s->gravity = qtEdges; +} + +void XdgPositionerStableInterface::Private::setConstraintAdjustmentCallback(wl_client *client, wl_resource *resource, uint32_t constraint_adjustment) { + Q_UNUSED(client) + auto s = cast(resource); + PositionerConstraints constraints; + if (constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X) { + constraints |= PositionerConstraint::SlideX; + } + if (constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y) { + constraints |= PositionerConstraint::SlideY; + } + if (constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X) { + constraints |= PositionerConstraint::FlipX; + } + if (constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y) { + constraints |= PositionerConstraint::FlipY; + } + if (constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X) { + constraints |= PositionerConstraint::ResizeX; + } + if (constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y) { + constraints |= PositionerConstraint::ResizeY; + } + s->constraintAdjustments = constraints; +} + +void XdgPositionerStableInterface::Private::setOffsetCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y) +{ + Q_UNUSED(client) + auto s = cast(resource); + s->anchorOffset = QPoint(x,y); +} + +void XdgTopLevelStableInterface::Private::close() +{ + xdg_toplevel_send_close(resource); + client->flush(); +} + +void XdgTopLevelStableInterface::Private::setMaxSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height) +{ + auto s = cast(resource); + Q_ASSERT(client == *s->client); + s->q_func()->maxSizeChanged(QSize(width, height)); +} + +void XdgTopLevelStableInterface::Private::setMinSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height) +{ + auto s = cast(resource); + Q_ASSERT(client == *s->client); + s->q_func()->minSizeChanged(QSize(width, height)); +} + +const struct xdg_toplevel_interface XdgTopLevelStableInterface::Private::s_interface = { + destroyCallback, + setParentCallback, + setTitleCallback, + setAppIdCallback, + showWindowMenuCallback, + moveCallback, + resizeCallback, + setMaxSizeCallback, + setMinSizeCallback, + setMaximizedCallback, + unsetMaximizedCallback, + setFullscreenCallback, + unsetFullscreenCallback, + setMinimizedCallback +}; + +void XdgTopLevelStableInterface::Private::destroyCallback(wl_client *client, wl_resource *resource) +{ + Q_UNUSED(client) + wl_resource_destroy(resource); +} + +void XdgTopLevelStableInterface::Private::setParentCallback(wl_client *client, wl_resource *resource, wl_resource *parent) +{ + auto s = cast(resource); + Q_ASSERT(client == *s->client); + if (!parent) { + //setting null is valid API. Clear + s->parent = nullptr; + emit s->q_func()->transientForChanged(); + } else { + auto parentSurface = static_cast(s->q->global())->getSurface(parent); + if (s->parent.data() != parentSurface) { + s->parent = QPointer(parentSurface); + emit s->q_func()->transientForChanged(); + } + } +} + +void XdgTopLevelStableInterface::Private::showWindowMenuCallback(wl_client *client, wl_resource *resource, wl_resource *seat, uint32_t serial, int32_t x, int32_t y) +{ + auto s = cast(resource); + Q_ASSERT(client == *s->client); + emit s->q_func()->windowMenuRequested(SeatInterface::get(seat), serial, QPoint(x, y)); +} + +XdgTopLevelStableInterface::Private::Private(XdgTopLevelStableInterface *q, XdgShellStableInterface *c, SurfaceInterface *surface, wl_resource *parentResource) + : XdgShellSurfaceInterface::Private(XdgShellInterfaceVersion::Stable, q, c, surface, parentResource, &xdg_toplevel_interface, &s_interface) +{ +} + +void XdgTopLevelStableInterface::Private::setMaximizedCallback(wl_client *client, wl_resource *resource) +{ + auto s = cast(resource); + Q_ASSERT(client == *s->client); + s->q_func()->maximizedChanged(true); +} + +void XdgTopLevelStableInterface::Private::unsetMaximizedCallback(wl_client *client, wl_resource *resource) +{ + auto s = cast(resource); + Q_ASSERT(client == *s->client); + s->q_func()->maximizedChanged(false); +} + +void XdgTopLevelStableInterface::Private::setFullscreenCallback(wl_client *client, wl_resource *resource, wl_resource *output) +{ + auto s = cast(resource); + Q_ASSERT(client == *s->client); + OutputInterface *o = nullptr; + if (output) { + o = OutputInterface::get(output); + } + s->q_func()->fullscreenChanged(true, o); +} + +void XdgTopLevelStableInterface::Private::unsetFullscreenCallback(wl_client *client, wl_resource *resource) +{ + auto s = cast(resource); + Q_ASSERT(client == *s->client); + s->q_func()->fullscreenChanged(false, nullptr); +} + +void XdgTopLevelStableInterface::Private::setMinimizedCallback(wl_client *client, wl_resource *resource) +{ + auto s = cast(resource); + Q_ASSERT(client == *s->client); + s->q_func()->minimizeRequested(); +} + +XdgTopLevelStableInterface::Private::~Private() = default; + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +const struct xdg_popup_interface XdgPopupStableInterface::Private::s_interface = { + resourceDestroyedCallback, + grabCallback +}; +#endif + +XdgPopupStableInterface::Private::Private(XdgPopupStableInterface *q, XdgShellStableInterface *c, SurfaceInterface *surface, wl_resource *parentResource) + : XdgShellPopupInterface::Private(XdgShellInterfaceVersion::Stable, q, c, surface, parentResource, &xdg_popup_interface, &s_interface) +{ +} + +void XdgPopupStableInterface::Private::grabCallback(wl_client *client, wl_resource *resource, wl_resource *seat, uint32_t serial) +{ + Q_UNUSED(client) + auto s = cast(resource); + auto seatInterface = SeatInterface::get(seat); + s->q_func()->grabRequested(seatInterface, serial); +} + +XdgPopupStableInterface::Private::~Private() = default; + +quint32 XdgPopupStableInterface::Private::configure(const QRect &rect) +{ + if (!resource) { + return 0; + } + const quint32 serial = global->display()->nextSerial(); + configureSerials << serial; + xdg_popup_send_configure(resource, rect.x(), rect.y(), rect.width(), rect.height()); + xdg_surface_send_configure(parentResource, serial); + client->flush(); + + return serial; +} + +void XdgPopupStableInterface::Private::popupDone() +{ + if (!resource) { + return; + } + // TODO: dismiss all child popups + xdg_popup_send_popup_done(resource); + client->flush(); +} + +XdgShellStableInterface::XdgShellStableInterface(Display *display, QObject *parent) + : XdgShellInterface(new Private(this, display), parent) +{ +} + +Display* XdgShellStableInterface::display() const +{ + return d->display; +} + +XdgShellStableInterface::~XdgShellStableInterface() = default; + +XdgSurfaceStableInterface::XdgSurfaceStableInterface(XdgShellStableInterface *parent, SurfaceInterface *surface, wl_resource *parentResource) + : KWayland::Server::Resource(new Private(this, parent, surface, parentResource)) +{ +} + +XdgSurfaceStableInterface::~XdgSurfaceStableInterface() = default; + +SurfaceInterface* XdgSurfaceStableInterface::surface() const +{ + Q_D(); + return d->m_surface; +} + +XdgPositionerStableInterface::XdgPositionerStableInterface(XdgShellStableInterface *parent, wl_resource *parentResource) + : KWayland::Server::Resource(new Private(this, parent, parentResource)) +{ +} + +QSize XdgPositionerStableInterface::initialSize() const +{ + Q_D(); + return d->initialSize; +} + +QRect XdgPositionerStableInterface::anchorRect() const +{ + Q_D(); + return d->anchorRect; +} + +Qt::Edges XdgPositionerStableInterface::anchorEdge() const +{ + Q_D(); + return d->anchorEdge; +} + +Qt::Edges XdgPositionerStableInterface::gravity() const +{ + Q_D(); + return d->gravity; +} + +PositionerConstraints XdgPositionerStableInterface::constraintAdjustments() const +{ + Q_D(); + return d->constraintAdjustments; +} + +QPoint XdgPositionerStableInterface::anchorOffset() const +{ + Q_D(); + return d->anchorOffset; +} + + +XdgPositionerStableInterface::Private *XdgPositionerStableInterface::d_func() const +{ + return static_cast(d.data()); +} + + +XdgTopLevelStableInterface* XdgSurfaceStableInterface::topLevel() const +{ + Q_D(); + return d->m_topLevel.data(); +} + +XdgPopupStableInterface* XdgSurfaceStableInterface::popup() const +{ + Q_D(); + return d->m_popup.data(); +} + +XdgSurfaceStableInterface::Private *XdgSurfaceStableInterface::d_func() const +{ + return static_cast(d.data()); +} + + +XdgTopLevelStableInterface::XdgTopLevelStableInterface(XdgShellStableInterface *parent, SurfaceInterface *surface, wl_resource *parentResource) + : KWayland::Server::XdgShellSurfaceInterface(new Private(this, parent, surface, parentResource)) +{ +} + +XdgTopLevelStableInterface::~XdgTopLevelStableInterface() = default; + +XdgTopLevelStableInterface::Private *XdgTopLevelStableInterface::d_func() const +{ + return static_cast(d.data()); +} + +XdgPopupStableInterface::XdgPopupStableInterface(XdgShellStableInterface *parent, SurfaceInterface *surface, wl_resource *parentResource) + : XdgShellPopupInterface(new Private(this, parent, surface, parentResource)) +{ +} + +XdgPopupStableInterface::~XdgPopupStableInterface() = default; + +XdgPopupStableInterface::Private *XdgPopupStableInterface::d_func() const +{ + return static_cast(d.data()); +} + +} +} + diff --git a/src/wayland/server/xdgshell_stable_interface_p.h b/src/wayland/server/xdgshell_stable_interface_p.h new file mode 100644 index 0000000000..51c0ea72ff --- /dev/null +++ b/src/wayland/server/xdgshell_stable_interface_p.h @@ -0,0 +1,148 @@ +/**************************************************************************** +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 . +****************************************************************************/ +#ifndef KWAYLAND_SERVER_XDGSHELL_STABLE_INTERFACE_P_H +#define KWAYLAND_SERVER_XDGSHELL_STABLE_INTERFACE_P_H + +#include "global.h" +#include "resource.h" +#include "xdgshell_interface.h" + +#include + +#include + +namespace KWayland +{ +namespace Server +{ + +class Display; +class OutputInterface; +class SeatInterface; +class SurfaceInterface; +class XdgTopLevelStableInterface; +class XdgPopupStableInterface; +class XdgPositionerStableInterface; +class XdgSurfaceStableInterface; +template +class GenericShellSurface; + +class XdgShellStableInterface : public XdgShellInterface +{ + Q_OBJECT +public: + virtual ~XdgShellStableInterface(); + + /** + * @returns The XdgTopLevelV6Interface for the @p native resource. + **/ + XdgTopLevelStableInterface *getSurface(wl_resource *native); + //DAVE we want to rename this, as it's bloody confusing. But XdgShellInterface::getSurface exists and expects that + //also use a less terrible argument name than native. It's obvious it's native from the type + + XdgPositionerStableInterface *getPositioner(wl_resource *native); + + XdgSurfaceStableInterface *realGetSurface(wl_resource *native); + + Display *display() const; + + void ping(XdgShellSurfaceInterface * surface); + +private: + explicit XdgShellStableInterface(Display *display, QObject *parent = nullptr); + friend class Display; + class Private; + Private *d_func() const; +}; + +class XdgSurfaceStableInterface : public KWayland::Server::Resource +{ + Q_OBJECT +public: + virtual ~XdgSurfaceStableInterface(); + SurfaceInterface* surface() const; + XdgTopLevelStableInterface* topLevel() const; + XdgPopupStableInterface *popup() const; + +private: + explicit XdgSurfaceStableInterface(XdgShellStableInterface *parent, SurfaceInterface *surface, wl_resource *parentResource); + friend class XdgShellStableInterface; + + class Private; + Private *d_func() const; +}; + +class XdgTopLevelStableInterface : public +XdgShellSurfaceInterface +{ + Q_OBJECT +public: + virtual ~XdgTopLevelStableInterface(); + +private: + explicit XdgTopLevelStableInterface(XdgShellStableInterface *parent, SurfaceInterface *surface, wl_resource *parentResource); + friend class XdgShellStableInterface; + friend class XdgSurfaceStableInterface; + + class Private; + Private *d_func() const; +}; + +class XdgPopupStableInterface : public XdgShellPopupInterface +{ + Q_OBJECT +public: + virtual ~XdgPopupStableInterface(); + +private: + explicit XdgPopupStableInterface(XdgShellStableInterface *parent, SurfaceInterface *surface, wl_resource *parentResource); + friend class XdgShellStableInterface; + friend class XdgSurfaceStableInterface; + friend class GenericShellSurface; + + class Private; + Private *d_func() const; +}; + +/* + * This is a private internal class that keeps track of sent data + * At the time of PopupCreation these values are copied to the popup + */ +class XdgPositionerStableInterface: public KWayland::Server::Resource +{ +public: + QSize initialSize() const; + QRect anchorRect() const; + Qt::Edges anchorEdge() const; + Qt::Edges gravity() const; + PositionerConstraints constraintAdjustments() const; + QPoint anchorOffset() const; +private: + explicit XdgPositionerStableInterface(XdgShellStableInterface *parent, wl_resource *parentResource); + friend class XdgShellStableInterface; + + class Private; + Private *d_func() const; +}; + +} +} + +#endif diff --git a/src/wayland/xdgshell_interface.h b/src/wayland/xdgshell_interface.h index 97150ece49..668ae88231 100644 --- a/src/wayland/xdgshell_interface.h +++ b/src/wayland/xdgshell_interface.h @@ -55,7 +55,12 @@ enum class XdgShellInterfaceVersion * zxdg_shell_v6 (unstable v6) * @since 5.39 **/ - UnstableV6 + UnstableV6, + /** + xdg_wm_base (stable) + @since 5.XDGSHELL_VERSION + */ + Stable }; /**