diff options
Diffstat (limited to 'tests')
21 files changed, 698 insertions, 101 deletions
diff --git a/tests/auto/client/client.pro b/tests/auto/client/client.pro index 916b3abe4..d19326797 100644 --- a/tests/auto/client/client.pro +++ b/tests/auto/client/client.pro @@ -1,3 +1,5 @@ TEMPLATE=subdirs -SUBDIRS += client +SUBDIRS += \ + client \ + xdgshellv6 diff --git a/tests/auto/client/client/client.pro b/tests/auto/client/client/client.pro index e6e607c3f..edf80bb9b 100644 --- a/tests/auto/client/client/client.pro +++ b/tests/auto/client/client/client.pro @@ -1,24 +1,4 @@ -CONFIG += testcase link_pkgconfig -TARGET = tst_client - -QT += testlib -QT += core-private gui-private waylandclient-private - -QMAKE_USE += wayland-client wayland-server +include (../shared/shared.pri) -CONFIG += wayland-scanner -WAYLANDSERVERSOURCES += \ - ../../../../src/3rdparty/protocol/wayland.xml - -SOURCES += \ - tst_client.cpp \ - mockcompositor.cpp \ - mockinput.cpp \ - mockshell.cpp \ - mocksurface.cpp \ - mockoutput.cpp - -HEADERS += \ - mockcompositor.h \ - mockinput.h \ - mocksurface.h +TARGET = tst_client +SOURCES += tst_client.cpp diff --git a/tests/auto/client/client/tst_client.cpp b/tests/auto/client/client/tst_client.cpp index aed601d8a..94198b457 100644 --- a/tests/auto/client/client/tst_client.cpp +++ b/tests/auto/client/client/tst_client.cpp @@ -97,6 +97,7 @@ public: void touchEvent(QTouchEvent *event) override { + Q_UNUSED(event); ++touchEventCount; } @@ -161,7 +162,10 @@ public slots: } private slots: - void screen(); + void primaryScreen(); + void screens(); + void windowScreens(); + void removePrimaryScreen(); void createDestroyWindow(); void events(); void backingStore(); @@ -176,11 +180,96 @@ private: MockCompositor *compositor; }; -void tst_WaylandClient::screen() +void tst_WaylandClient::primaryScreen() { + compositor->setOutputMode(screenSize); QTRY_COMPARE(QGuiApplication::primaryScreen()->size(), screenSize); } +void tst_WaylandClient::screens() +{ + QTRY_COMPARE(QGuiApplication::screens().size(), 1); + compositor->sendAddOutput(); + QTRY_COMPARE(QGuiApplication::screens().size(), 2); + QSharedPointer<MockOutput> secondOutput; + QTRY_VERIFY(secondOutput = compositor->output(1)); + compositor->sendRemoveOutput(secondOutput); + QTRY_COMPARE(QGuiApplication::screens().size(), 1); +} + +void tst_WaylandClient::windowScreens() +{ + QSharedPointer<MockOutput> firstOutput; + QTRY_VERIFY(firstOutput = compositor->output()); + + TestWindow window; + window.show(); + + QSharedPointer<MockSurface> surface; + QTRY_VERIFY(surface = compositor->surface()); + QTRY_COMPARE(QGuiApplication::screens().size(), 1); + QScreen *primaryScreen = QGuiApplication::screens().first(); + QCOMPARE(window.screen(), primaryScreen); + + compositor->sendAddOutput(); + + QTRY_COMPARE(QGuiApplication::screens().size(), 2); + QScreen *secondaryScreen = QGuiApplication::screens().at(1); + QVERIFY(secondaryScreen); + + window.setScreen(secondaryScreen); + QCOMPARE(window.screen(), secondaryScreen); + + QSharedPointer<MockOutput> secondOutput; + QTRY_VERIFY(secondOutput = compositor->output(1)); + compositor->sendSurfaceEnter(surface, firstOutput); + + compositor->sendSurfaceEnter(surface, secondOutput); + QTRY_COMPARE(window.screen(), primaryScreen); + + compositor->sendSurfaceLeave(surface, firstOutput); + QTRY_COMPARE(window.screen(), secondaryScreen); + + compositor->sendRemoveOutput(secondOutput); + QTRY_COMPARE(QGuiApplication::screens().size(), 1); + QCOMPARE(window.screen(), primaryScreen); + + window.destroy(); + QTRY_VERIFY(!compositor->surface()); +} + +void tst_WaylandClient::removePrimaryScreen() +{ + QSharedPointer<MockOutput> firstOutput; + QTRY_VERIFY(firstOutput = compositor->output()); + + TestWindow window; + window.show(); + + QSharedPointer<MockSurface> surface; + QTRY_VERIFY(surface = compositor->surface()); + QTRY_COMPARE(QGuiApplication::screens().size(), 1); + QScreen *primaryScreen = QGuiApplication::screens().first(); + QCOMPARE(window.screen(), primaryScreen); + + compositor->sendAddOutput(); + + QTRY_COMPARE(QGuiApplication::screens().size(), 2); + QScreen *secondaryScreen = QGuiApplication::screens().at(1); + QVERIFY(secondaryScreen); + + compositor->sendRemoveOutput(firstOutput); + QTRY_COMPARE(QGuiApplication::screens().size(), 1); + + compositor->sendMousePress(surface, window.frameOffset() + QPoint(10, 10)); + QTRY_COMPARE(window.mousePressEventCount, 1); + compositor->sendMouseRelease(surface); + QTRY_COMPARE(window.mouseReleaseEventCount, 1); + + window.destroy(); + QTRY_VERIFY(!compositor->surface()); +} + void tst_WaylandClient::createDestroyWindow() { TestWindow window; @@ -301,6 +390,7 @@ public: protected: void mousePressEvent(QMouseEvent *event) override { + Q_UNUSED(event); if (dragStarted) return; dragStarted = true; @@ -452,7 +542,7 @@ int main(int argc, char **argv) setenv("QT_QPA_PLATFORM", "wayland", 1); // force QGuiApplication to use wayland plugin MockCompositor compositor; - compositor.setOutputGeometry(QRect(QPoint(), screenSize)); + compositor.setOutputMode(screenSize); QGuiApplication app(argc, argv); diff --git a/tests/auto/client/client/mockcompositor.cpp b/tests/auto/client/shared/mockcompositor.cpp index 2c5f2541f..e7c6e90d2 100644 --- a/tests/auto/client/client/mockcompositor.cpp +++ b/tests/auto/client/shared/mockcompositor.cpp @@ -28,8 +28,11 @@ #include "mockcompositor.h" #include "mockinput.h" +#include "mockoutput.h" #include "mocksurface.h" +#include <wayland-xdg-shell-unstable-v6-server-protocol.h> + #include <stdio.h> MockCompositor::MockCompositor() : m_alive(true) @@ -75,10 +78,10 @@ void MockCompositor::processWaylandEvents() m_waitCondition.wakeOne(); } -void MockCompositor::setOutputGeometry(const QRect &rect) +void MockCompositor::setOutputMode(const QSize &size) { - Command command = makeCommand(Impl::Compositor::setOutputGeometry, m_compositor); - command.parameters << rect; + Command command = makeCommand(Impl::Compositor::setOutputMode, m_compositor); + command.parameters << size; processCommand(command); } @@ -180,6 +183,35 @@ void MockCompositor::sendDataDeviceLeave(const QSharedPointer<MockSurface> &surf processCommand(command); } +void MockCompositor::sendAddOutput() +{ + Command command = makeCommand(Impl::Compositor::sendAddOutput, m_compositor); + processCommand(command); +} + +void MockCompositor::sendRemoveOutput(const QSharedPointer<MockOutput> &output) +{ + Command command = makeCommand(Impl::Compositor::sendRemoveOutput, m_compositor); + command.parameters << QVariant::fromValue(output); + processCommand(command); +} + +void MockCompositor::sendSurfaceEnter(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output) +{ + Command command = makeCommand(Impl::Compositor::sendSurfaceEnter, m_compositor); + command.parameters << QVariant::fromValue(surface); + command.parameters << QVariant::fromValue(output); + processCommand(command); +} + +void MockCompositor::sendSurfaceLeave(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output) +{ + Command command = makeCommand(Impl::Compositor::sendSurfaceLeave, m_compositor); + command.parameters << QVariant::fromValue(surface); + command.parameters << QVariant::fromValue(output); + processCommand(command); +} + void MockCompositor::waitForStartDrag() { Command command = makeCommand(Impl::Compositor::waitForStartDrag, m_compositor); @@ -202,6 +234,15 @@ QSharedPointer<MockSurface> MockCompositor::surface() return result; } +QSharedPointer<MockOutput> MockCompositor::output(int index) +{ + QSharedPointer<MockOutput> result; + lock(); + result = m_compositor->outputs().at(index)->mockOutput(); + unlock(); + return result; +} + MockCompositor::Command MockCompositor::makeCommand(Command::Callback callback, void *target) { Command command; @@ -264,11 +305,7 @@ namespace Impl { Compositor::Compositor() : m_display(wl_display_create()) - , m_startDragSeen(false) - , m_time(0) { - wl_list_init(&m_outputResources); - if (wl_display_add_socket(m_display, 0)) { fprintf(stderr, "Fatal: Failed to open server socket\n"); exit(EXIT_FAILURE); @@ -285,8 +322,9 @@ Compositor::Compositor() m_keyboard = m_seat->keyboard(); m_touch = m_seat->touch(); - wl_global_create(m_display, &wl_output_interface, 1, this, bindOutput); + m_outputs.append(new Output(m_display, QSize(1920, 1080), QPoint(0, 0))); wl_global_create(m_display, &wl_shell_interface, 1, this, bindShell); + wl_global_create(m_display, &zxdg_shell_v6_interface, 1, this, bindXdgShellV6); m_loop = wl_display_get_event_loop(m_display); m_fd = wl_event_loop_get_fd(m_loop); @@ -349,6 +387,11 @@ QVector<Surface *> Compositor::surfaces() const return m_surfaces; } +QVector<Output *> Compositor::outputs() const +{ + return m_outputs; +} + uint32_t Compositor::nextSerial() { return wl_display_next_serial(m_display); @@ -366,5 +409,17 @@ void Compositor::removeSurface(Surface *surface) m_pointer->handleSurfaceDestroyed(surface); } +Surface *Compositor::resolveSurface(const QVariant &v) +{ + QSharedPointer<MockSurface> mockSurface = v.value<QSharedPointer<MockSurface> >(); + return mockSurface ? mockSurface->handle() : nullptr; +} + +Output *Compositor::resolveOutput(const QVariant &v) +{ + QSharedPointer<MockOutput> mockOutput = v.value<QSharedPointer<MockOutput> >(); + return mockOutput ? mockOutput->handle() : nullptr; +} + } diff --git a/tests/auto/client/client/mockcompositor.h b/tests/auto/client/shared/mockcompositor.h index dd6450fc9..9258b1926 100644 --- a/tests/auto/client/client/mockcompositor.h +++ b/tests/auto/client/shared/mockcompositor.h @@ -51,6 +51,7 @@ class Touch; class Seat; class DataDeviceManager; class Surface; +class Output; class Compositor { @@ -64,9 +65,8 @@ public: uint32_t nextSerial(); uint32_t time() { return ++m_time; } - static void setOutputGeometry(void *compositor, const QList<QVariant> ¶meters); - QVector<Surface *> surfaces() const; + QVector<Output *> outputs() const; void addSurface(Surface *surface); void removeSurface(Surface *surface); @@ -86,36 +86,40 @@ public: static void sendDataDeviceDrop(void *data, const QList<QVariant> ¶meters); static void sendDataDeviceLeave(void *data, const QList<QVariant> ¶meters); static void waitForStartDrag(void *data, const QList<QVariant> ¶meters); + static void setOutputMode(void *compositor, const QList<QVariant> ¶meters); + static void sendAddOutput(void *data, const QList<QVariant> ¶meters); + static void sendRemoveOutput(void *data, const QList<QVariant> ¶meters); + static void sendSurfaceEnter(void *data, const QList<QVariant> ¶meters); + static void sendSurfaceLeave(void *data, const QList<QVariant> ¶meters); public: - bool m_startDragSeen; + bool m_startDragSeen = false; private: static void bindCompositor(wl_client *client, void *data, uint32_t version, uint32_t id); - static void bindOutput(wl_client *client, void *data, uint32_t version, uint32_t id); static void bindShell(wl_client *client, void *data, uint32_t version, uint32_t id); + static void bindXdgShellV6(wl_client *client, void *compositorData, uint32_t version, uint32_t id); + static Surface *resolveSurface(const QVariant &v); + static Output *resolveOutput(const QVariant &v); void initShm(); - void sendOutputGeometry(wl_resource *resource); - void sendOutputMode(wl_resource *resource); - QRect m_outputGeometry; - wl_display *m_display; - wl_event_loop *m_loop; - wl_shm *m_shm; - int m_fd; + wl_display *m_display = nullptr; + wl_event_loop *m_loop = nullptr; + wl_shm *m_shm = nullptr; + int m_fd = -1; - wl_list m_outputResources; - uint32_t m_time; + uint32_t m_time = 0; QScopedPointer<Seat> m_seat; - Pointer *m_pointer; - Keyboard *m_keyboard; - Touch *m_touch; + Pointer *m_pointer = nullptr; + Keyboard *m_keyboard = nullptr; + Touch *m_touch = nullptr; QScopedPointer<DataDeviceManager> m_data_device_manager; QVector<Surface *> m_surfaces; + QVector<Output *> m_outputs; }; void registerResource(wl_list *list, wl_resource *resource); @@ -139,6 +143,16 @@ private: Q_DECLARE_METATYPE(QSharedPointer<MockSurface>) +class MockOutput { +public: + Impl::Output *handle() const { return m_output; } + MockOutput(Impl::Output *output); +private: + Impl::Output *m_output; +}; + +Q_DECLARE_METATYPE(QSharedPointer<MockOutput>) + class MockCompositor { public: @@ -150,7 +164,7 @@ public: int waylandFileDescriptor() const; void processWaylandEvents(); - void setOutputGeometry(const QRect &rect); + void setOutputMode(const QSize &size); void setKeyboardFocus(const QSharedPointer<MockSurface> &surface); void sendMousePress(const QSharedPointer<MockSurface> &surface, const QPoint &pos); void sendMouseRelease(const QSharedPointer<MockSurface> &surface); @@ -165,9 +179,14 @@ public: void sendDataDeviceMotion(const QPoint &position); void sendDataDeviceDrop(const QSharedPointer<MockSurface> &surface); void sendDataDeviceLeave(const QSharedPointer<MockSurface> &surface); + void sendAddOutput(); + void sendRemoveOutput(const QSharedPointer<MockOutput> &output); + void sendSurfaceEnter(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output); + void sendSurfaceLeave(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output); void waitForStartDrag(); QSharedPointer<MockSurface> surface(); + QSharedPointer<MockOutput> output(int index = 0); void lock(); void unlock(); diff --git a/tests/auto/client/client/mockinput.cpp b/tests/auto/client/shared/mockinput.cpp index b2bcdf2e6..9cea85b6d 100644 --- a/tests/auto/client/client/mockinput.cpp +++ b/tests/auto/client/shared/mockinput.cpp @@ -32,12 +32,6 @@ namespace Impl { -static Surface *resolveSurface(const QVariant &v) -{ - QSharedPointer<MockSurface> mockSurface = v.value<QSharedPointer<MockSurface> >(); - return mockSurface ? mockSurface->handle() : 0; -} - void Compositor::setKeyboardFocus(void *data, const QList<QVariant> ¶meters) { Compositor *compositor = static_cast<Compositor *>(data); @@ -194,6 +188,7 @@ void Compositor::sendDataDeviceLeave(void *data, const QList<QVariant> ¶mete void Compositor::waitForStartDrag(void *data, const QList<QVariant> ¶meters) { + Q_UNUSED(parameters); Compositor *compositor = static_cast<Compositor *>(data); Q_ASSERT(compositor); while (!compositor->m_startDragSeen) { @@ -239,8 +234,8 @@ void Seat::seat_get_touch(Resource *resource, uint32_t id) Keyboard::Keyboard(Compositor *compositor) : wl_keyboard() , m_compositor(compositor) - , m_focusResource(Q_NULLPTR) - , m_focus(Q_NULLPTR) + , m_focusResource(nullptr) + , m_focus(nullptr) { } @@ -293,8 +288,8 @@ void Keyboard::keyboard_destroy_resource(wl_keyboard::Resource *resource) Pointer::Pointer(Compositor *compositor) : wl_pointer() , m_compositor(compositor) - , m_focusResource(Q_NULLPTR) - , m_focus(Q_NULLPTR) + , m_focusResource(nullptr) + , m_focus(nullptr) { } @@ -447,6 +442,11 @@ DataDevice::~DataDevice() void DataDevice::data_device_start_drag(QtWaylandServer::wl_data_device::Resource *resource, wl_resource *source, wl_resource *origin, wl_resource *icon, uint32_t serial) { + Q_UNUSED(resource); + Q_UNUSED(source); + Q_UNUSED(origin); + Q_UNUSED(icon); + Q_UNUSED(serial); m_compositor->m_startDragSeen = true; } @@ -469,6 +469,7 @@ DataDevice *DataDeviceManager::dataDevice() const void DataDeviceManager::data_device_manager_get_data_device(Resource *resource, uint32_t id, struct ::wl_resource *seat) { + Q_UNUSED(seat); if (!m_data_device) m_data_device.reset(new DataDevice(m_compositor)); m_data_device->add(resource->client(), id, 1); diff --git a/tests/auto/client/client/mockinput.h b/tests/auto/client/shared/mockinput.h index 9c217b6ac..9c217b6ac 100644 --- a/tests/auto/client/client/mockinput.h +++ b/tests/auto/client/shared/mockinput.h diff --git a/tests/auto/client/shared/mockoutput.cpp b/tests/auto/client/shared/mockoutput.cpp new file mode 100644 index 000000000..7d7b7413a --- /dev/null +++ b/tests/auto/client/shared/mockoutput.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mockcompositor.h" +#include "mockoutput.h" + +#include <QDebug> + +namespace Impl { + +void Compositor::sendAddOutput(void *data, const QList<QVariant> ¶meters) { + Q_UNUSED(parameters); + Compositor *compositor = static_cast<Compositor *>(data); + auto output = new Output(compositor->m_display, QSize(1920, 1200), QPoint(0, 0)); + compositor->m_outputs.append(output); + + // Wait for the client to bind to the output + while (output->resourceMap().isEmpty()) + compositor->dispatchEvents(); +} + +void Compositor::sendRemoveOutput(void *data, const QList<QVariant> ¶meters) { + Compositor *compositor = static_cast<Compositor *>(data); + Q_ASSERT(compositor); + Output *output = resolveOutput(parameters.first()); + Q_ASSERT(output); + bool wasRemoved = compositor->m_outputs.removeOne(output); + Q_ASSERT(wasRemoved); + delete output; +} + +void Compositor::setOutputMode(void *data, const QList<QVariant> ¶meters) +{ + Compositor *compositor = static_cast<Compositor *>(data); + QSize size = parameters.first().toSize(); + Output *output = compositor->m_outputs.first(); + Q_ASSERT(output); + output->setCurrentMode(size); +} + +Output::Output(wl_display *display, const QSize &resolution, const QPoint &position) + : wl_output(display, 2) + , m_size(resolution) + , m_position(position) + , m_physicalSize(520, 320) + , m_mockOutput(new MockOutput(this)) +{ +} + +void Output::setCurrentMode(const QSize &size) +{ + qDebug() << Q_FUNC_INFO << size; + m_size = size; + for (Resource *resource : resourceMap()) + sendCurrentMode(resource); +} + +void Output::output_bind_resource(QtWaylandServer::wl_output::Resource *resource) +{ + sendGeometry(resource); + sendCurrentMode(resource); +} + +void Output::sendGeometry(Resource *resource) +{ + const int subPixel = 0; + const int transform = 0; + + send_geometry(resource->handle, + m_position.x(), m_position.y(), + m_physicalSize.width(), m_physicalSize.height(), + subPixel, "", "", transform ); +} + +void Output::sendCurrentMode(Resource *resource) +{ + send_mode(resource->handle, + WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED, + m_size.width(), m_size.height(), 60000); +} + +} // Impl + +MockOutput::MockOutput(Impl::Output *output) + : m_output(output) +{ +} diff --git a/tests/auto/client/client/mockoutput.cpp b/tests/auto/client/shared/mockoutput.h index 86561976f..d5a2bb56b 100644 --- a/tests/auto/client/client/mockoutput.cpp +++ b/tests/auto/client/shared/mockoutput.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -26,42 +26,37 @@ ** ****************************************************************************/ -#include "mockcompositor.h" +#ifndef MOCKOUTPUT_H +#define MOCKOUTPUT_H -namespace Impl { +#include <qglobal.h> -void Compositor::bindOutput(wl_client *client, void *compositorData, uint32_t version, uint32_t id) -{ - wl_resource *resource = wl_resource_create(client, &wl_output_interface, static_cast<int>(version), id); +#include "qwayland-server-wayland.h" - Compositor *compositor = static_cast<Compositor *>(compositorData); - registerResource(&compositor->m_outputResources, resource); +#include "mockcompositor.h" - compositor->sendOutputGeometry(resource); - compositor->sendOutputMode(resource); -} +namespace Impl { -void Compositor::sendOutputGeometry(wl_resource *resource) +class Output : public QtWaylandServer::wl_output { - const QRect &r = m_outputGeometry; - wl_output_send_geometry(resource, r.x(), r.y(), r.width(), r.height(), 0, "", "",0); -} +public: + Output(::wl_display *display, const QSize &resolution, const QPoint &position); -void Compositor::sendOutputMode(wl_resource *resource) -{ - const QRect &r = m_outputGeometry; - wl_output_send_mode(resource, WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED, r.width(), r.height(), 60); -} + QSharedPointer<MockOutput> mockOutput() const { return m_mockOutput; } + void setCurrentMode(const QSize &size); -void Compositor::setOutputGeometry(void *c, const QList<QVariant> ¶meters) -{ - Compositor *compositor = static_cast<Compositor *>(c); - compositor->m_outputGeometry = parameters.first().toRect(); +protected: + void output_bind_resource(Resource *resource) override; - wl_resource *resource; - wl_list_for_each(resource, &compositor->m_outputResources, link) - compositor->sendOutputGeometry(resource); -} +private: + void sendGeometry(Resource *resource); + void sendCurrentMode(Resource *resource); + QSize m_size; + QPoint m_position; + const QSize m_physicalSize; + QSharedPointer<MockOutput> m_mockOutput; +}; } +#endif // MOCKOUTPUT_H diff --git a/tests/auto/client/client/mockshell.cpp b/tests/auto/client/shared/mockshell.cpp index d5eede22e..d5eede22e 100644 --- a/tests/auto/client/client/mockshell.cpp +++ b/tests/auto/client/shared/mockshell.cpp diff --git a/tests/auto/client/client/mocksurface.cpp b/tests/auto/client/shared/mocksurface.cpp index 55712af11..7aa2a00b2 100644 --- a/tests/auto/client/client/mocksurface.cpp +++ b/tests/auto/client/shared/mocksurface.cpp @@ -27,13 +27,42 @@ ****************************************************************************/ #include "mocksurface.h" +#include "mockoutput.h" #include "mockcompositor.h" namespace Impl { +void Compositor::sendSurfaceEnter(void *data, const QList<QVariant> ¶meters) +{ + Q_UNUSED(data); + Surface *surface = resolveSurface(parameters.at(0)); + Output *output = resolveOutput(parameters.at(1)); + Q_ASSERT(surface && surface->resource()); + Q_ASSERT(output); + auto outputResources = output->resourceMap().values(surface->resource()->client()); + Q_ASSERT(!outputResources.isEmpty()); + + for (auto outputResource : outputResources) + surface->send_enter(outputResource->handle); +} + +void Compositor::sendSurfaceLeave(void *data, const QList<QVariant> ¶meters) +{ + Q_UNUSED(data); + Surface *surface = resolveSurface(parameters.at(0)); + Output *output = resolveOutput(parameters.at(1)); + Q_ASSERT(surface && surface->resource()); + Q_ASSERT(output); + auto outputResources = output->resourceMap().values(surface->resource()->client()); + Q_ASSERT(!outputResources.isEmpty()); + + for (auto outputResource : outputResources) + surface->send_leave(outputResource->handle); +} + Surface::Surface(wl_client *client, uint32_t id, int v, Compositor *compositor) : QtWaylandServer::wl_surface(client, id, v) - , m_buffer(Q_NULLPTR) + , m_buffer(nullptr) , m_compositor(compositor) , m_mockSurface(new MockSurface(this)) , m_mapped(false) diff --git a/tests/auto/client/client/mocksurface.h b/tests/auto/client/shared/mocksurface.h index 5155599bb..5155599bb 100644 --- a/tests/auto/client/client/mocksurface.h +++ b/tests/auto/client/shared/mocksurface.h diff --git a/tests/auto/client/shared/mockxdgshellv6.cpp b/tests/auto/client/shared/mockxdgshellv6.cpp new file mode 100644 index 000000000..b26ac1c8d --- /dev/null +++ b/tests/auto/client/shared/mockxdgshellv6.cpp @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mockcompositor.h" +#include "mocksurface.h" + +#include <qwayland-server-xdg-shell-unstable-v6.h> + +namespace Impl { + +class XdgSurfaceV6; + +class XdgToplevelV6 : public QtWaylandServer::zxdg_toplevel_v6 +{ +public: + XdgToplevelV6(XdgSurfaceV6 *xdgSurface, wl_client *client, uint32_t id, int version) + : QtWaylandServer::zxdg_toplevel_v6(client, id, version) + , m_xdgSurface(xdgSurface) + {} + void zxdg_toplevel_v6_destroy_resource(Resource *) override { delete this; } + void zxdg_toplevel_v6_destroy(Resource *resource) override; + XdgSurfaceV6 *m_xdgSurface = nullptr; +}; + +class XdgSurfaceV6 : public QtWaylandServer::zxdg_surface_v6 +{ +public: + XdgSurfaceV6(wl_client *client, uint32_t id, int version, Surface *surface); + void zxdg_surface_v6_destroy_resource(Resource *) override { delete this; } + void zxdg_surface_v6_get_toplevel(Resource *resource, uint32_t id) override; + void zxdg_surface_v6_destroy(Resource *resource) override + { + Q_ASSERT(!m_toplevel); + wl_resource_destroy(resource->handle); + } + Surface *m_surface = nullptr; + XdgToplevelV6 *m_toplevel = nullptr; +}; + +void XdgToplevelV6::zxdg_toplevel_v6_destroy(QtWaylandServer::zxdg_toplevel_v6::Resource *resource) +{ + m_xdgSurface->m_toplevel = nullptr; + wl_resource_destroy(resource->handle); +} + +XdgSurfaceV6::XdgSurfaceV6(wl_client *client, uint32_t id, int version, Surface *surface) + : QtWaylandServer::zxdg_surface_v6(client, id, version) + , m_surface(surface) +{ +} + +void XdgSurfaceV6::zxdg_surface_v6_get_toplevel(QtWaylandServer::zxdg_surface_v6::Resource *resource, uint32_t id) +{ + int version = wl_resource_get_version(resource->handle); + m_toplevel = new XdgToplevelV6(this, resource->client(), id, version); + m_surface->map(); +} + + +void shell_destroy(struct wl_client *client, + struct wl_resource *resource) +{ + Q_UNUSED(client); + Q_UNUSED(resource); +} + +void create_positioner(struct wl_client *client, + struct wl_resource *resource, + uint32_t id) +{ + Q_UNUSED(client); + Q_UNUSED(resource); + Q_UNUSED(id); +} + +void get_xdg_surface(struct wl_client *client, + struct wl_resource *compositorResource, + uint32_t id, + struct wl_resource *surfaceResource) +{ + int version = wl_resource_get_version(compositorResource); + new XdgSurfaceV6(client, id, version, Surface::fromResource(surfaceResource)); +} + +void pong(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial) +{ + Q_UNUSED(client); + Q_UNUSED(resource); + Q_UNUSED(serial); +} + +void Compositor::bindXdgShellV6(wl_client *client, void *compositorData, uint32_t version, uint32_t id) +{ + static const struct zxdg_shell_v6_interface shellInterface = { + shell_destroy, + create_positioner, + get_xdg_surface, + pong + }; + + wl_resource *resource = wl_resource_create(client, &zxdg_shell_v6_interface, static_cast<int>(version), id); + wl_resource_set_implementation(resource, &shellInterface, compositorData, nullptr); +} + +} diff --git a/tests/auto/client/shared/shared.pri b/tests/auto/client/shared/shared.pri new file mode 100644 index 000000000..608664bb7 --- /dev/null +++ b/tests/auto/client/shared/shared.pri @@ -0,0 +1,26 @@ +CONFIG += testcase link_pkgconfig +QT += testlib +QT += core-private gui-private waylandclient-private + +QMAKE_USE += wayland-client wayland-server + +CONFIG += wayland-scanner +WAYLANDSERVERSOURCES += \ + ../../../../src/3rdparty/protocol/wayland.xml \ + ../../../../src/3rdparty/protocol/xdg-shell-unstable-v6.xml + +INCLUDEPATH += ../shared + +SOURCES += \ + ../shared/mockcompositor.cpp \ + ../shared/mockinput.cpp \ + ../shared/mockshell.cpp \ + ../shared/mockxdgshellv6.cpp \ + ../shared/mocksurface.cpp \ + ../shared/mockoutput.cpp + +HEADERS += \ + ../shared/mockcompositor.h \ + ../shared/mockinput.h \ + ../shared/mocksurface.h \ + ../shared/mockoutput.h diff --git a/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp b/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp new file mode 100644 index 000000000..5aac336f2 --- /dev/null +++ b/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mockcompositor.h" + +#include <QBackingStore> +#include <QPainter> +#include <QScreen> +#include <QWindow> +#include <QMimeData> +#include <QPixmap> +#include <QDrag> + +#include <QtTest/QtTest> + +static const QSize screenSize(1600, 1200); + +class TestWindow : public QWindow +{ +public: + TestWindow() + { + setSurfaceType(QSurface::RasterSurface); + setGeometry(0, 0, 32, 32); + create(); + } +}; + +class tst_WaylandClientXdgShellV6 : public QObject +{ + Q_OBJECT +public: + tst_WaylandClientXdgShellV6(MockCompositor *c) + : m_compositor(c) + { + QSocketNotifier *notifier = new QSocketNotifier(m_compositor->waylandFileDescriptor(), QSocketNotifier::Read, this); + connect(notifier, &QSocketNotifier::activated, this, &tst_WaylandClientXdgShellV6::processWaylandEvents); + // connect to the event dispatcher to make sure to flush out the outgoing message queue + connect(QCoreApplication::eventDispatcher(), &QAbstractEventDispatcher::awake, this, &tst_WaylandClientXdgShellV6::processWaylandEvents); + connect(QCoreApplication::eventDispatcher(), &QAbstractEventDispatcher::aboutToBlock, this, &tst_WaylandClientXdgShellV6::processWaylandEvents); + } + +public slots: + void processWaylandEvents() + { + m_compositor->processWaylandEvents(); + } + + void cleanup() + { + // make sure the surfaces from the last test are properly cleaned up + // and don't show up as false positives in the next test + QTRY_VERIFY(!m_compositor->surface()); + } + +private slots: + void createDestroyWindow(); + +private: + MockCompositor *m_compositor; +}; + +void tst_WaylandClientXdgShellV6::createDestroyWindow() +{ + TestWindow window; + window.show(); + + QTRY_VERIFY(m_compositor->surface()); + + window.destroy(); + QTRY_VERIFY(!m_compositor->surface()); +} + +int main(int argc, char **argv) +{ + setenv("XDG_RUNTIME_DIR", ".", 1); + setenv("QT_QPA_PLATFORM", "wayland", 1); // force QGuiApplication to use wayland plugin + setenv("QT_WAYLAND_SHELL_INTEGRATION", "xdg-shell-v6", 1); + + // wayland-egl hangs in the test setup when we try to initialize. Until it gets + // figured out, avoid clientBufferIntegration() from being called in + // QWaylandWindow::createDecorations(). + setenv("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1", 1); + + MockCompositor compositor; + compositor.setOutputMode(screenSize); + + QGuiApplication app(argc, argv); + compositor.applicationInitialized(); + + tst_WaylandClientXdgShellV6 tc(&compositor); + return QTest::qExec(&tc, argc, argv); +} + +#include <tst_xdgshellv6.moc> diff --git a/tests/auto/client/xdgshellv6/xdgshellv6.pro b/tests/auto/client/xdgshellv6/xdgshellv6.pro new file mode 100644 index 000000000..4fec593df --- /dev/null +++ b/tests/auto/client/xdgshellv6/xdgshellv6.pro @@ -0,0 +1,5 @@ +include (../shared/shared.pri) + +TARGET = tst_client_xdgshellv6 +SOURCES += tst_xdgshellv6.cpp + diff --git a/tests/auto/cmake/test_waylandclient/main.cpp b/tests/auto/cmake/test_waylandclient/main.cpp index f0ccdef4b..33f4470bb 100644 --- a/tests/auto/cmake/test_waylandclient/main.cpp +++ b/tests/auto/cmake/test_waylandclient/main.cpp @@ -3,5 +3,5 @@ int main() { // use symbol - QtWaylandClient::QWaylandCursor cursor(Q_NULLPTR); + QtWaylandClient::QWaylandCursor cursor(nullptr); } diff --git a/tests/auto/compositor/compositor/mockclient.cpp b/tests/auto/compositor/compositor/mockclient.cpp index da1096fb9..bdc2b3b93 100644 --- a/tests/auto/compositor/compositor/mockclient.cpp +++ b/tests/auto/compositor/compositor/mockclient.cpp @@ -41,13 +41,13 @@ #include <sys/mman.h> const struct wl_registry_listener MockClient::registryListener = { - MockClient::handleGlobal + MockClient::handleGlobal, + MockClient::handleGlobalRemove }; MockClient::MockClient() : display(wl_display_connect("wayland-qt-test-0")) , compositor(0) - , output(0) , registry(0) , wlshell(0) , xdgShell(nullptr) @@ -74,9 +74,9 @@ MockClient::MockClient() timeout.start(); do { QCoreApplication::processEvents(); - } while (!(compositor && output) && timeout.elapsed() < 1000); + } while (!(compositor && !m_outputs.isEmpty()) && timeout.elapsed() < 1000); - if (!compositor || !output) + if (!compositor || m_outputs.empty()) qFatal("MockClient(): failed to receive globals from display"); } @@ -165,12 +165,19 @@ void MockClient::handleGlobal(void *data, wl_registry *registry, uint32_t id, co resolve(data)->handleGlobal(id, QByteArray(interface)); } +void MockClient::handleGlobalRemove(void *data, wl_registry *wl_registry, uint32_t id) +{ + Q_UNUSED(wl_registry); + resolve(data)->handleGlobalRemove(id); +} + void MockClient::handleGlobal(uint32_t id, const QByteArray &interface) { if (interface == "wl_compositor") { compositor = static_cast<wl_compositor *>(wl_registry_bind(registry, id, &wl_compositor_interface, 1)); } else if (interface == "wl_output") { - output = static_cast<wl_output *>(wl_registry_bind(registry, id, &wl_output_interface, 2)); + auto output = static_cast<wl_output *>(wl_registry_bind(registry, id, &wl_output_interface, 2)); + m_outputs.insert(id, output); wl_output_add_listener(output, &outputListener, this); } else if (interface == "wl_shm") { shm = static_cast<wl_shm *>(wl_registry_bind(registry, id, &wl_shm_interface, 1)); @@ -186,6 +193,11 @@ void MockClient::handleGlobal(uint32_t id, const QByteArray &interface) } } +void MockClient::handleGlobalRemove(uint32_t id) +{ + m_outputs.remove(id); +} + wl_surface *MockClient::createSurface() { flushDisplay(); @@ -248,7 +260,7 @@ ShmBuffer::ShmBuffer(const QSize &size, wl_shm *shm) ShmBuffer::~ShmBuffer() { - munmap(image.bits(), image.byteCount()); + munmap(image.bits(), image.sizeInBytes()); wl_buffer_destroy(handle); wl_shm_pool_destroy(shm_pool); } diff --git a/tests/auto/compositor/compositor/mockclient.h b/tests/auto/compositor/compositor/mockclient.h index 1881393a6..dd50f9a28 100644 --- a/tests/auto/compositor/compositor/mockclient.h +++ b/tests/auto/compositor/compositor/mockclient.h @@ -64,7 +64,7 @@ public: wl_display *display; wl_compositor *compositor; - wl_output *output; + QMap<uint, wl_output *> m_outputs; wl_shm *shm; wl_registry *registry; wl_shell *wlshell; @@ -96,6 +96,7 @@ private: static MockClient *resolve(void *data) { return static_cast<MockClient *>(data); } static const struct wl_registry_listener registryListener; static void handleGlobal(void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version); + static void handleGlobalRemove(void *data, struct wl_registry *wl_registry, uint32_t id); static int sourceUpdate(uint32_t mask, void *data); static void outputGeometryEvent(void *data, @@ -117,6 +118,7 @@ private: static void outputScale(void *data, wl_output *output, int factor); void handleGlobal(uint32_t id, const QByteArray &interface); + void handleGlobalRemove(uint32_t id); static const wl_output_listener outputListener; }; diff --git a/tests/auto/compositor/compositor/testcompositor.cpp b/tests/auto/compositor/compositor/testcompositor.cpp index 733bea5b3..f91d0d3f1 100644 --- a/tests/auto/compositor/compositor/testcompositor.cpp +++ b/tests/auto/compositor/compositor/testcompositor.cpp @@ -42,7 +42,7 @@ TestCompositor::TestCompositor(bool createInputDev) void TestCompositor::create() { - new QWaylandOutput(this, Q_NULLPTR); + new QWaylandOutput(this, nullptr); QWaylandCompositor::create(); connect(this, &QWaylandCompositor::surfaceCreated, this, &TestCompositor::onSurfaceCreated); diff --git a/tests/auto/compositor/compositor/tst_compositor.cpp b/tests/auto/compositor/compositor/tst_compositor.cpp index c51c13bd6..96095a0d4 100644 --- a/tests/auto/compositor/compositor/tst_compositor.cpp +++ b/tests/auto/compositor/compositor/tst_compositor.cpp @@ -67,6 +67,7 @@ private slots: void sizeFollowsWindow(); void mapSurface(); void frameCallback(); + void removeOutput(); void advertisesXdgShellSupport(); void createsXdgSurfaces(); @@ -201,7 +202,7 @@ void tst_WaylandCompositor::keyboardGrab() QTRY_COMPARE(grabKeyReleaseSpy.count(), 2); // Stop grabbing - seat->setKeyboardFocus(Q_NULLPTR); + seat->setKeyboardFocus(nullptr); seat->sendFullKeyEvent(&ke); seat->sendFullKeyEvent(&ke1); QTRY_COMPARE(grabKeyPressSpy.count(), 2); @@ -378,6 +379,22 @@ void tst_WaylandCompositor::frameCallback() wl_surface_destroy(surface); } +void tst_WaylandCompositor::removeOutput() +{ + TestCompositor compositor; + QWindow window; + window.resize(800, 600); + auto output = new QWaylandOutput(&compositor, &window); + + compositor.create(); + MockClient client; + QTRY_COMPARE(client.m_outputs.size(), 2); + + delete output; + compositor.flushClients(); + QTRY_COMPARE(client.m_outputs.size(), 1); +} + void tst_WaylandCompositor::seatCapabilities() { TestCompositor compositor; |