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.
This commit is contained in:
Vlad Zahorodnii 2020-05-04 16:32:23 +03:00
parent 5955d0486d
commit e3ad23ccd8
23 changed files with 1961 additions and 2845 deletions

View file

@ -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

View file

@ -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

View file

@ -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<XdgDecoration::Mode>();
qRegisterMetaType<XdgDecorationInterface::Mode>();
qRegisterMetaType<XdgToplevelDecorationV1Interface::Mode>();
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<quint32>(), compositorSpy.first().last().value<quint32>(), 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<quint32>(),
xdgShellSpy.first().last().value<quint32>(), 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<quint32>(),
@ -160,13 +156,13 @@ void TestXdgDecoration::testDecoration_data()
{
using namespace KWayland::Client;
using namespace KWaylandServer;
QTest::addColumn<KWaylandServer::XdgDecorationInterface::Mode>("configuredMode");
QTest::addColumn<KWaylandServer::XdgToplevelDecorationV1Interface::Mode>("configuredMode");
QTest::addColumn<KWayland::Client::XdgDecoration::Mode>("configuredModeExp");
QTest::addColumn<KWayland::Client::XdgDecoration::Mode>("setMode");
QTest::addColumn<KWaylandServer::XdgDecorationInterface::Mode>("setModeExp");
QTest::addColumn<KWaylandServer::XdgToplevelDecorationV1Interface::Mode>("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> 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<XdgShellSurfaceInterface*>();
auto decorationIface = decorationCreatedSpy.first().first().value<XdgDecorationInterface*>();
auto shellSurfaceIface = shellSurfaceCreatedSpy.first().first().value<XdgToplevelInterface *>();
auto decorationIface = decorationCreatedSpy.first().first().value<XdgToplevelDecorationV1Interface *>();
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<XdgDecoration::Mode>(), configuredModeExp);
@ -223,13 +218,14 @@ void TestXdgDecoration::testDecoration()
//client requesting another mode
decoration->setMode(setMode);
QVERIFY(modeRequestedSpy.wait());
QCOMPARE(modeRequestedSpy.first().first().value<XdgDecorationInterface::Mode>(), setModeExp);
QCOMPARE(decorationIface->requestedMode(), setModeExp);
QCOMPARE(modeRequestedSpy.first().first().value<XdgToplevelDecorationV1Interface::Mode>(), setModeExp);
QCOMPARE(decorationIface->preferredMode(), setModeExp);
modeRequestedSpy.clear();
decoration->unsetMode();
QVERIFY(modeRequestedSpy.wait());
QCOMPARE(modeRequestedSpy.first().first().value<XdgDecorationInterface::Mode>(), XdgDecorationInterface::Mode::Undefined);
QCOMPARE(modeRequestedSpy.first().first().value<XdgToplevelDecorationV1Interface::Mode>(),
XdgToplevelDecorationV1Interface::Mode::Undefined);
}
QTEST_GUILESS_MAIN(TestXdgDecoration)

View file

@ -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 <QtTest>
// 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> surface(m_compositor->createSurface()); \
QScopedPointer<XdgShellSurface> xdgSurface(m_xdgShell->createSurface(surface.data())); \
QCOMPARE(xdgSurface->size(), QSize()); \
QVERIFY(xdgSurfaceCreatedSpy.wait()); \
auto serverXdgToplevel = xdgSurfaceCreatedSpy.first().first().value<XdgToplevelInterface *>(); \
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(&registry, &Registry::outputAnnounced);
QVERIFY(outputAnnouncedSpy.isValid());
auto shellAnnouncedSignal = m_version == XdgShellInterfaceVersion::UnstableV5 ? &Registry::xdgShellUnstableV5Announced :
m_version == XdgShellInterfaceVersion::UnstableV6 ? &Registry::xdgShellUnstableV6Announced :
&Registry::xdgShellStableAnnounced;
QSignalSpy xdgShellAnnouncedSpy(&registry, shellAnnouncedSignal);
QSignalSpy xdgShellAnnouncedSpy(&registry, &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<XdgShellSurfaceInterface*>();
QVERIFY(serverXdgSurface);
QCOMPARE(serverXdgSurface->isConfigurePending(), false);
QCOMPARE(serverXdgSurface->title(), QString());
QCOMPARE(serverXdgSurface->windowClass(), QByteArray());
QCOMPARE(serverXdgSurface->isTransient(), false);
QCOMPARE(serverXdgSurface->transientFor(), QPointer<XdgShellSurfaceInterface>());
QCOMPARE(serverXdgSurface->surface(), serverSurface);
auto serverToplevel = xdgSurfaceCreatedSpy.first().first().value<XdgToplevelInterface *>();
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<OutputInterface*>();
// this test verifies going to/from fullscreen
QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated);
QVERIFY(xdgSurfaceCreatedSpy.isValid());
QScopedPointer<Surface> surface(m_compositor->createSurface());
QScopedPointer<XdgShellSurface> xdgSurface(m_xdgShell->createSurface(surface.data()));
QVERIFY(xdgSurfaceCreatedSpy.wait());
auto serverXdgSurface = xdgSurfaceCreatedSpy.first().first().value<XdgShellSurfaceInterface*>();
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<OutputInterface*>());
QVERIFY(fullscreenRequestedSpy.wait());
QCOMPARE(fullscreenRequestedSpy.count(), 1);
QVERIFY(!fullscreenRequestedSpy.last().at(0).value<OutputInterface*>());
// unset
xdgSurface->setFullscreen(false);
QVERIFY(fullscreenSpy.wait());
QCOMPARE(fullscreenSpy.count(), 2);
QCOMPARE(fullscreenSpy.last().at(0).toBool(), false);
QVERIFY(!fullscreenSpy.last().at(1).value<OutputInterface*>());
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<OutputInterface*>(), m_o1Interface);
QVERIFY(fullscreenRequestedSpy.wait());
QCOMPARE(fullscreenRequestedSpy.count(), 2);
QCOMPARE(fullscreenRequestedSpy.last().at(0).value<OutputInterface*>(), 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<OutputInterface*>(), m_o2Interface);
QVERIFY(fullscreenRequestedSpy.wait());
QCOMPARE(fullscreenRequestedSpy.count(), 3);
QCOMPARE(fullscreenRequestedSpy.last().at(0).value<OutputInterface*>(), 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<SeatInterface*>(), m_seatInterface);
QCOMPARE(windowMenuSpy.first().at(1).value<quint32>(), 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<quint32>(), 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<SeatInterface*>(), m_seatInterface);
QCOMPARE(resizeSpy.first().at(1).value<quint32>(), 60u);
QCOMPARE(resizeSpy.first().at(2).value<Qt::Edges>(), edges);
QCOMPARE(resizeSpy.first().at(1).value<Qt::Edges>(), edges);
QCOMPARE(resizeSpy.first().at(2).value<quint32>(), 60u);
}
void XdgShellTest::testTransient()
@ -373,30 +424,28 @@ void XdgShellTest::testTransient()
QScopedPointer<Surface> surface2(m_compositor->createSurface());
QScopedPointer<XdgShellSurface> xdgSurface2(m_xdgShell->createSurface(surface2.data()));
QVERIFY(xdgSurfaceCreatedSpy.wait());
auto serverXdgSurface2 = xdgSurfaceCreatedSpy.last().first().value<XdgShellSurfaceInterface*>();
QVERIFY(serverXdgSurface2);
auto serverXdgToplevel2 = xdgSurfaceCreatedSpy.last().first().value<XdgToplevelInterface *>();
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<quint32>(), 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<XdgShellSurfaceInterface::States>("serverStates");
QTest::addColumn<XdgToplevelInterface::States>("serverStates");
QTest::addColumn<XdgShellSurface::States>("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<XdgShellSurface::States>(), "clientStates");
QCOMPARE(configureSpy.first().at(2).value<quint32>(), m_display->serial());
QSignalSpy ackSpy(serverXdgSurface, &XdgShellSurfaceInterface::configureAcknowledged);
QSignalSpy ackSpy(serverXdgToplevel->xdgSurface(), &XdgSurfaceInterface::configureAcknowledged);
QVERIFY(ackSpy.isValid());
xdgSurface->ackConfigure(configureSpy.first().at(2).value<quint32>());
@ -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<quint32>(), serial1);
QCOMPARE(ackSpy.at(1).first().value<quint32>(), serial2);
QCOMPARE(ackSpy.at(2).first().value<quint32>(), serial3);
QCOMPARE(ackSpy.count(), 1);
QCOMPARE(ackSpy.last().first().value<quint32>(), 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"

View file

@ -1,92 +0,0 @@
/*
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
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 <QtTest>
// 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> surface(m_compositor->createSurface()); \
QScopedPointer<XdgShellSurface> xdgSurface(m_xdgShell->createSurface(surface.data())); \
QCOMPARE(xdgSurface->size(), QSize()); \
QVERIFY(xdgSurfaceCreatedSpy.wait()); \
auto serverXdgSurface = xdgSurfaceCreatedSpy.first().first().value<XdgShellSurfaceInterface*>(); \
QVERIFY(serverXdgSurface);
#endif

View file

@ -1,245 +0,0 @@
/*
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
SPDX-FileCopyrightText: 2017 David Edmundson <davidedmundson@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "test_xdg_shell.h"
#include <wayland-xdg-shell-client-protocol.h>
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<OutputInterface*>();
// this test verifies changing the window maxSize
QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated);
QVERIFY(xdgSurfaceCreatedSpy.isValid());
QScopedPointer<Surface> surface(m_compositor->createSurface());
QScopedPointer<XdgShellSurface> xdgSurface(m_xdgShell->createSurface(surface.data()));
QVERIFY(xdgSurfaceCreatedSpy.wait());
auto serverXdgSurface = xdgSurfaceCreatedSpy.first().first().value<XdgShellSurfaceInterface*>();
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>(), 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>(), QSize(200,200));
QCOMPARE(serverXdgSurface->maximumSize(), QSize(200, 200));
}
void XdgShellTestStable::testPopup_data()
{
QTest::addColumn<XdgPositioner>("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<Surface> parentSurface(m_compositor->createSurface());
QScopedPointer<XdgShellSurface> xdgParentSurface(m_xdgShell->createSurface(parentSurface.data()));
QVERIFY(xdgTopLevelCreatedSpy.wait());
auto serverXdgTopLevel = xdgTopLevelCreatedSpy.first().first().value<XdgShellSurfaceInterface*>();
QFETCH(XdgPositioner, positioner);
QScopedPointer<Surface> surface(m_compositor->createSurface());
QScopedPointer<XdgShellPopup> xdgSurface(m_xdgShell->createPopup(surface.data(), xdgParentSurface.data(), positioner));
QVERIFY(xdgPopupCreatedSpy.wait());
auto serverXdgPopup = xdgPopupCreatedSpy.first().first().value<XdgShellPopupInterface*>();
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<OutputInterface*>();
// this test verifies changing the window minSize
QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated);
QVERIFY(xdgSurfaceCreatedSpy.isValid());
QScopedPointer<Surface> surface(m_compositor->createSurface());
QScopedPointer<XdgShellSurface> xdgSurface(m_xdgShell->createSurface(surface.data()));
QVERIFY(xdgSurfaceCreatedSpy.wait());
auto serverXdgSurface = xdgSurfaceCreatedSpy.first().first().value<XdgShellSurfaceInterface*>();
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>(), 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>(), 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> 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> surface(m_compositor->createSurface());
QScopedPointer<Surface> 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<Surface> popupSurface(m_compositor->createSurface());
QScopedPointer<XdgShellPopup> xdgPopupSurface(m_xdgShell->createPopup(popupSurface.data(), xdgSurface.data(), positioner));
QVERIFY(xdgPopupCreatedSpy.wait());
auto serverXdgPopup = xdgPopupCreatedSpy.first().first().value<XdgShellPopupInterface*>();
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"

View file

@ -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 <QCoreApplication>
#include <QDebug>
@ -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;
}

View file

@ -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

View file

@ -1,113 +0,0 @@
/*
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
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 <wayland-server.h>
namespace KWaylandServer
{
template <class T>
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 <typename U>
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<typename T::Private*>(wl_resource_get_user_data(resource));
}
T *shellSurface;
};
template <class T>
void GenericShellSurface<T>::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 <class T>
void GenericShellSurface<T>::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 <class T>
void GenericShellSurface<T>::setTitle(const QString &t)
{
if (title == t) {
return;
}
title = t;
Q_Q(T);
emit q->titleChanged(title);
}
template <class T>
void GenericShellSurface<T>::setWindowClass(const QByteArray &wc)
{
if (windowClass == wc) {
return;
}
windowClass = wc;
Q_Q(T);
emit q->windowClassChanged(windowClass);
}
template <class T>
void GenericShellSurface<T>::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 <typename T>
Qt::Edges edgesToQtEdges(T edges);
}
template <class T>
template <typename U>
void GenericShellSurface<T>::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

View file

@ -1,233 +0,0 @@
/*
SPDX-FileCopyrightText: 2018 David Edmundson <kde@davidedmundson.co.uk>
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 <QtDebug>
#include <QPointer>
namespace KWaylandServer
{
class XdgDecorationManagerInterface::Private : public Global::Private
{
public:
Private(XdgDecorationManagerInterface *q, XdgShellInterface *shellInterface, Display *d);
QHash<XdgShellSurfaceInterface*, XdgDecorationInterface*> 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<Private*>(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<Private*>(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<XdgShellStableInterface*>(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<XdgDecorationInterface *>(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<Private*>(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<Private*>(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<XdgDecorationInterface::Private*>(d.data());
}
}

View file

@ -1,90 +0,0 @@
/*
SPDX-FileCopyrightText: 2018 David Edmundson <kde@davidedmundson.co.uk>
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 <KWaylandServer/kwaylandserver_export.h>
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

File diff suppressed because it is too large Load diff

View file

@ -1,131 +0,0 @@
/*
SPDX-FileCopyrightText: 2017 David Edmundson <davidedmundson@kde.org>
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 <KWaylandServer/kwaylandserver_export.h>
#include <QSize>
namespace KWaylandServer
{
class Display;
class OutputInterface;
class SeatInterface;
class SurfaceInterface;
class XdgTopLevelStableInterface;
class XdgPopupStableInterface;
class XdgPositionerStableInterface;
class XdgSurfaceStableInterface;
template <typename T>
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<XdgPopupStableInterface>;
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

View file

@ -25,4 +25,13 @@ SurfaceRole::~SurfaceRole()
}
}
SurfaceRole *SurfaceRole::get(SurfaceInterface *surface)
{
if (surface) {
return surface->d_func()->role;
}
return nullptr;
}
}

View file

@ -22,6 +22,8 @@ public:
virtual void commit() = 0;
static SurfaceRole *get(SurfaceInterface *surface);
private:
QPointer<SurfaceInterface> m_surface;

View file

@ -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<KWaylandServer::SeatInterface> &seat);
@ -94,7 +94,7 @@ protected:
private:
void updateFocus();
QList<KWaylandServer::XdgShellSurfaceInterface *> m_stackingOrder;
QList<KWaylandServer::XdgToplevelInterface *> m_stackingOrder;
QPointer<KWaylandServer::SeatInterface> 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<void (CompositorWindow::*)()>(&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)) {

View file

@ -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));

View file

@ -0,0 +1,151 @@
/*
SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
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

View file

@ -0,0 +1,114 @@
/*
SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#pragma once
#include <KWaylandServer/kwaylandserver_export.h>
#include <QObject>
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<XdgDecorationManagerV1InterfacePrivate> 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<XdgToplevelDecorationV1InterfacePrivate> d;
};
} // namespace KWaylandServer

View file

@ -0,0 +1,44 @@
/*
SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
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

File diff suppressed because it is too large Load diff

View file

@ -1,509 +1,533 @@
/*
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
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 <QSize>
#pragma once
#include <KWaylandServer/kwaylandserver_export.h>
#include <QObject>
#include <QSharedDataPointer>
struct wl_resource;
namespace KWaylandServer
{
class Display;
class OutputInterface;
class SeatInterface;
class SurfaceInterface;
class XdgShellPopupInterface;
class XdgShellSurfaceInterface;
template <typename T>
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<XdgShellInterfacePrivate> 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<XdgShellSurfaceInterface> 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<XdgSurfaceInterfacePrivate> 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<XdgShellSurfaceInterface>;
QScopedPointer<XdgToplevelInterfacePrivate> 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<SurfaceInterface> 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<XdgPositionerData> &data);
QSharedDataPointer<XdgPositionerData> 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<XdgShellPopupInterface>;
Private *d_func() const;
QScopedPointer<XdgPopupInterfacePrivate> 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)

View file

@ -1,94 +1,175 @@
/*
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
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 <QTimer>
#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 <quint32, QTimer *> 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<XdgShellSurfaceInterface>
{
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<XdgShellSurfaceInterface *>(q);
}
QVector<quint32> configureSerials;
QPointer<XdgShellSurfaceInterface> parent;
XdgShellInterfaceVersion interfaceVersion;
Display *display;
QMap<quint32, QTimer *> 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<wl_client *, XdgSurfaceInterface *> xdgSurfaces;
};
class XdgShellPopupInterface::Private : public Resource::Private, public GenericShellSurface<XdgShellPopupInterface>
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<XdgShellPopupInterface *>(q);
}
class XdgPositionerPrivate : public QtWaylandServer::xdg_positioner
{
public:
XdgPositionerPrivate(::wl_resource *resource);
virtual quint32 configure(const QRect &rect) {
Q_UNUSED(rect)
return 0;
QSharedDataPointer<XdgPositionerData> 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<XdgToplevelInterface> toplevel;
QPointer<XdgPopupInterface> popup;
QPointer<SurfaceInterface> surface;
bool isConfigured = false;
struct State
{
QRect windowGeometry;
};
QVector<quint32> configureSerials;
QPointer<SurfaceInterface> 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<XdgToplevelInterface> parentXdgToplevel;
QPointer<XdgToplevelDecorationV1Interface> 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