From 0848113845547b9ec9838496b61c50382ff7c099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Tue, 26 Aug 2014 16:07:39 +0200 Subject: [PATCH 1/5] [kwin_wayland] Initial addition of the WaylandServer module So far this new module contains: * Display * OutputInterface Display manages the server socket and server event loop. In general it's the entry point to any part of the server. OutputInterface is the abstraction for the wl_output interface on server side. An OutputInterface is created through the Display. The auto tests for ConnectionThread and Output are adjusted to use the internal server instead of starting Weston. Especially the Output test could be extended to test much more as we have absolute control over the server now. --- src/wayland/test_display.cpp | 80 ++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 src/wayland/test_display.cpp diff --git a/src/wayland/test_display.cpp b/src/wayland/test_display.cpp new file mode 100644 index 0000000000..d9a739cfa6 --- /dev/null +++ b/src/wayland/test_display.cpp @@ -0,0 +1,80 @@ +/******************************************************************** +KWin - the KDE window manager +This file is part of the KDE project. + +Copyright (C) 2014 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +// Qt +#include +// WaylandServer +#include "../../wayland_server/display.h" + +using namespace KWin::WaylandServer; + +class TestWaylandServerDisplay : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void testSocketName(); + void testStartStop(); +}; + +void TestWaylandServerDisplay::testSocketName() +{ + Display display; + QSignalSpy changedSpy(&display, SIGNAL(socketNameChanged(QString))); + QVERIFY(changedSpy.isValid()); + QCOMPARE(display.socketName(), QStringLiteral("wayland-0")); + const QString testSName = QStringLiteral("fooBar"); + display.setSocketName(testSName); + QCOMPARE(display.socketName(), testSName); + QCOMPARE(changedSpy.count(), 1); + QCOMPARE(changedSpy.first().first().toString(), testSName); + + // changing to same name again should not emit signal + display.setSocketName(testSName); + QCOMPARE(changedSpy.count(), 1); +} + +void TestWaylandServerDisplay::testStartStop() +{ + const QString testSocketName = QStringLiteral("kwin-wayland-server-display-test-0"); + QDir runtimeDir(qgetenv("XDG_RUNTIME_DIR")); + QVERIFY(runtimeDir.exists()); + QVERIFY(!runtimeDir.exists(testSocketName)); + + Display display; + QSignalSpy runningSpy(&display, SIGNAL(runningChanged(bool))); + QVERIFY(runningSpy.isValid()); + display.setSocketName(testSocketName); + QVERIFY(!display.isRunning()); + display.start(); +// QVERIFY(runningSpy.wait()); + QCOMPARE(runningSpy.count(), 1); + QVERIFY(runningSpy.first().first().toBool()); + QVERIFY(display.isRunning()); + QVERIFY(runtimeDir.exists(testSocketName)); + + display.terminate(); + QVERIFY(!display.isRunning()); + QCOMPARE(runningSpy.count(), 2); + QVERIFY(runningSpy.first().first().toBool()); + QVERIFY(!runningSpy.last().first().toBool()); + QVERIFY(!runtimeDir.exists(testSocketName)); +} + +QTEST_MAIN(TestWaylandServerDisplay) +#include "test_display.moc" From 3c7a59ba9edd336c4893c87ee7212ee5781b599e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Tue, 2 Sep 2014 09:34:31 +0200 Subject: [PATCH 2/5] [kwin_wayland] Add SeatInterface to server module So far the Seat interface is provided together with pointer and keyboard. As always touch is not yet implemented. The pointer interface is still lacking the set cursor callback. Keyboard on the other hand is complete. Both Keyboard and Pointer have the concept of a focused surface and only to the bound interface belonging to the same client as the focused surface events are sent. The change comes with a set of new auto tests also verifying the client side which wasn't possible before as we couldn't fake events. --- src/wayland/test_seat.cpp | 161 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 src/wayland/test_seat.cpp diff --git a/src/wayland/test_seat.cpp b/src/wayland/test_seat.cpp new file mode 100644 index 0000000000..d5c6bb85cf --- /dev/null +++ b/src/wayland/test_seat.cpp @@ -0,0 +1,161 @@ +/******************************************************************** +KWin - the KDE window manager +This file is part of the KDE project. + +Copyright (C) 2014 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +// Qt +#include +// WaylandServer +#include "../../wayland_server/display.h" +#include "../../wayland_server/seat_interface.h" + +using namespace KWin::WaylandServer; + + +class TestWaylandServerSeat : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void testCapabilities(); + void testName(); + void testPointerButton(); + void testPointerPos(); +}; + +static const QString s_socketName = QStringLiteral("kwin-wayland-server-seat-test-0"); + +void TestWaylandServerSeat::testCapabilities() +{ + Display display; + display.setSocketName(s_socketName); + display.start(); + SeatInterface *seat = display.createSeat(); + QVERIFY(!seat->hasKeyboard()); + QVERIFY(!seat->hasPointer()); + QVERIFY(!seat->hasTouch()); + + QSignalSpy keyboardSpy(seat, SIGNAL(hasKeyboardChanged(bool))); + QVERIFY(keyboardSpy.isValid()); + seat->setHasKeyboard(true); + QCOMPARE(keyboardSpy.count(), 1); + QVERIFY(keyboardSpy.last().first().toBool()); + QVERIFY(seat->hasKeyboard()); + seat->setHasKeyboard(false); + QCOMPARE(keyboardSpy.count(), 2); + QVERIFY(!keyboardSpy.last().first().toBool()); + QVERIFY(!seat->hasKeyboard()); + seat->setHasKeyboard(false); + QCOMPARE(keyboardSpy.count(), 2); + + QSignalSpy pointerSpy(seat, SIGNAL(hasPointerChanged(bool))); + QVERIFY(pointerSpy.isValid()); + seat->setHasPointer(true); + QCOMPARE(pointerSpy.count(), 1); + QVERIFY(pointerSpy.last().first().toBool()); + QVERIFY(seat->hasPointer()); + seat->setHasPointer(false); + QCOMPARE(pointerSpy.count(), 2); + QVERIFY(!pointerSpy.last().first().toBool()); + QVERIFY(!seat->hasPointer()); + seat->setHasPointer(false); + QCOMPARE(pointerSpy.count(), 2); + + QSignalSpy touchSpy(seat, SIGNAL(hasTouchChanged(bool))); + QVERIFY(touchSpy.isValid()); + seat->setHasTouch(true); + QCOMPARE(touchSpy.count(), 1); + QVERIFY(touchSpy.last().first().toBool()); + QVERIFY(seat->hasTouch()); + seat->setHasTouch(false); + QCOMPARE(touchSpy.count(), 2); + QVERIFY(!touchSpy.last().first().toBool()); + QVERIFY(!seat->hasTouch()); + seat->setHasTouch(false); + QCOMPARE(touchSpy.count(), 2); +} + +void TestWaylandServerSeat::testName() +{ + Display display; + display.setSocketName(s_socketName); + display.start(); + SeatInterface *seat = display.createSeat(); + QCOMPARE(seat->name(), QString()); + + QSignalSpy nameSpy(seat, SIGNAL(nameChanged(QString))); + QVERIFY(nameSpy.isValid()); + const QString name = QStringLiteral("foobar"); + seat->setName(name); + QCOMPARE(seat->name(), name); + QCOMPARE(nameSpy.count(), 1); + QCOMPARE(nameSpy.first().first().toString(), name); + seat->setName(name); + QCOMPARE(nameSpy.count(), 1); +} + +void TestWaylandServerSeat::testPointerButton() +{ + Display display; + display.setSocketName(s_socketName); + display.start(); + SeatInterface *seat = display.createSeat(); + PointerInterface *pointer = seat->pointer(); + + // no button pressed yet, should be released and no serial + QVERIFY(!pointer->isButtonPressed(0)); + QVERIFY(!pointer->isButtonPressed(1)); + QCOMPARE(pointer->buttonSerial(0), quint32(0)); + QCOMPARE(pointer->buttonSerial(1), quint32(0)); + + // mark the button as pressed + pointer->buttonPressed(0); + QVERIFY(pointer->isButtonPressed(0)); + QCOMPARE(pointer->buttonSerial(0), display.serial()); + + // other button should still be unpressed + QVERIFY(!pointer->isButtonPressed(1)); + QCOMPARE(pointer->buttonSerial(1), quint32(0)); + + // release it again + pointer->buttonReleased(0); + QVERIFY(!pointer->isButtonPressed(0)); + QCOMPARE(pointer->buttonSerial(0), display.serial()); +} + +void TestWaylandServerSeat::testPointerPos() +{ + Display display; + display.setSocketName(s_socketName); + display.start(); + SeatInterface *seat = display.createSeat(); + PointerInterface *pointer = seat->pointer(); + QSignalSpy posSpy(pointer, SIGNAL(globalPosChanged(QPoint))); + QVERIFY(posSpy.isValid()); + + QCOMPARE(pointer->globalPos(), QPoint()); + + pointer->setGlobalPos(QPoint(10, 15)); + QCOMPARE(pointer->globalPos(), QPoint(10, 15)); + QCOMPARE(posSpy.count(), 1); + QCOMPARE(posSpy.first().first().toPoint(), QPoint(10, 15)); + + pointer->setGlobalPos(QPoint(10, 15)); + QCOMPARE(posSpy.count(), 1); +} + +QTEST_MAIN(TestWaylandServerSeat) +#include "test_seat.moc" From d080ce73560f7cf086d1c2991c6a02501873d849 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Wed, 3 Sep 2014 20:01:54 +0200 Subject: [PATCH 3/5] [kwin_wayland] Test adding/removing Outputs in TestWaylandServerDisplay --- src/wayland/test_display.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/wayland/test_display.cpp b/src/wayland/test_display.cpp index d9a739cfa6..0c60693e0e 100644 --- a/src/wayland/test_display.cpp +++ b/src/wayland/test_display.cpp @@ -21,6 +21,7 @@ along with this program. If not, see . #include // WaylandServer #include "../../wayland_server/display.h" +#include "../../wayland_server/output_interface.h" using namespace KWin::WaylandServer; @@ -30,6 +31,7 @@ class TestWaylandServerDisplay : public QObject private Q_SLOTS: void testSocketName(); void testStartStop(); + void testAddRemoveOutput(); }; void TestWaylandServerDisplay::testSocketName() @@ -76,5 +78,28 @@ void TestWaylandServerDisplay::testStartStop() QVERIFY(!runtimeDir.exists(testSocketName)); } +void TestWaylandServerDisplay::testAddRemoveOutput() +{ + Display display; + display.setSocketName(QStringLiteral("kwin-wayland-server-display-test-output-0")); + display.start(); + + OutputInterface *output = display.createOutput(); + QCOMPARE(display.outputs().size(), 1); + QCOMPARE(display.outputs().first(), output); + // create a second output + OutputInterface *output2 = display.createOutput(); + QCOMPARE(display.outputs().size(), 2); + QCOMPARE(display.outputs().first(), output); + QCOMPARE(display.outputs().last(), output2); + // remove the first output + display.removeOutput(output); + QCOMPARE(display.outputs().size(), 1); + QCOMPARE(display.outputs().first(), output2); + // and delete the second + delete output2; + QVERIFY(display.outputs().isEmpty()); +} + QTEST_MAIN(TestWaylandServerDisplay) #include "test_display.moc" From 1574c47d2737eddf1959b1756e04f70883b57dd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Wed, 3 Sep 2014 20:02:42 +0200 Subject: [PATCH 4/5] [kwin_wayland] Test that Seat gets destroyed when Display terminates --- src/wayland/test_seat.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/wayland/test_seat.cpp b/src/wayland/test_seat.cpp index d5c6bb85cf..e37ce22f37 100644 --- a/src/wayland/test_seat.cpp +++ b/src/wayland/test_seat.cpp @@ -34,6 +34,7 @@ private Q_SLOTS: void testName(); void testPointerButton(); void testPointerPos(); + void testDestroyThroughTerminate(); }; static const QString s_socketName = QStringLiteral("kwin-wayland-server-seat-test-0"); @@ -157,5 +158,17 @@ void TestWaylandServerSeat::testPointerPos() QCOMPARE(posSpy.count(), 1); } +void TestWaylandServerSeat::testDestroyThroughTerminate() +{ + Display display; + display.setSocketName(s_socketName); + display.start(); + SeatInterface *seat = display.createSeat(); + QSignalSpy destroyedSpy(seat, SIGNAL(destroyed(QObject*))); + QVERIFY(destroyedSpy.isValid()); + display.terminate(); + QVERIFY(!destroyedSpy.isEmpty()); +} + QTEST_MAIN(TestWaylandServerSeat) #include "test_seat.moc" From bc93c5c6a80e3304e4a21507c5f25f0c97f2f30d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Wed, 17 Sep 2014 13:24:51 +0200 Subject: [PATCH 5/5] Move all files to autotests/server --- src/wayland/autotests/server/CMakeLists.txt | 35 +++++++++++++++++++ .../{ => autotests/server}/test_display.cpp | 0 .../{ => autotests/server}/test_seat.cpp | 0 3 files changed, 35 insertions(+) create mode 100644 src/wayland/autotests/server/CMakeLists.txt rename src/wayland/{ => autotests/server}/test_display.cpp (100%) rename src/wayland/{ => autotests/server}/test_seat.cpp (100%) diff --git a/src/wayland/autotests/server/CMakeLists.txt b/src/wayland/autotests/server/CMakeLists.txt new file mode 100644 index 0000000000..8260e6942d --- /dev/null +++ b/src/wayland/autotests/server/CMakeLists.txt @@ -0,0 +1,35 @@ +######################################################## +# Test WaylandServerDisplay +######################################################## +set( testWaylandServerDisplay_SRCS + test_display.cpp + ${KWIN_SOURCE_DIR}/wayland_server/buffer_interface.cpp + ${KWIN_SOURCE_DIR}/wayland_server/compositor_interface.cpp + ${KWIN_SOURCE_DIR}/wayland_server/display.cpp + ${KWIN_SOURCE_DIR}/wayland_server/output_interface.cpp + ${KWIN_SOURCE_DIR}/wayland_server/seat_interface.cpp + ${KWIN_SOURCE_DIR}/wayland_server/shell_interface.cpp + ${KWIN_SOURCE_DIR}/wayland_server/surface_interface.cpp + ) +add_executable(testWaylandServerDisplay ${testWaylandServerDisplay_SRCS}) +target_link_libraries( testWaylandServerDisplay Qt5::Test Qt5::Gui Wayland::Server) +add_test(kwin-testWaylandServerDisplay testWaylandServerDisplay) +ecm_mark_as_test(testWaylandServerDisplay) + +######################################################## +# Test WaylandServerSeat +######################################################## +set( testWaylandServerSeat_SRCS + test_seat.cpp + ${KWIN_SOURCE_DIR}/wayland_server/buffer_interface.cpp + ${KWIN_SOURCE_DIR}/wayland_server/compositor_interface.cpp + ${KWIN_SOURCE_DIR}/wayland_server/display.cpp + ${KWIN_SOURCE_DIR}/wayland_server/output_interface.cpp + ${KWIN_SOURCE_DIR}/wayland_server/seat_interface.cpp + ${KWIN_SOURCE_DIR}/wayland_server/shell_interface.cpp + ${KWIN_SOURCE_DIR}/wayland_server/surface_interface.cpp + ) +add_executable(testWaylandServerSeat ${testWaylandServerSeat_SRCS}) +target_link_libraries( testWaylandServerSeat Qt5::Test Qt5::Gui Wayland::Server) +add_test(kwin-testWaylandServerSeat testWaylandServerSeat) +ecm_mark_as_test(testWaylandServerSeat) diff --git a/src/wayland/test_display.cpp b/src/wayland/autotests/server/test_display.cpp similarity index 100% rename from src/wayland/test_display.cpp rename to src/wayland/autotests/server/test_display.cpp diff --git a/src/wayland/test_seat.cpp b/src/wayland/autotests/server/test_seat.cpp similarity index 100% rename from src/wayland/test_seat.cpp rename to src/wayland/autotests/server/test_seat.cpp