diff options
Diffstat (limited to 'tests/auto/compositor/compositor')
-rw-r--r-- | tests/auto/compositor/compositor/BLACKLIST | 2 | ||||
-rw-r--r-- | tests/auto/compositor/compositor/compositor.pro | 40 | ||||
-rw-r--r-- | tests/auto/compositor/compositor/mockclient.cpp | 215 | ||||
-rw-r--r-- | tests/auto/compositor/compositor/mockclient.h | 108 | ||||
-rw-r--r-- | tests/auto/compositor/compositor/mockseat.cpp | 43 | ||||
-rw-r--r-- | tests/auto/compositor/compositor/mockseat.h | 45 | ||||
-rw-r--r-- | tests/auto/compositor/compositor/testcompositor.cpp | 77 | ||||
-rw-r--r-- | tests/auto/compositor/compositor/testcompositor.h | 54 | ||||
-rw-r--r-- | tests/auto/compositor/compositor/testkeyboardgrabber.cpp | 58 | ||||
-rw-r--r-- | tests/auto/compositor/compositor/testkeyboardgrabber.h | 49 | ||||
-rw-r--r-- | tests/auto/compositor/compositor/testseat.cpp | 55 | ||||
-rw-r--r-- | tests/auto/compositor/compositor/testseat.h | 54 | ||||
-rw-r--r-- | tests/auto/compositor/compositor/tst_compositor.cpp | 576 |
13 files changed, 1376 insertions, 0 deletions
diff --git a/tests/auto/compositor/compositor/BLACKLIST b/tests/auto/compositor/compositor/BLACKLIST new file mode 100644 index 000000000..df4672be3 --- /dev/null +++ b/tests/auto/compositor/compositor/BLACKLIST @@ -0,0 +1,2 @@ +[keyboardGrab] +ubuntu-14.04 diff --git a/tests/auto/compositor/compositor/compositor.pro b/tests/auto/compositor/compositor/compositor.pro new file mode 100644 index 000000000..a3748697d --- /dev/null +++ b/tests/auto/compositor/compositor/compositor.pro @@ -0,0 +1,40 @@ +CONFIG += testcase link_pkgconfig +CONFIG += wayland-scanner +TARGET = tst_compositor + +QT += testlib +QT += core-private gui-private waylandcompositor waylandcompositor-private + +!contains(QT_CONFIG, no-pkg-config) { + PKGCONFIG += wayland-client wayland-server +} else { + LIBS += -lwayland-client -lwayland-server +} + +config_xkbcommon { + !contains(QT_CONFIG, no-pkg-config) { + PKGCONFIG_PRIVATE += xkbcommon + } else { + LIBS_PRIVATE += -lxkbcommon + } +} else { + DEFINES += QT_NO_WAYLAND_XKB +} + +WAYLANDCLIENTSOURCES += \ + ../../../../src/3rdparty/protocol/xdg-shell.xml \ + +SOURCES += \ + tst_compositor.cpp \ + testcompositor.cpp \ + testkeyboardgrabber.cpp \ + mockclient.cpp \ + mockseat.cpp \ + testseat.cpp + +HEADERS += \ + testcompositor.h \ + testkeyboardgrabber.h \ + mockclient.h \ + mockseat.h \ + testseat.h diff --git a/tests/auto/compositor/compositor/mockclient.cpp b/tests/auto/compositor/compositor/mockclient.cpp new file mode 100644 index 000000000..9b6d327a9 --- /dev/null +++ b/tests/auto/compositor/compositor/mockclient.cpp @@ -0,0 +1,215 @@ +/**************************************************************************** +** +** 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 "mockclient.h" +#include "mockseat.h" + +#include <QElapsedTimer> +#include <QSocketNotifier> + +#include <private/qguiapplication_p.h> + +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <errno.h> +#include <sys/mman.h> + +const struct wl_registry_listener MockClient::registryListener = { + MockClient::handleGlobal +}; + +MockClient::MockClient() + : display(wl_display_connect("wayland-qt-test-0")) + , compositor(0) + , output(0) + , registry(0) + , wlshell(0) + , xdgShell(nullptr) +{ + if (!display) + qFatal("MockClient(): wl_display_connect() failed"); + + registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istryListener, this); + + fd = wl_display_get_fd(display); + + QSocketNotifier *readNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this); + connect(readNotifier, SIGNAL(activated(int)), this, SLOT(readEvents())); + + QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher; + connect(dispatcher, SIGNAL(awake()), this, SLOT(flushDisplay())); + + QElapsedTimer timeout; + timeout.start(); + do { + QCoreApplication::processEvents(); + } while (!(compositor && output) && timeout.elapsed() < 1000); + + if (!compositor || !output) + qFatal("MockClient(): failed to receive globals from display"); +} + +const wl_output_listener MockClient::outputListener = { + MockClient::outputGeometryEvent, + MockClient::outputModeEvent, + MockClient::outputDone, + MockClient::outputScale +}; + +MockClient::~MockClient() +{ + wl_display_disconnect(display); +} + +void MockClient::outputGeometryEvent(void *data, wl_output *, + int32_t x, int32_t y, + int32_t width, int32_t height, + int, const char *, const char *, + int32_t ) +{ + Q_UNUSED(width); + Q_UNUSED(height); + resolve(data)->geometry.moveTopLeft(QPoint(x, y)); +} + +void MockClient::outputModeEvent(void *data, wl_output *, uint32_t, + int w, int h, int) +{ + resolve(data)->geometry.setSize(QSize(w, h)); +} + +void MockClient::outputDone(void *, wl_output *) +{ + +} + +void MockClient::outputScale(void *, wl_output *, int) +{ + +} + +void MockClient::readEvents() +{ + wl_display_dispatch(display); +} + +void MockClient::flushDisplay() +{ + wl_display_dispatch_pending(display); + wl_display_flush(display); +} + +void MockClient::handleGlobal(void *data, wl_registry *registry, uint32_t id, const char *interface, uint32_t version) +{ + Q_UNUSED(registry); + Q_UNUSED(version); + resolve(data)->handleGlobal(id, QByteArray(interface)); +} + +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)); + 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)); + } else if (interface == "wl_shell") { + wlshell = static_cast<wl_shell *>(wl_registry_bind(registry, id, &wl_shell_interface, 1)); + } else if (interface == "xdg_shell") { + xdgShell = static_cast<xdg_shell *>(wl_registry_bind(registry, id, &xdg_shell_interface, 1)); + } else if (interface == "wl_seat") { + wl_seat *s = static_cast<wl_seat *>(wl_registry_bind(registry, id, &wl_seat_interface, 1)); + m_seats << new MockSeat(s); + } +} + +wl_surface *MockClient::createSurface() +{ + flushDisplay(); + return wl_compositor_create_surface(compositor); +} + +wl_shell_surface *MockClient::createShellSurface(wl_surface *surface) +{ + flushDisplay(); + return wl_shell_get_shell_surface(wlshell, surface); +} + +xdg_surface *MockClient::createXdgSurface(wl_surface *surface) +{ + flushDisplay(); + return xdg_shell_get_xdg_surface(xdgShell, surface); +} + +ShmBuffer::ShmBuffer(const QSize &size, wl_shm *shm) + : handle(0) +{ + int stride = size.width() * 4; + int alloc = stride * size.height(); + + char filename[] = "/tmp/wayland-shm-XXXXXX"; + + int fd = mkstemp(filename); + if (fd < 0) { + qWarning("open %s failed: %s", filename, strerror(errno)); + return; + } + + if (ftruncate(fd, alloc) < 0) { + qWarning("ftruncate failed: %s", strerror(errno)); + close(fd); + return; + } + + void *data = mmap(0, alloc, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + unlink(filename); + + if (data == MAP_FAILED) { + qWarning("mmap failed: %s", strerror(errno)); + close(fd); + return; + } + + image = QImage(static_cast<uchar *>(data), size.width(), size.height(), stride, QImage::Format_ARGB32_Premultiplied); + shm_pool = wl_shm_create_pool(shm,fd,alloc); + handle = wl_shm_pool_create_buffer(shm_pool,0, size.width(), size.height(), + stride, WL_SHM_FORMAT_ARGB8888); + close(fd); +} + +ShmBuffer::~ShmBuffer() +{ + munmap(image.bits(), image.byteCount()); + 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 new file mode 100644 index 000000000..33ada638a --- /dev/null +++ b/tests/auto/compositor/compositor/mockclient.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** 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 <wayland-client.h> +#include <wayland-xdg-shell-client-protocol.h> + +#include <QObject> +#include <QImage> +#include <QRect> +#include <QList> + +class MockSeat; + +class ShmBuffer +{ +public: + ShmBuffer(const QSize &size, wl_shm *shm); + ~ShmBuffer(); + + struct wl_buffer *handle; + struct wl_shm_pool *shm_pool; + QImage image; +}; + +class MockClient : public QObject +{ + Q_OBJECT + +public: + MockClient(); + ~MockClient(); + + wl_surface *createSurface(); + wl_shell_surface *createShellSurface(wl_surface *surface); + xdg_surface *createXdgSurface(wl_surface *surface); + + wl_display *display; + wl_compositor *compositor; + wl_output *output; + wl_shm *shm; + wl_registry *registry; + wl_shell *wlshell; + xdg_shell *xdgShell; + + QList<MockSeat *> m_seats; + + QRect geometry; + + int fd; + +private slots: + void readEvents(); + void flushDisplay(); + +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 int sourceUpdate(uint32_t mask, void *data); + + static void outputGeometryEvent(void *data, + wl_output *output, + int32_t x, int32_t y, + int32_t width, int32_t height, + int subpixel, + const char *make, + const char *model, + int32_t transform); + + static void outputModeEvent(void *data, + wl_output *wl_output, + uint32_t flags, + int width, + int height, + int refresh); + static void outputDone(void *data, wl_output *output); + static void outputScale(void *data, wl_output *output, int factor); + + void handleGlobal(uint32_t id, const QByteArray &interface); + + static const wl_output_listener outputListener; +}; + diff --git a/tests/auto/compositor/compositor/mockseat.cpp b/tests/auto/compositor/compositor/mockseat.cpp new file mode 100644 index 000000000..29c4a4e13 --- /dev/null +++ b/tests/auto/compositor/compositor/mockseat.cpp @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2016 LG Electronics Ltd., author: <mikko.levonmaa@lge.com> +** 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 "mockseat.h" + +MockSeat::MockSeat(wl_seat *seat) + : m_seat(seat) +{ + // Bind to the keyboard interface so that the compositor has + // the right resource associations + m_keyboard = wl_seat_get_keyboard(seat); +} + +MockSeat::~MockSeat() +{ + wl_keyboard_destroy(m_keyboard); + wl_seat_destroy(m_seat); +} diff --git a/tests/auto/compositor/compositor/mockseat.h b/tests/auto/compositor/compositor/mockseat.h new file mode 100644 index 000000000..1c6d324c2 --- /dev/null +++ b/tests/auto/compositor/compositor/mockseat.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2016 LG Electronics Ltd., author: <mikko.levonmaa@lge.com> +** 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$ +** +****************************************************************************/ +#ifndef MOCKSEAT +#define MOCKSEAT + +#include <QObject> +#include <wayland-client.h> + +class MockSeat : public QObject +{ + Q_OBJECT + +public: + MockSeat(wl_seat *seat); + ~MockSeat(); + + wl_seat *m_seat; + wl_keyboard *m_keyboard; +}; +#endif diff --git a/tests/auto/compositor/compositor/testcompositor.cpp b/tests/auto/compositor/compositor/testcompositor.cpp new file mode 100644 index 000000000..733bea5b3 --- /dev/null +++ b/tests/auto/compositor/compositor/testcompositor.cpp @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** 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 "testcompositor.h" +#include "testseat.h" +#include "testkeyboardgrabber.h" + +#include <wayland-server.h> + +TestCompositor::TestCompositor(bool createInputDev) + : QWaylandCompositor() + , shell(new QWaylandWlShell(this)) + , m_createSeat(createInputDev) +{ + setSocketName("wayland-qt-test-0"); +} + +void TestCompositor::create() +{ + new QWaylandOutput(this, Q_NULLPTR); + QWaylandCompositor::create(); + + connect(this, &QWaylandCompositor::surfaceCreated, this, &TestCompositor::onSurfaceCreated); + connect(this, &QWaylandCompositor::surfaceAboutToBeDestroyed, this, &TestCompositor::onSurfaceAboutToBeDestroyed); +} + +void TestCompositor::flushClients() +{ + wl_display_flush_clients(display()); +} + +void TestCompositor::onSurfaceCreated(QWaylandSurface *surface) +{ + surfaces << surface; +} + +void TestCompositor::onSurfaceAboutToBeDestroyed(QWaylandSurface *surface) +{ + surfaces.removeOne(surface); +} + +QWaylandSeat *TestCompositor::createSeat() +{ + if (m_createSeat) + return new TestSeat(this, QWaylandSeat::Pointer | QWaylandSeat::Keyboard); + else + return QWaylandCompositor::createSeat(); +} + +QWaylandKeyboard *TestCompositor::createKeyboardDevice(QWaylandSeat *seat) { + return new TestKeyboardGrabber(seat); +} diff --git a/tests/auto/compositor/compositor/testcompositor.h b/tests/auto/compositor/compositor/testcompositor.h new file mode 100644 index 000000000..8eeb7ade6 --- /dev/null +++ b/tests/auto/compositor/compositor/testcompositor.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** 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 "qwaylandcompositor.h" +#include "qwaylandsurface.h" +#include "qwaylandwlshell.h" + +class TestCompositor : public QWaylandCompositor +{ + Q_OBJECT +public: + TestCompositor(bool createInputDev = false); + void create(); + void flushClients(); + +public slots: + void onSurfaceCreated(QWaylandSurface *surface); + void onSurfaceAboutToBeDestroyed(QWaylandSurface *surface); + +protected: + QWaylandSeat *createSeat() Q_DECL_OVERRIDE; + QWaylandKeyboard *createKeyboardDevice(QWaylandSeat *seat) Q_DECL_OVERRIDE; + +public: + QList<QWaylandSurface *> surfaces; + QWaylandWlShell* shell; + bool m_createSeat; +}; + diff --git a/tests/auto/compositor/compositor/testkeyboardgrabber.cpp b/tests/auto/compositor/compositor/testkeyboardgrabber.cpp new file mode 100644 index 000000000..a3aa42ac2 --- /dev/null +++ b/tests/auto/compositor/compositor/testkeyboardgrabber.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2016 LG Electronics, Inc., author: <mikko.levonmaa@lge.com> +** 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 "testkeyboardgrabber.h" + +TestKeyboardGrabber::TestKeyboardGrabber(QWaylandSeat *seat) + : QWaylandKeyboard(seat) +{ +} + +void TestKeyboardGrabber::setFocus(QWaylandSurface *surface) +{ + Q_EMIT focusedCalled(); + QWaylandKeyboard::setFocus(surface); +} + +void TestKeyboardGrabber::sendKeyPressEvent(uint code) +{ + Q_EMIT keyPressCalled(); + QWaylandKeyboard::sendKeyPressEvent(code); +} + +void TestKeyboardGrabber::sendKeyReleaseEvent(uint code) +{ + Q_EMIT keyReleaseCalled(); + QWaylandKeyboard::sendKeyReleaseEvent(code); +} + +void TestKeyboardGrabber::sendKeyModifiers(QWaylandClient *client, uint32_t serial) +{ + Q_EMIT modifiersCalled(); + QWaylandKeyboard::sendKeyModifiers(client, serial); +} diff --git a/tests/auto/compositor/compositor/testkeyboardgrabber.h b/tests/auto/compositor/compositor/testkeyboardgrabber.h new file mode 100644 index 000000000..0ef595987 --- /dev/null +++ b/tests/auto/compositor/compositor/testkeyboardgrabber.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2016 LG Electronics, Inc., author: <mikko.levonmaa@lge.com> +** 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 "qwaylandkeyboard.h" + +class TestKeyboardGrabber : public QWaylandKeyboard +{ + Q_OBJECT +public: + TestKeyboardGrabber(QWaylandSeat *seat); + + void setFocus(QWaylandSurface *surface) Q_DECL_OVERRIDE; + void sendKeyModifiers(QWaylandClient *client, uint32_t serial) Q_DECL_OVERRIDE; + void sendKeyPressEvent(uint code) Q_DECL_OVERRIDE; + void sendKeyReleaseEvent(uint code) Q_DECL_OVERRIDE; + +signals: + void focusedCalled(); + void keyPressCalled(); + void keyReleaseCalled(); + void modifiersCalled(); +}; + + diff --git a/tests/auto/compositor/compositor/testseat.cpp b/tests/auto/compositor/compositor/testseat.cpp new file mode 100644 index 000000000..38227872b --- /dev/null +++ b/tests/auto/compositor/compositor/testseat.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2016 LG Electronics, Inc., author: <mikko.levonmaa@lge.com> +** 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 "testseat.h" +#include <QMouseEvent> + +TestSeat::TestSeat(QWaylandCompositor *compositor, QWaylandSeat::CapabilityFlags caps) + : QWaylandSeat(compositor, caps) +{ + m_queryCount = 0; +} + +TestSeat::~TestSeat() +{ +} + +bool TestSeat::isOwner(QInputEvent *event) const +{ + m_queryCount++; + QMouseEvent *me = dynamic_cast<QMouseEvent *>(event); + return m_events.contains(me); +} + +QList<QMouseEvent *> TestSeat::createMouseEvents(int count) +{ + for (int i = 0; i < count; i++) { + m_events.append(new QMouseEvent(QEvent::MouseMove, QPointF(10 + i, 10 + i), Qt::NoButton, Qt::NoButton, Qt::NoModifier)); + } + return m_events; +} diff --git a/tests/auto/compositor/compositor/testseat.h b/tests/auto/compositor/compositor/testseat.h new file mode 100644 index 000000000..54641c07d --- /dev/null +++ b/tests/auto/compositor/compositor/testseat.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2016 LG Electronics, Inc., author: <mikko.levonmaa@lge.com> +** 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 <QWaylandSeat> +#include <QList> + +QT_BEGIN_NAMESPACE +class QInputEvent; +class QMouseEvent; +QT_END_NAMESPACE + +class TestSeat : public QWaylandSeat +{ + +public: + + TestSeat(QWaylandCompositor *compositor, QWaylandSeat::CapabilityFlags caps); + ~TestSeat(); + + bool isOwner(QInputEvent *inputEvent) const Q_DECL_OVERRIDE; + + QList<QMouseEvent *> createMouseEvents(int count); + + int queryCount() { return m_queryCount; } + +private: + mutable int m_queryCount; + QList<QMouseEvent *> m_events; +}; diff --git a/tests/auto/compositor/compositor/tst_compositor.cpp b/tests/auto/compositor/compositor/tst_compositor.cpp new file mode 100644 index 000000000..05e876dd0 --- /dev/null +++ b/tests/auto/compositor/compositor/tst_compositor.cpp @@ -0,0 +1,576 @@ +/**************************************************************************** +** +** 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 "mockclient.h" +#include "testcompositor.h" +#include "testkeyboardgrabber.h" +#include "testseat.h" + +#include "qwaylandview.h" +#include "qwaylandbufferref.h" +#include "qwaylandseat.h" + +#include <QtWaylandCompositor/QWaylandXdgShell> +#include <QtWaylandCompositor/QWaylandSurface> +#include <QtWaylandCompositor/QWaylandResource> +#include <qwayland-xdg-shell.h> + +#include <QtTest/QtTest> + +class tst_WaylandCompositor : public QObject +{ + Q_OBJECT + +private slots: + void init(); + void seatCapabilities(); + void keyboardGrab(); + void seatCreation(); + void seatKeyboardFocus(); + void singleClient(); + void multipleClients(); + void geometry(); + void mapSurface(); + void frameCallback(); + void advertisesXdgShellSupport(); + void createsXdgSurfaces(); + void reportsXdgSurfaceWindowGeometry(); + void setsXdgAppId(); + void sendsXdgConfigure(); +}; + +void tst_WaylandCompositor::init() { + qputenv("XDG_RUNTIME_DIR", "."); +} + +void tst_WaylandCompositor::singleClient() +{ + TestCompositor compositor; + compositor.create(); + + MockClient client; + + wl_surface *sa = client.createSurface(); + QTRY_COMPARE(compositor.surfaces.size(), 1); + + wl_surface *sb = client.createSurface(); + QTRY_COMPARE(compositor.surfaces.size(), 2); + + QWaylandClient *ca = compositor.surfaces.at(0)->client(); + QWaylandClient *cb = compositor.surfaces.at(1)->client(); + + QCOMPARE(ca, cb); + QVERIFY(ca != 0); + + QList<QWaylandSurface *> surfaces = compositor.surfacesForClient(ca); + QCOMPARE(surfaces.size(), 2); + QVERIFY((surfaces.at(0) == compositor.surfaces.at(0) && surfaces.at(1) == compositor.surfaces.at(1)) + || (surfaces.at(0) == compositor.surfaces.at(1) && surfaces.at(1) == compositor.surfaces.at(0))); + + wl_surface_destroy(sa); + QTRY_COMPARE(compositor.surfaces.size(), 1); + + wl_surface_destroy(sb); + QTRY_COMPARE(compositor.surfaces.size(), 0); +} + +void tst_WaylandCompositor::multipleClients() +{ + TestCompositor compositor; + compositor.create(); + + MockClient a; + MockClient b; + MockClient c; + + wl_surface *sa = a.createSurface(); + wl_surface *sb = b.createSurface(); + wl_surface *sc = c.createSurface(); + + QTRY_COMPARE(compositor.surfaces.size(), 3); + + QWaylandClient *ca = compositor.surfaces.at(0)->client(); + QWaylandClient *cb = compositor.surfaces.at(1)->client(); + QWaylandClient *cc = compositor.surfaces.at(2)->client(); + + QVERIFY(ca != cb); + QVERIFY(ca != cc); + QVERIFY(cb != cc); + QVERIFY(ca != 0); + + QCOMPARE(compositor.surfacesForClient(ca).size(), 1); + QCOMPARE(compositor.surfacesForClient(ca).at(0), compositor.surfaces.at(0)); + + QCOMPARE(compositor.surfacesForClient(cb).size(), 1); + QCOMPARE(compositor.surfacesForClient(cb).at(0), compositor.surfaces.at(1)); + + QCOMPARE(compositor.surfacesForClient(cc).size(), 1); + QCOMPARE(compositor.surfacesForClient(cc).at(0), compositor.surfaces.at(2)); + + wl_surface_destroy(sa); + wl_surface_destroy(sb); + wl_surface_destroy(sc); + + QTRY_COMPARE(compositor.surfaces.size(), 0); +} + +void tst_WaylandCompositor::keyboardGrab() +{ + TestCompositor compositor; + compositor.create(); + MockClient mc; + + mc.createSurface(); + // This is needed for timing purposes, otherwise the query for the + // compositor surfaces will return null + QTRY_COMPARE(compositor.surfaces.size(), 1); + + // Set the focused surface so that key event will flow through + QWaylandSurface *waylandSurface = compositor.surfaces.at(0); + QWaylandSeat* seat = compositor.defaultSeat(); + + TestKeyboardGrabber* grab = static_cast<TestKeyboardGrabber *>(seat->keyboard()); + QTRY_COMPARE(grab, seat->keyboard()); + QSignalSpy grabFocusSpy(grab, SIGNAL(focusedCalled())); + QSignalSpy grabKeyPressSpy(grab, SIGNAL(keyPressCalled())); + QSignalSpy grabKeyReleaseSpy(grab, SIGNAL(keyReleaseCalled())); + //QSignalSpy grabModifierSpy(grab, SIGNAL(modifiersCalled())); + + seat->setKeyboardFocus(waylandSurface); + QTRY_COMPARE(grabFocusSpy.count(), 1); + + QKeyEvent ke(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier, 30, 0, 0); + QKeyEvent ke1(QEvent::KeyRelease, Qt::Key_A, Qt::NoModifier, 30, 0, 0); + seat->sendFullKeyEvent(&ke); + seat->sendFullKeyEvent(&ke1); + QTRY_COMPARE(grabKeyPressSpy.count(), 1); + QTRY_COMPARE(grabKeyReleaseSpy.count(), 1); + + QKeyEvent ke2(QEvent::KeyPress, Qt::Key_Shift, Qt::NoModifier, 50, 0, 0); + QKeyEvent ke3(QEvent::KeyRelease, Qt::Key_Shift, Qt::NoModifier, 50, 0, 0); + seat->sendFullKeyEvent(&ke2); + seat->sendFullKeyEvent(&ke3); + //QTRY_COMPARE(grabModifierSpy.count(), 2); + // Modifiers are also keys + QTRY_COMPARE(grabKeyPressSpy.count(), 2); + QTRY_COMPARE(grabKeyReleaseSpy.count(), 2); + + // Stop grabbing + seat->setKeyboardFocus(Q_NULLPTR); + seat->sendFullKeyEvent(&ke); + seat->sendFullKeyEvent(&ke1); + QTRY_COMPARE(grabKeyPressSpy.count(), 2); +} + +void tst_WaylandCompositor::geometry() +{ + TestCompositor compositor; + compositor.create(); + + QRect geometry(0, 0, 4096, 3072); + compositor.defaultOutput()->setGeometry(geometry); + + MockClient client; + + QTRY_COMPARE(client.geometry, geometry); +} + +void tst_WaylandCompositor::mapSurface() +{ + TestCompositor compositor; + compositor.create(); + + MockClient client; + + wl_surface *surface = client.createSurface(); + QTRY_COMPARE(compositor.surfaces.size(), 1); + + QWaylandSurface *waylandSurface = compositor.surfaces.at(0); + + QSignalSpy hasContentSpy(waylandSurface, SIGNAL(hasContentChanged())); + + QCOMPARE(waylandSurface->size(), QSize()); + QCOMPARE(waylandSurface->hasContent(), false); + + QSize size(256, 256); + ShmBuffer buffer(size, client.shm); + + // we need to create a shell surface here or the surface won't be mapped + client.createShellSurface(surface); + wl_surface_attach(surface, buffer.handle, 0, 0); + wl_surface_damage(surface, 0, 0, size.width(), size.height()); + wl_surface_commit(surface); + + QTRY_COMPARE(waylandSurface->size(), size); + QTRY_COMPARE(waylandSurface->hasContent(), true); + QTRY_COMPARE(hasContentSpy.count(), 1); + + wl_surface_destroy(surface); +} + +static void frameCallbackFunc(void *data, wl_callback *callback, uint32_t) +{ + ++*static_cast<int *>(data); + wl_callback_destroy(callback); +} + +static void registerFrameCallback(wl_surface *surface, int *counter) +{ + static const wl_callback_listener frameCallbackListener = { + frameCallbackFunc + }; + + wl_callback_add_listener(wl_surface_frame(surface), &frameCallbackListener, counter); +} + +void tst_WaylandCompositor::frameCallback() +{ + class BufferView : public QWaylandView + { + public: + void attach(const QWaylandBufferRef &ref, const QRegion &damage) Q_DECL_OVERRIDE + { + Q_UNUSED(damage); + bufferRef = ref; + } + + QImage image() const + { + if (bufferRef.isNull() || !bufferRef.isSharedMemory()) + return QImage(); + return bufferRef.image(); + } + + QWaylandBufferRef bufferRef; + }; + + TestCompositor compositor; + compositor.create(); + + MockClient client; + + wl_surface *surface = client.createSurface(); + + int frameCounter = 0; + + QTRY_COMPARE(compositor.surfaces.size(), 1); + QWaylandSurface *waylandSurface = compositor.surfaces.at(0); + BufferView* view = new BufferView; + view->setSurface(waylandSurface); + view->setOutput(compositor.defaultOutput()); + + QSignalSpy damagedSpy(waylandSurface, SIGNAL(damaged(const QRegion &))); + + for (int i = 0; i < 10; ++i) { + QSize size(i * 8 + 2, i * 8 + 2); + ShmBuffer buffer(size, client.shm); + + // attach a new buffer every frame, else the damage signal won't be fired + wl_surface_attach(surface, buffer.handle, 0, 0); + registerFrameCallback(surface, &frameCounter); + wl_surface_damage(surface, 0, 0, size.width(), size.height()); + wl_surface_commit(surface); + + QTRY_COMPARE(waylandSurface->hasContent(), true); + QTRY_COMPARE(damagedSpy.count(), i + 1); + + QCOMPARE(static_cast<BufferView*>(waylandSurface->views().first())->image(), buffer.image); + compositor.defaultOutput()->frameStarted(); + compositor.defaultOutput()->sendFrameCallbacks(); + + QTRY_COMPARE(frameCounter, i + 1); + } + + wl_surface_destroy(surface); +} + +void tst_WaylandCompositor::seatCapabilities() +{ + TestCompositor compositor; + compositor.create(); + + MockClient client; + Q_UNUSED(client); + + QWaylandSeat dev(&compositor, QWaylandSeat::Pointer); + + QTRY_VERIFY(dev.pointer()); + QTRY_VERIFY(!dev.keyboard()); + QTRY_VERIFY(!dev.touch()); + + QWaylandSeat dev2(&compositor, QWaylandSeat::Keyboard | QWaylandSeat::Touch); + QTRY_VERIFY(!dev2.pointer()); + QTRY_VERIFY(dev2.keyboard()); + QTRY_VERIFY(dev2.touch()); +} + +void tst_WaylandCompositor::seatCreation() +{ + TestCompositor compositor(true); + compositor.create(); + + MockClient client; + Q_UNUSED(client); + + TestSeat* dev = static_cast<TestSeat*>(compositor.defaultSeat()); + + // The compositor will create the default input device + QTRY_COMPARE(compositor.defaultSeat(), dev); + + QList<QMouseEvent *> allEvents; + allEvents += dev->createMouseEvents(5); + foreach (QMouseEvent *me, allEvents) { + compositor.seatFor(me); + } + + // The default input device will get called exatly the number of times it has created + // the events + QTRY_COMPARE(dev->queryCount(), 5); +} + +void tst_WaylandCompositor::seatKeyboardFocus() +{ + TestCompositor compositor(true); + compositor.create(); + + // Create client after all the input devices have been set up as the mock client + // does not dynamically listen to new seats + MockClient client; + wl_surface *surface = client.createSurface(); + QTRY_COMPARE(compositor.surfaces.size(), 1); + + QWaylandSurface *waylandSurface = compositor.surfaces.at(0); + QWaylandSeat* dev = compositor.defaultSeat(); + dev->setKeyboardFocus(waylandSurface); + QTRY_COMPARE(compositor.defaultSeat()->keyboardFocus(), waylandSurface); + + wl_surface_destroy(surface); + QTRY_VERIFY(compositor.surfaces.size() == 0); + + QTRY_VERIFY(!compositor.defaultSeat()->keyboardFocus()); +} + +class XdgTestCompositor: public TestCompositor { + Q_OBJECT +public: + XdgTestCompositor() : xdgShell(this) {} + QWaylandXdgShell xdgShell; +}; + +void tst_WaylandCompositor::advertisesXdgShellSupport() +{ + XdgTestCompositor compositor; + compositor.create(); + + MockClient client; + QTRY_VERIFY(&client.xdgShell); +} + +void tst_WaylandCompositor::createsXdgSurfaces() +{ + XdgTestCompositor compositor; + compositor.create(); + + MockClient client; + QTRY_VERIFY(&client.xdgShell); + + QSignalSpy xdgSurfaceCreatedSpy(&compositor.xdgShell, &QWaylandXdgShell::xdgSurfaceCreated); + QWaylandXdgSurface *xdgSurface = nullptr; + QObject::connect(&compositor.xdgShell, &QWaylandXdgShell::xdgSurfaceCreated, [&](QWaylandXdgSurface *s) { + xdgSurface = s; + }); + + wl_surface *surface = client.createSurface(); + client.createXdgSurface(surface); + QTRY_COMPARE(xdgSurfaceCreatedSpy.count(), 1); + QTRY_VERIFY(xdgSurface); + QTRY_VERIFY(xdgSurface->surface()); +} + +void tst_WaylandCompositor::reportsXdgSurfaceWindowGeometry() +{ + XdgTestCompositor compositor; + compositor.create(); + + QWaylandXdgSurface *xdgSurface = nullptr; + QObject::connect(&compositor.xdgShell, &QWaylandXdgShell::xdgSurfaceCreated, [&](QWaylandXdgSurface *s) { + xdgSurface = s; + }); + + MockClient client; + wl_surface *surface = client.createSurface(); + xdg_surface *clientXdgSurface = client.createXdgSurface(surface); + QSize size(256, 256); + ShmBuffer buffer(size, client.shm); + wl_surface_attach(surface, buffer.handle, 0, 0); + wl_surface_damage(surface, 0, 0, size.width(), size.height()); + wl_surface_commit(surface); + + QTRY_VERIFY(xdgSurface); + QTRY_COMPARE(xdgSurface->windowGeometry(), QRect(QPoint(0, 0), QSize(256, 256))); + + xdg_surface_set_window_geometry(clientXdgSurface, 10, 20, 100, 50); + wl_surface_commit(surface); + + QTRY_COMPARE(xdgSurface->windowGeometry(), QRect(QPoint(10, 20), QSize(100, 50))); +} + +void tst_WaylandCompositor::setsXdgAppId() +{ + XdgTestCompositor compositor; + compositor.create(); + + QWaylandXdgSurface *xdgSurface = nullptr; + QObject::connect(&compositor.xdgShell, &QWaylandXdgShell::xdgSurfaceCreated, [&](QWaylandXdgSurface *s) { + xdgSurface = s; + }); + + MockClient client; + wl_surface *surface = client.createSurface(); + xdg_surface *clientXdgSurface = client.createXdgSurface(surface); + + xdg_surface_set_app_id(clientXdgSurface, "org.foo.bar"); + + QTRY_VERIFY(xdgSurface); + QTRY_COMPARE(xdgSurface->appId(), QString("org.foo.bar")); +} + +void tst_WaylandCompositor::sendsXdgConfigure() +{ + class MockXdgSurface : public QtWayland::xdg_surface + { + public: + MockXdgSurface(::xdg_surface *xdgSurface) : QtWayland::xdg_surface(xdgSurface) {} + void xdg_surface_configure(int32_t width, int32_t height, wl_array *rawStates, uint32_t serial) Q_DECL_OVERRIDE + { + configureSize = QSize(width, height); + configureSerial = serial; + + uint *states = reinterpret_cast<uint*>(rawStates->data); + configureStates.clear(); + size_t numStates = rawStates->size / sizeof(uint); + for (size_t i = 0; i < numStates; ++i) { + configureStates.push_back(states[i]); + } + } + + QList<uint> configureStates; + QSize configureSize; + uint configureSerial; + }; + + XdgTestCompositor compositor; + compositor.create(); + + QWaylandXdgSurface *xdgSurface = nullptr; + QObject::connect(&compositor.xdgShell, &QWaylandXdgShell::xdgSurfaceCreated, [&](QWaylandXdgSurface *s) { + xdgSurface = s; + }); + + MockClient client; + wl_surface *surface = client.createSurface(); + xdg_surface *clientXdgSurface = client.createXdgSurface(surface); + MockXdgSurface mockXdgSurface(clientXdgSurface); + + QTRY_VERIFY(xdgSurface); + QTRY_VERIFY(!xdgSurface->activated()); + QTRY_VERIFY(!xdgSurface->maximized()); + QTRY_VERIFY(!xdgSurface->fullscreen()); + QTRY_VERIFY(!xdgSurface->resizing()); + + xdgSurface->sendConfigure(QSize(10, 20), QVector<QWaylandXdgSurface::State>{QWaylandXdgSurface::State::ActivatedState}); + compositor.flushClients(); + QTRY_COMPARE(mockXdgSurface.configureStates, QList<uint>{QWaylandXdgSurface::State::ActivatedState}); + QTRY_COMPARE(mockXdgSurface.configureSize, QSize(10, 20)); + + xdgSurface->sendMaximized(QSize(800, 600)); + compositor.flushClients(); + QTRY_VERIFY(mockXdgSurface.configureStates.contains(QWaylandXdgSurface::State::MaximizedState)); + QTRY_VERIFY(mockXdgSurface.configureStates.contains(QWaylandXdgSurface::State::ActivatedState)); + QTRY_COMPARE(mockXdgSurface.configureSize, QSize(800, 600)); + + // There hasn't been any ack_configures, so state should still be unchanged + QTRY_VERIFY(!xdgSurface->activated()); + QTRY_VERIFY(!xdgSurface->maximized()); + xdg_surface_ack_configure(clientXdgSurface, mockXdgSurface.configureSerial); + wl_display_dispatch_pending(client.display); + wl_display_flush(client.display); + QTRY_VERIFY(xdgSurface->activated()); + QTRY_VERIFY(xdgSurface->maximized()); + + xdgSurface->sendUnmaximized(); + compositor.flushClients(); + QTRY_VERIFY(!mockXdgSurface.configureStates.contains(QWaylandXdgSurface::State::MaximizedState)); + QTRY_VERIFY(mockXdgSurface.configureStates.contains(QWaylandXdgSurface::State::ActivatedState)); + QTRY_COMPARE(mockXdgSurface.configureSize, QSize(0, 0)); + + // The unmaximized configure hasn't been acked, so maximized should still be true + QTRY_VERIFY(xdgSurface->maximized()); + QTRY_VERIFY(xdgSurface->activated()); + + xdgSurface->sendResizing(QSize(800, 600)); + compositor.flushClients(); + QTRY_VERIFY(mockXdgSurface.configureStates.contains(QWaylandXdgSurface::State::ResizingState)); + QTRY_COMPARE(mockXdgSurface.configureSize, QSize(800, 600)); + + xdgSurface->sendFullscreen(QSize(1024, 768)); + compositor.flushClients(); + QTRY_VERIFY(mockXdgSurface.configureStates.contains(QWaylandXdgSurface::State::ActivatedState)); + QTRY_VERIFY(mockXdgSurface.configureStates.contains(QWaylandXdgSurface::State::FullscreenState)); + QTRY_COMPARE(mockXdgSurface.configureSize, QSize(1024, 768)); + uint fullscreenSerial = mockXdgSurface.configureSerial; + + xdgSurface->sendUnmaximized(); + compositor.flushClients(); + QTRY_VERIFY(mockXdgSurface.configureStates.contains(QWaylandXdgSurface::State::ActivatedState)); + QTRY_VERIFY(!mockXdgSurface.configureStates.contains(QWaylandXdgSurface::State::FullscreenState)); + + xdgSurface->sendConfigure(QSize(0, 0), QVector<QWaylandXdgSurface::State>{}); + compositor.flushClients(); + QTRY_VERIFY(!mockXdgSurface.configureStates.contains(QWaylandXdgSurface::State::ActivatedState)); + + xdgSurface->sendMaximized(QSize(800, 600)); + compositor.flushClients(); + QTRY_VERIFY(!mockXdgSurface.configureStates.contains(QWaylandXdgSurface::State::ActivatedState)); + + xdgSurface->sendFullscreen(QSize(800, 600)); + compositor.flushClients(); + QTRY_VERIFY(!mockXdgSurface.configureStates.contains(QWaylandXdgSurface::State::MaximizedState)); + + // Verify that acking a configure that's not the most recently sent works + xdg_surface_ack_configure(clientXdgSurface, fullscreenSerial); + wl_display_dispatch_pending(client.display); + wl_display_flush(client.display); + QTRY_VERIFY(xdgSurface->fullscreen()); + QTRY_VERIFY(xdgSurface->activated()); + QTRY_VERIFY(!xdgSurface->maximized()); + QTRY_VERIFY(!xdgSurface->resizing()); +} + +#include <tst_compositor.moc> +QTEST_MAIN(tst_WaylandCompositor); |