From e3ad23ccd849dfdc85f6c765080749ccdc69c096 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Mon, 4 May 2020 16:32:23 +0300 Subject: [PATCH] xdg-shell: Rewrite wrappers for the xdg-shell protocol The current xdg-shell wrappers don't match existing abstractions in the xdg-shell protocol well, which makes it more difficult to refactor code that is responsible for managing configure events and geometry in kwin. Given that the xdg_decoration and the xdg_shell protocols are tightly coupled together, I had to rewrite our wrappers for the xdg_decoration protocol as well. --- src/wayland/CMakeLists.txt | 11 +- src/wayland/autotests/client/CMakeLists.txt | 15 +- .../autotests/client/test_xdg_decoration.cpp | 52 +- .../autotests/client/test_xdg_shell.cpp | 278 +++-- src/wayland/autotests/client/test_xdg_shell.h | 92 -- .../client/test_xdg_shell_stable.cpp | 245 ---- src/wayland/display.cpp | 25 +- src/wayland/display.h | 6 +- src/wayland/server/generic_shell_surface_p.h | 113 -- .../server/xdgdecoration_interface.cpp | 233 ---- src/wayland/server/xdgdecoration_interface.h | 90 -- .../server/xdgshell_stable_interface.cpp | 1104 ----------------- .../server/xdgshell_stable_interface_p.h | 131 -- src/wayland/surfacerole.cpp | 9 + src/wayland/surfacerole_p.h | 2 + src/wayland/tests/renderingservertest.cpp | 17 +- src/wayland/tests/waylandservertest.cpp | 4 +- src/wayland/xdgdecoration_v1_interface.cpp | 151 +++ src/wayland/xdgdecoration_v1_interface.h | 114 ++ src/wayland/xdgdecoration_v1_interface_p.h | 44 + src/wayland/xdgshell_interface.cpp | 1071 +++++++++++++--- src/wayland/xdgshell_interface.h | 790 ++++++------ src/wayland/xdgshell_interface_p.h | 209 +++- 23 files changed, 1961 insertions(+), 2845 deletions(-) delete mode 100644 src/wayland/autotests/client/test_xdg_shell.h delete mode 100644 src/wayland/autotests/client/test_xdg_shell_stable.cpp delete mode 100644 src/wayland/server/generic_shell_surface_p.h delete mode 100644 src/wayland/server/xdgdecoration_interface.cpp delete mode 100644 src/wayland/server/xdgdecoration_interface.h delete mode 100644 src/wayland/server/xdgshell_stable_interface.cpp delete mode 100644 src/wayland/server/xdgshell_stable_interface_p.h create mode 100644 src/wayland/xdgdecoration_v1_interface.cpp create mode 100644 src/wayland/xdgdecoration_v1_interface.h create mode 100644 src/wayland/xdgdecoration_v1_interface_p.h diff --git a/src/wayland/CMakeLists.txt b/src/wayland/CMakeLists.txt index ea0cd1083b..831aef3146 100644 --- a/src/wayland/CMakeLists.txt +++ b/src/wayland/CMakeLists.txt @@ -58,12 +58,11 @@ set(SERVER_LIB_SRCS textinput_interface_v0.cpp textinput_interface_v2.cpp touch_interface.cpp - xdgdecoration_interface.cpp + xdgdecoration_v1_interface.cpp xdgforeign_interface.cpp xdgforeign_v2_interface.cpp xdgoutput_interface.cpp xdgshell_interface.cpp - xdgshell_stable_interface.cpp ) ecm_qt_declare_logging_category(SERVER_LIB_SRCS @@ -199,14 +198,14 @@ ecm_add_wayland_server_protocol(SERVER_LIB_SRCS BASENAME xdg-output ) -ecm_add_wayland_server_protocol(SERVER_LIB_SRCS +ecm_add_qtwayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${WaylandProtocols_DATADIR}/stable/xdg-shell/xdg-shell.xml BASENAME xdg-shell ) -ecm_add_wayland_server_protocol(SERVER_LIB_SRCS +ecm_add_qtwayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${WaylandProtocols_DATADIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml - BASENAME xdg-decoration + BASENAME xdg-decoration-unstable-v1 ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS @@ -387,7 +386,7 @@ set(SERVER_LIB_HEADERS tablet_interface.h textinput_interface.h touch_interface.h - xdgdecoration_interface.h + xdgdecoration_v1_interface.h xdgforeign_interface.h xdgoutput_interface.h xdgshell_interface.h diff --git a/src/wayland/autotests/client/CMakeLists.txt b/src/wayland/autotests/client/CMakeLists.txt index 2632dea933..888c4b99d4 100644 --- a/src/wayland/autotests/client/CMakeLists.txt +++ b/src/wayland/autotests/client/CMakeLists.txt @@ -343,16 +343,13 @@ add_test(NAME kwayland-testXdgForeign COMMAND testXdgForeign) ecm_mark_as_test(testXdgForeign) ######################################################## -# Test XdgShellStable +# Test XdgShell ######################################################## -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 Plasma::KWaylandServer KF5::WaylandClient Wayland::Client) -add_test(NAME kwayland-testXdgShellStable COMMAND testXdgShellStable) -ecm_mark_as_test(testXdgShellStable) +set(testXdgShell_SRCS test_xdg_shell.cpp) +add_executable(testXdgShell ${testXdgShell_SRCS}) +target_link_libraries( testXdgShell Qt5::Test Qt5::Gui Plasma::KWaylandServer KF5::WaylandClient Wayland::Client) +add_test(NAME kwayland-testXdgShell COMMAND testXdgShell) +ecm_mark_as_test(testXdgShell) ######################################################## # Test Pointer Constraints diff --git a/src/wayland/autotests/client/test_xdg_decoration.cpp b/src/wayland/autotests/client/test_xdg_decoration.cpp index 86c45b617f..bd7570f0c0 100644 --- a/src/wayland/autotests/client/test_xdg_decoration.cpp +++ b/src/wayland/autotests/client/test_xdg_decoration.cpp @@ -16,7 +16,7 @@ #include "../../src/server/display.h" #include "../../src/server/compositor_interface.h" #include "../../src/server/xdgshell_interface.h" -#include "../../src/server/xdgdecoration_interface.h" +#include "../../src/server/xdgdecoration_v1_interface.h" class TestXdgDecoration : public QObject { @@ -34,7 +34,7 @@ private: KWaylandServer::Display *m_display = nullptr; KWaylandServer::CompositorInterface *m_compositorInterface = nullptr; KWaylandServer::XdgShellInterface *m_xdgShellInterface = nullptr; - KWaylandServer::XdgDecorationManagerInterface *m_xdgDecorationManagerInterface = nullptr; + KWaylandServer::XdgDecorationManagerV1Interface *m_xdgDecorationManagerInterface = nullptr; KWayland::Client::ConnectionThread *m_connection = nullptr; KWayland::Client::Compositor *m_compositor = nullptr; @@ -59,7 +59,7 @@ void TestXdgDecoration::init() using namespace KWayland::Client; qRegisterMetaType(); - qRegisterMetaType(); + qRegisterMetaType(); delete m_display; m_display = new Display(this); @@ -104,16 +104,12 @@ void TestXdgDecoration::init() QVERIFY(compositorSpy.wait()); m_compositor = m_registry->createCompositor(compositorSpy.first().first().value(), compositorSpy.first().last().value(), this); - m_xdgShellInterface = m_display->createXdgShell(XdgShellInterfaceVersion::Stable, m_display); - m_xdgShellInterface->create(); - QVERIFY(m_xdgShellInterface->isValid()); + m_xdgShellInterface = m_display->createXdgShell(m_display); QVERIFY(xdgShellSpy.wait()); m_xdgShell = m_registry->createXdgShell(xdgShellSpy.first().first().value(), xdgShellSpy.first().last().value(), this); - m_xdgDecorationManagerInterface = m_display->createXdgDecorationManager(m_xdgShellInterface, m_display); - m_xdgDecorationManagerInterface->create(); - QVERIFY(m_xdgDecorationManagerInterface->isValid()); + m_xdgDecorationManagerInterface = m_display->createXdgDecorationManagerV1(m_display); QVERIFY(xdgDecorationManagerSpy.wait()); m_xdgDecorationManager = m_registry->createXdgDecorationManager(xdgDecorationManagerSpy.first().first().value(), @@ -160,13 +156,13 @@ void TestXdgDecoration::testDecoration_data() { using namespace KWayland::Client; using namespace KWaylandServer; - QTest::addColumn("configuredMode"); + QTest::addColumn("configuredMode"); QTest::addColumn("configuredModeExp"); QTest::addColumn("setMode"); - QTest::addColumn("setModeExp"); + QTest::addColumn("setModeExp"); - const auto serverClient = XdgDecorationInterface::Mode::ClientSide; - const auto serverServer = XdgDecorationInterface::Mode::ServerSide; + const auto serverClient = XdgToplevelDecorationV1Interface::Mode::Client; + const auto serverServer = XdgToplevelDecorationV1Interface::Mode::Server; const auto clientClient = XdgDecoration::Mode::ClientSide; const auto clientServer = XdgDecoration::Mode::ServerSide; @@ -181,15 +177,14 @@ void TestXdgDecoration::testDecoration() using namespace KWayland::Client; using namespace KWaylandServer; - QFETCH(KWaylandServer::XdgDecorationInterface::Mode, configuredMode); + QFETCH(KWaylandServer::XdgToplevelDecorationV1Interface::Mode, configuredMode); QFETCH(KWayland::Client::XdgDecoration::Mode, configuredModeExp); QFETCH(KWayland::Client::XdgDecoration::Mode, setMode); - QFETCH(KWaylandServer::XdgDecorationInterface::Mode, setModeExp); - + QFETCH(KWaylandServer::XdgToplevelDecorationV1Interface::Mode, setModeExp); QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); - QSignalSpy shellSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated); - QSignalSpy decorationCreatedSpy(m_xdgDecorationManagerInterface, &XdgDecorationManagerInterface::xdgDecorationInterfaceCreated); + QSignalSpy shellSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::toplevelCreated); + QSignalSpy decorationCreatedSpy(m_xdgDecorationManagerInterface, &XdgDecorationManagerV1Interface::decorationCreated); // create shell surface and deco object QScopedPointer surface(m_compositor->createSurface()); @@ -201,20 +196,20 @@ void TestXdgDecoration::testDecoration() QVERIFY(shellSurfaceCreatedSpy.count() || shellSurfaceCreatedSpy.wait()); QVERIFY(decorationCreatedSpy.count() || decorationCreatedSpy.wait()); - auto shellSurfaceIface = shellSurfaceCreatedSpy.first().first().value(); - auto decorationIface = decorationCreatedSpy.first().first().value(); + auto shellSurfaceIface = shellSurfaceCreatedSpy.first().first().value(); + auto decorationIface = decorationCreatedSpy.first().first().value(); QVERIFY(decorationIface); QVERIFY(shellSurfaceIface); - QCOMPARE(decorationIface->surface(), shellSurfaceIface); - QCOMPARE(decorationIface->requestedMode(), XdgDecorationInterface::Mode::Undefined); + QCOMPARE(decorationIface->toplevel(), shellSurfaceIface); + QCOMPARE(decorationIface->preferredMode(), XdgToplevelDecorationV1Interface::Mode::Undefined); QSignalSpy clientConfiguredSpy(decoration.data(), &XdgDecoration::modeChanged); - QSignalSpy modeRequestedSpy(decorationIface, &XdgDecorationInterface::modeRequested); + QSignalSpy modeRequestedSpy(decorationIface, &XdgToplevelDecorationV1Interface::preferredModeChanged); //server configuring a client - decorationIface->configure(configuredMode); - quint32 serial = shellSurfaceIface->configure({}); + decorationIface->sendConfigure(configuredMode); + quint32 serial = shellSurfaceIface->sendConfigure(QSize(0, 0), {}); QVERIFY(clientConfiguredSpy.wait()); QCOMPARE(clientConfiguredSpy.first().first().value(), configuredModeExp); @@ -223,13 +218,14 @@ void TestXdgDecoration::testDecoration() //client requesting another mode decoration->setMode(setMode); QVERIFY(modeRequestedSpy.wait()); - QCOMPARE(modeRequestedSpy.first().first().value(), setModeExp); - QCOMPARE(decorationIface->requestedMode(), setModeExp); + QCOMPARE(modeRequestedSpy.first().first().value(), setModeExp); + QCOMPARE(decorationIface->preferredMode(), setModeExp); modeRequestedSpy.clear(); decoration->unsetMode(); QVERIFY(modeRequestedSpy.wait()); - QCOMPARE(modeRequestedSpy.first().first().value(), XdgDecorationInterface::Mode::Undefined); + QCOMPARE(modeRequestedSpy.first().first().value(), + XdgToplevelDecorationV1Interface::Mode::Undefined); } QTEST_GUILESS_MAIN(TestXdgDecoration) diff --git a/src/wayland/autotests/client/test_xdg_shell.cpp b/src/wayland/autotests/client/test_xdg_shell.cpp index 980d8ca6a8..4725094d4f 100644 --- a/src/wayland/autotests/client/test_xdg_shell.cpp +++ b/src/wayland/autotests/client/test_xdg_shell.cpp @@ -5,14 +5,86 @@ SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ -#include "test_xdg_shell.h" +// Qt +#include +// client +#include "KWayland/Client/xdgshell.h" +#include "KWayland/Client/connection_thread.h" +#include "KWayland/Client/compositor.h" +#include "KWayland/Client/event_queue.h" +#include "KWayland/Client/registry.h" +#include "KWayland/Client/output.h" +#include "KWayland/Client/seat.h" +#include "KWayland/Client/shm_pool.h" +#include "KWayland/Client/surface.h" +// server +#include "../../src/server/display.h" +#include "../../src/server/compositor_interface.h" +#include "../../src/server/output_interface.h" +#include "../../src/server/seat_interface.h" +#include "../../src/server/surface_interface.h" +#include "../../src/server/xdgshell_interface.h" -XdgShellTest::XdgShellTest(XdgShellInterfaceVersion version): - m_version(version) -{} +using namespace KWayland::Client; +using namespace KWaylandServer; + +Q_DECLARE_METATYPE(Qt::MouseButton) static const QString s_socketName = QStringLiteral("kwayland-test-xdg_shell-0"); +class XdgShellTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void init(); + void cleanup(); + + void testCreateSurface(); + void testTitle(); + void testWindowClass(); + void testMaximize(); + void testMinimize(); + void testFullscreen(); + void testShowWindowMenu(); + void testMove(); + void testResize_data(); + void testResize(); + void testTransient(); + void testPing(); + void testClose(); + void testConfigureStates_data(); + void testConfigureStates(); + void testConfigureMultipleAcks(); + +private: + XdgShellInterface *m_xdgShellInterface = nullptr; + Compositor *m_compositor = nullptr; + XdgShell *m_xdgShell = nullptr; + Display *m_display = nullptr; + CompositorInterface *m_compositorInterface = nullptr; + OutputInterface *m_o1Interface = nullptr; + OutputInterface *m_o2Interface = nullptr; + SeatInterface *m_seatInterface = nullptr; + ConnectionThread *m_connection = nullptr; + QThread *m_thread = nullptr; + EventQueue *m_queue = nullptr; + ShmPool *m_shmPool = nullptr; + Output *m_output1 = nullptr; + Output *m_output2 = nullptr; + Seat *m_seat = nullptr; +}; + +#define SURFACE \ + QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::toplevelCreated); \ + QVERIFY(xdgSurfaceCreatedSpy.isValid()); \ + QScopedPointer surface(m_compositor->createSurface()); \ + QScopedPointer xdgSurface(m_xdgShell->createSurface(surface.data())); \ + QCOMPARE(xdgSurface->size(), QSize()); \ + QVERIFY(xdgSurfaceCreatedSpy.wait()); \ + auto serverXdgToplevel = xdgSurfaceCreatedSpy.first().first().value(); \ + QVERIFY(serverXdgToplevel); + void XdgShellTest::init() { delete m_display; @@ -34,9 +106,7 @@ void XdgShellTest::init() m_seatInterface->create(); m_compositorInterface = m_display->createCompositor(m_display); m_compositorInterface->create(); - m_xdgShellInterface = m_display->createXdgShell(m_version, m_display); - QCOMPARE(m_xdgShellInterface->interfaceVersion(), m_version); - m_xdgShellInterface->create(); + m_xdgShellInterface = m_display->createXdgShell(m_display); // setup connection m_connection = new KWayland::Client::ConnectionThread; @@ -62,11 +132,7 @@ void XdgShellTest::init() QSignalSpy outputAnnouncedSpy(®istry, &Registry::outputAnnounced); QVERIFY(outputAnnouncedSpy.isValid()); - auto shellAnnouncedSignal = m_version == XdgShellInterfaceVersion::UnstableV5 ? &Registry::xdgShellUnstableV5Announced : - m_version == XdgShellInterfaceVersion::UnstableV6 ? &Registry::xdgShellUnstableV6Announced : - &Registry::xdgShellStableAnnounced; - - QSignalSpy xdgShellAnnouncedSpy(®istry, shellAnnouncedSignal); + QSignalSpy xdgShellAnnouncedSpy(®istry, &Registry::xdgShellStableAnnounced); QVERIFY(xdgShellAnnouncedSpy.isValid()); registry.setEventQueue(m_queue); registry.create(m_connection); @@ -92,21 +158,8 @@ void XdgShellTest::init() QCOMPARE(xdgShellAnnouncedSpy.count(), 1); - 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, + m_xdgShell = registry.createXdgShell(registry.interface(Registry::Interface::XdgShellStable).name, + registry.interface(Registry::Interface::XdgShellStable).version, this); QVERIFY(m_xdgShell); QVERIFY(m_xdgShell->isValid()); @@ -152,7 +205,7 @@ void XdgShellTest::testCreateSurface() // first created the signal spies for the server QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); QVERIFY(surfaceCreatedSpy.isValid()); - QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated); + QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::toplevelCreated); QVERIFY(xdgSurfaceCreatedSpy.isValid()); // create surface @@ -167,17 +220,15 @@ void XdgShellTest::testCreateSurface() QVERIFY(!xdgSurface.isNull()); QVERIFY(xdgSurfaceCreatedSpy.wait()); // verify base things - auto serverXdgSurface = xdgSurfaceCreatedSpy.first().first().value(); - QVERIFY(serverXdgSurface); - QCOMPARE(serverXdgSurface->isConfigurePending(), false); - QCOMPARE(serverXdgSurface->title(), QString()); - QCOMPARE(serverXdgSurface->windowClass(), QByteArray()); - QCOMPARE(serverXdgSurface->isTransient(), false); - QCOMPARE(serverXdgSurface->transientFor(), QPointer()); - QCOMPARE(serverXdgSurface->surface(), serverSurface); + auto serverToplevel = xdgSurfaceCreatedSpy.first().first().value(); + QVERIFY(serverToplevel); + QCOMPARE(serverToplevel->windowTitle(), QString()); + QCOMPARE(serverToplevel->windowClass(), QByteArray()); + QCOMPARE(serverToplevel->parentXdgToplevel(), nullptr); + QCOMPARE(serverToplevel->surface(), serverSurface); // now let's destroy it - QSignalSpy destroyedSpy(serverXdgSurface, &QObject::destroyed); + QSignalSpy destroyedSpy(serverToplevel, &QObject::destroyed); QVERIFY(destroyedSpy.isValid()); xdgSurface.reset(); QVERIFY(destroyedSpy.wait()); @@ -190,16 +241,16 @@ void XdgShellTest::testTitle() SURFACE // should not have a title yet - QCOMPARE(serverXdgSurface->title(), QString()); + QCOMPARE(serverXdgToplevel->windowTitle(), QString()); // lets' change the title - QSignalSpy titleChangedSpy(serverXdgSurface, &XdgShellSurfaceInterface::titleChanged); + QSignalSpy titleChangedSpy(serverXdgToplevel, &XdgToplevelInterface::windowTitleChanged); QVERIFY(titleChangedSpy.isValid()); xdgSurface->setTitle(QStringLiteral("foo")); QVERIFY(titleChangedSpy.wait()); QCOMPARE(titleChangedSpy.count(), 1); QCOMPARE(titleChangedSpy.first().first().toString(), QStringLiteral("foo")); - QCOMPARE(serverXdgSurface->title(), QStringLiteral("foo")); + QCOMPARE(serverXdgToplevel->windowTitle(), QStringLiteral("foo")); } void XdgShellTest::testWindowClass() @@ -209,16 +260,16 @@ void XdgShellTest::testWindowClass() SURFACE // should not have a window class yet - QCOMPARE(serverXdgSurface->windowClass(), QByteArray()); + QCOMPARE(serverXdgToplevel->windowClass(), QByteArray()); // let's change the window class - QSignalSpy windowClassChanged(serverXdgSurface, &XdgShellSurfaceInterface::windowClassChanged); + QSignalSpy windowClassChanged(serverXdgToplevel, &XdgToplevelInterface::windowClassChanged); QVERIFY(windowClassChanged.isValid()); xdgSurface->setAppId(QByteArrayLiteral("org.kde.xdgsurfacetest")); QVERIFY(windowClassChanged.wait()); QCOMPARE(windowClassChanged.count(), 1); QCOMPARE(windowClassChanged.first().first().toByteArray(), QByteArrayLiteral("org.kde.xdgsurfacetest")); - QCOMPARE(serverXdgSurface->windowClass(), QByteArrayLiteral("org.kde.xdgsurfacetest")); + QCOMPARE(serverXdgToplevel->windowClass(), QByteArrayLiteral("org.kde.xdgsurfacetest")); } void XdgShellTest::testMaximize() @@ -226,18 +277,18 @@ void XdgShellTest::testMaximize() // this test verifies that the maximize/unmaximize calls work SURFACE - QSignalSpy maximizeRequestedSpy(serverXdgSurface, &XdgShellSurfaceInterface::maximizedChanged); + QSignalSpy maximizeRequestedSpy(serverXdgToplevel, &XdgToplevelInterface::maximizeRequested); QVERIFY(maximizeRequestedSpy.isValid()); + QSignalSpy unmaximizeRequestedSpy(serverXdgToplevel, &XdgToplevelInterface::unmaximizeRequested); + QVERIFY(unmaximizeRequestedSpy.isValid()); xdgSurface->setMaximized(true); QVERIFY(maximizeRequestedSpy.wait()); QCOMPARE(maximizeRequestedSpy.count(), 1); - QCOMPARE(maximizeRequestedSpy.last().first().toBool(), true); xdgSurface->setMaximized(false); - QVERIFY(maximizeRequestedSpy.wait()); - QCOMPARE(maximizeRequestedSpy.count(), 2); - QCOMPARE(maximizeRequestedSpy.last().first().toBool(), false); + QVERIFY(unmaximizeRequestedSpy.wait()); + QCOMPARE(unmaximizeRequestedSpy.count(), 1); } void XdgShellTest::testMinimize() @@ -245,7 +296,7 @@ void XdgShellTest::testMinimize() // this test verifies that the minimize request is delivered SURFACE - QSignalSpy minimizeRequestedSpy(serverXdgSurface, &XdgShellSurfaceInterface::minimizeRequested); + QSignalSpy minimizeRequestedSpy(serverXdgToplevel, &XdgToplevelInterface::minimizeRequested); QVERIFY(minimizeRequestedSpy.isValid()); xdgSurface->requestMinimize(); @@ -257,44 +308,35 @@ void XdgShellTest::testFullscreen() { qRegisterMetaType(); // this test verifies going to/from fullscreen - 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); + SURFACE - QSignalSpy fullscreenSpy(serverXdgSurface, &XdgShellSurfaceInterface::fullscreenChanged); - QVERIFY(fullscreenSpy.isValid()); + QSignalSpy fullscreenRequestedSpy(serverXdgToplevel, &XdgToplevelInterface::fullscreenRequested); + QVERIFY(fullscreenRequestedSpy.isValid()); + QSignalSpy unfullscreenRequestedSpy(serverXdgToplevel, &XdgToplevelInterface::unfullscreenRequested); + QVERIFY(fullscreenRequestedSpy.isValid()); // without an output xdgSurface->setFullscreen(true, nullptr); - QVERIFY(fullscreenSpy.wait()); - QCOMPARE(fullscreenSpy.count(), 1); - QCOMPARE(fullscreenSpy.last().at(0).toBool(), true); - QVERIFY(!fullscreenSpy.last().at(1).value()); + QVERIFY(fullscreenRequestedSpy.wait()); + QCOMPARE(fullscreenRequestedSpy.count(), 1); + QVERIFY(!fullscreenRequestedSpy.last().at(0).value()); // unset xdgSurface->setFullscreen(false); - QVERIFY(fullscreenSpy.wait()); - QCOMPARE(fullscreenSpy.count(), 2); - QCOMPARE(fullscreenSpy.last().at(0).toBool(), false); - QVERIFY(!fullscreenSpy.last().at(1).value()); + QVERIFY(unfullscreenRequestedSpy.wait()); + QCOMPARE(unfullscreenRequestedSpy.count(), 1); // with outputs xdgSurface->setFullscreen(true, m_output1); - QVERIFY(fullscreenSpy.wait()); - QCOMPARE(fullscreenSpy.count(), 3); - QCOMPARE(fullscreenSpy.last().at(0).toBool(), true); - QCOMPARE(fullscreenSpy.last().at(1).value(), m_o1Interface); + QVERIFY(fullscreenRequestedSpy.wait()); + QCOMPARE(fullscreenRequestedSpy.count(), 2); + QCOMPARE(fullscreenRequestedSpy.last().at(0).value(), m_o1Interface); // now other output xdgSurface->setFullscreen(true, m_output2); - QVERIFY(fullscreenSpy.wait()); - QCOMPARE(fullscreenSpy.count(), 4); - QCOMPARE(fullscreenSpy.last().at(0).toBool(), true); - QCOMPARE(fullscreenSpy.last().at(1).value(), m_o2Interface); + QVERIFY(fullscreenRequestedSpy.wait()); + QCOMPARE(fullscreenRequestedSpy.count(), 3); + QCOMPARE(fullscreenRequestedSpy.last().at(0).value(), m_o2Interface); } void XdgShellTest::testShowWindowMenu() @@ -303,7 +345,10 @@ void XdgShellTest::testShowWindowMenu() // this test verifies that the show window menu request works SURFACE - QSignalSpy windowMenuSpy(serverXdgSurface, &XdgShellSurfaceInterface::windowMenuRequested); + // hack: pretend that the xdg-surface had been configured + serverXdgToplevel->sendConfigure(QSize(0, 0), XdgToplevelInterface::States()); + + QSignalSpy windowMenuSpy(serverXdgToplevel, &XdgToplevelInterface::windowMenuRequested); QVERIFY(windowMenuSpy.isValid()); // TODO: the serial needs to be a proper one @@ -311,8 +356,8 @@ void XdgShellTest::testShowWindowMenu() QVERIFY(windowMenuSpy.wait()); QCOMPARE(windowMenuSpy.count(), 1); QCOMPARE(windowMenuSpy.first().at(0).value(), m_seatInterface); - QCOMPARE(windowMenuSpy.first().at(1).value(), 20u); - QCOMPARE(windowMenuSpy.first().at(2).toPoint(), QPoint(30, 40)); + QCOMPARE(windowMenuSpy.first().at(1).toPoint(), QPoint(30, 40)); + QCOMPARE(windowMenuSpy.first().at(2).value(), 20u); } void XdgShellTest::testMove() @@ -321,7 +366,10 @@ void XdgShellTest::testMove() // this test verifies that the move request works SURFACE - QSignalSpy moveSpy(serverXdgSurface, &XdgShellSurfaceInterface::moveRequested); + // hack: pretend that the xdg-surface had been configured + serverXdgToplevel->sendConfigure(QSize(0, 0), XdgToplevelInterface::States()); + + QSignalSpy moveSpy(serverXdgToplevel, &XdgToplevelInterface::moveRequested); QVERIFY(moveSpy.isValid()); // TODO: the serial needs to be a proper one @@ -353,7 +401,10 @@ void XdgShellTest::testResize() // this test verifies that the resize request works SURFACE - QSignalSpy resizeSpy(serverXdgSurface, &XdgShellSurfaceInterface::resizeRequested); + // hack: pretend that the xdg-surface had been configured + serverXdgToplevel->sendConfigure(QSize(0, 0), XdgToplevelInterface::States()); + + QSignalSpy resizeSpy(serverXdgToplevel, &XdgToplevelInterface::resizeRequested); QVERIFY(resizeSpy.isValid()); // TODO: the serial needs to be a proper one @@ -362,8 +413,8 @@ void XdgShellTest::testResize() QVERIFY(resizeSpy.wait()); QCOMPARE(resizeSpy.count(), 1); QCOMPARE(resizeSpy.first().at(0).value(), m_seatInterface); - QCOMPARE(resizeSpy.first().at(1).value(), 60u); - QCOMPARE(resizeSpy.first().at(2).value(), edges); + QCOMPARE(resizeSpy.first().at(1).value(), edges); + QCOMPARE(resizeSpy.first().at(2).value(), 60u); } void XdgShellTest::testTransient() @@ -373,30 +424,28 @@ void XdgShellTest::testTransient() QScopedPointer surface2(m_compositor->createSurface()); QScopedPointer xdgSurface2(m_xdgShell->createSurface(surface2.data())); QVERIFY(xdgSurfaceCreatedSpy.wait()); - auto serverXdgSurface2 = xdgSurfaceCreatedSpy.last().first().value(); - QVERIFY(serverXdgSurface2); + auto serverXdgToplevel2 = xdgSurfaceCreatedSpy.last().first().value(); + QVERIFY(serverXdgToplevel2); - QVERIFY(!serverXdgSurface->isTransient()); - QVERIFY(!serverXdgSurface2->isTransient()); + QVERIFY(!serverXdgToplevel->parentXdgToplevel()); + QVERIFY(!serverXdgToplevel2->parentXdgToplevel()); // now make xdsgSurface2 a transient for xdgSurface - QSignalSpy transientForSpy(serverXdgSurface2, &XdgShellSurfaceInterface::transientForChanged); + QSignalSpy transientForSpy(serverXdgToplevel2, &XdgToplevelInterface::parentXdgToplevelChanged); QVERIFY(transientForSpy.isValid()); xdgSurface2->setTransientFor(xdgSurface.data()); QVERIFY(transientForSpy.wait()); QCOMPARE(transientForSpy.count(), 1); - QVERIFY(serverXdgSurface2->isTransient()); - QCOMPARE(serverXdgSurface2->transientFor().data(), serverXdgSurface); - QVERIFY(!serverXdgSurface->isTransient()); + QCOMPARE(serverXdgToplevel2->parentXdgToplevel(), serverXdgToplevel); + QVERIFY(!serverXdgToplevel->parentXdgToplevel()); // unset the transient for xdgSurface2->setTransientFor(nullptr); QVERIFY(transientForSpy.wait()); QCOMPARE(transientForSpy.count(), 2); - QVERIFY(!serverXdgSurface2->isTransient()); - QVERIFY(serverXdgSurface2->transientFor().isNull()); - QVERIFY(!serverXdgSurface->isTransient()); + QVERIFY(!serverXdgToplevel2->parentXdgToplevel()); + QVERIFY(!serverXdgToplevel->parentXdgToplevel()); } void XdgShellTest::testPing() @@ -407,7 +456,7 @@ void XdgShellTest::testPing() QSignalSpy pingSpy(m_xdgShellInterface, &XdgShellInterface::pongReceived); QVERIFY(pingSpy.isValid()); - quint32 serial = m_xdgShellInterface->ping(serverXdgSurface); + quint32 serial = m_xdgShellInterface->ping(serverXdgToplevel->xdgSurface()); QVERIFY(pingSpy.wait()); QCOMPARE(pingSpy.count(), 1); QCOMPARE(pingSpy.takeFirst().at(0).value(), serial); @@ -415,7 +464,7 @@ void XdgShellTest::testPing() // test of a ping failure // disconnecting the connection thread to the queue will break the connection and pings will do a timeout disconnect(m_connection, &ConnectionThread::eventsRead, m_queue, &EventQueue::dispatch); - m_xdgShellInterface->ping(serverXdgSurface); + m_xdgShellInterface->ping(serverXdgToplevel->xdgSurface()); QSignalSpy pingDelayedSpy(m_xdgShellInterface, &XdgShellInterface::pingDelayed); QVERIFY(pingDelayedSpy.wait()); @@ -431,11 +480,11 @@ void XdgShellTest::testClose() QSignalSpy closeSpy(xdgSurface.data(), &XdgShellSurface::closeRequested); QVERIFY(closeSpy.isValid()); - serverXdgSurface->close(); + serverXdgToplevel->sendClose(); QVERIFY(closeSpy.wait()); QCOMPARE(closeSpy.count(), 1); - QSignalSpy destroyedSpy(serverXdgSurface, &XdgShellSurfaceInterface::destroyed); + QSignalSpy destroyedSpy(serverXdgToplevel, &XdgToplevelInterface::destroyed); QVERIFY(destroyedSpy.isValid()); xdgSurface.reset(); QVERIFY(destroyedSpy.wait()); @@ -443,20 +492,20 @@ void XdgShellTest::testClose() void XdgShellTest::testConfigureStates_data() { - QTest::addColumn("serverStates"); + QTest::addColumn("serverStates"); QTest::addColumn("clientStates"); - const auto sa = XdgShellSurfaceInterface::States(XdgShellSurfaceInterface::State::Activated); - const auto sm = XdgShellSurfaceInterface::States(XdgShellSurfaceInterface::State::Maximized); - const auto sf = XdgShellSurfaceInterface::States(XdgShellSurfaceInterface::State::Fullscreen); - const auto sr = XdgShellSurfaceInterface::States(XdgShellSurfaceInterface::State::Resizing); + const auto sa = XdgToplevelInterface::States(XdgToplevelInterface::State::Activated); + const auto sm = XdgToplevelInterface::States(XdgToplevelInterface::State::Maximized); + const auto sf = XdgToplevelInterface::States(XdgToplevelInterface::State::FullScreen); + const auto sr = XdgToplevelInterface::States(XdgToplevelInterface::State::Resizing); const auto ca = XdgShellSurface::States(XdgShellSurface::State::Activated); const auto cm = XdgShellSurface::States(XdgShellSurface::State::Maximized); const auto cf = XdgShellSurface::States(XdgShellSurface::State::Fullscreen); const auto cr = XdgShellSurface::States(XdgShellSurface::State::Resizing); - QTest::newRow("none") << XdgShellSurfaceInterface::States() << XdgShellSurface::States(); + QTest::newRow("none") << XdgToplevelInterface::States() << XdgShellSurface::States(); QTest::newRow("Active") << sa << ca; QTest::newRow("Maximize") << sm << cm; QTest::newRow("Fullscreen") << sf << cf; @@ -485,15 +534,15 @@ void XdgShellTest::testConfigureStates() QSignalSpy configureSpy(xdgSurface.data(), &XdgShellSurface::configureRequested); QVERIFY(configureSpy.isValid()); - QFETCH(XdgShellSurfaceInterface::States, serverStates); - serverXdgSurface->configure(serverStates); + QFETCH(XdgToplevelInterface::States, serverStates); + serverXdgToplevel->sendConfigure(QSize(0, 0), serverStates); QVERIFY(configureSpy.wait()); QCOMPARE(configureSpy.count(), 1); QCOMPARE(configureSpy.first().at(0).toSize(), QSize(0, 0)); QTEST(configureSpy.first().at(1).value(), "clientStates"); QCOMPARE(configureSpy.first().at(2).value(), m_display->serial()); - QSignalSpy ackSpy(serverXdgSurface, &XdgShellSurfaceInterface::configureAcknowledged); + QSignalSpy ackSpy(serverXdgToplevel->xdgSurface(), &XdgSurfaceInterface::configureAcknowledged); QVERIFY(ackSpy.isValid()); xdgSurface->ackConfigure(configureSpy.first().at(2).value()); @@ -512,15 +561,15 @@ void XdgShellTest::testConfigureMultipleAcks() QVERIFY(configureSpy.isValid()); QSignalSpy sizeChangedSpy(xdgSurface.data(), &XdgShellSurface::sizeChanged); QVERIFY(sizeChangedSpy.isValid()); - QSignalSpy ackSpy(serverXdgSurface, &XdgShellSurfaceInterface::configureAcknowledged); + QSignalSpy ackSpy(serverXdgToplevel->xdgSurface(), &XdgSurfaceInterface::configureAcknowledged); QVERIFY(ackSpy.isValid()); - serverXdgSurface->configure(XdgShellSurfaceInterface::States(), QSize(10, 20)); + serverXdgToplevel->sendConfigure(QSize(10, 20), XdgToplevelInterface::States()); const quint32 serial1 = m_display->serial(); - serverXdgSurface->configure(XdgShellSurfaceInterface::States(), QSize(20, 30)); + serverXdgToplevel->sendConfigure(QSize(20, 30), XdgToplevelInterface::States()); const quint32 serial2 = m_display->serial(); QVERIFY(serial1 != serial2); - serverXdgSurface->configure(XdgShellSurfaceInterface::States(), QSize(30, 40)); + serverXdgToplevel->sendConfigure(QSize(30, 40), XdgToplevelInterface::States()); const quint32 serial3 = m_display->serial(); QVERIFY(serial1 != serial3); QVERIFY(serial2 != serial3); @@ -544,16 +593,17 @@ void XdgShellTest::testConfigureMultipleAcks() xdgSurface->ackConfigure(serial3); QVERIFY(ackSpy.wait()); - QCOMPARE(ackSpy.count(), 3); - QCOMPARE(ackSpy.at(0).first().value(), serial1); - QCOMPARE(ackSpy.at(1).first().value(), serial2); - QCOMPARE(ackSpy.at(2).first().value(), serial3); + QCOMPARE(ackSpy.count(), 1); + QCOMPARE(ackSpy.last().first().value(), serial3); // configure once more with a null size - serverXdgSurface->configure(XdgShellSurfaceInterface::States()); + serverXdgToplevel->sendConfigure(QSize(0, 0), XdgToplevelInterface::States()); // should not change size QVERIFY(configureSpy.wait()); QCOMPARE(configureSpy.count(), 4); QCOMPARE(sizeChangedSpy.count(), 3); QCOMPARE(xdgSurface->size(), QSize(30, 40)); } + +QTEST_GUILESS_MAIN(XdgShellTest) +#include "test_xdg_shell.moc" diff --git a/src/wayland/autotests/client/test_xdg_shell.h b/src/wayland/autotests/client/test_xdg_shell.h deleted file mode 100644 index eb76312d05..0000000000 --- a/src/wayland/autotests/client/test_xdg_shell.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - SPDX-FileCopyrightText: 2016 Martin Gräßlin - - SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL -*/ -#ifndef TEST_XDG_SHELL_H -#define TEST_XDG_SHELL_H - -// Qt -#include -// client -#include "KWayland/Client/xdgshell.h" -#include "KWayland/Client/connection_thread.h" -#include "KWayland/Client/compositor.h" -#include "KWayland/Client/event_queue.h" -#include "KWayland/Client/registry.h" -#include "KWayland/Client/output.h" -#include "KWayland/Client/seat.h" -#include "KWayland/Client/shm_pool.h" -#include "KWayland/Client/surface.h" -// server -#include "../../src/server/display.h" -#include "../../src/server/compositor_interface.h" -#include "../../src/server/output_interface.h" -#include "../../src/server/seat_interface.h" -#include "../../src/server/surface_interface.h" -#include "../../src/server/xdgshell_interface.h" - -using namespace KWayland::Client; -using namespace KWaylandServer; - -Q_DECLARE_METATYPE(Qt::MouseButton) - -class XdgShellTest : public QObject -{ - Q_OBJECT - -protected: - XdgShellTest(XdgShellInterfaceVersion version); -private Q_SLOTS: - void init(); - void cleanup(); - - void testCreateSurface(); - void testTitle(); - void testWindowClass(); - void testMaximize(); - void testMinimize(); - void testFullscreen(); - void testShowWindowMenu(); - void testMove(); - void testResize_data(); - void testResize(); - void testTransient(); - void testPing(); - void testClose(); - void testConfigureStates_data(); - void testConfigureStates(); - void testConfigureMultipleAcks(); - -protected: - XdgShellInterface *m_xdgShellInterface = nullptr; - Compositor *m_compositor = nullptr; - XdgShell *m_xdgShell = nullptr; - Display *m_display = nullptr; - CompositorInterface *m_compositorInterface = nullptr; - OutputInterface *m_o1Interface = nullptr; - OutputInterface *m_o2Interface = nullptr; - SeatInterface *m_seatInterface = nullptr; - ConnectionThread *m_connection = nullptr; - QThread *m_thread = nullptr; - EventQueue *m_queue = nullptr; - ShmPool *m_shmPool = nullptr; - Output *m_output1 = nullptr; - Output *m_output2 = nullptr; - Seat *m_seat = nullptr; - -private: - XdgShellInterfaceVersion m_version; -}; - -#define SURFACE \ - QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated); \ - QVERIFY(xdgSurfaceCreatedSpy.isValid()); \ - QScopedPointer surface(m_compositor->createSurface()); \ - QScopedPointer xdgSurface(m_xdgShell->createSurface(surface.data())); \ - QCOMPARE(xdgSurface->size(), QSize()); \ - QVERIFY(xdgSurfaceCreatedSpy.wait()); \ - auto serverXdgSurface = xdgSurfaceCreatedSpy.first().first().value(); \ - QVERIFY(serverXdgSurface); - -#endif diff --git a/src/wayland/autotests/client/test_xdg_shell_stable.cpp b/src/wayland/autotests/client/test_xdg_shell_stable.cpp deleted file mode 100644 index d17e2deb85..0000000000 --- a/src/wayland/autotests/client/test_xdg_shell_stable.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/* - SPDX-FileCopyrightText: 2016 Martin Gräßlin - SPDX-FileCopyrightText: 2017 David Edmundson - - SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL -*/ - -#include "test_xdg_shell.h" -#include - -class XdgShellTestStable : public XdgShellTest { - Q_OBJECT -public: - XdgShellTestStable() : - XdgShellTest(KWaylandServer::XdgShellInterfaceVersion::Stable) {} - -private Q_SLOTS: - void testMaxSize(); - void testMinSize(); - - void testPopup_data(); - void testPopup(); - - void testMultipleRoles1(); - void testMultipleRoles2(); - - void testWindowGeometry(); -}; - -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)); - surface->commit(Surface::CommitFlag::None); - QVERIFY(maxSizeSpy.wait()); - QCOMPARE(maxSizeSpy.count(), 1); - QCOMPARE(maxSizeSpy.last().at(0).value(), QSize(100,100)); - QCOMPARE(serverXdgSurface->maximumSize(), QSize(100, 100)); - - xdgSurface->setMaxSize(QSize(200, 200)); - surface->commit(Surface::CommitFlag::None); - QVERIFY(maxSizeSpy.wait()); - QCOMPARE(maxSizeSpy.count(), 2); - QCOMPARE(maxSizeSpy.last().at(0).value(), QSize(200,200)); - QCOMPARE(serverXdgSurface->maximumSize(), 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)); - surface->commit(Surface::CommitFlag::None); - QVERIFY(minSizeSpy.wait()); - QCOMPARE(minSizeSpy.count(), 1); - QCOMPARE(minSizeSpy.last().at(0).value(), QSize(200,200)); - QCOMPARE(serverXdgSurface->minimumSize(), QSize(200, 200)); - - xdgSurface->setMinSize(QSize(100, 100)); - surface->commit(Surface::CommitFlag::None); - QVERIFY(minSizeSpy.wait()); - QCOMPARE(minSizeSpy.count(), 2); - QCOMPARE(minSizeSpy.last().at(0).value(), QSize(100,100)); - QCOMPARE(serverXdgSurface->minimumSize(), 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); -} - -void XdgShellTestStable::testWindowGeometry() -{ - SURFACE - QSignalSpy windowGeometryChangedSpy(serverXdgSurface, &XdgShellSurfaceInterface::windowGeometryChanged); - xdgSurface->setWindowGeometry(QRect(50, 50, 400, 400)); - surface->commit(Surface::CommitFlag::None); - QVERIFY(windowGeometryChangedSpy.wait()); - QCOMPARE(serverXdgSurface->windowGeometry(), QRect(50, 50, 400, 400)); - - //add a popup to this surface - XdgPositioner positioner(QSize(10,10), QRect(100,100,50,50)); - QSignalSpy xdgPopupCreatedSpy(m_xdgShellInterface, &XdgShellInterface::xdgPopupCreated); - QScopedPointer popupSurface(m_compositor->createSurface()); - QScopedPointer xdgPopupSurface(m_xdgShell->createPopup(popupSurface.data(), xdgSurface.data(), positioner)); - QVERIFY(xdgPopupCreatedSpy.wait()); - auto serverXdgPopup = xdgPopupCreatedSpy.first().first().value(); - QVERIFY(serverXdgPopup); - - QSignalSpy popupWindowGeometryChangedSpy(serverXdgPopup, &XdgShellPopupInterface::windowGeometryChanged); - xdgPopupSurface->setWindowGeometry(QRect(60, 60, 300, 300)); - popupSurface->commit(Surface::CommitFlag::None); - QVERIFY(popupWindowGeometryChangedSpy.wait()); - QCOMPARE(serverXdgPopup->windowGeometry(), QRect(60, 60, 300, 300)); -} - - -QTEST_GUILESS_MAIN(XdgShellTestStable) - -#include "test_xdg_shell_stable.moc" - diff --git a/src/wayland/display.cpp b/src/wayland/display.cpp index f3cab23dc3..51a214fcde 100644 --- a/src/wayland/display.cpp +++ b/src/wayland/display.cpp @@ -39,10 +39,10 @@ #include "subcompositor_interface.h" #include "tablet_interface.h" #include "textinput_interface_p.h" -#include "xdgdecoration_interface.h" +#include "xdgdecoration_v1_interface.h" #include "xdgforeign_interface.h" #include "xdgoutput_interface.h" -#include "xdgshell_stable_interface_p.h" +#include "xdgshell_interface.h" #include #include @@ -377,20 +377,11 @@ TextInputManagerInterface *Display::createTextInputManager(const TextInputInterf return t; } -XdgShellInterface *Display::createXdgShell(const XdgShellInterfaceVersion &version, QObject *parent) +XdgShellInterface *Display::createXdgShell(QObject *parent) { - XdgShellInterface *x = nullptr; - switch (version) { - case XdgShellInterfaceVersion::UnstableV5: - return nullptr; - case XdgShellInterfaceVersion::UnstableV6: - return nullptr; - case XdgShellInterfaceVersion::Stable: - x = new XdgShellStableInterface(this, parent); - break; - } - connect(this, &Display::aboutToTerminate, x, [x] { delete x; }); - return x; + XdgShellInterface *shell = new XdgShellInterface(this, parent); + connect(this, &Display::aboutToTerminate, shell, [shell] { delete shell; }); + return shell; } RelativePointerManagerInterface *Display::createRelativePointerManager(const RelativePointerInterfaceVersion &version, QObject *parent) @@ -483,9 +474,9 @@ XdgOutputManagerInterface *Display::createXdgOutputManager(QObject *parent) return b; } -XdgDecorationManagerInterface *Display::createXdgDecorationManager(XdgShellInterface *shellInterface, QObject *parent) +XdgDecorationManagerV1Interface *Display::createXdgDecorationManagerV1(QObject *parent) { - auto d = new XdgDecorationManagerInterface(this, shellInterface, parent); + auto d = new XdgDecorationManagerV1Interface(this, parent); connect(this, &Display::aboutToTerminate, d, [d] { delete d; }); return d; } diff --git a/src/wayland/display.h b/src/wayland/display.h index f44f6083a3..f0c7de27bd 100644 --- a/src/wayland/display.h +++ b/src/wayland/display.h @@ -72,7 +72,7 @@ class AppMenuManagerInterface; class ServerSideDecorationPaletteManagerInterface; class PlasmaVirtualDesktopManagementInterface; class XdgOutputManagerInterface; -class XdgDecorationManagerInterface; +class XdgDecorationManagerV1Interface; class EglStreamControllerInterface; class KeyStateInterface; class LinuxDmabufUnstableV1Interface; @@ -210,7 +210,7 @@ public: * * @since 5.25 **/ - XdgShellInterface *createXdgShell(const XdgShellInterfaceVersion &version, QObject *parent = nullptr); + XdgShellInterface *createXdgShell(QObject *parent = nullptr); /** * Creates the RelativePointerManagerInterface in interface @p version @@ -299,7 +299,7 @@ public: * @return the created manager * @since 5.54 */ - XdgDecorationManagerInterface *createXdgDecorationManager(XdgShellInterface *shellInterface, QObject *parent = nullptr); + XdgDecorationManagerV1Interface *createXdgDecorationManagerV1(QObject *parent = nullptr); /** * Creates the EglStreamControllerInterface diff --git a/src/wayland/server/generic_shell_surface_p.h b/src/wayland/server/generic_shell_surface_p.h deleted file mode 100644 index fb33e08733..0000000000 --- a/src/wayland/server/generic_shell_surface_p.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - SPDX-FileCopyrightText: 2016 Martin Gräßlin - - SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL -*/ -#ifndef KWAYLAND_SERVER_GENERIC_SHELL_SURFACE_P_H -#define KWAYLAND_SERVER_GENERIC_SHELL_SURFACE_P_H - -#include "seat_interface.h" -#include "surface_interface.h" -#include "surfacerole_p.h" -#include - -namespace KWaylandServer -{ - -template -class GenericShellSurface : public SurfaceRole -{ -public: - GenericShellSurface(T *shellSurface, SurfaceInterface *surface) - : SurfaceRole(surface) - , surface(surface) - , shellSurface(shellSurface) - {} - - SurfaceInterface *surface; - QString title; - QByteArray windowClass; - -protected: - void setTitle(const QString &title); - void setWindowClass(const QByteArray &wc); - - static void moveCallback(wl_client *client, wl_resource *resource, wl_resource *seat, uint32_t serial); - template - static void resizeCallback(wl_client *client, wl_resource *resource, wl_resource * seat, uint32_t serial, uint32_t edges); - static void setTitleCallback(wl_client *client, wl_resource *resource, const char *title); - static void setAppIdCallback(wl_client *client, wl_resource *resource, const char *app_id); - -private: - T *q_func() { - return shellSurface; - } - static typename T::Private *userData(wl_resource *resource) { - return reinterpret_cast(wl_resource_get_user_data(resource)); - } - T *shellSurface; -}; - -template -void GenericShellSurface::setTitleCallback(wl_client *client, wl_resource *resource, const char *title) -{ - auto s = userData(resource); - Q_ASSERT(client == *s->client); - s->setTitle(QString::fromUtf8(title)); -} - -template -void GenericShellSurface::setAppIdCallback(wl_client *client, wl_resource *resource, const char *app_id) -{ - auto s = userData(resource); - Q_ASSERT(client == *s->client); - s->setWindowClass(QByteArray(app_id)); -} - -template -void GenericShellSurface::setTitle(const QString &t) -{ - if (title == t) { - return; - } - title = t; - Q_Q(T); - emit q->titleChanged(title); -} - -template -void GenericShellSurface::setWindowClass(const QByteArray &wc) -{ - if (windowClass == wc) { - return; - } - windowClass = wc; - Q_Q(T); - emit q->windowClassChanged(windowClass); -} - -template -void GenericShellSurface::moveCallback(wl_client *client, wl_resource *resource, wl_resource *seat, uint32_t serial) -{ - auto s = userData(resource); - Q_ASSERT(client == *s->client); - emit s->q_func()->moveRequested(SeatInterface::get(seat), serial); -} - -namespace { -template -Qt::Edges edgesToQtEdges(T edges); -} - -template -template -void GenericShellSurface::resizeCallback(wl_client *client, wl_resource *resource, wl_resource * seat, uint32_t serial, uint32_t edges) -{ - auto s = userData(resource); - Q_ASSERT(client == *s->client); - emit s->q_func()->resizeRequested(SeatInterface::get(seat), serial, edgesToQtEdges(U(edges))); -} - -} - -#endif diff --git a/src/wayland/server/xdgdecoration_interface.cpp b/src/wayland/server/xdgdecoration_interface.cpp deleted file mode 100644 index 324cef9322..0000000000 --- a/src/wayland/server/xdgdecoration_interface.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018 David Edmundson - - SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL -*/ -#include "xdgdecoration_interface.h" - - -#include "display.h" -#include "global_p.h" -#include "resource_p.h" -#include "xdgshell_interface.h" -#include "xdgshell_stable_interface_p.h" - -#include "wayland-xdg-decoration-server-protocol.h" - -#include -#include - -namespace KWaylandServer -{ - -class XdgDecorationManagerInterface::Private : public Global::Private -{ -public: - Private(XdgDecorationManagerInterface *q, XdgShellInterface *shellInterface, Display *d); - - QHash m_decorations; - KWaylandServer::XdgShellStableInterface *m_shellInterface; -private: - void bind(wl_client *client, uint32_t version, uint32_t id) override; - - static void unbind(wl_resource *resource); - static Private *cast(wl_resource *r) { - return reinterpret_cast(wl_resource_get_user_data(r)); - } - - static void destroyCallback(wl_client *client, wl_resource *resource); - static void getToplevelDecorationCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * toplevel); - - XdgDecorationManagerInterface *q; - static const struct zxdg_decoration_manager_v1_interface s_interface; - static const quint32 s_version; -}; - -const quint32 XdgDecorationManagerInterface::Private::s_version = 1; - -XdgDecorationManagerInterface::XdgDecorationManagerInterface(Display *display, XdgShellInterface *shellInterface, QObject *parent): - Global(new Private(this, shellInterface, display), parent) -{ -} - -XdgDecorationManagerInterface::~XdgDecorationManagerInterface() {} - -#ifndef K_DOXYGEN -const struct zxdg_decoration_manager_v1_interface XdgDecorationManagerInterface::Private::s_interface = { - destroyCallback, - getToplevelDecorationCallback -}; -#endif - -void XdgDecorationManagerInterface::Private::destroyCallback(wl_client *client, wl_resource *resource) -{ - Q_UNUSED(client) - wl_resource_destroy(resource); -} - -void XdgDecorationManagerInterface::Private::getToplevelDecorationCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * toplevel) -{ - auto p = reinterpret_cast(wl_resource_get_user_data(resource)); - Q_ASSERT(p); - - auto shell = p->m_shellInterface->getSurface(toplevel); - if (!shell) { - wl_resource_post_error(resource, ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ORPHANED, "No XDGToplevel found object"); - return; - } - if (p->m_decorations.contains(shell)) { - wl_resource_post_error(resource, ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ALREADY_CONSTRUCTED, "XDGDecoration already exists for this surface"); - return; - } - - auto xdgDecoration = new XdgDecorationInterface(p->q, shell, resource); - xdgDecoration->create(p->display->getConnection(client), wl_resource_get_version(resource), id); - if (!xdgDecoration->resource()) { - wl_resource_post_no_memory(resource); - delete xdgDecoration; - return; - } - p->m_decorations[shell] = xdgDecoration; - QObject::connect(xdgDecoration, &QObject::destroyed, p->q, [=]() { - p->m_decorations.remove(shell); - }); - emit p->q->xdgDecorationInterfaceCreated(xdgDecoration); -} - -XdgDecorationManagerInterface::Private::Private(XdgDecorationManagerInterface *q, XdgShellInterface *shellInterface, Display *d) - : Global::Private(d, &zxdg_decoration_manager_v1_interface, s_version) - , q(q) -{ - m_shellInterface = qobject_cast(shellInterface); - Q_ASSERT(m_shellInterface); -} - -void XdgDecorationManagerInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id) -{ - auto c = display->getConnection(client); - wl_resource *resource = c->createResource(&zxdg_decoration_manager_v1_interface, qMin(version, s_version), id); - if (!resource) { - wl_client_post_no_memory(client); - return; - } - wl_resource_set_implementation(resource, &s_interface, this, unbind); -} - -void XdgDecorationManagerInterface::Private::unbind(wl_resource *resource) -{ - Q_UNUSED(resource) -} - -class XdgDecorationInterface::Private : public Resource::Private -{ -public: - Private(XdgDecorationInterface *q, XdgDecorationManagerInterface *c, XdgShellSurfaceInterface *s, wl_resource *parentResource); - ~Private(); - Mode m_requestedMode = Mode::Undefined; - XdgShellSurfaceInterface* m_shell; - -private: - static void setModeCallback(wl_client *client, wl_resource *resource, uint32_t mode); - static void unsetModeCallback(wl_client *client, wl_resource *resource); - - XdgDecorationInterface *q_func() { - return reinterpret_cast(q); - } - - static const struct zxdg_toplevel_decoration_v1_interface s_interface; -}; - -#ifndef K_DOXYGEN -const struct zxdg_toplevel_decoration_v1_interface XdgDecorationInterface::Private::s_interface = { - resourceDestroyedCallback, - setModeCallback, - unsetModeCallback -}; -#endif - -void XdgDecorationInterface::Private::setModeCallback(wl_client *client, wl_resource *resource, uint32_t mode_raw) -{ - Q_UNUSED(client); - auto p = reinterpret_cast(wl_resource_get_user_data(resource)); - Q_ASSERT(p); - - Mode mode = Mode::Undefined; - switch (mode_raw) { - case ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE: - mode = Mode::ClientSide; - break; - case ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE: - mode = Mode::ServerSide; - break; - default: - break; - } - - p->m_requestedMode = mode; - emit p->q_func()->modeRequested(p->m_requestedMode); -} - -void XdgDecorationInterface::Private::unsetModeCallback(wl_client *client, wl_resource *resource) -{ - Q_UNUSED(client); - auto p = reinterpret_cast(wl_resource_get_user_data(resource)); - Q_ASSERT(p); - - p->m_requestedMode = Mode::Undefined; - emit p->q_func()->modeRequested(p->m_requestedMode); -} - -XdgDecorationInterface::Private::Private(XdgDecorationInterface *q, XdgDecorationManagerInterface *c, XdgShellSurfaceInterface *shell, wl_resource *parentResource) - : Resource::Private(q, c, parentResource, &zxdg_toplevel_decoration_v1_interface, &s_interface) - , m_shell(shell) -{ -} - -XdgDecorationInterface::Private::~Private() -{ - if (resource) { - wl_resource_destroy(resource); - resource = nullptr; - } -} - -XdgDecorationInterface::XdgDecorationInterface(XdgDecorationManagerInterface *parent, XdgShellSurfaceInterface *shell, wl_resource *parentResource) - : Resource(new Private(this, parent, shell, parentResource)) -{ -} - -XdgDecorationInterface::~XdgDecorationInterface() {} - -void XdgDecorationInterface::configure(XdgDecorationInterface::Mode mode) -{ - switch(mode) { - case Mode::ClientSide: - zxdg_toplevel_decoration_v1_send_configure(resource(), ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); - break; - case Mode::ServerSide: - zxdg_toplevel_decoration_v1_send_configure(resource(), ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); - break; - default: - //configure(Mode::Undefined) should no-op, as it semantically makes no sense - break; - } -} - -XdgDecorationInterface::Mode XdgDecorationInterface::requestedMode() const -{ - Q_D(); - return d->m_requestedMode; -} - -XdgShellSurfaceInterface* XdgDecorationInterface::surface() const -{ - Q_D(); - return d->m_shell; -} - -XdgDecorationInterface::Private *XdgDecorationInterface::d_func() const -{ - return reinterpret_cast(d.data()); -} - -} diff --git a/src/wayland/server/xdgdecoration_interface.h b/src/wayland/server/xdgdecoration_interface.h deleted file mode 100644 index 0118053341..0000000000 --- a/src/wayland/server/xdgdecoration_interface.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018 David Edmundson - - SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL -*/ -#ifndef KWAYLAND_SERVER_XDG_DECORATION_UNSTABLE_V1_H -#define KWAYLAND_SERVER_XDG_DECORATION_UNSTABLE_V1_H - -#include "global.h" -#include "resource.h" - -#include - -namespace KWaylandServer -{ - -class Display; -class XdgDecorationInterface; -class XdgShellInterface; -class XdgShellSurfaceInterface; - -/** - * @brief The XdgDecorationManagerInterface class - * @since 5.54 - */ -class KWAYLANDSERVER_EXPORT XdgDecorationManagerInterface : public Global -{ - Q_OBJECT -public: - ~XdgDecorationManagerInterface() override; -Q_SIGNALS: - void xdgDecorationInterfaceCreated(XdgDecorationInterface *iface); -private: - explicit XdgDecorationManagerInterface(Display *display, XdgShellInterface *shellInterface, QObject *parent = nullptr); - friend class Display; - class Private; -}; - -/** - * @brief The XdgDecorationInterface class - * @since 5.54 - */ -class KWAYLANDSERVER_EXPORT XdgDecorationInterface : public Resource -{ - Q_OBJECT -public: - enum class Mode { - Undefined, - ClientSide, - ServerSide - }; - - Q_ENUM(Mode); - - ~XdgDecorationInterface() override; - - /** - * Sets the mode the client should be using. - * It should be followed by a call to XDGShellSurface::configure() - * Once acked, it can relied upon to be applied in the next surface - */ - void configure(Mode requestedMode); - - /** - * The last mode requested by the client - */ - Mode requestedMode() const; - - /** - * The surface this decoration is attached to - */ - XdgShellSurfaceInterface *surface() const; - -Q_SIGNALS: - /** - * New mode requested by the client - */ - void modeRequested(KWaylandServer::XdgDecorationInterface::Mode requestedMode); - -private: - explicit XdgDecorationInterface(XdgDecorationManagerInterface *parent, XdgShellSurfaceInterface *surface, wl_resource *parentResource); - friend class XdgDecorationManagerInterface; - - class Private; - Private *d_func() const; -}; - -} - -#endif diff --git a/src/wayland/server/xdgshell_stable_interface.cpp b/src/wayland/server/xdgshell_stable_interface.cpp deleted file mode 100644 index aff81045c0..0000000000 --- a/src/wayland/server/xdgshell_stable_interface.cpp +++ /dev/null @@ -1,1104 +0,0 @@ -/* - SPDX-FileCopyrightText: 2017 David Edmundson - SPDX-FileCopyrightText: 2019 Vlad Zahorodnii - - SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL -*/ -#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 KWaylandServer -{ - -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; - - QRect windowGeometry() const override; - void commit() 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: - void setWindowGeometryCallback(const QRect &rect); - - static void grabCallback(wl_client *client, wl_resource *resource, wl_resource *seat, uint32_t serial); - - static const struct xdg_popup_interface s_interface; - - struct ShellSurfaceState - { - QRect windowGeometry; - - bool windowGeometryIsSet = false; - }; - - ShellSurfaceState m_currentState; - ShellSurfaceState m_pendingState; - - friend class XdgSurfaceStableInterface; -}; - -class XdgSurfaceStableInterface::Private : public KWaylandServer::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; - - QRect windowGeometry() const override; - QSize minimumSize() const override; - QSize maximumSize() const override; - void close() override; - void commit() 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: - void setWindowGeometryCallback(const QRect &rect); - - 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; - - struct ShellSurfaceState - { - QRect windowGeometry; - QSize minimumSize = QSize(0, 0); - QSize maximiumSize = QSize(INT32_MAX, INT32_MAX); - - bool windowGeometryIsSet = false; - bool minimumSizeIsSet = false; - bool maximumSizeIsSet = false; - }; - - ShellSurfaceState m_currentState; - ShellSurfaceState m_pendingState; - - friend class XdgSurfaceStableInterface; -}; - - -const quint32 XdgShellStableInterface::Private::s_version = 1; - -#ifndef K_DOXYGEN -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 K_DOXYGEN -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) -{ - // FIXME: That's incorrect! The client may have asked us to create an xdg-toplevel - // for a pointer surface or a subsurface. We have to post an error in that case. - 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) -{ - // FIXME: That's incorrect! The client may have asked us to create an xdg-popup - // for a pointer surface or a subsurface. We have to post an error in that case. - 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) -{ - auto s = cast(resource); - Q_ASSERT(client == *s->client); - - if (width < 0 || height < 0) { - wl_resource_post_error(resource, XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE , "Tried to set invalid xdg-surface geometry"); - return; - } - - if (s->m_topLevel) { - s->m_topLevel->d_func()->setWindowGeometryCallback(QRect(x, y, width, height)); - } else if (s->m_popup) { - s->m_popup->d_func()->setWindowGeometryCallback(QRect(x, y, width, height)); - } -} - -XdgSurfaceStableInterface::Private::Private(XdgSurfaceStableInterface *q, XdgShellStableInterface *c, SurfaceInterface *surface, wl_resource *parentResource) - : KWaylandServer::Resource::Private(q, c, parentResource, &xdg_surface_interface, &s_interface), - m_shell(c), - m_surface(surface) -{ -} - -XdgSurfaceStableInterface::Private::~Private() = default; - - -class XdgPositionerStableInterface::Private : public KWaylandServer::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) - : KWaylandServer::Resource::Private(q, c, parentResource, &xdg_positioner_interface, &s_interface) -{ -} - -#ifndef K_DOXYGEN -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); -} - -QRect XdgTopLevelStableInterface::Private::windowGeometry() const -{ - return m_currentState.windowGeometry; -} - -QSize XdgTopLevelStableInterface::Private::minimumSize() const -{ - return m_currentState.minimumSize; -} - -QSize XdgTopLevelStableInterface::Private::maximumSize() const -{ - return m_currentState.maximiumSize; -} - -void XdgTopLevelStableInterface::Private::close() -{ - xdg_toplevel_send_close(resource); - client->flush(); -} - -void XdgTopLevelStableInterface::Private::commit() -{ - const bool windowGeometryChanged = m_pendingState.windowGeometryIsSet; - const bool minimumSizeChanged = m_pendingState.minimumSizeIsSet; - const bool maximumSizeChanged = m_pendingState.maximumSizeIsSet; - - if (windowGeometryChanged) { - m_currentState.windowGeometry = m_pendingState.windowGeometry; - } - if (minimumSizeChanged) { - m_currentState.minimumSize = m_pendingState.minimumSize; - } - if (maximumSizeChanged) { - m_currentState.maximiumSize = m_pendingState.maximiumSize; - } - - m_pendingState = ShellSurfaceState{}; - - if (windowGeometryChanged) { - emit q_func()->windowGeometryChanged(m_currentState.windowGeometry); - } - if (minimumSizeChanged) { - emit q_func()->minSizeChanged(m_currentState.minimumSize); - } - if (maximumSizeChanged) { - emit q_func()->maxSizeChanged(m_currentState.maximiumSize); - } -} - -void XdgTopLevelStableInterface::Private::setMaxSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height) -{ - if (width < 0 || height < 0) { - wl_resource_post_error(resource, XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, "Tried to set invalid xdg-toplevel maximum size"); - return; - } - if (width == 0) { - width = INT32_MAX; - } - if (height == 0) { - height = INT32_MAX; - } - auto s = cast(resource); - Q_ASSERT(client == *s->client); - s->m_pendingState.maximiumSize = QSize(width, height); - s->m_pendingState.maximumSizeIsSet = true; -} - -void XdgTopLevelStableInterface::Private::setMinSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height) -{ - if (width < 0 || height < 0) { - wl_resource_post_error(resource, XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, "Tried to set invalid xdg-toplevel minimum size"); - return; - } - auto s = cast(resource); - Q_ASSERT(client == *s->client); - s->m_pendingState.minimumSize = QSize(width, height); - s->m_pendingState.minimumSizeIsSet = true; -} - -void XdgTopLevelStableInterface::Private::setWindowGeometryCallback(const QRect &rect) -{ - m_pendingState.windowGeometry = rect; - m_pendingState.windowGeometryIsSet = true; -} - -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 K_DOXYGEN -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) -{ -} - -QRect XdgPopupStableInterface::Private::windowGeometry() const -{ - return m_currentState.windowGeometry; -} - -void XdgPopupStableInterface::Private::commit() -{ - const bool windowGeometryChanged = m_pendingState.windowGeometryIsSet; - - if (windowGeometryChanged) { - m_currentState.windowGeometry = m_pendingState.windowGeometry; - } - - m_pendingState = ShellSurfaceState{}; - - if (windowGeometryChanged) { - emit q_func()->windowGeometryChanged(m_currentState.windowGeometry); - } -} - -void XdgPopupStableInterface::Private::setWindowGeometryCallback(const QRect &rect) -{ - m_pendingState.windowGeometry = rect; - m_pendingState.windowGeometryIsSet = true; -} - -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) - : KWaylandServer::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) - : KWaylandServer::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) - : KWaylandServer::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 deleted file mode 100644 index e36afa33d9..0000000000 --- a/src/wayland/server/xdgshell_stable_interface_p.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - SPDX-FileCopyrightText: 2017 David Edmundson - - SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL -*/ -#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 KWaylandServer -{ - -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 KWaylandServer::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 KWaylandServer::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/surfacerole.cpp b/src/wayland/surfacerole.cpp index a5ccd75e06..c07f3c79a4 100644 --- a/src/wayland/surfacerole.cpp +++ b/src/wayland/surfacerole.cpp @@ -25,4 +25,13 @@ SurfaceRole::~SurfaceRole() } } +SurfaceRole *SurfaceRole::get(SurfaceInterface *surface) +{ + if (surface) { + return surface->d_func()->role; + } + + return nullptr; +} + } diff --git a/src/wayland/surfacerole_p.h b/src/wayland/surfacerole_p.h index 04dc93941d..68f23996ec 100644 --- a/src/wayland/surfacerole_p.h +++ b/src/wayland/surfacerole_p.h @@ -22,6 +22,8 @@ public: virtual void commit() = 0; + static SurfaceRole *get(SurfaceInterface *surface); + private: QPointer m_surface; diff --git a/src/wayland/tests/renderingservertest.cpp b/src/wayland/tests/renderingservertest.cpp index f94da97645..07c0f5c7dd 100644 --- a/src/wayland/tests/renderingservertest.cpp +++ b/src/wayland/tests/renderingservertest.cpp @@ -79,7 +79,7 @@ public: explicit CompositorWindow(QWidget *parent = nullptr); virtual ~CompositorWindow(); - void surfaceCreated(KWaylandServer::XdgShellSurfaceInterface *surface); + void surfaceCreated(KWaylandServer::XdgToplevelInterface *surface); void setSeat(const QPointer &seat); @@ -94,7 +94,7 @@ protected: private: void updateFocus(); - QList m_stackingOrder; + QList m_stackingOrder; QPointer m_seat; }; @@ -106,13 +106,13 @@ CompositorWindow::CompositorWindow(QWidget *parent) CompositorWindow::~CompositorWindow() = default; -void CompositorWindow::surfaceCreated(KWaylandServer::XdgShellSurfaceInterface *surface) +void CompositorWindow::surfaceCreated(KWaylandServer::XdgToplevelInterface *surface) { using namespace KWaylandServer; - surface->configure(XdgShellSurfaceInterface::States()); + surface->sendConfigure(QSize(), XdgToplevelInterface::States()); m_stackingOrder << surface; connect(surface->surface(), &SurfaceInterface::damaged, this, static_cast(&CompositorWindow::update)); - connect(surface, &XdgShellSurfaceInterface::destroyed, this, + connect(surface, &XdgToplevelInterface::destroyed, this, [surface, this] { m_stackingOrder.removeAll(surface); updateFocus(); @@ -129,7 +129,7 @@ void CompositorWindow::updateFocus() return; } auto it = std::find_if(m_stackingOrder.constBegin(), m_stackingOrder.constEnd(), - [](XdgShellSurfaceInterface *toplevel) { + [](XdgToplevelInterface *toplevel) { return toplevel->surface()->isMapped(); } ); @@ -243,8 +243,7 @@ int main(int argc, char **argv) ddm->create(); CompositorInterface *compositor = display.createCompositor(&display); compositor->create(); - XdgShellInterface *shell = display.createXdgShell(XdgShellInterfaceVersion::Stable); - shell->create(); + XdgShellInterface *shell = display.createXdgShell(); display.createShm(); OutputInterface *output = display.createOutput(&display); output->setPhysicalSize(QSize(269, 202)); @@ -263,7 +262,7 @@ int main(int argc, char **argv) compositorWindow.setMaximumSize(windowSize); compositorWindow.setGeometry(QRect(QPoint(0, 0), windowSize)); compositorWindow.show(); - QObject::connect(shell, &XdgShellInterface::surfaceCreated, &compositorWindow, &CompositorWindow::surfaceCreated); + QObject::connect(shell, &XdgShellInterface::toplevelCreated, &compositorWindow, &CompositorWindow::surfaceCreated); // start XWayland if (parser.isSet(xwaylandOption)) { diff --git a/src/wayland/tests/waylandservertest.cpp b/src/wayland/tests/waylandservertest.cpp index 46ee0b64ae..79761bb232 100644 --- a/src/wayland/tests/waylandservertest.cpp +++ b/src/wayland/tests/waylandservertest.cpp @@ -77,8 +77,8 @@ int main(int argc, char **argv) display.createShm(); CompositorInterface *compositor = display.createCompositor(&display); compositor->create(); - XdgShellInterface *shell = display.createXdgShell(XdgShellInterfaceVersion::Stable); - shell->create(); + XdgShellInterface *shell = display.createXdgShell(); + Q_UNUSED(shell) OutputInterface *output = display.createOutput(&display); output->setPhysicalSize(QSize(10, 10)); output->addMode(QSize(1024, 768)); diff --git a/src/wayland/xdgdecoration_v1_interface.cpp b/src/wayland/xdgdecoration_v1_interface.cpp new file mode 100644 index 0000000000..c8cc5bdd7e --- /dev/null +++ b/src/wayland/xdgdecoration_v1_interface.cpp @@ -0,0 +1,151 @@ +/* + SPDX-FileCopyrightText: 2020 Vlad Zahorodnii + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ + +#include "xdgdecoration_v1_interface.h" +#include "display.h" +#include "xdgdecoration_v1_interface_p.h" +#include "xdgshell_interface_p.h" + +namespace KWaylandServer +{ + +// TODO: We need to wait for an ack_configure either here or in xdgshellclient.cpp. + +XdgDecorationManagerV1InterfacePrivate::XdgDecorationManagerV1InterfacePrivate(XdgDecorationManagerV1Interface *manager) + : q(manager) +{ +} + +void XdgDecorationManagerV1InterfacePrivate::zxdg_decoration_manager_v1_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +void XdgDecorationManagerV1InterfacePrivate::zxdg_decoration_manager_v1_get_toplevel_decoration(Resource *resource, + uint32_t id, + ::wl_resource *toplevelResource) +{ + XdgToplevelInterfacePrivate *toplevelPrivate = XdgToplevelInterfacePrivate::get(toplevelResource); + if (!toplevelPrivate) { + wl_resource_post_error(resource->handle, + QtWaylandServer::zxdg_toplevel_decoration_v1::error_orphaned, + "no xdg-toplevel object"); + return; + } + + if (toplevelPrivate->decoration) { + wl_resource_post_error(resource->handle, + QtWaylandServer::zxdg_toplevel_decoration_v1::error_already_constructed, + "decoration has been already constructed"); + return; + } + + wl_resource *decorationResource = wl_resource_create(resource->client(), + &zxdg_toplevel_decoration_v1_interface, + resource->version(), id); + + auto decoration = new XdgToplevelDecorationV1Interface(toplevelPrivate->q, decorationResource); + toplevelPrivate->decoration = decoration; + + emit q->decorationCreated(decoration); +} + +XdgDecorationManagerV1Interface::XdgDecorationManagerV1Interface(Display *display, QObject *parent) + : QObject(parent) + , d(new XdgDecorationManagerV1InterfacePrivate(this)) +{ + d->init(*display, 1); +} + +XdgDecorationManagerV1Interface::~XdgDecorationManagerV1Interface() +{ +} + +XdgToplevelDecorationV1InterfacePrivate::XdgToplevelDecorationV1InterfacePrivate(XdgToplevelDecorationV1Interface *decoration) + : q(decoration) +{ +} + +void XdgToplevelDecorationV1InterfacePrivate::zxdg_toplevel_decoration_v1_destroy_resource(Resource *resource) +{ + Q_UNUSED(resource) + delete q; +} + +void XdgToplevelDecorationV1InterfacePrivate::zxdg_toplevel_decoration_v1_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +void XdgToplevelDecorationV1InterfacePrivate::zxdg_toplevel_decoration_v1_set_mode(Resource *resource, uint32_t mode) +{ + Q_UNUSED(resource) + + switch (mode) { + case mode_client_side: + preferredMode = XdgToplevelDecorationV1Interface::Mode::Client; + break; + case mode_server_side: + preferredMode = XdgToplevelDecorationV1Interface::Mode::Server; + break; + default: + preferredMode = XdgToplevelDecorationV1Interface::Mode::Undefined; + break; + } + + emit q->preferredModeChanged(preferredMode); +} + +void XdgToplevelDecorationV1InterfacePrivate::zxdg_toplevel_decoration_v1_unset_mode(Resource *resource) +{ + Q_UNUSED(resource) + preferredMode = XdgToplevelDecorationV1Interface::Mode::Undefined; + emit q->preferredModeChanged(preferredMode); +} + +XdgToplevelDecorationV1Interface::XdgToplevelDecorationV1Interface(XdgToplevelInterface *toplevel, + ::wl_resource *resource) + : d(new XdgToplevelDecorationV1InterfacePrivate(this)) +{ + d->toplevel = toplevel; + d->init(resource); +} + +XdgToplevelDecorationV1Interface::~XdgToplevelDecorationV1Interface() +{ +} + +XdgToplevelInterface *XdgToplevelDecorationV1Interface::toplevel() const +{ + return d->toplevel; +} + +XdgToplevelDecorationV1Interface::Mode XdgToplevelDecorationV1Interface::preferredMode() const +{ + return d->preferredMode; +} + +void XdgToplevelDecorationV1Interface::sendConfigure(Mode mode) +{ + switch (mode) { + case Mode::Client: + d->send_configure(QtWaylandServer::zxdg_toplevel_decoration_v1::mode_client_side); + break; + case Mode::Server: + d->send_configure(QtWaylandServer::zxdg_toplevel_decoration_v1::mode_server_side); + break; + case Mode::Undefined: + break; + } +} + +XdgToplevelDecorationV1Interface *XdgToplevelDecorationV1Interface::get(XdgToplevelInterface *toplevel) +{ + XdgToplevelInterfacePrivate *toplevelPrivate = XdgToplevelInterfacePrivate::get(toplevel); + return toplevelPrivate->decoration; +} + +} // namespace KWaylandServer diff --git a/src/wayland/xdgdecoration_v1_interface.h b/src/wayland/xdgdecoration_v1_interface.h new file mode 100644 index 0000000000..a5533b07ce --- /dev/null +++ b/src/wayland/xdgdecoration_v1_interface.h @@ -0,0 +1,114 @@ +/* + SPDX-FileCopyrightText: 2020 Vlad Zahorodnii + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ + +#pragma once + +#include + +#include + +struct wl_resource; + +namespace KWaylandServer +{ + +class Display; +class XdgDecorationManagerV1InterfacePrivate; +class XdgToplevelDecorationV1Interface; +class XdgToplevelDecorationV1InterfacePrivate; +class XdgToplevelInterface; + +/** + * The XdgDecorationManagerV1Interface class provides a way for the compositor and an xdg-shell + * client to negotiate the use of server-side window decorations. + * + * XdgDecorationManagerV1Interface corresponds to the interface \c zxdg_decoration_manager_v1. + * + * \since 5.20 + */ +class KWAYLANDSERVER_EXPORT XdgDecorationManagerV1Interface : public QObject +{ + Q_OBJECT + +public: + /** + * Constructs a decoration manager with the given \a display and \a parent. + */ + XdgDecorationManagerV1Interface(Display *display, QObject *parent = nullptr); + /** + * Destructs the XdgDecorationManagerV1Interface object. + */ + ~XdgDecorationManagerV1Interface() override; + +Q_SIGNALS: + /** + * This signal is emitted when a new \a decoration has been created. + */ + void decorationCreated(XdgToplevelDecorationV1Interface *decoration); + +private: + QScopedPointer d; +}; + +/** + * The XdgToplevelDecorationV1Interface class allows the compositor to toggle server-side window + * decoration on an xdg-toplevel surface. + * + * XdgToplevelDecorationV1Interface corresponds to the interface \c zxdg_toplevel_decoration_v1. + * + * \since 5.20 + */ +class KWAYLANDSERVER_EXPORT XdgToplevelDecorationV1Interface : public QObject +{ + Q_OBJECT + +public: + enum class Mode { Undefined, Client, Server }; + Q_ENUM(Mode) + + /** + * Constructs a XdgToplevelDecorationV1Interface for the given \a toplevel and initializes + * it with \a resource. + */ + XdgToplevelDecorationV1Interface(XdgToplevelInterface *toplevel, ::wl_resource *resource); + /** + * Destructs the XdgToplevelDecorationV1Interface object. + */ + ~XdgToplevelDecorationV1Interface() override; + + /** + * Returns the toplevel for this XdgToplevelDecorationV1Interface. + */ + XdgToplevelInterface *toplevel() const; + /** + * Returns the decoration mode preferred by the client. + */ + Mode preferredMode() const; + /** + * Sends a configure event to the client. \a mode indicates the decoration mode the client + * should be using. The client must send an ack_configure in response to this event. + * + * \see XdgToplevelInterface::sendConfigure + */ + void sendConfigure(Mode mode); + + /** + * Returns the XdgToplevelDecorationV1Interface for the specified \a toplevel. + */ + static XdgToplevelDecorationV1Interface *get(XdgToplevelInterface *toplevel); + +Q_SIGNALS: + /** + * This signal is emitted when the client has specified the preferred decoration mode. The + * compositor can decide not to use the client's mode and enforce a different mode instead. + */ + void preferredModeChanged(KWaylandServer::XdgToplevelDecorationV1Interface::Mode mode); + +private: + QScopedPointer d; +}; + +} // namespace KWaylandServer diff --git a/src/wayland/xdgdecoration_v1_interface_p.h b/src/wayland/xdgdecoration_v1_interface_p.h new file mode 100644 index 0000000000..5d067fd3ea --- /dev/null +++ b/src/wayland/xdgdecoration_v1_interface_p.h @@ -0,0 +1,44 @@ +/* + SPDX-FileCopyrightText: 2020 Vlad Zahorodnii + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ + +#pragma once + +#include "xdgdecoration_v1_interface.h" + +#include "qwayland-server-xdg-decoration-unstable-v1.h" + +namespace KWaylandServer +{ + +class XdgDecorationManagerV1InterfacePrivate : public QtWaylandServer::zxdg_decoration_manager_v1 +{ +public: + XdgDecorationManagerV1InterfacePrivate(XdgDecorationManagerV1Interface *manager); + + XdgDecorationManagerV1Interface *q; + +protected: + void zxdg_decoration_manager_v1_destroy(Resource *resource) override; + void zxdg_decoration_manager_v1_get_toplevel_decoration(Resource *resource, uint32_t id, ::wl_resource *toplevel) override; +}; + +class XdgToplevelDecorationV1InterfacePrivate : public QtWaylandServer::zxdg_toplevel_decoration_v1 +{ +public: + XdgToplevelDecorationV1InterfacePrivate(XdgToplevelDecorationV1Interface *decoration); + + XdgToplevelDecorationV1Interface *q; + XdgToplevelInterface *toplevel; + XdgToplevelDecorationV1Interface::Mode preferredMode = XdgToplevelDecorationV1Interface::Mode::Undefined; + +protected: + void zxdg_toplevel_decoration_v1_destroy_resource(Resource *resource) override; + void zxdg_toplevel_decoration_v1_destroy(Resource *resource) override; + void zxdg_toplevel_decoration_v1_set_mode(Resource *resource, uint32_t mode) override; + void zxdg_toplevel_decoration_v1_unset_mode(Resource *resource) override; +}; + +} // namespace KWaylandServer diff --git a/src/wayland/xdgshell_interface.cpp b/src/wayland/xdgshell_interface.cpp index 032f436b07..22b09b7d5e 100644 --- a/src/wayland/xdgshell_interface.cpp +++ b/src/wayland/xdgshell_interface.cpp @@ -1,280 +1,947 @@ /* - SPDX-FileCopyrightText: 2016 Martin Gräßlin + SPDX-FileCopyrightText: 2020 Vlad Zahorodnii SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ + +#include "xdgshell_interface.h" #include "xdgshell_interface_p.h" +#include "display.h" +#include "output_interface.h" +#include "seat_interface.h" + +#include + namespace KWaylandServer { -XdgShellInterface::Private::Private(XdgShellInterfaceVersion interfaceVersion, XdgShellInterface *q, Display *d, const wl_interface *interface, quint32 version) - : Global::Private(d, interface, version) - , interfaceVersion(interfaceVersion) - , q(q) +// TODO: Reset the surface when it becomes unmapped. + +XdgShellInterfacePrivate::XdgShellInterfacePrivate(XdgShellInterface *shell) + : q(shell) { } -void XdgShellInterface::Private::setupTimer(quint32 serial) +static wl_client *clientFromXdgSurface(XdgSurfaceInterface *surface) { - QTimer *pingTimer = new QTimer(); - pingTimer->setSingleShot(false); - pingTimer->setInterval(1000); - int attempt = 0; - connect(pingTimer, &QTimer::timeout, q, [this, serial, attempt]() mutable { + return XdgSurfaceInterfacePrivate::get(surface)->resource()->client(); +} + +void XdgShellInterfacePrivate::registerXdgSurface(XdgSurfaceInterface *surface) +{ + xdgSurfaces.insert(clientFromXdgSurface(surface), surface); +} + +void XdgShellInterfacePrivate::unregisterXdgSurface(XdgSurfaceInterface *surface) +{ + xdgSurfaces.remove(clientFromXdgSurface(surface), surface); +} + +/** + * @todo Whether the ping is delayed or has timed out is out of domain of the XdgShellInterface. + * Such matter must be handled somewhere else, e.g. XdgToplevelClient, not here! + */ +void XdgShellInterfacePrivate::registerPing(quint32 serial) +{ + QTimer *timer = new QTimer(q); + timer->setInterval(1000); + QObject::connect(timer, &QTimer::timeout, q, [this, serial, attempt = 0]() mutable { ++attempt; if (attempt == 1) { emit q->pingDelayed(serial); - } else { - emit q->pingTimeout(serial); - auto timerIt = pingTimers.find(serial); - if (timerIt != pingTimers.end()) { - delete timerIt.value(); - pingTimers.erase(timerIt); - } + return; } + emit q->pingTimeout(serial); + delete pings.take(serial); }); - - pingTimers.insert(serial, pingTimer); - pingTimer->start(); + pings.insert(serial, timer); + timer->start(); } -XdgShellInterface::XdgShellInterface(Private *d, QObject *parent) - : Global(d, parent) +XdgShellInterfacePrivate *XdgShellInterfacePrivate::get(XdgShellInterface *shell) +{ + return shell->d.data(); +} + +void XdgShellInterfacePrivate::xdg_wm_base_destroy(Resource *resource) +{ + if (xdgSurfaces.contains(resource->client())) { + wl_resource_post_error(resource->handle, error_defunct_surfaces, + "xdg_wm_base was destroyed before children"); + return; + } + wl_resource_destroy(resource->handle); +} + +void XdgShellInterfacePrivate::xdg_wm_base_create_positioner(Resource *resource, uint32_t id) +{ + wl_resource *positionerResource = wl_resource_create(resource->client(), &xdg_positioner_interface, + resource->version(), id); + new XdgPositionerPrivate(positionerResource); +} + +void XdgShellInterfacePrivate::xdg_wm_base_get_xdg_surface(Resource *resource, uint32_t id, + ::wl_resource *surfaceResource) +{ + SurfaceInterface *surface = SurfaceInterface::get(surfaceResource); + + if (surface->buffer()) { + wl_resource_post_error(resource->handle, XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER, + "xdg_surface must not have a buffer at creation"); + return; + } + + wl_resource *xdgSurfaceResource = wl_resource_create(resource->client(), &xdg_surface_interface, + resource->version(), id); + + XdgSurfaceInterface *xdgSurface = new XdgSurfaceInterface(q, surface, xdgSurfaceResource); + registerXdgSurface(xdgSurface); +} + +void XdgShellInterfacePrivate::xdg_wm_base_pong(Resource *resource, uint32_t serial) +{ + Q_UNUSED(resource) + if (QTimer *timer = pings.take(serial)) { + delete timer; + emit q->pongReceived(serial); + } +} + +XdgShellInterface::XdgShellInterface(Display *display, QObject *parent) + : QObject(parent) + , d(new XdgShellInterfacePrivate(this)) +{ + d->display = display; + d->init(*display, 1); +} + +XdgShellInterface::~XdgShellInterface() { } -XdgShellInterface::~XdgShellInterface() = default; - -XdgShellSurfaceInterface *XdgShellInterface::getSurface(wl_resource *native) +Display *XdgShellInterface::display() const { - Q_UNUSED(native) + return d->display; +} + +quint32 XdgShellInterface::ping(XdgSurfaceInterface *surface) +{ + ::wl_client *client = clientFromXdgSurface(surface); + + XdgShellInterfacePrivate::Resource *clientResource = d->resourceMap().value(client); + if (!clientResource) + return 0; + + quint32 serial = d->display->nextSerial(); + d->send_ping(clientResource->handle, serial); + d->registerPing(serial); + + return serial; +} + +XdgSurfaceInterfacePrivate::XdgSurfaceInterfacePrivate(XdgSurfaceInterface *xdgSurface) + : q(xdgSurface) +{ +} + +void XdgSurfaceInterfacePrivate::commit() +{ + if (current.windowGeometry != next.windowGeometry) { + current.windowGeometry = next.windowGeometry; + emit q->windowGeometryChanged(current.windowGeometry); + } +} + +XdgSurfaceInterfacePrivate *XdgSurfaceInterfacePrivate::get(XdgSurfaceInterface *surface) +{ + return surface->d.data(); +} + +void XdgSurfaceInterfacePrivate::xdg_surface_destroy_resource(Resource *resource) +{ + Q_UNUSED(resource) + XdgShellInterfacePrivate::get(shell)->unregisterXdgSurface(q); + delete q; +} + +void XdgSurfaceInterfacePrivate::xdg_surface_destroy(Resource *resource) +{ + if (toplevel || popup) { + qWarning() << "Tried to destroy xdg_surface before its role object"; + } + wl_resource_destroy(resource->handle); +} + +void XdgSurfaceInterfacePrivate::xdg_surface_get_toplevel(Resource *resource, uint32_t id) +{ + if (SurfaceRole::get(surface)) { + wl_resource_post_error(resource->handle, error_already_constructed, + "xdg_surface has already been constructured"); + return; + } + + wl_resource *toplevelResource = wl_resource_create(resource->client(), &xdg_toplevel_interface, + resource->version(), id); + + toplevel = new XdgToplevelInterface(q, toplevelResource); + emit shell->toplevelCreated(toplevel); +} + +void XdgSurfaceInterfacePrivate::xdg_surface_get_popup(Resource *resource, uint32_t id, + ::wl_resource *parentResource, + ::wl_resource *positionerResource) +{ + if (SurfaceRole::get(surface)) { + wl_resource_post_error(resource->handle, error_already_constructed, + "xdg_surface has already been constructured"); + return; + } + + XdgPositioner positioner = XdgPositioner::get(positionerResource); + if (!positioner.isComplete()) { + wl_resource_post_error(resource->handle, QtWaylandServer::xdg_wm_base::error_invalid_positioner, + "xdg_positioner is incomplete"); + return; + } + + // Notice that the parent surface may be null, in which case it must be specified via + // "some other protocol", before committing the initial state. However, we don't have + // support for any such protocol right now. + XdgSurfaceInterface *parentSurface = XdgSurfaceInterface::get(parentResource); + if (!parentSurface) { + wl_resource_post_error(resource->handle, -1, "parent surface is not set"); + return; + } + + wl_resource *popupResource = wl_resource_create(resource->client(), &xdg_popup_interface, + resource->version(), id); + + popup = new XdgPopupInterface(q, parentSurface, positioner, popupResource); + emit shell->popupCreated(popup); +} + +void XdgSurfaceInterfacePrivate::xdg_surface_set_window_geometry(Resource *resource, + int32_t x, int32_t y, + int32_t width, int32_t height) +{ + if (!toplevel && !popup) { + wl_resource_post_error(resource->handle, error_not_constructed, + "xdg_surface must have a role"); + return; + } + + if (width < 1 || height < 1) { + wl_resource_post_error(resource->handle, -1, "invalid window geometry size"); + return; + } + + next.windowGeometry = QRect(x, y, width, height); +} + +void XdgSurfaceInterfacePrivate::xdg_surface_ack_configure(Resource *resource, uint32_t serial) +{ + Q_UNUSED(resource) + emit q->configureAcknowledged(serial); +} + +XdgSurfaceInterface::XdgSurfaceInterface(XdgShellInterface *shell, SurfaceInterface *surface, + ::wl_resource *resource) + : d(new XdgSurfaceInterfacePrivate(this)) +{ + d->shell = shell; + d->surface = surface; + d->init(resource); +} + +XdgSurfaceInterface::~XdgSurfaceInterface() +{ +} + +XdgToplevelInterface *XdgSurfaceInterface::toplevel() const +{ + return d->toplevel; +} + +XdgPopupInterface *XdgSurfaceInterface::popup() const +{ + return d->popup; +} + +XdgShellInterface *XdgSurfaceInterface::shell() const +{ + return d->shell; +} + +SurfaceInterface *XdgSurfaceInterface::surface() const +{ + return d->surface; +} + +bool XdgSurfaceInterface::isConfigured() const +{ + return d->isConfigured; +} + +QRect XdgSurfaceInterface::windowGeometry() const +{ + return d->current.windowGeometry; +} + +XdgSurfaceInterface *XdgSurfaceInterface::get(::wl_resource *resource) +{ + if (auto surface = QtWaylandServer::xdg_surface::Resource::fromResource(resource)) + return static_cast(surface->object())->q; return nullptr; } -XdgShellInterfaceVersion XdgShellInterface::interfaceVersion() const -{ - Q_D(); - return d->interfaceVersion; -} - -quint32 XdgShellInterface::ping(XdgShellSurfaceInterface * surface) -{ - return d_func()->ping(surface); -} - -XdgShellInterface::Private *XdgShellInterface::d_func() const -{ - return reinterpret_cast(d.data()); -} - -XdgShellSurfaceInterface::Private::Private(XdgShellInterfaceVersion interfaceVersion, XdgShellSurfaceInterface *q, Global *c, SurfaceInterface *surface, wl_resource *parentResource, const wl_interface *interface, const void *implementation) - : Resource::Private(q, c, parentResource, interface, implementation) - , GenericShellSurface(q, surface) - , interfaceVersion(interfaceVersion) +XdgToplevelInterfacePrivate::XdgToplevelInterfacePrivate(XdgToplevelInterface *toplevel, + XdgSurfaceInterface *surface) + : SurfaceRole(surface->surface()) + , q(toplevel) + , xdgSurface(surface) { } -XdgShellSurfaceInterface::Private::~Private() = default; +void XdgToplevelInterfacePrivate::commit() +{ + auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface); -XdgShellSurfaceInterface::XdgShellSurfaceInterface(Private *p) - : Resource(p) + if (xdgSurfacePrivate->isConfigured) { + xdgSurfacePrivate->commit(); + } else { + emit q->initializeRequested(); + return; + } + + if (current.minimumSize != next.minimumSize) { + current.minimumSize = next.minimumSize; + emit q->minimumSizeChanged(current.minimumSize); + } + if (current.maximumSize != next.maximumSize) { + current.maximumSize = next.maximumSize; + emit q->maximumSizeChanged(current.maximumSize); + } +} + +void XdgToplevelInterfacePrivate::xdg_toplevel_destroy_resource(Resource *resource) +{ + Q_UNUSED(resource) + delete q; +} + +void XdgToplevelInterfacePrivate::xdg_toplevel_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +void XdgToplevelInterfacePrivate::xdg_toplevel_set_parent(Resource *resource, + ::wl_resource *parentResource) +{ + Q_UNUSED(resource) + XdgToplevelInterface *parent = XdgToplevelInterface::get(parentResource); + if (parentXdgToplevel == parent) { + return; + } + parentXdgToplevel = parent; + emit q->parentXdgToplevelChanged(); +} + +void XdgToplevelInterfacePrivate::xdg_toplevel_set_title(Resource *resource, const QString &title) +{ + Q_UNUSED(resource) + if (windowTitle == title) { + return; + } + windowTitle = title; + emit q->windowTitleChanged(title); +} + +void XdgToplevelInterfacePrivate::xdg_toplevel_set_app_id(Resource *resource, const QString &app_id) +{ + Q_UNUSED(resource) + if (windowClass == app_id) { + return; + } + windowClass = app_id; + emit q->windowClassChanged(app_id); +} + +void XdgToplevelInterfacePrivate::xdg_toplevel_show_window_menu(Resource *resource, ::wl_resource *seatResource, + uint32_t serial, int32_t x, int32_t y) +{ + auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface); + + if (!xdgSurfacePrivate->isConfigured) { + wl_resource_post_error(resource->handle, QtWaylandServer::xdg_surface::error_not_constructed, + "surface has not been configured yet"); + return; + } + + SeatInterface *seat = SeatInterface::get(seatResource); + emit q->windowMenuRequested(seat, QPoint(x, y), serial); +} + +void XdgToplevelInterfacePrivate::xdg_toplevel_move(Resource *resource, ::wl_resource *seatResource, uint32_t serial) +{ + auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface); + + if (!xdgSurfacePrivate->isConfigured) { + wl_resource_post_error(resource->handle, QtWaylandServer::xdg_surface::error_not_constructed, + "surface has not been configured yet"); + return; + } + + SeatInterface *seat = SeatInterface::get(seatResource); + emit q->moveRequested(seat, serial); +} + +void XdgToplevelInterfacePrivate::xdg_toplevel_resize(Resource *resource, ::wl_resource *seatResource, + uint32_t serial, uint32_t xdgEdges) +{ + auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface); + + if (!xdgSurfacePrivate->isConfigured) { + wl_resource_post_error(resource->handle, QtWaylandServer::xdg_surface::error_not_constructed, + "surface has not been configured yet"); + return; + } + + SeatInterface *seat = SeatInterface::get(seatResource); + + Qt::Edges edges; + if (xdgEdges & XDG_TOPLEVEL_RESIZE_EDGE_TOP) { + edges |= Qt::TopEdge; + } + if (xdgEdges & XDG_TOPLEVEL_RESIZE_EDGE_RIGHT) { + edges |= Qt::RightEdge; + } + if (xdgEdges & XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM) { + edges |= Qt::BottomEdge; + } + if (xdgEdges & XDG_TOPLEVEL_RESIZE_EDGE_LEFT) { + edges |= Qt::LeftEdge; + } + + emit q->resizeRequested(seat, edges, serial); +} + +void XdgToplevelInterfacePrivate::xdg_toplevel_set_max_size(Resource *resource, int32_t width, int32_t height) +{ + if (width < 0 || height < 0) { + wl_resource_post_error(resource->handle, -1, "width and height must be positive or zero"); + return; + } + next.maximumSize = QSize(width, height); +} + +void XdgToplevelInterfacePrivate::xdg_toplevel_set_min_size(Resource *resource, int32_t width, int32_t height) +{ + if (width < 0 || height < 0) { + wl_resource_post_error(resource->handle, -1, "width and height must be positive or zero"); + return; + } + next.minimumSize = QSize(width, height); +} + +void XdgToplevelInterfacePrivate::xdg_toplevel_set_maximized(Resource *resource) +{ + Q_UNUSED(resource) + emit q->maximizeRequested(); +} + +void XdgToplevelInterfacePrivate::xdg_toplevel_unset_maximized(Resource *resource) +{ + Q_UNUSED(resource) + emit q->unmaximizeRequested(); +} + +void XdgToplevelInterfacePrivate::xdg_toplevel_set_fullscreen(Resource *resource, ::wl_resource *outputResource) +{ + Q_UNUSED(resource) + OutputInterface *output = OutputInterface::get(outputResource); + emit q->fullscreenRequested(output); +} + +void XdgToplevelInterfacePrivate::xdg_toplevel_unset_fullscreen(Resource *resource) +{ + Q_UNUSED(resource) + emit q->unfullscreenRequested(); +} + +void XdgToplevelInterfacePrivate::xdg_toplevel_set_minimized(Resource *resource) +{ + Q_UNUSED(resource) + emit q->minimizeRequested(); +} + +XdgToplevelInterfacePrivate *XdgToplevelInterfacePrivate::get(XdgToplevelInterface *toplevel) +{ + return toplevel->d.data(); +} + +XdgToplevelInterfacePrivate *XdgToplevelInterfacePrivate::get(wl_resource *resource) +{ + if (auto toplevel = QtWaylandServer::xdg_toplevel::Resource::fromResource(resource)) + return static_cast(toplevel->object()); + return nullptr; +} + +XdgToplevelInterface::XdgToplevelInterface(XdgSurfaceInterface *surface, ::wl_resource *resource) + : d(new XdgToplevelInterfacePrivate(this, surface)) +{ + d->init(resource); +} + +XdgToplevelInterface::~XdgToplevelInterface() { } -XdgShellSurfaceInterface::~XdgShellSurfaceInterface() = default; - -XdgShellInterfaceVersion XdgShellSurfaceInterface::interfaceVersion() const +XdgShellInterface *XdgToplevelInterface::shell() const { - Q_D(); - return d->interfaceVersion; + return d->xdgSurface->shell(); } -quint32 XdgShellSurfaceInterface::configure(States states, const QSize &size) +XdgSurfaceInterface *XdgToplevelInterface::xdgSurface() const { - Q_D(); - return d->configure(states, size); + return d->xdgSurface; } -bool XdgShellSurfaceInterface::isConfigurePending() const +SurfaceInterface *XdgToplevelInterface::surface() const { - Q_D(); - return !d->configureSerials.isEmpty(); + return d->xdgSurface->surface(); } -SurfaceInterface *XdgShellSurfaceInterface::surface() const +bool XdgToplevelInterface::isConfigured() const { - Q_D(); - return d->surface; + return d->xdgSurface->isConfigured(); } -QString XdgShellSurfaceInterface::title() const +XdgToplevelInterface *XdgToplevelInterface::parentXdgToplevel() const { - Q_D(); - return d->title; + return d->parentXdgToplevel; } -QByteArray XdgShellSurfaceInterface::windowClass() const +QString XdgToplevelInterface::windowTitle() const +{ + return d->windowTitle; +} + +QString XdgToplevelInterface::windowClass() const { - Q_D(); return d->windowClass; } -bool XdgShellSurfaceInterface::isTransient() const +QSize XdgToplevelInterface::minimumSize() const { - Q_D(); - return !d->parent.isNull(); + return d->current.minimumSize.isEmpty() ? QSize(0, 0) : d->current.minimumSize; } -QPointer XdgShellSurfaceInterface::transientFor() const +QSize XdgToplevelInterface::maximumSize() const { - Q_D(); - return d->parent; + return d->current.maximumSize.isEmpty() ? QSize(INT_MAX, INT_MAX) : d->current.maximumSize; } -void XdgShellSurfaceInterface::close() +quint32 XdgToplevelInterface::sendConfigure(const QSize &size, const States &states) { - Q_D(); - d->close(); -} + // Note that the states listed in the configure event must be an array of uint32_t. -QRect XdgShellSurfaceInterface::windowGeometry() const -{ - Q_D(); - return d->windowGeometry(); -} + uint32_t statesData[4] = { 0 }; + int i = 0; -QSize XdgShellSurfaceInterface::minimumSize() const -{ - Q_D(); - return d->minimumSize(); -} - -QSize XdgShellSurfaceInterface::maximumSize() const -{ - Q_D(); - return d->maximumSize(); -} - -XdgShellSurfaceInterface::Private *XdgShellSurfaceInterface::d_func() const -{ - return reinterpret_cast(d.data()); -} - -XdgShellPopupInterface::Private::Private(XdgShellInterfaceVersion interfaceVersion, XdgShellPopupInterface *q, XdgShellInterface *c, SurfaceInterface *surface, wl_resource *parentResource, const wl_interface *interface, const void *implementation) - : Resource::Private(q, c, parentResource, interface, implementation) - , GenericShellSurface(q, surface) - , interfaceVersion(interfaceVersion) -{ -} - -XdgShellPopupInterface::Private::~Private() = default; - -XdgShellPopupInterface::XdgShellPopupInterface(Private *p) - : Resource(p) -{ -} - -XdgShellPopupInterface::~XdgShellPopupInterface() = default; - -SurfaceInterface *XdgShellPopupInterface::surface() const -{ - Q_D(); - return d->surface; -} - -QPointer XdgShellPopupInterface::transientFor() const -{ - Q_D(); - return d->parent; -} - -QSize XdgShellPopupInterface::initialSize() const -{ - Q_D(); - return d->initialSize; -} - -QPoint XdgShellPopupInterface::transientOffset() const -{ - QRect rect = anchorRect(); - const QPoint center = rect.isEmpty() ? rect.topLeft() : rect.center(); - rect = rect.adjusted(0,0,1,1); //compensate for the stupid QRect::right +1 fiasco - - switch(anchorEdge()) { - case Qt::TopEdge | Qt::LeftEdge: - return rect.topLeft(); - case Qt::TopEdge: - return QPoint(center.x(), rect.y()); - case Qt::TopEdge | Qt::RightEdge: - return rect.topRight(); - case Qt::RightEdge: - return QPoint(rect.right(), center.y()); - case Qt::BottomEdge | Qt::RightEdge: - return rect.bottomRight(); - case Qt::BottomEdge: - return QPoint(center.x(), rect.bottom()); - case Qt::BottomEdge | Qt::LeftEdge: - return rect.bottomLeft(); - case Qt::LeftEdge: - return QPoint(rect.left(), center.y()); - default: - return center; + if (states & State::MaximizedHorizontal && states & State::MaximizedVertical) { + statesData[i++] = QtWaylandServer::xdg_toplevel::state_maximized; } - Q_UNREACHABLE(); + if (states & State::FullScreen) { + statesData[i++] = QtWaylandServer::xdg_toplevel::state_fullscreen; + } + if (states & State::Resizing) { + statesData[i++] = QtWaylandServer::xdg_toplevel::state_resizing; + } + if (states & State::Activated) { + statesData[i++] = QtWaylandServer::xdg_toplevel::state_activated; + } + + const QByteArray xdgStates = QByteArray::fromRawData(reinterpret_cast(statesData), + sizeof(uint32_t) * i); + const quint32 serial = xdgSurface()->shell()->display()->nextSerial(); + + d->send_configure(size.width(), size.height(), xdgStates); + + auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface()); + xdgSurfacePrivate->send_configure(serial); + xdgSurfacePrivate->isConfigured = true; + + return serial; } -QRect XdgShellPopupInterface::anchorRect() const +void XdgToplevelInterface::sendClose() +{ + d->send_close(); +} + +XdgToplevelInterface *XdgToplevelInterface::get(::wl_resource *resource) +{ + if (auto toplevel = QtWaylandServer::xdg_toplevel::Resource::fromResource(resource)) { + return static_cast(toplevel->object())->q; + } + return nullptr; +} + +XdgPopupInterfacePrivate::XdgPopupInterfacePrivate(XdgPopupInterface *popup, + XdgSurfaceInterface *surface) + : SurfaceRole(surface->surface()) + , q(popup) + , xdgSurface(surface) +{ +} + +void XdgPopupInterfacePrivate::commit() +{ + auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface); + + if (xdgSurfacePrivate->isConfigured) { + xdgSurfacePrivate->commit(); + } else { + emit q->initializeRequested(); + } +} + +void XdgPopupInterfacePrivate::xdg_popup_destroy_resource(Resource *resource) +{ + Q_UNUSED(resource) + delete q; +} + +void XdgPopupInterfacePrivate::xdg_popup_destroy(Resource *resource) +{ + // TODO: We need to post an error with the code XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP if + // this popup is not the topmost grabbing popup. We most likely need a grab abstraction or + // something to determine whether the given popup has an explicit grab. + wl_resource_destroy(resource->handle); +} + +void XdgPopupInterfacePrivate::xdg_popup_grab(Resource *resource, ::wl_resource *seatHandle, uint32_t serial) +{ + if (xdgSurface->surface()->buffer()) { + wl_resource_post_error(resource->handle, error_invalid_grab, + "xdg_surface is already mapped"); + return; + } + SeatInterface *seat = SeatInterface::get(seatHandle); + emit q->grabRequested(seat, serial); +} + +XdgPopupInterface::XdgPopupInterface(XdgSurfaceInterface *surface, + XdgSurfaceInterface *parentSurface, + const XdgPositioner &positioner, + ::wl_resource *resource) + : d(new XdgPopupInterfacePrivate(this, surface)) +{ + d->parentXdgSurface = parentSurface; + d->positioner = positioner; + d->init(resource); +} + +XdgPopupInterface::~XdgPopupInterface() +{ +} + +XdgSurfaceInterface *XdgPopupInterface::parentXdgSurface() const +{ + return d->parentXdgSurface; +} + +XdgSurfaceInterface *XdgPopupInterface::xdgSurface() const +{ + return d->xdgSurface; +} + +SurfaceInterface *XdgPopupInterface::surface() const +{ + return d->xdgSurface->surface(); +} + +bool XdgPopupInterface::isConfigured() const +{ + return d->xdgSurface->isConfigured(); +} + +XdgPositioner XdgPopupInterface::positioner() const +{ + return d->positioner; +} + +quint32 XdgPopupInterface::sendConfigure(const QRect &rect) +{ + const quint32 serial = xdgSurface()->shell()->display()->nextSerial(); + + d->send_configure(rect.x(), rect.y(), rect.width(), rect.height()); + + auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface()); + xdgSurfacePrivate->send_configure(serial); + xdgSurfacePrivate->isConfigured = true; + + return serial; +} + +void XdgPopupInterface::sendPopupDone() +{ + d->send_popup_done(); +} + +XdgPopupInterface *XdgPopupInterface::get(::wl_resource *resource) +{ + if (auto popup = QtWaylandServer::xdg_popup::Resource::fromResource(resource)) + return static_cast(popup->object())->q; + return nullptr; +} + +XdgPositionerPrivate::XdgPositionerPrivate(::wl_resource *resource) + : data(new XdgPositionerData) +{ + init(resource); +} + +XdgPositionerPrivate *XdgPositionerPrivate::get(wl_resource *resource) +{ + if (auto positioner = QtWaylandServer::xdg_positioner::Resource::fromResource(resource)) + return static_cast(positioner->object()); + return nullptr; +} + +void XdgPositionerPrivate::xdg_positioner_destroy_resource(Resource *resource) +{ + Q_UNUSED(resource) + delete this; +} + +void XdgPositionerPrivate::xdg_positioner_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +void XdgPositionerPrivate::xdg_positioner_set_size(Resource *resource, int32_t width, int32_t height) +{ + if (width < 1 || height < 1) { + wl_resource_post_error(resource->handle, error_invalid_input, + "width and height must be positive and non-zero"); + return; + } + data->size = QSize(width, height); +} + +void XdgPositionerPrivate::xdg_positioner_set_anchor_rect(Resource *resource, int32_t x, int32_t y, + int32_t width, int32_t height) +{ + if (width < 1 || height < 1) { + wl_resource_post_error(resource->handle, error_invalid_input, + "width and height must be positive and non-zero"); + return; + } + data->anchorRect = QRect(x, y, width, height); +} + +void XdgPositionerPrivate::xdg_positioner_set_anchor(Resource *resource, uint32_t anchor) +{ + if (anchor > anchor_bottom_right) { + wl_resource_post_error(resource->handle, error_invalid_input, "unknown anchor point"); + return; + } + + switch (anchor) { + case anchor_top: + data->anchorEdges = Qt::TopEdge; + break; + case anchor_top_right: + data->anchorEdges = Qt::TopEdge | Qt::RightEdge; + break; + case anchor_right: + data->anchorEdges = Qt::RightEdge; + break; + case anchor_bottom_right: + data->anchorEdges = Qt::BottomEdge | Qt::RightEdge; + break; + case anchor_bottom: + data->anchorEdges = Qt::BottomEdge; + break; + case anchor_bottom_left: + data->anchorEdges = Qt::BottomEdge | Qt::LeftEdge; + break; + case anchor_left: + data->anchorEdges = Qt::LeftEdge; + break; + case anchor_top_left: + data->anchorEdges = Qt::TopEdge | Qt::LeftEdge; + break; + default: + data->anchorEdges = Qt::Edges(); + break; + } +} + +void XdgPositionerPrivate::xdg_positioner_set_gravity(Resource *resource, uint32_t gravity) +{ + if (gravity > gravity_bottom_right) { + wl_resource_post_error(resource->handle, error_invalid_input, "unknown gravity direction"); + return; + } + + switch (gravity) { + case gravity_top: + data->gravityEdges = Qt::TopEdge; + break; + case gravity_top_right: + data->gravityEdges = Qt::TopEdge | Qt::RightEdge; + break; + case gravity_right: + data->gravityEdges = Qt::RightEdge; + break; + case gravity_bottom_right: + data->gravityEdges = Qt::BottomEdge | Qt::RightEdge; + break; + case gravity_bottom: + data->gravityEdges = Qt::BottomEdge; + break; + case gravity_bottom_left: + data->gravityEdges = Qt::BottomEdge | Qt::LeftEdge; + break; + case gravity_left: + data->gravityEdges = Qt::LeftEdge; + break; + case gravity_top_left: + data->gravityEdges = Qt::TopEdge | Qt::LeftEdge; + break; + default: + data->gravityEdges = Qt::Edges(); + break; + } +} + +void XdgPositionerPrivate::xdg_positioner_set_constraint_adjustment(Resource *resource, + uint32_t constraint_adjustment) +{ + Q_UNUSED(resource) + + if (constraint_adjustment & constraint_adjustment_flip_x) { + data->flipConstraintAdjustments |= Qt::Horizontal; + } else { + data->flipConstraintAdjustments &= ~Qt::Horizontal; + } + + if (constraint_adjustment & constraint_adjustment_flip_y) { + data->flipConstraintAdjustments |= Qt::Vertical; + } else { + data->flipConstraintAdjustments &= ~Qt::Vertical; + } + + if (constraint_adjustment & constraint_adjustment_slide_x) { + data->slideConstraintAdjustments |= Qt::Horizontal; + } else { + data->slideConstraintAdjustments &= ~Qt::Horizontal; + } + + if (constraint_adjustment & constraint_adjustment_slide_y) { + data->slideConstraintAdjustments |= Qt::Vertical; + } else { + data->slideConstraintAdjustments &= ~Qt::Vertical; + } + + if (constraint_adjustment & constraint_adjustment_resize_x) { + data->resizeConstraintAdjustments |= Qt::Horizontal; + } else { + data->resizeConstraintAdjustments &= ~Qt::Horizontal; + } + + if (constraint_adjustment & constraint_adjustment_resize_y) { + data->resizeConstraintAdjustments |= Qt::Vertical; + } else { + data->resizeConstraintAdjustments &= ~Qt::Vertical; + } +} + +void XdgPositionerPrivate::xdg_positioner_set_offset(Resource *resource, int32_t x, int32_t y) +{ + Q_UNUSED(resource) + data->offset = QPoint(x, y); +} + +XdgPositioner::XdgPositioner() + : d(new XdgPositionerData) +{ +} + +XdgPositioner::XdgPositioner(const XdgPositioner &other) + : d(other.d) +{ +} + +XdgPositioner::~XdgPositioner() +{ +} + +XdgPositioner &XdgPositioner::operator=(const XdgPositioner &other) +{ + d = other.d; + return *this; +} + +bool XdgPositioner::isComplete() const +{ + return d->size.isValid() && d->anchorRect.isValid(); +} + +Qt::Orientations XdgPositioner::slideConstraintAdjustments() const +{ + return d->slideConstraintAdjustments; +} + +Qt::Orientations XdgPositioner::flipConstraintAdjustments() const +{ + return d->flipConstraintAdjustments; +} + +Qt::Orientations XdgPositioner::resizeConstraintAdjustments() const +{ + return d->resizeConstraintAdjustments; +} + +Qt::Edges XdgPositioner::anchorEdges() const +{ + return d->anchorEdges; +} + +Qt::Edges XdgPositioner::gravityEdges() const +{ + return d->gravityEdges; +} + +QSize XdgPositioner::size() const +{ + return d->size; +} + +QRect XdgPositioner::anchorRect() const { - Q_D(); return d->anchorRect; } -Qt::Edges XdgShellPopupInterface::anchorEdge() const +QPoint XdgPositioner::offset() const { - Q_D(); - return d->anchorEdge; + return d->offset; } -Qt::Edges XdgShellPopupInterface::gravity() const +XdgPositioner XdgPositioner::get(::wl_resource *resource) { - Q_D(); - return d->gravity; + XdgPositionerPrivate *xdgPositionerPrivate = XdgPositionerPrivate::get(resource); + if (xdgPositionerPrivate) + return XdgPositioner(xdgPositionerPrivate->data); + return XdgPositioner(); } -QPoint XdgShellPopupInterface::anchorOffset() const +XdgPositioner::XdgPositioner(const QSharedDataPointer &data) + : d(data) { - Q_D(); - return d->anchorOffset; } -PositionerConstraints XdgShellPopupInterface::constraintAdjustments() const -{ - Q_D(); - return d->constraintAdjustments; -} - -QRect XdgShellPopupInterface::windowGeometry() const -{ - Q_D(); - return d->windowGeometry(); -} - -void XdgShellPopupInterface::popupDone() -{ - Q_D(); - return d->popupDone(); -} - -quint32 XdgShellPopupInterface::configure(const QRect &rect) -{ - Q_D(); - return d->configure(rect); -} - -XdgShellPopupInterface::Private *XdgShellPopupInterface::d_func() const -{ - return reinterpret_cast(d.data()); -} - -} +} // namespace KWaylandServer diff --git a/src/wayland/xdgshell_interface.h b/src/wayland/xdgshell_interface.h index f5d47ae250..05eccba3f3 100644 --- a/src/wayland/xdgshell_interface.h +++ b/src/wayland/xdgshell_interface.h @@ -1,509 +1,533 @@ /* - SPDX-FileCopyrightText: 2016 Martin Gräßlin + SPDX-FileCopyrightText: 2020 Vlad Zahorodnii SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ -#ifndef KWAYLAND_SERVER_XDGSHELL_INTERFACE_H -#define KWAYLAND_SERVER_XDGSHELL_INTERFACE_H -#include "global.h" -#include "resource.h" - -#include +#pragma once #include +#include +#include + +struct wl_resource; + namespace KWaylandServer { +class Display; class OutputInterface; class SeatInterface; class SurfaceInterface; -class XdgShellPopupInterface; -class XdgShellSurfaceInterface; -template -class GenericShellSurface; +class XdgShellInterfacePrivate; +class XdgSurfaceInterfacePrivate; +class XdgToplevelInterfacePrivate; +class XdgPopupInterfacePrivate; +class XdgPositionerData; +class XdgToplevelInterface; +class XdgPopupInterface; +class XdgSurfaceInterface; /** - * Enum describing the different InterfaceVersion encapsulated in this implementation. + * The XdgShellInterface class represents an extension for destrop-style user interfaces. * - * @since 5.25 - **/ -enum class XdgShellInterfaceVersion -{ - /** - * xdg_shell (unstable v5) - **/ - UnstableV5, - /** - * zxdg_shell_v6 (unstable v6) - * @since 5.39 - **/ - UnstableV6, - /** - xdg_wm_base (stable) - @since 5.48 - */ - Stable -}; - -/** - * Flags describing how a popup should be reposition if constrained - * @since 5.39 + * The XdgShellInterface class provides a way for a client to extend a regular Wayland surface + * with functionality required to construct user interface elements, e.g. toplevel windows or + * menus. + * + * XdgShellInterface corresponds to the WaylandInterface \c xdg_wm_base. + * + * \since 5.20 */ -enum class PositionerConstraint { - /** - * Slide the popup on the X axis until there is room - */ - SlideX = 1 << 0, - /** - * Slide the popup on the Y axis until there is room - */ - SlideY = 1 << 1, - /** - * Invert the anchor and gravity on the X axis - */ - FlipX = 1 << 2, - /** - * Invert the anchor and gravity on the Y axis - */ - FlipY = 1 << 3, - /** - * Resize the popup in the X axis - */ - ResizeX = 1 << 4, - /** - * Resize the popup in the Y axis - */ - ResizeY = 1 << 5 -}; - -Q_DECLARE_FLAGS(PositionerConstraints, PositionerConstraint) - -/** - * - * @since 5.25 - **/ -class KWAYLANDSERVER_EXPORT XdgShellInterface : public Global +class KWAYLANDSERVER_EXPORT XdgShellInterface : public QObject { Q_OBJECT + public: - virtual ~XdgShellInterface(); - /** - * @returns The interface version used by this XdgShellInterface - **/ - XdgShellInterfaceVersion interfaceVersion() const; - - /** - * @returns The XdgShellSurfaceInterface for the @p native resource. - **/ - //TODO KF6 make virtual - XdgShellSurfaceInterface *getSurface(wl_resource *native); - - /** - * Confirm the client is still alive and responding - * - * Will result in pong being emitted - * - * @returns unique identifier for this request - * @since 5.39 + * Constructs an XdgShellInterface object with the given wayland display \a display. */ - quint32 ping(XdgShellSurfaceInterface * surface); + XdgShellInterface(Display *display, QObject *parent = nullptr); + /** + * Destructs the XdgShellInterface object. + */ + ~XdgShellInterface() override; + + /** + * Returns the wayland display of the XdgShellInterface. + */ + Display *display() const; + + /** + * Sends a ping event to the client with the given xdg-surface \a surface. If the client + * replies to the event within a reasonable amount of time, pongReceived signal will be + * emitted. + */ + quint32 ping(XdgSurfaceInterface *surface); Q_SIGNALS: - void surfaceCreated(KWaylandServer::XdgShellSurfaceInterface *surface); + /** + * This signal is emitted when a new XdgToplevelInterface object is created. + */ + void toplevelCreated(XdgToplevelInterface *toplevel); /** - * Emitted whenever a new popup got created. - * - * A popup only gets created in response to an action on the @p seat. - * - * - * @param surface The popup xdg shell surface which got created - * @param seat The seat on which an action triggered the popup - * @param serial The serial of the action on the seat - * - * XDGV5 only - * Use both xdgPopupCreated and XdgShellPopupInterface::grabbed to cover both XDGV5 and XDGV6 - **/ - - void popupCreated(KWaylandServer::XdgShellPopupInterface *surface, KWaylandServer::SeatInterface *seat, quint32 serial); - - /* - * Emitted whenever a new popup gets created. - * - * @param surface The popup xdg shell surface which got created - * @since 5.39 + * This signal is emitted when a new XdgPopupInterface object is created. */ - void xdgPopupCreated(KWaylandServer::XdgShellPopupInterface *surface); + void popupCreated(XdgPopupInterface *popup); - /* - * Emitted in response to a ping request - * - * @param serial unique identifier for the request - * @since 5.39 + /** + * This signal is emitted when the client has responded to a ping event with serial \a serial. */ void pongReceived(quint32 serial); - /* - * Emitted when the application takes more than expected - * to answer to a ping, this will always be emitted before - * eventuallt pingTimeout gets emitted + /** + * @todo Drop this signal. * - * @param serial unique identifier for the request - * @since 5.39 - */ - void pingDelayed(quint32 serial); - - /* - * Emitted when the application doesn't answer to a ping - * and the serve gave up on it - * - * @param serial unique identifier for the request - * @since 5.39 + * This signal is emitted when the client has not responded to a ping event with serial + * \a serial within a reasonable amount of time and the compositor gave up on it. */ void pingTimeout(quint32 serial); -protected: - class Private; - explicit XdgShellInterface(Private *d, QObject *parent = nullptr); + /** + * This signal is emitted when the client has not responded to a ping event with serial + * \a serial within a reasonable amount of time. + */ + void pingDelayed(quint32 serial); private: - Private *d_func() const; + QScopedPointer d; + friend class XdgShellInterfacePrivate; }; - /** + * The XdgSurfaceInterface class provides a base set of functionality required to construct + * user interface elements. * - * @since 5.25 - **/ -class KWAYLANDSERVER_EXPORT XdgShellSurfaceInterface : public Resource + * XdgSurfaceInterface corresponds to the Wayland interface \c xdg_surface. + * + * \since 5.20 + */ +class KWAYLANDSERVER_EXPORT XdgSurfaceInterface : public QObject { Q_OBJECT + public: - virtual ~XdgShellSurfaceInterface(); + /** + * Constructs an XdgSurfaceInterface for the given \a shell and \a surface. + */ + XdgSurfaceInterface(XdgShellInterface *shell, SurfaceInterface *surface, + ::wl_resource *resource); + /** + * Destructs the XdgSurfaceInterface object. + */ + ~XdgSurfaceInterface() override; /** - * @returns The interface version used by this XdgShellSurfaceInterface - **/ - XdgShellInterfaceVersion interfaceVersion() const; - - /** - * States the Surface can be in - **/ - enum class State { - /** - * The Surface is maximized. - **/ - Maximized = 1 << 0, - /** - * The Surface is fullscreen. - **/ - Fullscreen = 1 << 1, - /** - * The Surface is currently being resized by the Compositor. - **/ - Resizing = 1 << 2, - /** - * The Surface is considered active. Does not imply keyboard focus. - **/ - Activated = 1 << 3 - }; - Q_DECLARE_FLAGS(States, State) - - /** - * Sends a configure event to the Surface. - * This tells the Surface the current @p states it is in and the @p size it should have. - * If @p size has width and height at @c 0, the Surface can choose the size. + * Returns the XdgToplevelInterface associated with this XdgSurfaceInterface. * - * The Surface acknowledges the configure event with {@link configureAcknowledged}. + * This method will return \c null if no xdg_toplevel object is associated with this surface. + */ + XdgToplevelInterface *toplevel() const; + + /** + * Returns the XdgPopupInterface associated with this XdgSurfaceInterface. * - * @param states The states the surface is in - * @param size The requested size - * @returns The serial of the configure event - * @see configureAcknowledged - * @see isConfigurePending - **/ - quint32 configure(States states, const QSize &size = QSize(0, 0)); + * This method will return \c null if no xdg_popup object is associated with this surface. + */ + XdgPopupInterface *popup() const; /** - * @returns @c true if there is a not yet acknowledged configure event. - * @see configure - * @see configureAcknowledged - **/ - bool isConfigurePending() const; + * Returns the XdgShellInterface associated with this XdgSurfaceInterface. + */ + XdgShellInterface *shell() const; /** - * @return The SurfaceInterface this XdgSurfaceV5Interface got created for. - **/ + * Returns the SurfaceInterface assigned to this XdgSurfaceInterface. + */ SurfaceInterface *surface() const; /** - * @returns The title of this surface. - * @see titleChanged - **/ - QString title() const; - QByteArray windowClass() const; + * Returns \c true if the surface has been configured; otherwise returns \c false. + */ + bool isConfigured() const; /** - * @returns Whether this Surface is a transient for another Surface, that is it has a parent. - * @see transientFor - **/ - bool isTransient() const; - /** - * @returns the parent surface if the surface is a transient for another surface - * @see isTransient - **/ - QPointer transientFor() const; - - /** - * Request the client to close the window. - **/ - void close(); - - /** - * @brief windowGeometry - * The geometry of the window within the buffer + * Returns the window geometry of the XdgSurfaceInterface. * - * If invalid, the geometry of the bufer should be used instead - * @since 5.59 + * This method will return an invalid QRect if the window geometry is not set by the client. */ QRect windowGeometry() const; /** - * @returns The minimum size for the window specified by the client. - * @since 5.65 + * Returns the XdgSurfaceInterface for the specified wayland resource object \a resource. + */ + static XdgSurfaceInterface *get(::wl_resource *resource); + +Q_SIGNALS: + /** + * This signal is emitted when a configure event with serial \a serial has been acknowledged. + */ + void configureAcknowledged(quint32 serial); + + /** + * This signal is emitted when the window geometry has been changed. + */ + void windowGeometryChanged(const QRect &rect); + +private: + QScopedPointer d; + friend class XdgSurfaceInterfacePrivate; +}; + +/** + * The XdgToplevelInterface class represents a surface with window-like functionality such + * as maximize, fullscreen, resizing, minimizing, etc. + * + * XdgToplevelInterface corresponds to the Wayland interface \c xdg_toplevel. + * + * \since 5.20 + */ +class KWAYLANDSERVER_EXPORT XdgToplevelInterface : public QObject +{ + Q_OBJECT + +public: + enum State { + MaximizedHorizontal = 0x1, + MaximizedVertical = 0x2, + FullScreen = 0x4, + Resizing = 0x8, + Activated = 0x10, + Maximized = MaximizedHorizontal | MaximizedVertical + }; + Q_DECLARE_FLAGS(States, State) + + /** + * Constructs an XdgToplevelInterface for the given xdg-surface \a surface. + */ + XdgToplevelInterface(XdgSurfaceInterface *surface, ::wl_resource *resource); + /** + * Destructs the XdgToplevelInterface object. + */ + ~XdgToplevelInterface() override; + + /** + * Returns the XdgShellInterface for this XdgToplevelInterface. + * + * This is equivalent to xdgSurface()->shell(). + */ + XdgShellInterface *shell() const; + + /** + * Returns the XdgSurfaceInterface associated with the XdgToplevelInterface. + */ + XdgSurfaceInterface *xdgSurface() const; + + /** + * Returns the SurfaceInterface associated with the XdgToplevelInterface. + */ + SurfaceInterface *surface() const; + + /** + * Returns the parent XdgToplevelInterface above which this toplevel is stacked. + */ + XdgToplevelInterface *parentXdgToplevel() const; + + /** + * Returns \c true if the toplevel has been configured; otherwise returns \c false. + */ + bool isConfigured() const; + + /** + * Returns the window title of the toplevel surface. + */ + QString windowTitle() const; + + /** + * Returns the window class of the toplevel surface. + */ + QString windowClass() const; + + /** + * Returns the minimum window geometry size of the toplevel surface. */ QSize minimumSize() const; /** - * @returns The maximum size for the window specified by the client. - * @since 5.65 + * Returns the maximum window geometry size of the toplevel surface. */ QSize maximumSize() const; + /** + * Sends a configure event to the client. \a size specifies the new window geometry size. A size + * of zero means the client should decide its own window dimensions. + */ + quint32 sendConfigure(const QSize &size, const States &states); + + /** + * Sends a close event to the client. The client may choose to ignore this request. + */ + void sendClose(); + + /** + * Returns the XdgToplevelInterface for the specified wayland resource object \a resource. + */ + static XdgToplevelInterface *get(::wl_resource *resource); + Q_SIGNALS: /** - * Emitted whenever the title changes. - * - * @see title - **/ - void titleChanged(const QString&); + * This signal is emitted when the xdg-toplevel has commited the initial state and wants to + * be configured. After initializing the toplevel, you must send a configure event. + */ + void initializeRequested(); + /** - * Emitted whenever the window class changes. - * - * @see windowClass - **/ - void windowClassChanged(const QByteArray&); + * This signal is emitted when the toplevel's title has been changed. + */ + void windowTitleChanged(const QString &windowTitle); + /** - * The surface requested a window move. - * - * @param seat The SeatInterface on which the surface requested the move - * @param serial The serial of the implicit mouse grab which triggered the move - **/ + * This signal is emitted when the toplevel's application id has been changed. + */ + void windowClassChanged(const QString &windowClass); + + /** + * This signal is emitted when the toplevel has requested the window menu to be shown at + * \a pos. The \a seat and the \a serial indicate the user action that triggerred the request. + */ + void windowMenuRequested(KWaylandServer::SeatInterface *seat, const QPoint &pos, quint32 serial); + + /** + * This signal is emitted when the toplevel's minimum size has been changed. + */ + void minimumSizeChanged(const QSize &size); + + /** + * This signal is emitted when the toplevel's maximum size has been changed. + */ + void maximumSizeChanged(const QSize &size); + + /** + * This signal is emitted when the toplevel wants to be interactively moved. The \a seat and + * the \a serial indicate the user action in response to which this request has been issued. + */ void moveRequested(KWaylandServer::SeatInterface *seat, quint32 serial); + /** - * The surface requested a window resize. - * - * @param seat The SeatInterface on which the surface requested the resize - * @param serial The serial of the implicit mouse grab which triggered the resize - * @param edges A hint which edges are involved in the resize - **/ - void resizeRequested(KWaylandServer::SeatInterface *seat, quint32 serial, Qt::Edges edges); - void windowMenuRequested(KWaylandServer::SeatInterface *seat, quint32 serial, const QPoint &surfacePos); + * This signal is emitted when the toplevel wants to be interactively resized along the + * specified window edges \a edges. The \a seat and the \a serial indicate the user action + * in response to which this request has been issued. + */ + void resizeRequested(KWaylandServer::SeatInterface *seat, Qt::Edges edges, quint32 serial); + /** - * The surface requested a change of maximized state. - * @param maximized Whether the window wants to be maximized - **/ - void maximizedChanged(bool maximized); + * This signal is emitted when the toplevel surface wants to become maximized. + */ + void maximizeRequested(); + /** - * The surface requested a change of fullscreen state - * @param fullscreen Whether the window wants to be fullscreen - * @param output An optional output hint on which the window wants to be fullscreen - **/ - void fullscreenChanged(bool fullscreen, KWaylandServer::OutputInterface *output); + * This signal is emitted when the toplevel surface wants to become unmaximized. + */ + void unmaximizeRequested(); + /** - * The surface requested to be minimized. - **/ + * This signal is emitted when the toplevel wants to be shown in the full screen mode. + */ + void fullscreenRequested(KWaylandServer::OutputInterface *output); + + /** + * This signal is emitted when the toplevel surface wants to leave the full screen mode. + */ + void unfullscreenRequested(); + + /** + * This signal is emitted when the toplevel wants to be iconified. + */ void minimizeRequested(); - /** - * A configure event with @p serial got acknowledged. - * @see configure - **/ - void configureAcknowledged(quint32 serial); - /** - * Emitted whenever the parent surface changes. - * @see isTransient - * @see transientFor - **/ - void transientForChanged(); /** - * Emitted whenever the maximum size hint changes - * @since 5.39 + * This signal is emitted when the parent toplevel has changed. */ - void maxSizeChanged(const QSize &size); - - /** - * Emitted whenever the minimum size hint changes - * @since 5.39 - */ - void minSizeChanged(const QSize &size); - - /** - * @brief windowGeometryChanged - * @param windowGeometry the newly changed windowGeometry - * @since 5.59 - */ - void windowGeometryChanged(const QRect &windowGeometry); - -protected: - class Private; - explicit XdgShellSurfaceInterface(Private *p); + void parentXdgToplevelChanged(); private: - Private *d_func() const; - friend class GenericShellSurface; + QScopedPointer d; + friend class XdgToplevelInterfacePrivate; }; /** + * The XdgPositioner class provides a collection of rules for the placement of a popup surface. * - * @since 5.25 - **/ -class KWAYLANDSERVER_EXPORT XdgShellPopupInterface : public Resource + * XdgPositioner corresponds to the Wayland interface \c xdg_positioner. + * + * \since 5.20 + */ +class KWAYLANDSERVER_EXPORT XdgPositioner { - Q_OBJECT public: - virtual ~XdgShellPopupInterface(); - /** - * @return The SurfaceInterface this XdgShellPopupInterface got created for. - **/ - SurfaceInterface *surface() const; - - /* - * Ask the popup surface to configure itself for the given configuration. - * - * @arg rect. The position of the surface relative to the transient parent - * @since 5.39 + * Constructs an incomplete XdgPositioner object. */ - quint32 configure(const QRect &rect); - + XdgPositioner(); /** - * @returns the parent surface. - * @see transientOffset - **/ - QPointer transientFor() const; - - /** - * The offset of the Surface in the coordinate system of the SurfaceInterface this surface is a transient for. - * - * For XDG V6 this returns the point on the anchorRect defined by the anchor edge. - * - * @returns offset in parent coordinate system. - * @see transientFor - **/ - QPoint transientOffset() const; - - /** - * The size of the surface that is to be positioned. - * - * @since 5.39 + * Constructs a copy of the XdgPositioner object. */ - QSize initialSize() const; + XdgPositioner(const XdgPositioner &other); + /** + * Destructs the XdgPositioner object. + */ + ~XdgPositioner(); /** - * The area this popup should be positioned around - * @since 5.39 + * Assigns the value of \a other to this XdgPositioner object. + */ + XdgPositioner &operator=(const XdgPositioner &other); + + /** + * Returns \c true if the positioner object is complete; otherwise returns \c false. + * + * An xdg positioner considered complete if it has a valid size and a valid anchor rect. + */ + bool isComplete() const; + + /** + * Returns the set of orientations along which the compositor may slide the popup to ensure + * that it is entirely inside the compositor's defined "work area." + */ + Qt::Orientations slideConstraintAdjustments() const; + + /** + * Returns the set of orientations along which the compositor may flip the popup to ensure + * that it is entirely inside the compositor's defined "work area." + */ + Qt::Orientations flipConstraintAdjustments() const; + + /** + * Returns the set of orientations along which the compositor can resize the popup to ensure + * that it is entirely inside the compositor's defined "work area." + */ + Qt::Orientations resizeConstraintAdjustments() const; + + /** + * Returns the set of edges on the anchor rectangle that the surface should be positioned + * around. + */ + Qt::Edges anchorEdges() const; + + /** + * Returns the direction in which the surface should be positioned, relative to the anchor + * point of the parent surface. + */ + Qt::Edges gravityEdges() const; + + /** + * Returns the window geometry size of the surface that is to be positioned. + */ + QSize size() const; + + /** + * Returns the anchor rectangle relative to the upper left corner of the window geometry of + * the parent surface that the popup should be positioned around. */ QRect anchorRect() const; /** - * Which edge of the anchor should the popup be positioned around - * @since 5.39 + * Returns the surface position offset relative to the position of the anchor on the anchor + * rectangle and the anchor on the surface. */ - Qt::Edges anchorEdge() const; + QPoint offset() const; /** - * An additional offset that should be applied to the popup from the anchor rect + * Returns the current state of the xdg positioner object identified by \a resource. + */ + static XdgPositioner get(::wl_resource *resource); + +private: + XdgPositioner(const QSharedDataPointer &data); + QSharedDataPointer d; +}; + +/** + * The XdgPopupInterface class represents a surface that can be used to implement context menus, + * popovers and other similar short-lived user interface elements. + * + * XdgPopupInterface corresponds to the Wayland interface \c xdg_popup. + * + * \since 5.20 + */ +class KWAYLANDSERVER_EXPORT XdgPopupInterface : public QObject +{ + Q_OBJECT + +public: + XdgPopupInterface(XdgSurfaceInterface *surface, XdgSurfaceInterface *parentSurface, + const XdgPositioner &positioner, ::wl_resource *resource); + /** + * Destructs the XdgPopupInterface object. + */ + ~XdgPopupInterface() override; + + XdgShellInterface *shell() const; + + /** + * Returns the parent XdgSurfaceInterface. * - * @since 5.39 + * This method may return \c null, in which case the parent xdg-surface must be specified + * using "some other protocol", before commiting the initial state. */ - QPoint anchorOffset() const; + XdgSurfaceInterface *parentXdgSurface() const; /** - * Specifies in what direction the popup should be positioned around the anchor - * i.e if the gravity is "bottom", then then the top of top of the popup will be at the anchor edge - * if the gravity is top, then the bottom of the popup will be at the anchor edge - * - * @since 5.39 + * Returns the XdgSurfaceInterface associated with the XdgPopupInterface. */ - - //DAVE left + right is illegal, so this is possible a useless return value? Maybe an enum with 9 entries left, topleft, top, .. - Qt::Edges gravity() const; + XdgSurfaceInterface *xdgSurface() const; /** - * Specifies how the compositor should position the popup if it does not fit in the requested position - * @since 5.39 + * Returns the SurfaceInterface associated with the XdgPopupInterface. */ - PositionerConstraints constraintAdjustments() const; + SurfaceInterface *surface() const; /** - * Dismiss this popup. This indicates to the client that it should destroy this popup. - * The Compositor can invoke this method when e.g. the user clicked outside the popup - * to dismiss it. - **/ - void popupDone(); + * Returns the XdgPositioner assigned to this XdgPopupInterface. + */ + XdgPositioner positioner() const; /** - * @brief windowGeometryChanged - * @param windowGeometry the newly changed geometry of the window contents within the buffer - * @since 5.59 + * Returns \c true if the popup has been configured; otherwise returns \c false. */ - QRect windowGeometry()const; + bool isConfigured() const; + + /** + * Sends a configure event to the client and returns the serial number of the event. + */ + quint32 sendConfigure(const QRect &rect); + + /** + * Sends a popup done event to the client. + */ + void sendPopupDone(); + + /** + * Returns the XdgPopupInterface for the specified wayland resource object \a resource. + */ + static XdgPopupInterface *get(::wl_resource *resource); Q_SIGNALS: /** - * A configure event with @p serial got acknowledged. - * Note: XdgV6 only - * @see configure - * @since 5.39 - **/ - void configureAcknowledged(quint32 serial); - - /** - * The client requested that this popup takes an explicit grab - * - * @param seat The seat on which an action triggered the popup - * @param serial The serial of the action on the seat - * @since 5.39 + * This signal is emitted when the xdg-popup has commited the initial state and wants to + * be configured. After initializing the popup, you must send a configure event. */ - void grabRequested(KWaylandServer::SeatInterface *seat, quint32 serial); - - /** - * @brief windowGeometryChanged - * @param windowGeometry the newly changed windowGeometry - * @since 5.59 - */ - void windowGeometryChanged(const QRect &windowGeometry); - -protected: - class Private; - explicit XdgShellPopupInterface(Private *p); + void initializeRequested(); + void grabRequested(SeatInterface *seat, quint32 serial); private: - friend class GenericShellSurface; - - Private *d_func() const; + QScopedPointer d; }; -} +} // namespace KWaylandServer -Q_DECLARE_METATYPE(KWaylandServer::XdgShellSurfaceInterface *) -Q_DECLARE_METATYPE(KWaylandServer::XdgShellPopupInterface *) -Q_DECLARE_METATYPE(KWaylandServer::XdgShellSurfaceInterface::State) -Q_DECLARE_METATYPE(KWaylandServer::XdgShellSurfaceInterface::States) -Q_DECLARE_OPERATORS_FOR_FLAGS(KWaylandServer::PositionerConstraints) - -#endif +Q_DECLARE_OPERATORS_FOR_FLAGS(KWaylandServer::XdgToplevelInterface::States) +Q_DECLARE_METATYPE(KWaylandServer::XdgToplevelInterface::State) +Q_DECLARE_METATYPE(KWaylandServer::XdgToplevelInterface::States) diff --git a/src/wayland/xdgshell_interface_p.h b/src/wayland/xdgshell_interface_p.h index 34f35e9750..720fe84ecd 100644 --- a/src/wayland/xdgshell_interface_p.h +++ b/src/wayland/xdgshell_interface_p.h @@ -1,94 +1,175 @@ /* - SPDX-FileCopyrightText: 2016 Martin Gräßlin + SPDX-FileCopyrightText: 2020 Vlad Zahorodnii SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ -#ifndef KWAYLAND_SERVER_XDGSHELL_INTERFACE_P_H -#define KWAYLAND_SERVER_XDGSHELL_INTERFACE_P_H -#include "xdgshell_interface.h" -#include "global_p.h" -#include "generic_shell_surface_p.h" -#include "resource_p.h" -#include +#pragma once + +#include "xdgshell_interface.h" +#include "qwayland-server-xdg-shell.h" + +#include "surface_interface.h" +#include "surfacerole_p.h" namespace KWaylandServer { -class XdgShellInterface::Private : public Global::Private +class XdgToplevelDecorationV1Interface; + +class XdgShellInterfacePrivate : public QtWaylandServer::xdg_wm_base { public: - XdgShellInterfaceVersion interfaceVersion; + XdgShellInterfacePrivate(XdgShellInterface *shell); - virtual quint32 ping(XdgShellSurfaceInterface * surface) = 0; - void setupTimer(quint32 serial); - //pingserial/timer correspondence - QHash pingTimers; + void registerXdgSurface(XdgSurfaceInterface *surface); + void unregisterXdgSurface(XdgSurfaceInterface *surface); + + void registerPing(quint32 serial); + + static XdgShellInterfacePrivate *get(XdgShellInterface *shell); -protected: - Private(XdgShellInterfaceVersion interfaceVersion, XdgShellInterface *q, Display *d, const wl_interface *interface, quint32 version); XdgShellInterface *q; -}; - -class XdgShellSurfaceInterface::Private : public Resource::Private, public GenericShellSurface -{ -public: - virtual ~Private(); - - virtual void close() = 0; - virtual quint32 configure(States states, const QSize &size) = 0; - virtual QRect windowGeometry() const = 0; - virtual QSize minimumSize() const = 0; - virtual QSize maximumSize() const = 0; - - XdgShellSurfaceInterface *q_func() { - return reinterpret_cast(q); - } - - QVector configureSerials; - QPointer parent; - XdgShellInterfaceVersion interfaceVersion; + Display *display; + QMap pings; protected: - Private(XdgShellInterfaceVersion interfaceVersion, XdgShellSurfaceInterface *q, Global *c, SurfaceInterface *surface, wl_resource *parentResource, const wl_interface *interface, const void *implementation); + void xdg_wm_base_destroy(Resource *resource) override; + void xdg_wm_base_create_positioner(Resource *resource, uint32_t id) override; + void xdg_wm_base_get_xdg_surface(Resource *resource, uint32_t id, ::wl_resource *surface) override; + void xdg_wm_base_pong(Resource *resource, uint32_t serial) override; + +private: + QMultiMap xdgSurfaces; }; -class XdgShellPopupInterface::Private : public Resource::Private, public GenericShellSurface +class XdgPositionerData : public QSharedData { public: - virtual ~Private(); - virtual void popupDone() = 0; - virtual QRect windowGeometry() const = 0; + Qt::Orientations slideConstraintAdjustments; + Qt::Orientations flipConstraintAdjustments; + Qt::Orientations resizeConstraintAdjustments; + Qt::Edges anchorEdges; + Qt::Edges gravityEdges; + QPoint offset; + QSize size; + QRect anchorRect; +}; - XdgShellPopupInterface *q_func() { - return reinterpret_cast(q); - } +class XdgPositionerPrivate : public QtWaylandServer::xdg_positioner +{ +public: + XdgPositionerPrivate(::wl_resource *resource); - virtual quint32 configure(const QRect &rect) { - Q_UNUSED(rect) - return 0; + QSharedDataPointer data; + + static XdgPositionerPrivate *get(::wl_resource *resource); + +protected: + void xdg_positioner_destroy_resource(Resource *resource) override; + void xdg_positioner_destroy(Resource *resource) override; + void xdg_positioner_set_size(Resource *resource, int32_t width, int32_t height) override; + void xdg_positioner_set_anchor_rect(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) override; + void xdg_positioner_set_anchor(Resource *resource, uint32_t anchor) override; + void xdg_positioner_set_gravity(Resource *resource, uint32_t gravity) override; + void xdg_positioner_set_constraint_adjustment(Resource *resource, uint32_t constraint_adjustment) override; + void xdg_positioner_set_offset(Resource *resource, int32_t x, int32_t y) override; +}; + +class XdgSurfaceInterfacePrivate : public QtWaylandServer::xdg_surface +{ +public: + XdgSurfaceInterfacePrivate(XdgSurfaceInterface *xdgSurface); + + void commit(); + + XdgSurfaceInterface *q; + XdgShellInterface *shell; + QPointer toplevel; + QPointer popup; + QPointer surface; + bool isConfigured = false; + + struct State + { + QRect windowGeometry; }; - QVector configureSerials; - QPointer parent; - QSize initialSize; + State next; + State current; - /* - * - */ - QRect anchorRect; - Qt::Edges anchorEdge; - Qt::Edges gravity; - PositionerConstraints constraintAdjustments; - QPoint anchorOffset; - - XdgShellInterfaceVersion interfaceVersion; + static XdgSurfaceInterfacePrivate *get(XdgSurfaceInterface *surface); protected: - Private(XdgShellInterfaceVersion interfaceVersion, XdgShellPopupInterface *q, XdgShellInterface *c, SurfaceInterface *surface, wl_resource *parentResource, const wl_interface *interface, const void *implementation); - + void xdg_surface_destroy_resource(Resource *resource) override; + void xdg_surface_destroy(Resource *resource) override; + void xdg_surface_get_toplevel(Resource *resource, uint32_t id) override; + void xdg_surface_get_popup(Resource *resource, uint32_t id, ::wl_resource *parent, ::wl_resource *positioner) override; + void xdg_surface_set_window_geometry(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) override; + void xdg_surface_ack_configure(Resource *resource, uint32_t serial) override; }; -} +class XdgToplevelInterfacePrivate : public SurfaceRole, public QtWaylandServer::xdg_toplevel +{ +public: + XdgToplevelInterfacePrivate(XdgToplevelInterface *toplevel, XdgSurfaceInterface *surface); -#endif + void commit() override; + + static XdgToplevelInterfacePrivate *get(XdgToplevelInterface *toplevel); + static XdgToplevelInterfacePrivate *get(::wl_resource *resource); + + XdgToplevelInterface *q; + QPointer parentXdgToplevel; + QPointer decoration; + XdgSurfaceInterface *xdgSurface; + + QString windowTitle; + QString windowClass; + + struct State + { + QSize minimumSize; + QSize maximumSize; + }; + + State next; + State current; + +protected: + void xdg_toplevel_destroy_resource(Resource *resource) override; + void xdg_toplevel_destroy(Resource *resource) override; + void xdg_toplevel_set_parent(Resource *resource, ::wl_resource *parent) override; + void xdg_toplevel_set_title(Resource *resource, const QString &title) override; + void xdg_toplevel_set_app_id(Resource *resource, const QString &app_id) override; + void xdg_toplevel_show_window_menu(Resource *resource, ::wl_resource *seat, uint32_t serial, int32_t x, int32_t y) override; + void xdg_toplevel_move(Resource *resource, ::wl_resource *seat, uint32_t serial) override; + void xdg_toplevel_resize(Resource *resource, ::wl_resource *seat, uint32_t serial, uint32_t edges) override; + void xdg_toplevel_set_max_size(Resource *resource, int32_t width, int32_t height) override; + void xdg_toplevel_set_min_size(Resource *resource, int32_t width, int32_t height) override; + void xdg_toplevel_set_maximized(Resource *resource) override; + void xdg_toplevel_unset_maximized(Resource *resource) override; + void xdg_toplevel_set_fullscreen(Resource *resource, ::wl_resource *output) override; + void xdg_toplevel_unset_fullscreen(Resource *resource) override; + void xdg_toplevel_set_minimized(Resource *resource) override; +}; + +class XdgPopupInterfacePrivate : public SurfaceRole, public QtWaylandServer::xdg_popup +{ +public: + XdgPopupInterfacePrivate(XdgPopupInterface *popup, XdgSurfaceInterface *surface); + + void commit() override; + + XdgPopupInterface *q; + XdgSurfaceInterface *parentXdgSurface; + XdgSurfaceInterface *xdgSurface; + XdgPositioner positioner; + +protected: + void xdg_popup_destroy_resource(Resource *resource) override; + void xdg_popup_destroy(Resource *resource) override; + void xdg_popup_grab(Resource *resource, ::wl_resource *seat, uint32_t serial) override; +}; + +} // namespace KWaylandServer