summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/client/client/tst_client.cpp20
-rw-r--r--tests/auto/client/shared/mockcompositor.cpp5
-rw-r--r--tests/auto/client/shared/mockcompositor.h14
-rw-r--r--tests/auto/client/shared/mocksurface.cpp5
-rw-r--r--tests/auto/client/shared/mockxdgshellv6.cpp35
-rw-r--r--tests/auto/client/shared/mockxdgshellv6.h5
-rw-r--r--tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp189
-rw-r--r--tests/auto/compositor/compositor/compositor.pro4
-rw-r--r--tests/auto/compositor/compositor/mockclient.h2
-rw-r--r--tests/auto/compositor/compositor/mockkeyboard.cpp101
-rw-r--r--tests/auto/compositor/compositor/mockkeyboard.h50
-rw-r--r--tests/auto/compositor/compositor/mockseat.cpp5
-rw-r--r--tests/auto/compositor/compositor/mockseat.h4
-rw-r--r--tests/auto/compositor/compositor/tst_compositor.cpp141
14 files changed, 561 insertions, 19 deletions
diff --git a/tests/auto/client/client/tst_client.cpp b/tests/auto/client/client/tst_client.cpp
index 978a9d5e6..21f748ecd 100644
--- a/tests/auto/client/client/tst_client.cpp
+++ b/tests/auto/client/client/tst_client.cpp
@@ -172,6 +172,7 @@ private slots:
void windowScreens();
void removePrimaryScreen();
void createDestroyWindow();
+ void activeWindowFollowsKeyboardFocus();
void events();
void backingStore();
void touchDrag();
@@ -307,7 +308,7 @@ void tst_WaylandClient::createDestroyWindow()
QTRY_VERIFY(!compositor->surface());
}
-void tst_WaylandClient::events()
+void tst_WaylandClient::activeWindowFollowsKeyboardFocus()
{
TestWindow window;
window.show();
@@ -318,6 +319,9 @@ void tst_WaylandClient::events()
QTRY_VERIFY(window.isExposed());
+ if (compositor->xdgToplevelV6())
+ QSKIP("On xdg-shell v6 focus is handled by configure events");
+
QCOMPARE(window.focusInEventCount, 0);
compositor->setKeyboardFocus(surface);
QTRY_COMPARE(window.focusInEventCount, 1);
@@ -327,9 +331,21 @@ void tst_WaylandClient::events()
compositor->setKeyboardFocus(QSharedPointer<MockSurface>(nullptr));
QTRY_COMPARE(window.focusOutEventCount, 1);
QTRY_COMPARE(QGuiApplication::focusWindow(), static_cast<QWindow *>(nullptr));
+}
+
+void tst_WaylandClient::events()
+{
+ TestWindow window;
+ window.show();
+
+ QSharedPointer<MockSurface> surface;
+ QTRY_VERIFY(surface = compositor->surface());
+ compositor->sendShellSurfaceConfigure(surface);
+
+ QTRY_VERIFY(window.isExposed());
compositor->setKeyboardFocus(surface);
- QTRY_COMPARE(window.focusInEventCount, 2);
+ QTRY_COMPARE(window.focusInEventCount, 1);
QTRY_COMPARE(QGuiApplication::focusWindow(), &window);
uint keyCode = 80; // arbitrarily chosen
diff --git a/tests/auto/client/shared/mockcompositor.cpp b/tests/auto/client/shared/mockcompositor.cpp
index 9ef08ad95..11b40d9fc 100644
--- a/tests/auto/client/shared/mockcompositor.cpp
+++ b/tests/auto/client/shared/mockcompositor.cpp
@@ -236,11 +236,14 @@ void MockCompositor::sendIviSurfaceConfigure(const QSharedPointer<MockIviSurface
processCommand(command);
}
-void MockCompositor::sendXdgToplevelV6Configure(const QSharedPointer<MockXdgToplevelV6> toplevel, const QSize &size)
+void MockCompositor::sendXdgToplevelV6Configure(const QSharedPointer<MockXdgToplevelV6> toplevel, const QSize &size, const QVector<uint> &states)
{
Command command = makeCommand(Impl::Compositor::sendXdgToplevelV6Configure, m_compositor);
command.parameters << QVariant::fromValue(toplevel);
command.parameters << QVariant::fromValue(size);
+ auto statesBytes = QByteArray::fromRawData(reinterpret_cast<const char *>(states.data()),
+ states.size() * static_cast<int>(sizeof(uint)));
+ command.parameters << statesBytes;
processCommand(command);
}
diff --git a/tests/auto/client/shared/mockcompositor.h b/tests/auto/client/shared/mockcompositor.h
index 34c20943a..d3568c165 100644
--- a/tests/auto/client/shared/mockcompositor.h
+++ b/tests/auto/client/shared/mockcompositor.h
@@ -175,12 +175,21 @@ private:
Q_DECLARE_METATYPE(QSharedPointer<MockIviSurface>)
-class MockXdgToplevelV6
+class MockXdgToplevelV6 : public QObject
{
+ Q_OBJECT
public:
Impl::XdgToplevelV6 *handle() const { return m_toplevel; }
void sendConfigure(const QSharedPointer<MockXdgToplevelV6> toplevel);
+
+signals:
+ uint setMinimizedRequested();
+ uint setMaximizedRequested();
+ uint unsetMaximizedRequested();
+ uint setFullscreenRequested();
+ uint unsetFullscreenRequested();
+
private:
MockXdgToplevelV6(Impl::XdgToplevelV6 *toplevel) : m_toplevel(toplevel) {}
friend class Impl::Compositor;
@@ -234,7 +243,8 @@ public:
void sendSurfaceLeave(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output);
void sendShellSurfaceConfigure(const QSharedPointer<MockSurface> surface, const QSize &size = QSize(0, 0));
void sendIviSurfaceConfigure(const QSharedPointer<MockIviSurface> iviSurface, const QSize &size);
- void sendXdgToplevelV6Configure(const QSharedPointer<MockXdgToplevelV6> toplevel, const QSize &size = QSize(0, 0));
+ void sendXdgToplevelV6Configure(const QSharedPointer<MockXdgToplevelV6> toplevel, const QSize &size = QSize(0, 0),
+ const QVector<uint> &states = { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED });
void waitForStartDrag();
QSharedPointer<MockSurface> surface();
diff --git a/tests/auto/client/shared/mocksurface.cpp b/tests/auto/client/shared/mocksurface.cpp
index 81a865f11..82ce37acb 100644
--- a/tests/auto/client/shared/mocksurface.cpp
+++ b/tests/auto/client/shared/mocksurface.cpp
@@ -70,7 +70,10 @@ void Compositor::sendShellSurfaceConfigure(void *data, const QList<QVariant> &pa
QSize size = parameters.at(1).toSize();
Q_ASSERT(size.isValid());
if (auto toplevel = surface->xdgToplevelV6()) {
- toplevel->send_configure(size.width(), size.height(), QByteArray());
+ QVector<uint> states = { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED };
+ auto statesBytes = QByteArray::fromRawData(reinterpret_cast<const char *>(states.data()),
+ states.size() * static_cast<int>(sizeof(uint)));
+ toplevel->send_configure(size.width(), size.height(), statesBytes);
toplevel->xdgSurface()->send_configure(compositor->nextSerial());
} else if (auto wlShellSurface = surface->wlShellSurface()) {
const uint edges = 0;
diff --git a/tests/auto/client/shared/mockxdgshellv6.cpp b/tests/auto/client/shared/mockxdgshellv6.cpp
index 39e03296d..6f6f0b905 100644
--- a/tests/auto/client/shared/mockxdgshellv6.cpp
+++ b/tests/auto/client/shared/mockxdgshellv6.cpp
@@ -39,8 +39,8 @@ void Compositor::sendXdgToplevelV6Configure(void *data, const QList<QVariant> &p
Q_ASSERT(toplevel && toplevel->resource());
QSize size = parameters.at(1).toSize();
Q_ASSERT(size.isValid());
- QByteArray states;
- toplevel->send_configure(size.width(), size.height(), states);
+ auto statesBytes = parameters.at(2).toByteArray();
+ toplevel->send_configure(size.width(), size.height(), statesBytes);
toplevel->xdgSurface()->send_configure(compositor->nextSerial());
}
@@ -87,6 +87,37 @@ void XdgToplevelV6::zxdg_toplevel_v6_destroy(QtWaylandServer::zxdg_toplevel_v6::
wl_resource_destroy(resource->handle);
}
+void XdgToplevelV6::zxdg_toplevel_v6_set_minimized(QtWaylandServer::zxdg_toplevel_v6::Resource *resource)
+{
+ Q_UNUSED(resource);
+ emit m_mockToplevel->setMinimizedRequested();
+}
+
+void XdgToplevelV6::zxdg_toplevel_v6_set_maximized(QtWaylandServer::zxdg_toplevel_v6::Resource *resource)
+{
+ Q_UNUSED(resource);
+ emit m_mockToplevel->setMaximizedRequested();
+}
+
+void XdgToplevelV6::zxdg_toplevel_v6_unset_maximized(QtWaylandServer::zxdg_toplevel_v6::Resource *resource)
+{
+ Q_UNUSED(resource);
+ emit m_mockToplevel->unsetMaximizedRequested();
+}
+
+void XdgToplevelV6::zxdg_toplevel_v6_set_fullscreen(QtWaylandServer::zxdg_toplevel_v6::Resource *resource, wl_resource *output)
+{
+ Q_UNUSED(resource);
+ Q_UNUSED(output);
+ emit m_mockToplevel->setFullscreenRequested();
+}
+
+void XdgToplevelV6::zxdg_toplevel_v6_unset_fullscreen(QtWaylandServer::zxdg_toplevel_v6::Resource *resource)
+{
+ Q_UNUSED(resource);
+ emit m_mockToplevel->unsetFullscreenRequested();
+}
+
void Impl::XdgShellV6::zxdg_shell_v6_get_xdg_surface(QtWaylandServer::zxdg_shell_v6::Resource *resource, uint32_t id, wl_resource *surface)
{
new XdgSurfaceV6(this, Surface::fromResource(surface), resource->client(), id);
diff --git a/tests/auto/client/shared/mockxdgshellv6.h b/tests/auto/client/shared/mockxdgshellv6.h
index 92b808ba8..faadb785a 100644
--- a/tests/auto/client/shared/mockxdgshellv6.h
+++ b/tests/auto/client/shared/mockxdgshellv6.h
@@ -74,6 +74,11 @@ public:
protected:
void zxdg_toplevel_v6_destroy_resource(Resource *) override { delete this; }
void zxdg_toplevel_v6_destroy(Resource *resource) override;
+ void zxdg_toplevel_v6_set_minimized(Resource *resource) override;
+ void zxdg_toplevel_v6_set_maximized(Resource *resource) override;
+ void zxdg_toplevel_v6_unset_maximized(Resource *resource) override;
+ void zxdg_toplevel_v6_set_fullscreen(Resource *resource, struct ::wl_resource *output) override;
+ void zxdg_toplevel_v6_unset_fullscreen(Resource *resource) override;
private:
XdgSurfaceV6 *m_xdgSurface = nullptr;
diff --git a/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp b/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp
index 364cd1099..0f72f58a9 100644
--- a/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp
+++ b/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp
@@ -42,6 +42,7 @@ static const QSize screenSize(1600, 1200);
class TestWindow : public QWindow
{
+ Q_OBJECT
public:
TestWindow()
{
@@ -49,6 +50,16 @@ public:
setGeometry(0, 0, 32, 32);
create();
}
+
+ bool event(QEvent *event) override
+ {
+ if (event->type() == QEvent::WindowStateChange)
+ emit windowStateChangeEventReceived(static_cast<QWindowStateChangeEvent *>(event)->oldState());
+ return QWindow::event(event);
+ }
+
+signals:
+ void windowStateChangeEventReceived(uint oldState);
};
class tst_WaylandClientXdgShellV6 : public QObject
@@ -58,6 +69,7 @@ public:
tst_WaylandClientXdgShellV6(MockCompositor *c)
: m_compositor(c)
{
+ qRegisterMetaType<Qt::WindowState>();
QSocketNotifier *notifier = new QSocketNotifier(m_compositor->waylandFileDescriptor(), QSocketNotifier::Read, this);
connect(notifier, &QSocketNotifier::activated, this, &tst_WaylandClientXdgShellV6::processWaylandEvents);
// connect to the event dispatcher to make sure to flush out the outgoing message queue
@@ -82,6 +94,11 @@ public slots:
private slots:
void createDestroyWindow();
void configure();
+ void showMinimized();
+ void setMinimized();
+ void unsetMaximized();
+ void focusWindowFollowsConfigure();
+ void windowStateChangedEvents();
private:
MockCompositor *m_compositor = nullptr;
@@ -118,10 +135,182 @@ void tst_WaylandClientXdgShellV6::configure()
QSharedPointer<MockXdgToplevelV6> toplevel;
QTRY_VERIFY(toplevel = m_compositor->xdgToplevelV6());
+
const QSize newSize(123, 456);
m_compositor->sendXdgToplevelV6Configure(toplevel, newSize);
QTRY_VERIFY(window.isExposed());
+ QTRY_COMPARE(window.visibility(), QWindow::Windowed);
+ QTRY_COMPARE(window.windowStates(), Qt::WindowNoState);
QTRY_COMPARE(window.frameGeometry(), QRect(QPoint(), newSize));
+
+ m_compositor->sendXdgToplevelV6Configure(toplevel, screenSize, { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED, ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED });
+ QTRY_COMPARE(window.visibility(), QWindow::Maximized);
+ QTRY_COMPARE(window.windowStates(), Qt::WindowMaximized);
+ QTRY_COMPARE(window.frameGeometry(), QRect(QPoint(), screenSize));
+
+ m_compositor->sendXdgToplevelV6Configure(toplevel, screenSize, { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED, ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN });
+ QTRY_COMPARE(window.visibility(), QWindow::FullScreen);
+ QTRY_COMPARE(window.windowStates(), Qt::WindowFullScreen);
+ QTRY_COMPARE(window.frameGeometry(), QRect(QPoint(), screenSize));
+
+ //The window should remember it's original size
+ m_compositor->sendXdgToplevelV6Configure(toplevel, QSize(0, 0), { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED });
+ QTRY_COMPARE(window.visibility(), QWindow::Windowed);
+ QTRY_COMPARE(window.windowStates(), Qt::WindowNoState);
+ QTRY_COMPARE(window.frameGeometry(), QRect(QPoint(), newSize));
+}
+
+void tst_WaylandClientXdgShellV6::showMinimized()
+{
+ // On xdg-shell v6 there's really no way for the compositor to tell the window if it's minimized
+ // There are wl_surface.enter events and so on, but there's really no way to differentiate
+ // between a window preview and an unminimized window.
+ TestWindow window;
+ window.showMinimized();
+ QCOMPARE(window.windowStates(), Qt::WindowMinimized); // should return minimized until
+ QTRY_COMPARE(window.windowStates(), Qt::WindowNoState); // rejected by handleWindowStateChanged
+}
+
+void tst_WaylandClientXdgShellV6::setMinimized()
+{
+ TestWindow window;
+ window.show();
+
+ QSharedPointer<MockXdgToplevelV6> toplevel;
+ QTRY_VERIFY(toplevel = m_compositor->xdgToplevelV6());
+
+ m_compositor->sendXdgToplevelV6Configure(toplevel);
+ QTRY_COMPARE(window.visibility(), QWindow::Windowed);
+ QTRY_COMPARE(window.windowStates(), Qt::WindowNoState);
+
+ QSignalSpy setMinimizedSpy(toplevel.data(), SIGNAL(setMinimizedRequested()));
+ QSignalSpy windowStateChangeSpy(&window, SIGNAL(windowStateChangeEventReceived(uint)));
+
+ window.setVisibility(QWindow::Minimized);
+ QCOMPARE(window.visibility(), QWindow::Minimized);
+ QCOMPARE(window.windowStates(), Qt::WindowMinimized);
+ QTRY_COMPARE(setMinimizedSpy.count(), 1);
+ {
+ QTRY_VERIFY(windowStateChangeSpy.count() > 0);
+ Qt::WindowStates oldStates(windowStateChangeSpy.takeFirst().at(0).toUInt());
+ QCOMPARE(oldStates, Qt::WindowNoState);
+ }
+
+ // In the meantime the compositor may minimize, do nothing or reshow the window without
+ // telling us.
+
+ QTRY_COMPARE(window.visibility(), QWindow::Windowed); // verify that we don't know anything
+ QTRY_COMPARE(window.windowStates(), Qt::WindowNoState);
+ {
+ QTRY_COMPARE(windowStateChangeSpy.count(), 1);
+ Qt::WindowStates oldStates(windowStateChangeSpy.takeFirst().at(0).toUInt());
+ QCOMPARE(oldStates, Qt::WindowNoState); // because the window never was minimized
+ }
+
+ // Setting visibility again should send another set_minimized request
+ window.setVisibility(QWindow::Minimized);
+ QTRY_COMPARE(setMinimizedSpy.count(), 2);
+}
+
+void tst_WaylandClientXdgShellV6::unsetMaximized()
+{
+ TestWindow window;
+ window.show();
+
+ QSharedPointer<MockXdgToplevelV6> toplevel;
+ QTRY_VERIFY(toplevel = m_compositor->xdgToplevelV6());
+
+ QSignalSpy unsetMaximizedSpy(toplevel.data(), SIGNAL(unsetMaximizedRequested()));
+
+ QSignalSpy windowStateChangedSpy(&window, SIGNAL(windowStateChanged(Qt::WindowState)));
+
+ m_compositor->sendXdgToplevelV6Configure(toplevel, screenSize, { ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED });
+
+ QTRY_COMPARE(windowStateChangedSpy.count(), 1);
+ QCOMPARE(windowStateChangedSpy.takeFirst().at(0).toUInt(), Qt::WindowMaximized);
+
+ window.setWindowStates(Qt::WindowNoState);
+
+ QTRY_COMPARE(unsetMaximizedSpy.count(), 1);
+ QTRY_COMPARE(windowStateChangedSpy.count(), 1);
+ QCOMPARE(windowStateChangedSpy.takeFirst().at(0).toUInt(), Qt::WindowNoState);
+
+ m_compositor->sendXdgToplevelV6Configure(toplevel, QSize(0, 0), {});
+
+ QTRY_COMPARE(windowStateChangedSpy.count(), 1);
+ QCOMPARE(windowStateChangedSpy.takeFirst().at(0).toUInt(), Qt::WindowNoState);
+}
+
+void tst_WaylandClientXdgShellV6::focusWindowFollowsConfigure()
+{
+ TestWindow window;
+ window.show();
+
+ QSharedPointer<MockXdgToplevelV6> toplevel;
+ QTRY_VERIFY(toplevel = m_compositor->xdgToplevelV6());
+ QTRY_VERIFY(!window.isActive());
+
+ QSignalSpy windowStateChangeSpy(&window, SIGNAL(windowStateChangeEventReceived(uint)));
+
+ m_compositor->sendXdgToplevelV6Configure(toplevel, QSize(0, 0), { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED });
+ QTRY_VERIFY(window.isActive());
+
+ m_compositor->sendXdgToplevelV6Configure(toplevel, QSize(0, 0), {});
+ QTRY_VERIFY(!window.isActive());
+}
+
+void tst_WaylandClientXdgShellV6::windowStateChangedEvents()
+{
+ TestWindow window;
+ window.show();
+
+ QSharedPointer<MockXdgToplevelV6> toplevel;
+ QTRY_VERIFY(toplevel = m_compositor->xdgToplevelV6());
+
+ QSignalSpy eventSpy(&window, SIGNAL(windowStateChangeEventReceived(uint)));
+ QSignalSpy signalSpy(&window, SIGNAL(windowStateChanged(Qt::WindowState)));
+
+ m_compositor->sendXdgToplevelV6Configure(toplevel, screenSize, { ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED });
+
+ QTRY_COMPARE(window.windowStates(), Qt::WindowMaximized);
+ QTRY_COMPARE(window.windowState(), Qt::WindowMaximized);
+ {
+ QTRY_COMPARE(eventSpy.count(), 1);
+ Qt::WindowStates oldStates(eventSpy.takeFirst().at(0).toUInt());
+ QCOMPARE(oldStates, Qt::WindowNoState);
+
+ QTRY_COMPARE(signalSpy.count(), 1);
+ uint newState = signalSpy.takeFirst().at(0).toUInt();
+ QCOMPARE(newState, Qt::WindowMaximized);
+ }
+
+ m_compositor->sendXdgToplevelV6Configure(toplevel, screenSize, { ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN });
+
+ QTRY_COMPARE(window.windowStates(), Qt::WindowFullScreen);
+ QTRY_COMPARE(window.windowState(), Qt::WindowFullScreen);
+ {
+ QTRY_COMPARE(eventSpy.count(), 1);
+ Qt::WindowStates oldStates(eventSpy.takeFirst().at(0).toUInt());
+ QCOMPARE(oldStates, Qt::WindowMaximized);
+
+ QTRY_COMPARE(signalSpy.count(), 1);
+ uint newState = signalSpy.takeFirst().at(0).toUInt();
+ QCOMPARE(newState, Qt::WindowFullScreen);
+ }
+
+ m_compositor->sendXdgToplevelV6Configure(toplevel, QSize(0, 0), {});
+
+ QTRY_COMPARE(window.windowStates(), Qt::WindowNoState);
+ QTRY_COMPARE(window.windowState(), Qt::WindowNoState);
+ {
+ QTRY_COMPARE(eventSpy.count(), 1);
+ Qt::WindowStates oldStates(eventSpy.takeFirst().at(0).toUInt());
+ QCOMPARE(oldStates, Qt::WindowFullScreen);
+
+ QTRY_COMPARE(signalSpy.count(), 1);
+ uint newState = signalSpy.takeFirst().at(0).toUInt();
+ QCOMPARE(newState, Qt::WindowNoState);
+ }
}
int main(int argc, char **argv)
diff --git a/tests/auto/compositor/compositor/compositor.pro b/tests/auto/compositor/compositor/compositor.pro
index 2919fa4bb..d69db4ca5 100644
--- a/tests/auto/compositor/compositor/compositor.pro
+++ b/tests/auto/compositor/compositor/compositor.pro
@@ -11,7 +11,7 @@ qtConfig(xkbcommon-evdev): \
QMAKE_USE += xkbcommon_evdev
WAYLANDCLIENTSOURCES += \
- ../../../../src/3rdparty/protocol/xdg-shell.xml \
+ ../../../../src/3rdparty/protocol/xdg-shell-unstable-v5.xml \
../../../../src/3rdparty/protocol/ivi-application.xml \
SOURCES += \
@@ -21,6 +21,7 @@ SOURCES += \
mockclient.cpp \
mockseat.cpp \
testseat.cpp \
+ mockkeyboard.cpp \
mockpointer.cpp
HEADERS += \
@@ -29,4 +30,5 @@ HEADERS += \
mockclient.h \
mockseat.h \
testseat.h \
+ mockkeyboard.h \
mockpointer.h
diff --git a/tests/auto/compositor/compositor/mockclient.h b/tests/auto/compositor/compositor/mockclient.h
index 6d5bf31df..6bfb652ed 100644
--- a/tests/auto/compositor/compositor/mockclient.h
+++ b/tests/auto/compositor/compositor/mockclient.h
@@ -27,7 +27,7 @@
****************************************************************************/
#include <wayland-client.h>
-#include <wayland-xdg-shell-client-protocol.h>
+#include <qwayland-xdg-shell-unstable-v5.h>
#include <wayland-ivi-application-client-protocol.h>
#include <QObject>
diff --git a/tests/auto/compositor/compositor/mockkeyboard.cpp b/tests/auto/compositor/compositor/mockkeyboard.cpp
new file mode 100644
index 000000000..e5f5f8d36
--- /dev/null
+++ b/tests/auto/compositor/compositor/mockkeyboard.cpp
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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 "mockkeyboard.h"
+
+void keyboardKeymap(void *keyboard, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size)
+{
+ Q_UNUSED(keyboard);
+ Q_UNUSED(wl_keyboard);
+ Q_UNUSED(format);
+ Q_UNUSED(fd);
+ Q_UNUSED(size);
+}
+
+void keyboardEnter(void *keyboard, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys)
+{
+ Q_UNUSED(wl_keyboard);
+ Q_UNUSED(serial);
+ Q_UNUSED(surface);
+ Q_UNUSED(keys);
+
+ static_cast<MockKeyboard *>(keyboard)->m_enteredSurface = surface;
+}
+
+void keyboardLeave(void *keyboard, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface)
+{
+ Q_UNUSED(wl_keyboard);
+ Q_UNUSED(serial);
+ Q_UNUSED(surface);
+
+ static_cast<MockKeyboard *>(keyboard)->m_enteredSurface = nullptr;
+}
+
+void keyboardKey(void *keyboard, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
+{
+ Q_UNUSED(keyboard);
+ Q_UNUSED(wl_keyboard);
+ Q_UNUSED(serial);
+ Q_UNUSED(time);
+ Q_UNUSED(key);
+ Q_UNUSED(state);
+ auto kb = static_cast<MockKeyboard *>(keyboard);
+ kb->m_lastKeyCode = key;
+ kb->m_lastKeyState = state;
+}
+
+void keyboardModifiers(void *keyboard, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
+{
+ Q_UNUSED(keyboard);
+ Q_UNUSED(wl_keyboard);
+ Q_UNUSED(serial);
+ Q_UNUSED(mods_depressed);
+ Q_UNUSED(mods_latched);
+ Q_UNUSED(mods_locked);
+ auto kb = static_cast<MockKeyboard *>(keyboard);
+ kb->m_group = group;
+}
+
+static const struct wl_keyboard_listener keyboardListener = {
+ keyboardKeymap,
+ keyboardEnter,
+ keyboardLeave,
+ keyboardKey,
+ keyboardModifiers
+};
+
+MockKeyboard::MockKeyboard(wl_seat *seat)
+ : m_keyboard(wl_seat_get_keyboard(seat))
+{
+ wl_keyboard_add_listener(m_keyboard, &keyboardListener, this);
+}
+
+MockKeyboard::~MockKeyboard()
+{
+ wl_keyboard_destroy(m_keyboard);
+}
diff --git a/tests/auto/compositor/compositor/mockkeyboard.h b/tests/auto/compositor/compositor/mockkeyboard.h
new file mode 100644
index 000000000..1090db597
--- /dev/null
+++ b/tests/auto/compositor/compositor/mockkeyboard.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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$
+**
+****************************************************************************/
+
+#ifndef MOCKKEYBOARD_H
+#define MOCKKEYBOARD_H
+
+#include <QObject>
+#include <wayland-client.h>
+
+class MockKeyboard : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit MockKeyboard(wl_seat *seat);
+ ~MockKeyboard() override;
+
+ wl_keyboard *m_keyboard = nullptr;
+ wl_surface *m_enteredSurface = nullptr;
+ uint m_lastKeyCode = 0;
+ uint m_lastKeyState = 0;
+ uint m_group = 0;
+};
+
+#endif // MOCKKEYBOARD_H
diff --git a/tests/auto/compositor/compositor/mockseat.cpp b/tests/auto/compositor/compositor/mockseat.cpp
index 052c2f90b..ce873c129 100644
--- a/tests/auto/compositor/compositor/mockseat.cpp
+++ b/tests/auto/compositor/compositor/mockseat.cpp
@@ -31,14 +31,11 @@
MockSeat::MockSeat(wl_seat *seat)
: m_seat(seat)
, m_pointer(new MockPointer(seat))
+ , m_keyboard(new MockKeyboard(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
index 73d289281..f8c103ed4 100644
--- a/tests/auto/compositor/compositor/mockseat.h
+++ b/tests/auto/compositor/compositor/mockseat.h
@@ -29,6 +29,7 @@
#define MOCKSEAT
#include "mockpointer.h"
+#include "mockkeyboard.h"
#include <QObject>
#include <wayland-client.h>
@@ -41,12 +42,13 @@ public:
MockSeat(wl_seat *seat);
~MockSeat() override;
MockPointer *pointer() const { return m_pointer.data(); }
+ MockKeyboard *keyboard() const { return m_keyboard.data(); }
wl_seat *m_seat = nullptr;
- wl_keyboard *m_keyboard = nullptr;
private:
QScopedPointer<MockPointer> m_pointer;
+ QScopedPointer<MockKeyboard> m_keyboard;
};
#endif
diff --git a/tests/auto/compositor/compositor/tst_compositor.cpp b/tests/auto/compositor/compositor/tst_compositor.cpp
index ae5ea927d..e3c4daccc 100644
--- a/tests/auto/compositor/compositor/tst_compositor.cpp
+++ b/tests/auto/compositor/compositor/tst_compositor.cpp
@@ -40,11 +40,13 @@
#include <QtGui/QScreen>
#include <QtWaylandCompositor/QWaylandXdgShellV5>
#include <QtWaylandCompositor/private/qwaylandxdgshellv6_p.h>
+#include <QtWaylandCompositor/private/qwaylandkeyboard_p.h>
#include <QtWaylandCompositor/QWaylandIviApplication>
#include <QtWaylandCompositor/QWaylandIviSurface>
#include <QtWaylandCompositor/QWaylandSurface>
#include <QtWaylandCompositor/QWaylandResource>
-#include <qwayland-xdg-shell.h>
+#include <QtWaylandCompositor/QWaylandKeymap>
+#include <qwayland-xdg-shell-unstable-v5.h>
#include <qwayland-ivi-application.h>
#include <QtTest/QtTest>
@@ -56,6 +58,11 @@ class tst_WaylandCompositor : public QObject
private slots:
void init();
void seatCapabilities();
+#if QT_CONFIG(xkbcommon_evdev)
+ void simpleKeyboard();
+ void keyboardKeymaps();
+ void keyboardLayoutSwitching();
+#endif
void keyboardGrab();
void seatCreation();
void seatKeyboardFocus();
@@ -160,6 +167,121 @@ void tst_WaylandCompositor::multipleClients()
QTRY_COMPARE(compositor.surfaces.size(), 0);
}
+#if QT_CONFIG(xkbcommon_evdev)
+
+void tst_WaylandCompositor::simpleKeyboard()
+{
+ TestCompositor compositor;
+ compositor.create();
+
+ QWaylandSeat* seat = compositor.defaultSeat();
+ seat->keymap()->setLayout("us");
+
+ MockClient client;
+
+ QTRY_COMPARE(client.m_seats.size(), 1);
+ MockKeyboard *mockKeyboard = client.m_seats.at(0)->keyboard();
+
+ wl_surface *mockSurface = client.createSurface();
+ QTRY_COMPARE(compositor.surfaces.size(), 1);
+ seat->setKeyboardFocus(compositor.surfaces.at(0));
+
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_enteredSurface, mockSurface);
+
+ seat->sendKeyEvent(Qt::Key_A, true);
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_lastKeyState, 1u);
+ QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 30u); // 30 is the scan code for A on us keyboard layouts
+
+ seat->sendKeyEvent(Qt::Key_A, false);
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_lastKeyState, 0u);
+ QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 30u);
+
+ seat->sendKeyEvent(Qt::Key_Super_L, true);
+ seat->sendKeyEvent(Qt::Key_Super_L, false);
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 125u);
+}
+
+void tst_WaylandCompositor::keyboardKeymaps()
+{
+ TestCompositor compositor;
+ compositor.create();
+ QWaylandSeat* seat = compositor.defaultSeat();
+ MockClient client;
+ QTRY_COMPARE(client.m_seats.size(), 1);
+ MockKeyboard *mockKeyboard = client.m_seats.at(0)->keyboard();
+ client.createSurface();
+ QTRY_COMPARE(compositor.surfaces.size(), 1);
+ seat->setKeyboardFocus(compositor.surfaces.at(0));
+
+ seat->keymap()->setLayout("us");
+
+ seat->sendKeyEvent(Qt::Key_Y, true);
+ seat->sendKeyEvent(Qt::Key_Y, false);
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 21u);
+
+ seat->sendKeyEvent(Qt::Key_Z, true);
+ seat->sendKeyEvent(Qt::Key_Z, false);
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 44u);
+
+ seat->keymap()->setLayout("de"); // In the German layout y and z have changed places
+
+ seat->sendKeyEvent(Qt::Key_Y, true);
+ seat->sendKeyEvent(Qt::Key_Y, false);
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 44u);
+
+ seat->sendKeyEvent(Qt::Key_Z, true);
+ seat->sendKeyEvent(Qt::Key_Z, false);
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 21u);
+}
+
+void tst_WaylandCompositor::keyboardLayoutSwitching()
+{
+ TestCompositor compositor;
+ compositor.create();
+ QWaylandSeat* seat = compositor.defaultSeat();
+ MockClient client;
+ QTRY_COMPARE(client.m_seats.size(), 1);
+ MockKeyboard *mockKeyboard = client.m_seats.at(0)->keyboard();
+ client.createSurface();
+ QTRY_COMPARE(compositor.surfaces.size(), 1);
+ seat->setKeyboardFocus(compositor.surfaces.at(0));
+
+ seat->keymap()->setLayout("us,de");
+ seat->keymap()->setOptions("grp:lalt_toggle"); //toggle keyboard layout with left alt
+
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_group, 0u);
+
+ seat->sendKeyEvent(Qt::Key_Y, true);
+ seat->sendKeyEvent(Qt::Key_Y, false);
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 21u);
+
+ // It's not currently possible to switch layouts programmatically with the public APIs
+ // We will just fake it with the private APIs here.
+ auto keyboardPrivate = QWaylandKeyboardPrivate::get(seat->keyboard());
+ const uint leftAltCode = 64;
+ keyboardPrivate->updateModifierState(leftAltCode, WL_KEYBOARD_KEY_STATE_PRESSED);
+ keyboardPrivate->updateModifierState(leftAltCode, WL_KEYBOARD_KEY_STATE_RELEASED);
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_group, 1u);
+
+ seat->sendKeyEvent(Qt::Key_Y, true);
+ seat->sendKeyEvent(Qt::Key_Y, false);
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 44u);
+}
+
+#endif // QT_CONFIG(xkbcommon_evdev)
+
void tst_WaylandCompositor::keyboardGrab()
{
TestCompositor compositor;
@@ -450,13 +572,24 @@ void tst_WaylandCompositor::seatKeyboardFocus()
// Create client after all the input devices have been set up as the mock client
// does not dynamically listen to new seats
MockClient client;
+
+ QTRY_COMPARE(client.m_seats.size(), 1);
+ MockKeyboard *mockKeyboard = client.m_seats.first()->keyboard();
+ QVERIFY(mockKeyboard);
+ QCOMPARE(mockKeyboard->m_enteredSurface, nullptr);
+
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);
+ QWaylandSeat* seat = compositor.defaultSeat();
+ QVERIFY(seat->setKeyboardFocus(waylandSurface));
+ QCOMPARE(compositor.defaultSeat()->keyboardFocus(), waylandSurface);
+
+ compositor.flushClients();
+
+ qDebug() << mockKeyboard->m_enteredSurface;
+ QTRY_COMPARE(mockKeyboard->m_enteredSurface, surface);
wl_surface_destroy(surface);
QTRY_VERIFY(compositor.surfaces.size() == 0);