Commit 3c67cc13 authored by David Edmundson's avatar David Edmundson
Browse files

Support XDG v6

Summary:

The main clever part that's not just boring boiler plate is how we
handle the structure change
A surface now has an XDGSurface which then has a an Xdg TopLevel or a
Xdg Popup

We need to fit this into the public API which assumes a surface has a
Surface or a Popup.
The old Surface is similar to the new TopLevel.

The shoehorning works by relying on the fact that a surface without a
role is pretty useless.

Clients create the surface implicitly with the toplevel or implicitly
with the popup.
The server only announced it has a new "XdgSurface" when it gets a new
zxdg_surface_get_toplevel.

----

Popup decisions:
- On popup creation the server should copy the current info from the
positioner and then it gets deleted. Given kwaylands job is to keep
state, we expose all these parameter via popup.

- Due to this positioner is not exposed as a resource anywhere.

- Server API is 100% backwards compatiable.
i.e new code will work identically with v5 clients.

- Client API is not.  Grabs are called separately from the constructor,
and the parent surface changed to an xdgsurface, not a raw surface.
V5 code still works as-is, just not with the new constructors.

It seemed better to match the v6 (and what will be the stable v7) than
to try and do hacks and lose functionality.
Given the client needs to change the code to opt into V6 anyway. I don't
think this is a huge problem.

Test Plan: Current test still passes.

Reviewers: #plasma, graesslin

Reviewed By: #plasma, graesslin

Subscribers: graesslin, mart, plasma-devel, #frameworks

Tags: #frameworks, #plasma_on_wayland

Differential Revision: https://phabricator.kde.org/D6047
parent f1491e00
......@@ -45,6 +45,7 @@ set(SERVER_LIB_SRCS
textinput_interface_v2.cpp
xdgshell_interface.cpp
xdgshell_v5_interface.cpp
xdgshell_v6_interface.cpp
)
ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
......@@ -131,6 +132,11 @@ ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
BASENAME xdg-shell-v5
)
ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/xdg-shell-unstable-v6.xml
BASENAME xdg-shell-v6
)
ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/pointer-gestures-unstable-v1.xml
BASENAME pointer-gestures-unstable-v1
......
......@@ -342,12 +342,25 @@ ecm_mark_as_test(testSelection)
########################################################
set( testXdgShellV5_SRCS
test_xdg_shell.cpp
test_xdg_shell_v5.cpp
)
add_executable(testXdgShellV5 ${testXdgShellV5_SRCS})
target_link_libraries( testXdgShellV5 Qt5::Test Qt5::Gui KF5::WaylandServer KF5::WaylandClient Wayland::Client)
add_test(NAME kwayland-testXdgShellV5 COMMAND testXdgShellV5)
ecm_mark_as_test(testXdgShellV5)
########################################################
# Test XdgShellV6
########################################################
set( testXdgShellV6_SRCS
test_xdg_shell.cpp
test_xdg_shell_v6.cpp
)
add_executable(testXdgShellV6 ${testXdgShellV6_SRCS})
target_link_libraries( testXdgShellV6 Qt5::Test Qt5::Gui KF5::WaylandServer KF5::WaylandClient Wayland::Client)
add_test(kwayland-testXdgShellV6 testXdgShellV6)
ecm_mark_as_test(testXdgShellV6)
########################################################
# Test Pointer Constraints
########################################################
......
......@@ -17,72 +17,12 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
// Qt
#include <QtTest/QtTest>
// client
#include "../../src/client/xdgshell.h"
#include "../../src/client/connection_thread.h"
#include "../../src/client/compositor.h"
#include "../../src/client/event_queue.h"
#include "../../src/client/registry.h"
#include "../../src/client/output.h"
#include "../../src/client/seat.h"
#include "../../src/client/shm_pool.h"
#include "../../src/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 KWayland::Server;
Q_DECLARE_METATYPE(Qt::MouseButton)
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 testClose();
void testConfigureStates_data();
void testConfigureStates();
void testConfigureMultipleAcks();
void testPopup();
private:
Display *m_display = nullptr;
CompositorInterface *m_compositorInterface = nullptr;
OutputInterface *m_o1Interface = nullptr;
OutputInterface *m_o2Interface = nullptr;
SeatInterface *m_seatInterface = nullptr;
XdgShellInterface *m_xdgShellInterface = nullptr;
ConnectionThread *m_connection = nullptr;
QThread *m_thread = nullptr;
EventQueue *m_queue = nullptr;
Compositor *m_compositor = nullptr;
ShmPool *m_shmPool = nullptr;
XdgShell *m_xdgShell = nullptr;
Output *m_output1 = nullptr;
Output *m_output2 = nullptr;
Seat *m_seat = nullptr;
};
#include "test_xdg_shell.h"
XdgShellTest::XdgShellTest(XdgShellInterfaceVersion version):
m_version(version)
{}
static const QString s_socketName = QStringLiteral("kwayland-test-xdg_shell-0");
......@@ -107,8 +47,8 @@ void XdgShellTest::init()
m_seatInterface->create();
m_compositorInterface = m_display->createCompositor(m_display);
m_compositorInterface->create();
m_xdgShellInterface = m_display->createXdgShell(XdgShellInterfaceVersion::UnstableV5, m_display);
QCOMPARE(m_xdgShellInterface->interfaceVersion(), XdgShellInterfaceVersion::UnstableV5);
m_xdgShellInterface = m_display->createXdgShell(m_version, m_display);
QCOMPARE(m_xdgShellInterface->interfaceVersion(), m_version);
m_xdgShellInterface->create();
// setup connection
......@@ -134,7 +74,11 @@ void XdgShellTest::init()
QVERIFY(interfaceAnnouncedSpy.isValid());
QSignalSpy outputAnnouncedSpy(&registry, &Registry::outputAnnounced);
QVERIFY(outputAnnouncedSpy.isValid());
QSignalSpy xdgShellAnnouncedSpy(&registry, &Registry::xdgShellUnstableV5Announced);
auto shellAnnouncedSignal = m_version == XdgShellInterfaceVersion::UnstableV5 ?
&Registry::xdgShellUnstableV5Announced : &Registry::xdgShellUnstableV6Announced;
QSignalSpy xdgShellAnnouncedSpy(&registry, shellAnnouncedSignal);
QVERIFY(xdgShellAnnouncedSpy.isValid());
registry.setEventQueue(m_queue);
registry.create(m_connection);
......@@ -160,8 +104,10 @@ void XdgShellTest::init()
QCOMPARE(xdgShellAnnouncedSpy.count(), 1);
m_xdgShell = registry.createXdgShell(registry.interface(Registry::Interface::XdgShellUnstableV5).name,
registry.interface(Registry::Interface::XdgShellUnstableV5).version,
Registry::Interface iface = m_version == XdgShellInterfaceVersion::UnstableV5 ? Registry::Interface::XdgShellUnstableV5 : Registry::Interface::XdgShellUnstableV6;
m_xdgShell = registry.createXdgShell(registry.interface(iface).name,
registry.interface(iface).version,
this);
QVERIFY(m_xdgShell);
QVERIFY(m_xdgShell->isValid());
......@@ -238,16 +184,6 @@ void XdgShellTest::testCreateSurface()
QVERIFY(destroyedSpy.wait());
}
#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);
void XdgShellTest::testTitle()
{
// this test verifies that we can change the title of a shell surface
......@@ -464,6 +400,30 @@ void XdgShellTest::testTransient()
QVERIFY(!serverXdgSurface->isTransient());
}
void XdgShellTest::testPing()
{
// this test verifies that a ping request is sent to the client
SURFACE
QSignalSpy pingSpy(m_xdgShellInterface, &XdgShellInterface::pongReceived);
QVERIFY(pingSpy.isValid());
quint32 serial = m_xdgShellInterface->ping(serverXdgSurface);
QVERIFY(pingSpy.wait());
QCOMPARE(pingSpy.count(), 1);
QCOMPARE(pingSpy.takeFirst().at(0).value<quint32>(), serial);
// 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);
QSignalSpy pingDelayedSpy(m_xdgShellInterface, &XdgShellInterface::pingDelayed);
QVERIFY(pingDelayedSpy.wait());
QSignalSpy pingTimeoutSpy(m_xdgShellInterface, &XdgShellInterface::pingTimeout);
QVERIFY(pingTimeoutSpy.wait());
}
void XdgShellTest::testClose()
{
// this test verifies that a close request is sent to the client
......@@ -599,51 +559,4 @@ void XdgShellTest::testConfigureMultipleAcks()
QCOMPARE(xdgSurface->size(), QSize(30, 40));
}
void XdgShellTest::testPopup()
{
// this test verifies that the creation of popups works correctly
SURFACE
QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
QVERIFY(surfaceCreatedSpy.isValid());
QSignalSpy xdgPopupSpy(m_xdgShellInterface, &XdgShellInterface::popupCreated);
QVERIFY(xdgPopupSpy.isValid());
QScopedPointer<Surface> popupSurface(m_compositor->createSurface());
QVERIFY(surfaceCreatedSpy.wait());
// TODO: proper serial
QScopedPointer<XdgShellPopup> xdgPopup(m_xdgShell->createPopup(popupSurface.data(), surface.data(), m_seat, 120, QPoint(10, 20)));
QVERIFY(xdgPopupSpy.wait());
QCOMPARE(xdgPopupSpy.count(), 1);
QCOMPARE(xdgPopupSpy.first().at(1).value<SeatInterface*>(), m_seatInterface);
QCOMPARE(xdgPopupSpy.first().at(2).value<quint32>(), 120u);
auto serverXdgPopup = xdgPopupSpy.first().first().value<XdgShellPopupInterface*>();
QVERIFY(serverXdgPopup);
QCOMPARE(serverXdgPopup->surface(), surfaceCreatedSpy.first().first().value<SurfaceInterface*>());
QCOMPARE(serverXdgPopup->transientFor().data(), serverXdgSurface->surface());
QCOMPARE(serverXdgPopup->transientOffset(), QPoint(10, 20));
// now also a popup for the popup
QScopedPointer<Surface> popup2Surface(m_compositor->createSurface());
QScopedPointer<XdgShellPopup> xdgPopup2(m_xdgShell->createPopup(popup2Surface.data(), popupSurface.data(), m_seat, 121, QPoint(5, 7)));
QVERIFY(xdgPopupSpy.wait());
QCOMPARE(xdgPopupSpy.count(), 2);
QCOMPARE(xdgPopupSpy.last().at(1).value<SeatInterface*>(), m_seatInterface);
QCOMPARE(xdgPopupSpy.last().at(2).value<quint32>(), 121u);
auto serverXdgPopup2 = xdgPopupSpy.last().first().value<XdgShellPopupInterface*>();
QVERIFY(serverXdgPopup2);
QCOMPARE(serverXdgPopup2->surface(), surfaceCreatedSpy.last().first().value<SurfaceInterface*>());
QCOMPARE(serverXdgPopup2->transientFor().data(), serverXdgPopup->surface());
QCOMPARE(serverXdgPopup2->transientOffset(), QPoint(5, 7));
QSignalSpy popup2DoneSpy(xdgPopup2.data(), &XdgShellPopup::popupDone);
QVERIFY(popup2DoneSpy.isValid());
serverXdgPopup2->popupDone();
QVERIFY(popup2DoneSpy.wait());
// TODO: test that this sends also the done to all parents
}
QTEST_GUILESS_MAIN(XdgShellTest)
#include "test_xdg_shell.moc"
/********************************************************************
Copyright 2016 Martin Gräßlin <mgraesslin@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) version 3, or any
later version accepted by the membership of KDE e.V. (or its
successor approved by the membership of KDE e.V.), which shall
act as a proxy defined in Section 6 of version 3 of the license.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
// Qt
#include <QtTest/QtTest>
// client
#include "../../src/client/xdgshell.h"
#include "../../src/client/connection_thread.h"
#include "../../src/client/compositor.h"
#include "../../src/client/event_queue.h"
#include "../../src/client/registry.h"
#include "../../src/client/output.h"
#include "../../src/client/seat.h"
#include "../../src/client/shm_pool.h"
#include "../../src/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 KWayland::Server;
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);
#include "test_xdg_shell.h"
class XdgShellTestV5 : public XdgShellTest {
Q_OBJECT
public:
XdgShellTestV5() :
XdgShellTest(KWayland::Server::XdgShellInterfaceVersion::UnstableV5) {}
private Q_SLOTS:
void testPopup();
};
void XdgShellTestV5::testPopup()
{
// this test verifies that the creation of popups works correctly
SURFACE
QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
QVERIFY(surfaceCreatedSpy.isValid());
QSignalSpy xdgPopupSpy(m_xdgShellInterface, &XdgShellInterface::popupCreated);
//check as well as the compat signal, the new signal is also fired
QSignalSpy xdgPopupSpyNew(m_xdgShellInterface, &XdgShellInterface::xdgPopupCreated);
QVERIFY(xdgPopupSpy.isValid());
QScopedPointer<Surface> popupSurface(m_compositor->createSurface());
QVERIFY(surfaceCreatedSpy.wait());
// TODO: proper serial
QScopedPointer<XdgShellPopup> xdgPopup(m_xdgShell->createPopup(popupSurface.data(), surface.data(), m_seat, 120, QPoint(10, 20)));
QVERIFY(xdgPopupSpy.wait());
QCOMPARE(xdgPopupSpy.count(), 1);
QCOMPARE(xdgPopupSpyNew.count(), 1);
QCOMPARE(xdgPopupSpy.first().at(1).value<SeatInterface*>(), m_seatInterface);
QCOMPARE(xdgPopupSpy.first().at(2).value<quint32>(), 120u);
auto serverXdgPopup = xdgPopupSpy.first().first().value<XdgShellPopupInterface*>();
QVERIFY(serverXdgPopup);
QCOMPARE(serverXdgPopup->surface(), surfaceCreatedSpy.first().first().value<SurfaceInterface*>());
QCOMPARE(serverXdgPopup->transientFor().data(), serverXdgSurface->surface());
QCOMPARE(serverXdgPopup->transientOffset(), QPoint(10, 20));
// now also a popup for the popup
QScopedPointer<Surface> popup2Surface(m_compositor->createSurface());
QScopedPointer<XdgShellPopup> xdgPopup2(m_xdgShell->createPopup(popup2Surface.data(), popupSurface.data(), m_seat, 121, QPoint(5, 7)));
QVERIFY(xdgPopupSpy.wait());
QCOMPARE(xdgPopupSpy.count(), 2);
QCOMPARE(xdgPopupSpy.last().at(1).value<SeatInterface*>(), m_seatInterface);
QCOMPARE(xdgPopupSpy.last().at(2).value<quint32>(), 121u);
auto serverXdgPopup2 = xdgPopupSpy.last().first().value<XdgShellPopupInterface*>();
QVERIFY(serverXdgPopup2);
QCOMPARE(serverXdgPopup2->surface(), surfaceCreatedSpy.last().first().value<SurfaceInterface*>());
QCOMPARE(serverXdgPopup2->transientFor().data(), serverXdgPopup->surface());
QCOMPARE(serverXdgPopup2->transientOffset(), QPoint(5, 7));
QSignalSpy popup2DoneSpy(xdgPopup2.data(), &XdgShellPopup::popupDone);
QVERIFY(popup2DoneSpy.isValid());
serverXdgPopup2->popupDone();
QVERIFY(popup2DoneSpy.wait());
// TODO: test that this sends also the done to all parents
}
QTEST_GUILESS_MAIN(XdgShellTestV5)
#include "test_xdg_shell_v5.moc"
#include "test_xdg_shell.h"
#include <wayland-xdg-shell-v6-client-protocol.h>
class XdgShellTestV6 : public XdgShellTest {
Q_OBJECT
public:
XdgShellTestV6() :
XdgShellTest(KWayland::Server::XdgShellInterfaceVersion::UnstableV6) {}
private Q_SLOTS:
void testMaxSize();
void testMinSize();
void testPopup_data();
void testPopup();
void testMultipleRoles1();
void testMultipleRoles2();
};
void XdgShellTestV6::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));
QVERIFY(maxSizeSpy.wait());
QCOMPARE(maxSizeSpy.count(), 1);
QCOMPARE(maxSizeSpy.last().at(0).value<QSize>(), QSize(100,100));
xdgSurface->setMaxSize(QSize(200, 200));
QVERIFY(maxSizeSpy.wait());
QCOMPARE(maxSizeSpy.count(), 2);
QCOMPARE(maxSizeSpy.last().at(0).value<QSize>(), QSize(200,200));
}
void XdgShellTestV6::testPopup_data()
{
QTest::addColumn<XdgPositioner>("positioners");
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 XdgShellTestV6::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*>();
XdgPositioner positioner(QSize(10,10), QRect(100,100,50,50));
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 XdgShellTestV6::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));
QVERIFY(minSizeSpy.wait());
QCOMPARE(minSizeSpy.count(), 1);
QCOMPARE(minSizeSpy.last().at(0).value<QSize>(), QSize(200,200));
xdgSurface->setMinSize(QSize(100, 100));
QVERIFY(minSizeSpy.wait());
QCOMPARE(minSizeSpy.count(), 2);
QCOMPARE(minSizeSpy.last().at(0).value<QSize>(), QSize(100,100));
}
//top level then toplevel
void XdgShellTestV6::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
auto xdgSurface = zxdg_shell_v6_get_xdg_surface(*m_xdgShell, *surface.data());
//create a top level
auto xdgTopLevel1 = zxdg_surface_v6_get_toplevel(xdgSurface);
QVERIFY(xdgSurfaceCreatedSpy.wait());
//now try to create another top level for the same xdg surface. It should fail
auto xdgTopLevel2 = zxdg_surface_v6_get_toplevel(xdgSurface);
QVERIFY(!xdgSurfaceCreatedSpy.wait(10));