summaryrefslogtreecommitdiffstats
path: root/tests/auto/compositor/compositor
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/compositor/compositor')
-rw-r--r--tests/auto/compositor/compositor/BLACKLIST2
-rw-r--r--tests/auto/compositor/compositor/compositor.pro40
-rw-r--r--tests/auto/compositor/compositor/mockclient.cpp215
-rw-r--r--tests/auto/compositor/compositor/mockclient.h108
-rw-r--r--tests/auto/compositor/compositor/mockseat.cpp43
-rw-r--r--tests/auto/compositor/compositor/mockseat.h45
-rw-r--r--tests/auto/compositor/compositor/testcompositor.cpp77
-rw-r--r--tests/auto/compositor/compositor/testcompositor.h54
-rw-r--r--tests/auto/compositor/compositor/testkeyboardgrabber.cpp58
-rw-r--r--tests/auto/compositor/compositor/testkeyboardgrabber.h49
-rw-r--r--tests/auto/compositor/compositor/testseat.cpp55
-rw-r--r--tests/auto/compositor/compositor/testseat.h54
-rw-r--r--tests/auto/compositor/compositor/tst_compositor.cpp576
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, &registryListener, 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);