From ddef100d9fa7014b21280b1380e6fbcef80277b3 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Wed, 24 Oct 2018 08:46:06 +0200 Subject: Create a new type of mock compositor for client tests There are a number of issues with the current client testing: - Adding new compositor functionality is cumbersome (need to add compositor send method, command, implementation, not to mention creating new wrapper objects. - Customizing available globals and their versions is not possible and would be hard to implement. I.e. how to test that functionality works with old and new versions of an interface? Handle globals being destroyed. We did this with wl_output, but it was painfully cumbersome. - Hard to verify that the compositor state is clean between tests. It is currently done in some tests, but requires boiler plate code which needs to be added and maintained for each test. - In general lots of boiler-plate for new tests. (We have to have separate tests as long as Qt has global/static state. I.e. if one shell extension has been initialized, we can't deinitialize and initialize another one, so tests have to be separate.) - Dispatching server events tied to the client event loop sometimes makes it hard to write tests without deadlocks. - Abstraction, encapsulation and automatic behavior that can't be disabled makes it hard to test low-level functionality like surface exposure. So, in an attempt to mitigate these issues, I wrote a new testing framework. - Compositor dispatch is running continuously in it's own thread, access to compositor state is guarded by a mutex on the compositor, locking this will make dispatching stop, so the test can safely access internals. Although a bit cumbersome at first this makes it much easier to directly use server protocol commands from the test itself, i.e. no need to create commands for every single thing we want to test. - The CoreCompositor::exec template method can accept a lambda that will be run with dispatching stopped. It can also return a value, conveniently letting us safely extract or modify compositor state from tests. - This framework also takes full advantage of the qtwaylandscanner, using wrapper classes for everything, reducing boiler plate considerably. - The compositor parts are designed to do as little as possible automatically, but still provide easy ways to enable common functionality, like releasing buffers automatically, configuring shell surfaces etc. - Compositor globals are pluggable, use add() and remove() to add new global interfaces. I.e. easy to create a compositor with or without data_device_manager for instance. - DefaultCompositor provides a sensible default set of functionality and convenience methods for most test-cases. Custom ones can still be made by inheriting from CoreCompositor directly instead or by removing or adding globals to DefaultCompositor. - Globals have an isClean() method. Implement it to verify that the client didn't leave any objects lying around from the previous test. CoreCompositor::isClean calls isClean on the globals so a single call is all that's needed. In short, we've traded mock compositor encapsulation and thread safety guarantees for less boiler-plate, easier and more convenient access to internals. Anything accessing compositor state should go into a exec() call, or through the wrapper macros QCOMPOSITOR_VERIFY and QCOMPOSITOR_COMPARE (or the TRY versions). I've also tried to make the compositor print warnings if compositor state is accessed in an unsafe way. The mock compositor is currently built once per test due to CI limitations (same thing as with the old tests). Change-Id: Ia3feb80ce175d3814292b7f4768a0cc719f8b0e8 Reviewed-by: Paul Olav Tvete --- tests/auto/client/client.pro | 7 +- tests/auto/client/client/client.pro | 2 +- .../client/fullscreenshellv1/fullscreenshellv1.pro | 2 +- .../auto/client/iviapplication/iviapplication.pro | 2 +- tests/auto/client/seatv4/seatv4.pro | 4 + tests/auto/client/seatv4/tst_seatv4.cpp | 266 ++++++++++ tests/auto/client/shared/corecompositor.cpp | 140 ++++++ tests/auto/client/shared/corecompositor.h | 209 ++++++++ tests/auto/client/shared/coreprotocol.cpp | 322 +++++++++++++ tests/auto/client/shared/coreprotocol.h | 313 ++++++++++++ tests/auto/client/shared/mockcompositor.cpp | 534 ++------------------- tests/auto/client/shared/mockcompositor.h | 293 ++--------- tests/auto/client/shared/mockfullscreenshellv1.cpp | 43 -- tests/auto/client/shared/mockfullscreenshellv1.h | 58 --- tests/auto/client/shared/mockinput.cpp | 474 ------------------ tests/auto/client/shared/mockinput.h | 172 ------- tests/auto/client/shared/mockiviapplication.cpp | 72 --- tests/auto/client/shared/mockiviapplication.h | 85 ---- tests/auto/client/shared/mockoutput.cpp | 135 ------ tests/auto/client/shared/mockoutput.h | 63 --- tests/auto/client/shared/mocksurface.cpp | 191 -------- tests/auto/client/shared/mocksurface.h | 87 ---- tests/auto/client/shared/mockwlshell.cpp | 52 -- tests/auto/client/shared/mockwlshell.h | 58 --- tests/auto/client/shared/mockxdgshellv6.cpp | 145 ------ tests/auto/client/shared/mockxdgshellv6.h | 114 ----- tests/auto/client/shared/shared.pri | 43 +- tests/auto/client/shared/xdgshell.cpp | 186 +++++++ tests/auto/client/shared/xdgshell.h | 127 +++++ tests/auto/client/shared_old/mockcompositor.cpp | 520 ++++++++++++++++++++ tests/auto/client/shared_old/mockcompositor.h | 290 +++++++++++ .../client/shared_old/mockfullscreenshellv1.cpp | 43 ++ .../auto/client/shared_old/mockfullscreenshellv1.h | 58 +++ tests/auto/client/shared_old/mockinput.cpp | 474 ++++++++++++++++++ tests/auto/client/shared_old/mockinput.h | 172 +++++++ .../auto/client/shared_old/mockiviapplication.cpp | 72 +++ tests/auto/client/shared_old/mockiviapplication.h | 85 ++++ tests/auto/client/shared_old/mockoutput.cpp | 135 ++++++ tests/auto/client/shared_old/mockoutput.h | 63 +++ tests/auto/client/shared_old/mocksurface.cpp | 191 ++++++++ tests/auto/client/shared_old/mocksurface.h | 87 ++++ tests/auto/client/shared_old/mockwlshell.cpp | 52 ++ tests/auto/client/shared_old/mockwlshell.h | 58 +++ tests/auto/client/shared_old/mockxdgshellv6.cpp | 145 ++++++ tests/auto/client/shared_old/mockxdgshellv6.h | 114 +++++ tests/auto/client/shared_old/shared_old.pri | 34 ++ tests/auto/client/surface/surface.pro | 5 + tests/auto/client/surface/tst_surface.cpp | 158 ++++++ tests/auto/client/xdgshell/tst_xdgshell.cpp | 269 +++++++++++ tests/auto/client/xdgshell/xdgshell.pro | 5 + tests/auto/client/xdgshellv6/xdgshellv6.pro | 2 +- 51 files changed, 4716 insertions(+), 2515 deletions(-) create mode 100644 tests/auto/client/seatv4/seatv4.pro create mode 100644 tests/auto/client/seatv4/tst_seatv4.cpp create mode 100644 tests/auto/client/shared/corecompositor.cpp create mode 100644 tests/auto/client/shared/corecompositor.h create mode 100644 tests/auto/client/shared/coreprotocol.cpp create mode 100644 tests/auto/client/shared/coreprotocol.h delete mode 100644 tests/auto/client/shared/mockfullscreenshellv1.cpp delete mode 100644 tests/auto/client/shared/mockfullscreenshellv1.h delete mode 100644 tests/auto/client/shared/mockinput.cpp delete mode 100644 tests/auto/client/shared/mockinput.h delete mode 100644 tests/auto/client/shared/mockiviapplication.cpp delete mode 100644 tests/auto/client/shared/mockiviapplication.h delete mode 100644 tests/auto/client/shared/mockoutput.cpp delete mode 100644 tests/auto/client/shared/mockoutput.h delete mode 100644 tests/auto/client/shared/mocksurface.cpp delete mode 100644 tests/auto/client/shared/mocksurface.h delete mode 100644 tests/auto/client/shared/mockwlshell.cpp delete mode 100644 tests/auto/client/shared/mockwlshell.h delete mode 100644 tests/auto/client/shared/mockxdgshellv6.cpp delete mode 100644 tests/auto/client/shared/mockxdgshellv6.h create mode 100644 tests/auto/client/shared/xdgshell.cpp create mode 100644 tests/auto/client/shared/xdgshell.h create mode 100644 tests/auto/client/shared_old/mockcompositor.cpp create mode 100644 tests/auto/client/shared_old/mockcompositor.h create mode 100644 tests/auto/client/shared_old/mockfullscreenshellv1.cpp create mode 100644 tests/auto/client/shared_old/mockfullscreenshellv1.h create mode 100644 tests/auto/client/shared_old/mockinput.cpp create mode 100644 tests/auto/client/shared_old/mockinput.h create mode 100644 tests/auto/client/shared_old/mockiviapplication.cpp create mode 100644 tests/auto/client/shared_old/mockiviapplication.h create mode 100644 tests/auto/client/shared_old/mockoutput.cpp create mode 100644 tests/auto/client/shared_old/mockoutput.h create mode 100644 tests/auto/client/shared_old/mocksurface.cpp create mode 100644 tests/auto/client/shared_old/mocksurface.h create mode 100644 tests/auto/client/shared_old/mockwlshell.cpp create mode 100644 tests/auto/client/shared_old/mockwlshell.h create mode 100644 tests/auto/client/shared_old/mockxdgshellv6.cpp create mode 100644 tests/auto/client/shared_old/mockxdgshellv6.h create mode 100644 tests/auto/client/shared_old/shared_old.pri create mode 100644 tests/auto/client/surface/surface.pro create mode 100644 tests/auto/client/surface/tst_surface.cpp create mode 100644 tests/auto/client/xdgshell/tst_xdgshell.cpp create mode 100644 tests/auto/client/xdgshell/xdgshell.pro diff --git a/tests/auto/client/client.pro b/tests/auto/client/client.pro index 14ce4407d..af7889d5f 100644 --- a/tests/auto/client/client.pro +++ b/tests/auto/client/client.pro @@ -4,5 +4,8 @@ SUBDIRS += \ client \ fullscreenshellv1 \ iviapplication \ - xdgshellv6 \ - wl_connect + seatv4 \ + surface \ + wl_connect \ + xdgshell \ + xdgshellv6 diff --git a/tests/auto/client/client/client.pro b/tests/auto/client/client/client.pro index f4ced252c..7c3a934d0 100644 --- a/tests/auto/client/client/client.pro +++ b/tests/auto/client/client/client.pro @@ -1,4 +1,4 @@ -include (../shared/shared.pri) +include (../shared_old/shared_old.pri) TARGET = tst_client SOURCES += tst_client.cpp diff --git a/tests/auto/client/fullscreenshellv1/fullscreenshellv1.pro b/tests/auto/client/fullscreenshellv1/fullscreenshellv1.pro index 8ce6dfe5c..49d19d5c3 100644 --- a/tests/auto/client/fullscreenshellv1/fullscreenshellv1.pro +++ b/tests/auto/client/fullscreenshellv1/fullscreenshellv1.pro @@ -1,4 +1,4 @@ -include (../shared/shared.pri) +include (../shared_old/shared_old.pri) TARGET = tst_client_fullscreenshell1 SOURCES += tst_fullscreenshellv1.cpp diff --git a/tests/auto/client/iviapplication/iviapplication.pro b/tests/auto/client/iviapplication/iviapplication.pro index 326921373..f2d596e6c 100644 --- a/tests/auto/client/iviapplication/iviapplication.pro +++ b/tests/auto/client/iviapplication/iviapplication.pro @@ -1,4 +1,4 @@ -include (../shared/shared.pri) +include (../shared_old/shared_old.pri) TARGET = tst_client_iviapplication SOURCES += tst_iviapplication.cpp diff --git a/tests/auto/client/seatv4/seatv4.pro b/tests/auto/client/seatv4/seatv4.pro new file mode 100644 index 000000000..c02db5855 --- /dev/null +++ b/tests/auto/client/seatv4/seatv4.pro @@ -0,0 +1,4 @@ +include (../shared/shared.pri) + +TARGET = tst_seatv4 +SOURCES += tst_seatv4.cpp diff --git a/tests/auto/client/seatv4/tst_seatv4.cpp b/tests/auto/client/seatv4/tst_seatv4.cpp new file mode 100644 index 000000000..a95dbfcc2 --- /dev/null +++ b/tests/auto/client/seatv4/tst_seatv4.cpp @@ -0,0 +1,266 @@ +/**************************************************************************** +** +** 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 "mockcompositor.h" + +#include +#include + +using namespace MockCompositor; + +// wl_seat version 5 was introduced in wayland 1.10, and although that's pretty old, +// there are still compositors that have yet to update their implementation to support +// the new version (most importantly our own QtWaylandCompositor). +// As long as that's the case, this test makes sure input events still works on version 4. +class SeatV4Compositor : public DefaultCompositor { +public: + explicit SeatV4Compositor() + { + exec([this] { + m_config.autoConfigure = true; + + removeAll(); + + uint capabilities = MockCompositor::Seat::capability_pointer; + int version = 4; + add(capabilities, version); + }); + } +}; + +class tst_seatv4 : public QObject, private SeatV4Compositor +{ + Q_OBJECT +private slots: + void cleanup(); + void bindsToSeat(); + void createsPointer(); + void setsCursorOnEnter(); + void usesEnterSerial(); + void simpleAxis_data(); + void simpleAxis(); + void invalidPointerEvents(); + void scaledCursor(); +}; + +void tst_seatv4::cleanup() +{ + QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage())); + QCOMPOSITOR_COMPARE(getAll().size(), 1); // No extra outputs left +} + +void tst_seatv4::bindsToSeat() +{ + QCOMPOSITOR_COMPARE(get()->resourceMap().size(), 1); + QCOMPOSITOR_COMPARE(get()->resourceMap().first()->version(), 4); +} + +void tst_seatv4::createsPointer() +{ + QCOMPOSITOR_TRY_COMPARE(pointer()->resourceMap().size(), 1); + QCOMPOSITOR_TRY_COMPARE(pointer()->resourceMap().first()->version(), 4); +} + +void tst_seatv4::setsCursorOnEnter() +{ + QRasterWindow window; + window.resize(64, 64); + window.show(); + QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial); + + exec([=] { pointer()->sendEnter(xdgSurface()->m_surface, {32, 32}); }); + QCOMPOSITOR_TRY_VERIFY(pointer()->cursorSurface()); +} + +void tst_seatv4::usesEnterSerial() +{ + QSignalSpy setCursorSpy(exec([=] { return pointer(); }), &Pointer::setCursor); + QRasterWindow window; + window.resize(64, 64); + window.show(); + QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial); + + uint enterSerial = exec([=] { + return pointer()->sendEnter(xdgSurface()->m_surface, {32, 32}); + }); + QCOMPOSITOR_TRY_VERIFY(pointer()->cursorSurface()); + + QTRY_COMPARE(setCursorSpy.count(), 1); + QCOMPARE(setCursorSpy.takeFirst().at(0).toUInt(), enterSerial); +} + +void tst_seatv4::simpleAxis_data() +{ + QTest::addColumn("axis"); + QTest::addColumn("value"); + QTest::addColumn("orientation"); + QTest::addColumn("angleDelta"); + + // Directions in regular windows/linux terms (no "natural" scrolling) + QTest::newRow("down") << uint(Pointer::axis_vertical_scroll) << 1.0 << Qt::Vertical << QPoint{0, -12}; + QTest::newRow("up") << uint(Pointer::axis_vertical_scroll) << -1.0 << Qt::Vertical << QPoint{0, 12}; + QTest::newRow("left") << uint(Pointer::axis_horizontal_scroll) << 1.0 << Qt::Horizontal << QPoint{-12, 0}; + QTest::newRow("right") << uint(Pointer::axis_horizontal_scroll) << -1.0 << Qt::Horizontal << QPoint{12, 0}; + QTest::newRow("up big") << uint(Pointer::axis_vertical_scroll) << -10.0 << Qt::Vertical << QPoint{0, 120}; +} + +void tst_seatv4::simpleAxis() +{ + QFETCH(uint, axis); + QFETCH(qreal, value); + QFETCH(Qt::Orientation, orientation); + QFETCH(QPoint, angleDelta); + + class WheelWindow : QRasterWindow { + public: + explicit WheelWindow() + { + resize(64, 64); + show(); + } + void wheelEvent(QWheelEvent *event) override + { + QRasterWindow::wheelEvent(event); + // Angle delta should always be provided (says docs) + QVERIFY(!event->angleDelta().isNull()); + + // There are now scroll phases on Wayland prior to v5 + QCOMPARE(event->phase(), Qt::NoScrollPhase); + + // Pixel delta should only be set if we know it's a high-res input device (which we don't) + QCOMPARE(event->pixelDelta(), QPoint(0, 0)); + + // The axis vector of the event is already in surface space, so there is now way to tell + // whether it is inverted or not. + QCOMPARE(event->inverted(), false); + + // We didn't press any buttons + QCOMPARE(event->buttons(), Qt::NoButton); + + if (event->orientation() == Qt::Horizontal) + QCOMPARE(event->delta(), event->angleDelta().x()); + else + QCOMPARE(event->delta(), event->angleDelta().y()); + + // There has been no information about what created the event. + // Documentation says not synthesized is appropriate in such cases + QCOMPARE(event->source(), Qt::MouseEventNotSynthesized); + + m_events.append(Event(event->pixelDelta(), event->angleDelta(), event->orientation())); + } + struct Event // Because I didn't find a convenient way to copy it entirely + { + // TODO: Constructors can be removed when we start supporting brace-initializers + Event() = default; + Event(const QPoint &pixelDelta, const QPoint &angleDelta, Qt::Orientation orientation) + : pixelDelta(pixelDelta), angleDelta(angleDelta), orientation(orientation) + {} + const QPoint pixelDelta; + const QPoint angleDelta; // eights of a degree, positive is upwards, left + const Qt::Orientation orientation{}; + }; + QVector m_events; + }; + + WheelWindow window; + QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial); + + exec([=] { + Surface *surface = xdgSurface()->m_surface; + pointer()->sendEnter(surface, {32, 32}); + wl_client *client = surface->resource()->client(); + // Length of vector in surface-local space. i.e. positive is downwards + pointer()->sendAxis( + client, + Pointer::axis(axis), + value // Length of vector in surface-local space. i.e. positive is downwards + ); + }); + + QTRY_COMPARE(window.m_events.size(), 1); + auto event = window.m_events.takeFirst(); + QCOMPARE(event.angleDelta, angleDelta); + QCOMPARE(event.orientation, orientation); +} + +void tst_seatv4::invalidPointerEvents() +{ + QRasterWindow window; + window.resize(64, 64); + window.show(); + QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial); + + exec([=] { + auto *p = pointer(); + auto *c = client(); + // Purposefully send events without a wl_pointer.enter + p->sendMotion(c, {32, 32}); + p->sendButton(c, BTN_LEFT, Pointer::button_state_pressed); + p->sendAxis(c, Pointer::axis_vertical_scroll, 1.0); + }); + + // Make sure we get here without crashing + xdgPingAndWaitForPong(); +} + +void tst_seatv4::scaledCursor() +{ + QSKIP("Currently broken and should be fixed"); + // Add a highdpi output + exec([&] { + int scale = 2; + add(scale); + }); + + QRasterWindow window; + window.resize(64, 64); + window.show(); + QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial); + + exec([=] { pointer()->sendEnter(xdgSurface()->m_surface, {32, 32}); }); + QCOMPOSITOR_TRY_VERIFY(pointer()->cursorSurface()); + QCOMPOSITOR_TRY_VERIFY(pointer()->cursorSurface()->m_committed.buffer); + QCOMPOSITOR_TRY_COMPARE(pointer()->cursorSurface()->m_committed.bufferScale, 1); + QSize unscaledPixelSize = exec([=] { + return pointer()->cursorSurface()->m_committed.buffer->size(); + }); + + exec([=] { + auto *surface = pointer()->cursorSurface(); + surface->sendEnter(getAll()[1]); + surface->sendLeave(getAll()[0]); + }); + + QCOMPOSITOR_TRY_COMPARE(pointer()->cursorSurface()->m_committed.buffer->size(), unscaledPixelSize * 2); + + // Remove the extra output to clean up for the next test + exec([&] { remove(getAll()[1]); }); +} + +QCOMPOSITOR_TEST_MAIN(tst_seatv4) +#include "tst_seatv4.moc" diff --git a/tests/auto/client/shared/corecompositor.cpp b/tests/auto/client/shared/corecompositor.cpp new file mode 100644 index 000000000..afa25e94c --- /dev/null +++ b/tests/auto/client/shared/corecompositor.cpp @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** 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 "corecompositor.h" + +namespace MockCompositor { + +CoreCompositor::CoreCompositor() + : m_display(wl_display_create()) + , m_socketName(wl_display_add_socket_auto(m_display)) + , m_eventLoop(wl_display_get_event_loop(m_display)) + + // Start dispatching + , m_dispatchThread([this](){ + while (m_running) { + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + dispatch(); + } + }) +{ + m_timer.start(); + Q_ASSERT(isClean()); +} + +CoreCompositor::~CoreCompositor() +{ + m_running = false; + m_dispatchThread.join(); + wl_display_destroy(m_display); +} + +bool CoreCompositor::isClean() +{ + Lock lock(this); + for (auto *global : qAsConst(m_globals)) { + if (!global->isClean()) + return false; + } + return true; +} + +QString CoreCompositor::dirtyMessage() +{ + Lock lock(this); + QStringList messages; + for (auto *global : qAsConst(m_globals)) { + if (!global->isClean()) + messages << (global->metaObject()->className() % QLatin1String(": ") % global->dirtyMessage()); + } + return messages.join(", "); +} + +void CoreCompositor::dispatch() +{ + Lock lock(this); + wl_display_flush_clients(m_display); + constexpr int timeout = 0; // immediate return + wl_event_loop_dispatch(m_eventLoop, timeout); +} + +/*! + * \brief Adds a new global interface for the compositor + * + * Takes ownership of \a global + */ +void CoreCompositor::add(Global *global) +{ + warnIfNotLockedByThread(Q_FUNC_INFO); + m_globals.append(global); +} + +void CoreCompositor::remove(Global *global) +{ + warnIfNotLockedByThread(Q_FUNC_INFO); + //TODO: Need to delete global as well! + m_globals.removeAll(global); +} + +uint CoreCompositor::nextSerial() +{ + warnIfNotLockedByThread(Q_FUNC_INFO); + return wl_display_next_serial(m_display); +} + +uint CoreCompositor::currentTimeMilliseconds() +{ + warnIfNotLockedByThread(Q_FUNC_INFO); + return uint(m_timer.elapsed()); +} + +wl_client *CoreCompositor::client(int index) +{ + warnIfNotLockedByThread(Q_FUNC_INFO); + wl_list *clients = wl_display_get_client_list(m_display); + wl_client *client = nullptr; + int i = 0; + wl_client_for_each(client, clients) { + if (i++ == index) + return client; + } + return nullptr; +} + +void CoreCompositor::warnIfNotLockedByThread(const char *caller) +{ + if (!m_lock || !m_lock->isOwnedByCurrentThread()) { + qWarning() << caller << "called without locking the compositor to the current thread." + << "This means the compositor can start dispatching at any moment," + << "potentially leading to threading issues." + << "Unless you know what you are doing you should probably fix the test" + << "by locking the compositor before accessing it (see mutex())."; + } +} + +} // namespace MockCompositor diff --git a/tests/auto/client/shared/corecompositor.h b/tests/auto/client/shared/corecompositor.h new file mode 100644 index 000000000..875b7d050 --- /dev/null +++ b/tests/auto/client/shared/corecompositor.h @@ -0,0 +1,209 @@ +/**************************************************************************** +** +** 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 MOCKCOMPOSITOR_CORECOMPOSITOR_H +#define MOCKCOMPOSITOR_CORECOMPOSITOR_H + +#include + +#include + +struct wl_resource; + +namespace MockCompositor { + +class Global : public QObject +{ + Q_OBJECT +public: + virtual bool isClean() { return true; } + virtual QString dirtyMessage() { return isClean() ? "clean" : "dirty"; } +}; + +class CoreCompositor +{ +public: + explicit CoreCompositor(); + ~CoreCompositor(); + bool isClean(); + QString dirtyMessage(); + void dispatch(); + + template + auto exec(function_type func, arg_types&&... args) -> decltype(func()) + { + Lock lock(this); + return func(std::forward(args)...); + } + + template + auto call(function_type func, arg_types&&... args) -> decltype(func()) + { + Lock lock(this); + auto boundFunc = std::bind(func, this); + return boundFunc(this, std::forward(args)...); + } + + // Unsafe section below, YOU are responsible that the compositor is locked or + // this is run through the mutex() method! + + void add(Global *global); + void remove(Global *global); + + /*! + * \brief Constructs and adds a new global with the given parameters + * + * Convenience function. i.e. + * + * compositor->add(new MyGlobal(compositor, version); + * + * can be written as: + * + * compositor->add(version); + * + * Returns the new global + */ + template + global_type *add(arg_types&&... args) + { + warnIfNotLockedByThread(Q_FUNC_INFO); + auto *global = new global_type(this, std::forward(args)...); + m_globals.append(global); + return global; + } + + /*! + * \brief Removes all globals of the given type + * + * Convenience function + */ + template + void removeAll() + { + const auto globals = getAll(); + for (auto global : globals) + remove(global); + } + + /*! + * \brief Returns a global with the given type, if any + */ + template + global_type *get() + { + warnIfNotLockedByThread(Q_FUNC_INFO); + for (auto *global : qAsConst(m_globals)) { + if (auto *casted = qobject_cast(global)) + return casted; + } + return nullptr; + } + + /*! + * \brief Returns all globals with the given type, if any + */ + template + QVector getAll() + { + warnIfNotLockedByThread(Q_FUNC_INFO); + QVector matching; + for (auto *global : qAsConst(m_globals)) { + if (auto *casted = qobject_cast(global)) + matching.append(casted); + } + return matching; + } + + uint nextSerial(); + uint currentTimeMilliseconds(); + wl_client *client(int index = 0); + void warnIfNotLockedByThread(const char* caller = "warnIfNotLockedbyThread"); + +public: + // Only use this carefully from the test thread (i.e. lock first) + wl_display *m_display = nullptr; +protected: + class Lock { + public: + explicit Lock(CoreCompositor *compositor) + : m_compositor(compositor) + , m_threadId(std::this_thread::get_id()) + { + // Can't use a QMutexLocker here, as it's not movable + compositor->m_mutex.lock(); + Q_ASSERT(compositor->m_lock == nullptr); + compositor->m_lock = this; + } + ~Lock() + { + Q_ASSERT(m_compositor->m_lock == this); + m_compositor->m_lock = nullptr; + m_compositor->m_mutex.unlock(); + } + + // Move semantics + Lock(Lock &&) = default; + Lock &operator=(Lock &&) = default; + + // Disable copying + Lock(const Lock &) = delete; + Lock &operator=(const Lock &) = delete; + + bool isOwnedByCurrentThread() const { return m_threadId == std::this_thread::get_id(); } + private: + CoreCompositor *m_compositor = nullptr; + std::thread::id m_threadId; + }; + QByteArray m_socketName; + wl_event_loop *m_eventLoop = nullptr; + bool m_running = true; + QVector m_globals; + QElapsedTimer m_timer; + +private: + Lock *m_lock = nullptr; + QMutex m_mutex; + std::thread m_dispatchThread; +}; + +template +QByteArray toByteArray(container_type container) +{ + return QByteArray(reinterpret_cast(container.data()), sizeof (container[0]) * container.size()); +} + +template +return_type *fromResource(::wl_resource *resource) { + if (auto *r = return_type::Resource::fromResource(resource)) + return static_cast(r->object()); + return nullptr; +} + +} // namespace MockCompositor + +#endif // MOCKCOMPOSITOR_CORECOMPOSITOR_H diff --git a/tests/auto/client/shared/coreprotocol.cpp b/tests/auto/client/shared/coreprotocol.cpp new file mode 100644 index 000000000..46d46d980 --- /dev/null +++ b/tests/auto/client/shared/coreprotocol.cpp @@ -0,0 +1,322 @@ +/**************************************************************************** +** +** 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 "coreprotocol.h" + +namespace MockCompositor { + +void Surface::sendFrameCallbacks() +{ + uint time = m_wlCompositor->m_compositor->currentTimeMilliseconds(); + for (auto *callback : m_waitingFrameCallbacks) + callback->sendDone(time); + m_waitingFrameCallbacks.clear(); +} + +void Surface::sendEnter(Output *output) +{ + m_outputs.append(output); + const auto outputResources = output->resourceMap().values(resource()->client()); + for (auto outputResource: outputResources) + wl_surface::send_enter(resource()->handle, outputResource->handle); +} + +void Surface::sendLeave(Output *output) +{ + m_outputs.removeOne(output); + const auto outputResources = output->resourceMap().values(resource()->client()); + for (auto outputResource: outputResources) + wl_surface::send_leave(resource()->handle, outputResource->handle); +} + +void Surface::surface_destroy_resource(Resource *resource) +{ + Q_UNUSED(resource); + for (auto *commit : m_commits) + delete commit->commitSpecific.frame; + bool removed = m_wlCompositor->m_surfaces.removeOne(this); + Q_ASSERT(removed); + delete this; +} + +void Surface::surface_attach(Resource *resource, wl_resource *buffer, int32_t x, int32_t y) +{ + Q_UNUSED(resource); + QPoint offset(x, y); + m_pending.buffer = fromResource(buffer); + m_pending.commitSpecific.attachOffset = offset; + m_pending.commitSpecific.attached = true; + emit attach(buffer, offset); +} + +void Surface::surface_set_buffer_scale(QtWaylandServer::wl_surface::Resource *resource, int32_t scale) +{ + Q_UNUSED(resource); + m_pending.bufferScale = scale; +} + +void Surface::surface_commit(Resource *resource) +{ + Q_UNUSED(resource); + m_committed = m_pending; + m_commits.append(new DoubleBufferedState(m_committed)); + + if (auto *frame = m_pending.commitSpecific.frame) + m_waitingFrameCallbacks.append(frame); + + m_pending.commitSpecific = PerCommitData(); + emit commit(); + if (m_committed.commitSpecific.attached) + emit bufferCommitted(); +} + +void Surface::surface_frame(Resource *resource, uint32_t callback) +{ + // Although valid, there is really no point having multiple frame requests in the same commit. + // Make sure we don't do it + QCOMPARE(m_pending.commitSpecific.frame, nullptr); + + auto *frame = new Callback(resource->client(), callback, 1); + m_pending.commitSpecific.frame = frame; +} + +bool WlCompositor::isClean() { + for (auto *surface : qAsConst(m_surfaces)) { + if (!CursorRole::fromSurface(surface)) + return false; + } + return true; +} + +QString WlCompositor::dirtyMessage() +{ + if (isClean()) + return "clean"; + QStringList messages; + for (auto *s : qAsConst(m_surfaces)) { + QString role = s->m_role ? s->m_role->staticMetaObject.className(): "none/unknown"; + messages << "Surface with role: " + role; + } + return "Dirty, surfaces left:\n\t" + messages.join("\n\t"); +} + +void Output::sendScale(int factor) +{ + Q_ASSERT(m_version >= WL_OUTPUT_SCALE_SINCE_VERSION); + m_scale = factor; + const auto resources = resourceMap().values(); + for (auto r: resources) + wl_output::send_scale(r->handle, factor); +} + +void Output::sendDone() +{ + Q_ASSERT(m_version >= WL_OUTPUT_DONE_SINCE_VERSION); + const auto resources = resourceMap().values(); + for (auto r: resources) + wl_output::send_done(r->handle); +} + +void Output::output_bind_resource(QtWaylandServer::wl_output::Resource *resource) +{ + if (m_version >= WL_OUTPUT_SCALE_SINCE_VERSION) + wl_output::send_scale(resource->handle, m_scale); + //TODO: send other required stuff as well + if (m_version >= WL_OUTPUT_DONE_SINCE_VERSION) + wl_output::send_done(resource->handle); +} + +// Seat stuff +Seat::Seat(CoreCompositor *compositor, uint capabilities, int version) //TODO: check version + : QtWaylandServer::wl_seat(compositor->m_display, version) + , m_compositor(compositor) +{ + setCapabilities(capabilities); +} + +Seat::~Seat() +{ + qDeleteAll(m_oldPointers); + delete m_pointer; +} + +void Seat::setCapabilities(uint capabilities) { + // TODO: Add support for touch and keyboard + Q_ASSERT(capabilities == 0 || capabilities == capability_pointer); + + m_capabilities = capabilities; + + if (m_capabilities & capability_pointer) { + if (!m_pointer) + m_pointer = (new Pointer(this)); + } else if (m_pointer) { + m_oldPointers << m_pointer; + m_pointer = nullptr; + } + + for (auto *resource : resourceMap()) + wl_seat::send_capabilities(resource->handle, capabilities); +} + +void Seat::seat_get_pointer(Resource *resource, uint32_t id) +{ + if (~m_capabilities & capability_pointer) { + qWarning() << "Client requested a wl_pointer without the capability being available." + << "This Could be a race condition when hotunplugging," + << "but is most likely a client error"; + Pointer *pointer = new Pointer(this); + pointer->add(resource->client(), id, resource->version()); + // TODO: mark as destroyed + m_oldPointers << pointer; + return; + } + m_pointer->add(resource->client(), id, resource->version()); +} + +Surface *Pointer::cursorSurface() +{ + return m_cursorRole ? m_cursorRole->m_surface : nullptr; +} + +uint Pointer::sendEnter(Surface *surface, const QPointF &position) +{ + wl_fixed_t x = wl_fixed_from_double(position.x()); + wl_fixed_t y = wl_fixed_from_double(position.y()); + m_enterSerial = m_seat->m_compositor->nextSerial(); + + wl_client *client = surface->resource()->client(); + const auto pointerResources = resourceMap().values(client); + for (auto *r : pointerResources) + send_enter(r->handle, m_enterSerial, surface->resource()->handle, x ,y); + return m_enterSerial; +} + +// Make sure you call enter, frame etc. first +void Pointer::sendMotion(wl_client *client, const QPointF &position) +{ + wl_fixed_t x = wl_fixed_from_double(position.x()); + wl_fixed_t y = wl_fixed_from_double(position.y()); + auto time = m_seat->m_compositor->currentTimeMilliseconds(); + const auto pointerResources = resourceMap().values(client); + for (auto *r : pointerResources) + send_motion(r->handle, time, x, y); +} + +// Make sure you call enter, frame etc. first +uint Pointer::sendButton(wl_client *client, uint button, uint state) +{ + Q_ASSERT(state == button_state_pressed || state == button_state_released); + auto time = m_seat->m_compositor->currentTimeMilliseconds(); + uint serial = m_seat->m_compositor->nextSerial(); + const auto pointerResources = resourceMap().values(client); + for (auto *r : pointerResources) + send_button(r->handle, serial, time, button, state); + return serial; +} + +// Make sure you call enter, frame etc. first +void Pointer::sendAxis(wl_client *client, axis axis, qreal value) +{ + auto time = m_seat->m_compositor->currentTimeMilliseconds(); + wl_fixed_t val = wl_fixed_from_double(value); + const auto pointerResources = resourceMap().values(client); + for (auto *r : pointerResources) + send_axis(r->handle, time, axis, val); +} + +void Pointer::pointer_set_cursor(Resource *resource, uint32_t serial, wl_resource *surface, int32_t hotspot_x, int32_t hotspot_y) +{ + Q_UNUSED(resource); + Q_UNUSED(hotspot_x); + Q_UNUSED(hotspot_y); + auto *s = fromResource(surface); + QVERIFY(s); + + if (s->m_role) { + auto *cursorRole = CursorRole::fromSurface(s); + QVERIFY(cursorRole); + QVERIFY(cursorRole == m_cursorRole); + } else { + m_cursorRole = new CursorRole(s); //TODO: make sure we don't leak CursorRole + s->m_role = m_cursorRole; + } +// QCOMPARE(serial, m_enterSerial); //TODO: uncomment when this bug is fixed + emit setCursor(serial); +} + +// Shm implementation +Shm::Shm(CoreCompositor *compositor, QVector formats, int version) + : QtWaylandServer::wl_shm(compositor->m_display, version) + , m_compositor(compositor) + , m_formats(formats) +{ + // Some formats are specified as mandatory + Q_ASSERT(m_formats.contains(format_argb8888)); + Q_ASSERT(m_formats.contains(format_xrgb8888)); +} + +bool Shm::isClean() +{ +// for (ShmPool *pool : qAsConst(m_pools)) { +// //TODO: return false if not cursor buffer +// if (pool->m_buffers.isEmpty()) { +// return false; +// } +// } + return true; +} + +void Shm::shm_create_pool(Resource *resource, uint32_t id, int32_t fd, int32_t size) +{ + Q_UNUSED(fd); + Q_UNUSED(size); + auto *pool = new ShmPool(this, resource->client(), id, 1); + m_pools.append(pool); +} + +ShmPool::ShmPool(Shm *shm, wl_client *client, int id, int version) + : QtWaylandServer::wl_shm_pool(client, id, version) + , m_shm(shm) +{ +} + +void ShmPool::shm_pool_create_buffer(Resource *resource, uint32_t id, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format) +{ + QSize size(width, height); + new ShmBuffer(offset, size, stride, Shm::format(format), resource->client(), id); +} + +void ShmPool::shm_pool_destroy_resource(Resource *resource) +{ + Q_UNUSED(resource); + bool removed = m_shm->m_pools.removeOne(this); + Q_ASSERT(removed); + delete this; +} + +} // namespace MockCompositor diff --git a/tests/auto/client/shared/coreprotocol.h b/tests/auto/client/shared/coreprotocol.h new file mode 100644 index 000000000..2fbe9b139 --- /dev/null +++ b/tests/auto/client/shared/coreprotocol.h @@ -0,0 +1,313 @@ +/**************************************************************************** +** +** 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 MOCKCOMPOSITOR_COREPROTOCOL_H +#define MOCKCOMPOSITOR_COREPROTOCOL_H + +#include "corecompositor.h" + +#include + +namespace MockCompositor { + +class WlCompositor; +class Output; +class Pointer; +class CursorRole; +class ShmPool; +class ShmBuffer; + +class Buffer : public QObject, public QtWaylandServer::wl_buffer +{ + Q_OBJECT +public: + explicit Buffer(wl_client *client, int id, int version) + : QtWaylandServer::wl_buffer(client, id, version) + { + } + virtual QSize size() const = 0; + bool m_destroyed = false; + +protected: + void buffer_destroy_resource(Resource *resource) override + { + Q_UNUSED(resource); + m_destroyed = true; + // The client side resource has been destroyed, but we keep this object because it may be + // be used as a reference by e.g. surface for the currently committed buffer so it's not + // yet safe to free it. + + //TODO: The memory should be freed by its factory + } + void buffer_destroy(Resource *resource) override { wl_resource_destroy(resource->handle); } +}; + +class Callback : public QObject, public QtWaylandServer::wl_callback +{ + Q_OBJECT +public: + explicit Callback(wl_client *client, int id, int version = 1) + : QtWaylandServer::wl_callback(client, id, version) + { + } + ~Callback() override { if (!m_destroyed) wl_resource_destroy(resource()->handle); } + void send_done(uint32_t data) = delete; // use state-tracking method below instead + void sendDone(uint data) { Q_ASSERT(!m_done); QtWaylandServer::wl_callback::send_done(data); m_done = true; } + void sendDoneAndDestroy(uint data) { sendDone(data); wl_resource_destroy(resource()->handle); } + bool m_done = false; + bool m_destroyed = false; +protected: + void callback_destroy_resource(Resource *resource) override { Q_UNUSED(resource); m_destroyed = true; } +}; + +class SurfaceRole : public QObject { + Q_OBJECT +}; + +class Surface : public QObject, public QtWaylandServer::wl_surface +{ + Q_OBJECT +public: + explicit Surface(WlCompositor *wlCompositor, wl_client *client, int id, int version) + : QtWaylandServer::wl_surface(client, id, version) + , m_wlCompositor(wlCompositor) + { + } + ~Surface() override { qDeleteAll(m_commits); } // TODO: maybe make sure buffers are released? + void sendFrameCallbacks(); + void sendEnter(Output *output); + void send_enter(::wl_resource *output) = delete; + void sendLeave(Output *output); + void send_leave(::wl_resource *output) = delete; + + WlCompositor *m_wlCompositor; + struct PerCommitData { + Callback *frame = nullptr; + QPoint attachOffset; + bool attached = false; + }; + struct DoubleBufferedState { + PerCommitData commitSpecific; + Buffer *buffer = nullptr; + uint configureSerial = 0; + int bufferScale = 1; + } m_pending, m_committed; + QVector m_commits; + QVector m_waitingFrameCallbacks; + QVector m_outputs; + SurfaceRole *m_role = nullptr; + +signals: + void attach(void *buffer, QPoint offset); + void commit(); + void bufferCommitted(); + +protected: + void surface_destroy_resource(Resource *resource) override; + void surface_destroy(Resource *resource) override { wl_resource_destroy(resource->handle); } + void surface_attach(Resource *resource, wl_resource *buffer, int32_t x, int32_t y) override; + void surface_set_buffer_scale(Resource *resource, int32_t scale) override; + void surface_commit(Resource *resource) override; + void surface_frame(Resource *resource, uint32_t callback) override; +}; + +class WlCompositor : public Global, public QtWaylandServer::wl_compositor +{ + Q_OBJECT +public: + explicit WlCompositor(CoreCompositor *compositor, int version = 3) + : QtWaylandServer::wl_compositor(compositor->m_display, version) + , m_compositor(compositor) + {} + bool isClean() override; + QString dirtyMessage() override; + QVector m_surfaces; + CoreCompositor *m_compositor = nullptr; + +signals: + void surfaceCreated(Surface *surface); + +protected: + void compositor_create_surface(Resource *resource, uint32_t id) override + { + auto *surface = new Surface(this, resource->client(), id, resource->version()); + m_surfaces.append(surface); + emit surfaceCreated(surface); + } +}; + +class SubCompositor : public Global, public QtWaylandServer::wl_subcompositor +{ + Q_OBJECT +public: + explicit SubCompositor(CoreCompositor *compositor, int version = 1) + : QtWaylandServer::wl_subcompositor(compositor->m_display, version) + {} + // TODO +}; + +class Output : public Global, public QtWaylandServer::wl_output +{ + Q_OBJECT +public: + explicit Output(CoreCompositor *compositor, int scale = 1, int version = 2) + : QtWaylandServer::wl_output(compositor->m_display, version) + , m_scale(scale) + , m_version(version) + {} + void sendScale(int factor); + void send_scale(int32_t factor) = delete; + void send_scale(struct ::wl_resource *resource, int32_t factor) = delete; + void sendDone(); + int m_scale = 1; + int m_version = 1; // TODO: remove on libwayland upgrade + +protected: + void output_bind_resource(Resource *resource) override; +}; + +class Seat : public Global, public QtWaylandServer::wl_seat +{ + Q_OBJECT +public: + explicit Seat(CoreCompositor *compositor, uint capabilities, int version = 4); + ~Seat() override; + void send_capabilities(Resource *resource, uint capabilities) = delete; // Use wrapper instead + void send_capabilities(uint capabilities) = delete; // Use wrapper instead + void setCapabilities(uint capabilities); + + CoreCompositor *m_compositor = nullptr; + + Pointer* m_pointer = nullptr; + QVector m_oldPointers; + + uint m_capabilities = 0; + +protected: + void seat_bind_resource(Resource *resource) override + { + wl_seat::send_capabilities(resource->handle, m_capabilities); + } + + void seat_get_pointer(Resource *resource, uint32_t id) override; +// void seat_get_keyboard(Resource *resource, uint32_t id) override; +// void seat_get_touch(Resource *resource, uint32_t id) override; + +// void seat_release(Resource *resource) override; +}; + +class Pointer : public QObject, public QtWaylandServer::wl_pointer +{ + Q_OBJECT +public: + explicit Pointer(Seat *seat) : m_seat(seat) {} + Surface *cursorSurface(); + CursorRole* m_cursorRole = nullptr; //TODO: cleanup + uint sendEnter(Surface *surface, const QPointF &position); + void sendMotion(wl_client *client, const QPointF &position); + uint sendButton(wl_client *client, uint button, uint state); + void sendAxis(wl_client *client, axis axis, qreal value); + + Seat *m_seat = nullptr; + uint m_enterSerial = 0; + +signals: + void setCursor(uint serial); //TODO: add arguments? + +protected: + void pointer_set_cursor(Resource *resource, uint32_t serial, ::wl_resource *surface, int32_t hotspot_x, int32_t hotspot_y) override; + //TODO +}; + +class CursorRole : public SurfaceRole { + Q_OBJECT +public: + explicit CursorRole(Surface *surface) // TODO: needs some more args + : m_surface(surface) + { + } + static CursorRole *fromSurface(Surface *surface) { return qobject_cast(surface->m_role); } + Surface *m_surface = nullptr; +}; + +class Shm : public Global, public QtWaylandServer::wl_shm +{ + Q_OBJECT +public: + explicit Shm(CoreCompositor *compositor, QVector formats = {format_argb8888, format_xrgb8888, format_rgb888}, int version = 1); + bool isClean() override; + CoreCompositor *m_compositor = nullptr; + QVector m_pools; + const QVector m_formats; + +protected: + void shm_create_pool(Resource *resource, uint32_t id, int32_t fd, int32_t size) override; + void shm_bind_resource(Resource *resource) override + { + for (auto format : qAsConst(m_formats)) + send_format(resource->handle, format); + } +}; + +class ShmPool : QObject, public QtWaylandServer::wl_shm_pool +{ + Q_OBJECT +public: + explicit ShmPool(Shm *shm, wl_client *client, int id, int version = 1); + Shm *m_shm = nullptr; + QVector m_buffers; + +protected: + void shm_pool_create_buffer(Resource *resource, uint32_t id, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format) override; + void shm_pool_destroy_resource(Resource *resource) override; + void shm_pool_destroy(Resource *resource) override { wl_resource_destroy(resource->handle); } +}; + +class ShmBuffer : public Buffer +{ + Q_OBJECT +public: + static ShmBuffer *fromBuffer(Buffer *buffer) { return qobject_cast(buffer); } + explicit ShmBuffer(int offset, const QSize &size, int stride, Shm::format format, wl_client *client, int id, int version = 1) + : Buffer(client, id, version) + , m_offset(offset) + , m_size(size) + , m_stride(stride) + , m_format(format) + { + } + QSize size() const override { return m_size; } + const int m_offset; + const QSize m_size; + const int m_stride; + const Shm::format m_format; +}; + +} // namespace MockCompositor + +#endif // MOCKCOMPOSITOR_COREPROTOCOL_H diff --git a/tests/auto/client/shared/mockcompositor.cpp b/tests/auto/client/shared/mockcompositor.cpp index df24b4091..45d62a153 100644 --- a/tests/auto/client/shared/mockcompositor.cpp +++ b/tests/auto/client/shared/mockcompositor.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** 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. @@ -27,494 +27,64 @@ ****************************************************************************/ #include "mockcompositor.h" -#include "mockinput.h" -#include "mockoutput.h" -#include "mocksurface.h" -#include "mockwlshell.h" -#include "mockxdgshellv6.h" -#include "mockiviapplication.h" -#include - -#include -MockCompositor::MockCompositor() -{ - pthread_create(&m_thread, 0, run, this); - - m_mutex.lock(); - m_waitCondition.wait(&m_mutex); - m_mutex.unlock(); -} - -MockCompositor::~MockCompositor() -{ - m_alive = false; - m_waitCondition.wakeOne(); - pthread_join(m_thread, 0); -} - -void MockCompositor::lock() -{ - m_mutex.lock(); -} - -void MockCompositor::unlock() -{ - m_mutex.unlock(); -} - -void MockCompositor::applicationInitialized() -{ - m_ready = true; -} - -int MockCompositor::waylandFileDescriptor() const -{ - return m_compositor->fileDescriptor(); -} - -void MockCompositor::processWaylandEvents() -{ - m_waitCondition.wakeOne(); -} - -void MockCompositor::setOutputMode(const QSize &size) -{ - Command command = makeCommand(Impl::Compositor::setOutputMode, m_compositor); - command.parameters << size; - processCommand(command); -} - -void MockCompositor::setKeyboardFocus(const QSharedPointer &surface) -{ - Command command = makeCommand(Impl::Compositor::setKeyboardFocus, m_compositor); - command.parameters << QVariant::fromValue(surface); - processCommand(command); -} - -void MockCompositor::sendMousePress(const QSharedPointer &surface, const QPoint &pos) -{ - Command command = makeCommand(Impl::Compositor::sendMousePress, m_compositor); - command.parameters << QVariant::fromValue(surface) << pos; - processCommand(command); -} - -void MockCompositor::sendMouseRelease(const QSharedPointer &surface) -{ - Command command = makeCommand(Impl::Compositor::sendMouseRelease, m_compositor); - command.parameters << QVariant::fromValue(surface); - processCommand(command); -} - -void MockCompositor::sendKeyPress(const QSharedPointer &surface, uint code) -{ - Command command = makeCommand(Impl::Compositor::sendKeyPress, m_compositor); - command.parameters << QVariant::fromValue(surface) << code; - processCommand(command); -} - -void MockCompositor::sendKeyRelease(const QSharedPointer &surface, uint code) -{ - Command command = makeCommand(Impl::Compositor::sendKeyRelease, m_compositor); - command.parameters << QVariant::fromValue(surface) << code; - processCommand(command); -} - -void MockCompositor::sendTouchDown(const QSharedPointer &surface, const QPoint &position, int id) -{ - Command command = makeCommand(Impl::Compositor::sendTouchDown, m_compositor); - command.parameters << QVariant::fromValue(surface) << position << id; - processCommand(command); -} - -void MockCompositor::sendTouchMotion(const QSharedPointer &surface, const QPoint &position, int id) -{ - Command command = makeCommand(Impl::Compositor::sendTouchMotion, m_compositor); - command.parameters << QVariant::fromValue(surface) << position << id; - processCommand(command); -} - -void MockCompositor::sendTouchUp(const QSharedPointer &surface, int id) -{ - Command command = makeCommand(Impl::Compositor::sendTouchUp, m_compositor); - command.parameters << QVariant::fromValue(surface) << id; - processCommand(command); -} - -void MockCompositor::sendTouchFrame(const QSharedPointer &surface) -{ - Command command = makeCommand(Impl::Compositor::sendTouchFrame, m_compositor); - command.parameters << QVariant::fromValue(surface); - processCommand(command); -} - -void MockCompositor::sendDataDeviceDataOffer(const QSharedPointer &surface) -{ - Command command = makeCommand(Impl::Compositor::sendDataDeviceDataOffer, m_compositor); - command.parameters << QVariant::fromValue(surface); - processCommand(command); -} - -void MockCompositor::sendDataDeviceEnter(const QSharedPointer &surface, const QPoint& position) -{ - Command command = makeCommand(Impl::Compositor::sendDataDeviceEnter, m_compositor); - command.parameters << QVariant::fromValue(surface) << QVariant::fromValue(position); - processCommand(command); -} - -void MockCompositor::sendDataDeviceMotion(const QPoint &position) -{ - Command command = makeCommand(Impl::Compositor::sendDataDeviceMotion, m_compositor); - command.parameters << QVariant::fromValue(position); - processCommand(command); -} - -void MockCompositor::sendDataDeviceDrop(const QSharedPointer &surface) -{ - Command command = makeCommand(Impl::Compositor::sendDataDeviceDrop, m_compositor); - command.parameters << QVariant::fromValue(surface); - processCommand(command); -} - -void MockCompositor::sendDataDeviceLeave(const QSharedPointer &surface) -{ - Command command = makeCommand(Impl::Compositor::sendDataDeviceLeave, m_compositor); - command.parameters << QVariant::fromValue(surface); - processCommand(command); -} - -void MockCompositor::sendAddOutput() -{ - Command command = makeCommand(Impl::Compositor::sendAddOutput, m_compositor); - processCommand(command); -} - -void MockCompositor::sendRemoveOutput(const QSharedPointer &output) -{ - Command command = makeCommand(Impl::Compositor::sendRemoveOutput, m_compositor); - command.parameters << QVariant::fromValue(output); - processCommand(command); -} - -void MockCompositor::sendOutputGeometry(const QSharedPointer &output, const QRect &geometry) -{ - Command command = makeCommand(Impl::Compositor::sendOutputGeometry, m_compositor); - command.parameters << QVariant::fromValue(output); - command.parameters << QVariant::fromValue(geometry); - processCommand(command); -} - -void MockCompositor::sendSurfaceEnter(const QSharedPointer &surface, QSharedPointer &output) -{ - Command command = makeCommand(Impl::Compositor::sendSurfaceEnter, m_compositor); - command.parameters << QVariant::fromValue(surface); - command.parameters << QVariant::fromValue(output); - processCommand(command); -} - -void MockCompositor::sendSurfaceLeave(const QSharedPointer &surface, QSharedPointer &output) -{ - Command command = makeCommand(Impl::Compositor::sendSurfaceLeave, m_compositor); - command.parameters << QVariant::fromValue(surface); - command.parameters << QVariant::fromValue(output); - processCommand(command); -} - -void MockCompositor::sendShellSurfaceConfigure(const QSharedPointer surface, const QSize &size) -{ - Command command = makeCommand(Impl::Compositor::sendShellSurfaceConfigure, m_compositor); - command.parameters << QVariant::fromValue(surface); - command.parameters << QVariant::fromValue(size); - processCommand(command); -} - -void MockCompositor::sendIviSurfaceConfigure(const QSharedPointer iviSurface, const QSize &size) -{ - Command command = makeCommand(Impl::Compositor::sendIviSurfaceConfigure, m_compositor); - command.parameters << QVariant::fromValue(iviSurface); - command.parameters << QVariant::fromValue(size); - processCommand(command); -} - -void MockCompositor::sendXdgToplevelV6Configure(const QSharedPointer toplevel, const QSize &size, const QVector &states) -{ - Command command = makeCommand(Impl::Compositor::sendXdgToplevelV6Configure, m_compositor); - command.parameters << QVariant::fromValue(toplevel); - command.parameters << QVariant::fromValue(size); - QByteArray statesBytes(reinterpret_cast(states.data()), - states.size() * static_cast(sizeof(uint))); - command.parameters << statesBytes; - processCommand(command); -} - -void MockCompositor::waitForStartDrag() -{ - Command command = makeCommand(Impl::Compositor::waitForStartDrag, m_compositor); - processCommand(command); -} - -QSharedPointer MockCompositor::surface() -{ - QSharedPointer result; - lock(); - QVector surfaces = m_compositor->surfaces(); - foreach (Impl::Surface *surface, surfaces) { - // we don't want to mistake the cursor surface for a window surface - if (surface->isMapped()) { - result = surface->mockSurface(); - break; - } - } - unlock(); - return result; -} - -QSharedPointer MockCompositor::output(int index) -{ - QSharedPointer result; - lock(); - if (Impl::Output *output = m_compositor->outputs().value(index, nullptr)) - result = output->mockOutput(); - unlock(); - return result; -} - -QSharedPointer MockCompositor::iviSurface(int index) -{ - QSharedPointer result; - lock(); - if (Impl::IviSurface *toplevel = m_compositor->iviApplication()->iviSurfaces().value(index, nullptr)) - result = toplevel->mockIviSurface(); - unlock(); - return result; -} - -QSharedPointer MockCompositor::xdgToplevelV6(int index) -{ - QSharedPointer result; - lock(); - if (Impl::XdgToplevelV6 *toplevel = m_compositor->xdgShellV6()->toplevels().value(index, nullptr)) - result = toplevel->mockToplevel(); - unlock(); - return result; -} - -QSharedPointer MockCompositor::fullScreenShellV1Surface(int index) -{ - QSharedPointer result; - lock(); - if (Impl::Surface *surface = m_compositor->fullScreenShellV1()->surfaces().value(index, nullptr)) - result = surface->mockSurface(); - unlock(); - return result; -} - -MockCompositor::Command MockCompositor::makeCommand(Command::Callback callback, void *target) -{ - Command command; - command.callback = callback; - command.target = target; - return command; -} - -void MockCompositor::processCommand(const Command &command) -{ - lock(); - m_commandQueue << command; - unlock(); - - m_waitCondition.wakeOne(); -} - -void MockCompositor::dispatchCommands() -{ - lock(); - int count = m_commandQueue.length(); - unlock(); - - for (int i = 0; i < count; ++i) { - lock(); - const Command command = m_commandQueue.takeFirst(); - unlock(); - command.callback(command.target, command.parameters); +namespace MockCompositor { + +DefaultCompositor::DefaultCompositor() +{ + { + Lock l(this); + + // Globals: Should ideally always be at least the latest versions we support. + // Legacy versions can override in separate tests by removing and adding. + add(); + add(); + add(); + add(Seat::capability_pointer); + add(); + add(); + // TODO: other shells, viewporter, xdgoutput etc + + QObject::connect(get(), &WlCompositor::surfaceCreated, [&] (Surface *surface){ + QObject::connect(surface, &Surface::bufferCommitted, [=] { + if (m_config.autoRelease) { + // Pretend we made a copy of the buffer and just release it immediately + surface->m_committed.buffer->send_release(); + } + if (m_config.autoEnter && surface->m_outputs.empty()) + surface->sendEnter(get()); + wl_display_flush_clients(m_display); + }); + }); + + QObject::connect(get(), &XdgWmBase::toplevelCreated, [&] (XdgToplevel *toplevel) { + // Needed because lambdas don't support Qt::DirectConnection + exec([&]{ + if (m_config.autoConfigure) + toplevel->sendCompleteConfigure(); + }); + }); } + Q_ASSERT(isClean()); } -void *MockCompositor::run(void *data) -{ - MockCompositor *controller = static_cast(data); - - Impl::Compositor compositor; - - controller->m_compositor = &compositor; - controller->m_waitCondition.wakeOne(); - - while (!controller->m_ready) { - controller->dispatchCommands(); - compositor.dispatchEvents(20); - } - - while (controller->m_alive) { - { - QMutexLocker locker(&controller->m_mutex); - if (controller->m_commandQueue.isEmpty()) - controller->m_waitCondition.wait(&controller->m_mutex); - } - controller->dispatchCommands(); - compositor.dispatchEvents(20); - } - - return 0; -} - -namespace Impl { - -Compositor::Compositor() - : m_display(wl_display_create()) -{ - if (wl_display_add_socket(m_display, 0)) { - fprintf(stderr, "Fatal: Failed to open server socket\n"); - exit(EXIT_FAILURE); - } - - wl_global_create(m_display, &wl_compositor_interface, 1, this, bindCompositor); - - m_data_device_manager.reset(new DataDeviceManager(this, m_display)); - - wl_display_init_shm(m_display); - - m_seat.reset(new Seat(this, m_display)); - m_pointer = m_seat->pointer(); - m_keyboard = m_seat->keyboard(); - m_touch = m_seat->touch(); - - m_outputs.append(new Output(m_display, QSize(1920, 1080), QPoint(0, 0))); - m_iviApplication.reset(new IviApplication(m_display)); - m_wlShell.reset(new WlShell(m_display)); - m_xdgShellV6.reset(new XdgShellV6(m_display)); - m_fullScreenShellV1.reset(new FullScreenShellV1(m_display)); - - m_loop = wl_display_get_event_loop(m_display); - m_fd = wl_event_loop_get_fd(m_loop); -} - -Compositor::~Compositor() -{ - wl_display_destroy(m_display); -} - -void Compositor::dispatchEvents(int timeout) -{ - wl_display_flush_clients(m_display); - wl_event_loop_dispatch(m_loop, timeout); -} - -static void compositor_create_surface(wl_client *client, wl_resource *compositorResource, uint32_t id) +uint DefaultCompositor::sendXdgShellPing() { - Compositor *compositor = static_cast(wl_resource_get_user_data(compositorResource)); - compositor->addSurface(new Surface(client, id, wl_resource_get_version(compositorResource), compositor)); + warnIfNotLockedByThread(Q_FUNC_INFO); + uint serial = nextSerial(); + auto *base = get(); + const auto resourceMap = base->resourceMap(); + Q_ASSERT(resourceMap.size() == 1); // binding more than once shouldn't be needed + base->send_ping(resourceMap.first()->handle, serial); + return serial; } -static void compositor_create_region(wl_client *client, wl_resource *compositorResource, uint32_t id) +void DefaultCompositor::xdgPingAndWaitForPong() { - Q_UNUSED(client); - Q_UNUSED(compositorResource); - Q_UNUSED(id); + QSignalSpy pongSpy(exec([=] { return get(); }), &XdgWmBase::pong); + uint serial = exec([=] { return sendXdgShellPing(); }); + QTRY_COMPARE(pongSpy.count(), 1); + QTRY_COMPARE(pongSpy.first().at(0).toUInt(), serial); } -void Compositor::bindCompositor(wl_client *client, void *compositorData, uint32_t version, uint32_t id) -{ - static const struct wl_compositor_interface compositorInterface = { - compositor_create_surface, - compositor_create_region - }; - - wl_resource *resource = wl_resource_create(client, &wl_compositor_interface, static_cast(version), id); - wl_resource_set_implementation(resource, &compositorInterface, compositorData, nullptr); -} - -static void unregisterResourceCallback(wl_listener *listener, void *data) -{ - struct wl_resource *resource = reinterpret_cast(data); - wl_list_remove(wl_resource_get_link(resource)); - delete listener; -} - -void registerResource(wl_list *list, wl_resource *resource) -{ - wl_list_insert(list, wl_resource_get_link(resource)); - - wl_listener *listener = new wl_listener; - listener->notify = unregisterResourceCallback; - - wl_resource_add_destroy_listener(resource, listener); -} - -QVector Compositor::surfaces() const -{ - return m_surfaces; -} - -QVector Compositor::outputs() const -{ - return m_outputs; -} - -IviApplication *Compositor::iviApplication() const -{ - return m_iviApplication.data(); -} - -XdgShellV6 *Compositor::xdgShellV6() const -{ - return m_xdgShellV6.data(); -} - -FullScreenShellV1 *Compositor::fullScreenShellV1() const -{ - return m_fullScreenShellV1.data(); -} - -uint32_t Compositor::nextSerial() -{ - return wl_display_next_serial(m_display); -} - -void Compositor::addSurface(Surface *surface) -{ - m_surfaces << surface; -} - -void Compositor::removeSurface(Surface *surface) -{ - m_surfaces.removeOne(surface); - m_keyboard->handleSurfaceDestroyed(surface); - m_pointer->handleSurfaceDestroyed(surface); - m_fullScreenShellV1->removeSurface(surface); -} - -Surface *Compositor::resolveSurface(const QVariant &v) -{ - QSharedPointer mockSurface = v.value >(); - return mockSurface ? mockSurface->handle() : nullptr; -} - -Output *Compositor::resolveOutput(const QVariant &v) -{ - QSharedPointer mockOutput = v.value >(); - return mockOutput ? mockOutput->handle() : nullptr; -} - -IviSurface *Compositor::resolveIviSurface(const QVariant &v) -{ - QSharedPointer mockIviSurface = v.value>(); - return mockIviSurface ? mockIviSurface->handle() : nullptr; -} - -XdgToplevelV6 *Compositor::resolveToplevel(const QVariant &v) -{ - QSharedPointer mockToplevel = v.value>(); - return mockToplevel ? mockToplevel->handle() : nullptr; -} - -} +} // namespace MockCompositor diff --git a/tests/auto/client/shared/mockcompositor.h b/tests/auto/client/shared/mockcompositor.h index 4bab1ed67..07366a493 100644 --- a/tests/auto/client/shared/mockcompositor.h +++ b/tests/auto/client/shared/mockcompositor.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** 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. @@ -29,262 +29,55 @@ #ifndef MOCKCOMPOSITOR_H #define MOCKCOMPOSITOR_H -#include "mockxdgshellv6.h" -#include "mockiviapplication.h" -#include "mockfullscreenshellv1.h" +#include "corecompositor.h" +#include "coreprotocol.h" +#include "xdgshell.h" -#include -#include -#include +#include -#include -#include -#include -#include -#include -#include -#include - -namespace Impl { - -typedef void (**Implementation)(void); - -class Keyboard; -class Pointer; -class Touch; -class Seat; -class DataDeviceManager; -class Surface; -class Output; -class IviApplication; -class WlShell; -class XdgShellV6; - -class Compositor -{ -public: - Compositor(); - ~Compositor(); - - int fileDescriptor() const { return m_fd; } - void dispatchEvents(int timeout = 0); - - uint32_t nextSerial(); - uint32_t time() { return ++m_time; } - - QVector surfaces() const; - QVector outputs() const; - - IviApplication *iviApplication() const; - XdgShellV6 *xdgShellV6() const; - FullScreenShellV1 *fullScreenShellV1() const; - - void addSurface(Surface *surface); - void removeSurface(Surface *surface); - - static void setKeyboardFocus(void *data, const QList ¶meters); - static void sendMousePress(void *data, const QList ¶meters); - static void sendMouseRelease(void *data, const QList ¶meters); - static void sendKeyPress(void *data, const QList ¶meters); - static void sendKeyRelease(void *data, const QList ¶meters); - static void sendTouchDown(void *data, const QList ¶meters); - static void sendTouchUp(void *data, const QList ¶meters); - static void sendTouchMotion(void *data, const QList ¶meters); - static void sendTouchFrame(void *data, const QList ¶meters); - static void sendDataDeviceDataOffer(void *data, const QList ¶meters); - static void sendDataDeviceEnter(void *data, const QList ¶meters); - static void sendDataDeviceMotion(void *data, const QList ¶meters); - static void sendDataDeviceDrop(void *data, const QList ¶meters); - static void sendDataDeviceLeave(void *data, const QList ¶meters); - static void waitForStartDrag(void *data, const QList ¶meters); - static void setOutputMode(void *compositor, const QList ¶meters); - static void sendAddOutput(void *data, const QList ¶meters); - static void sendRemoveOutput(void *data, const QList ¶meters); - static void sendOutputGeometry(void *data, const QList ¶meters); - static void sendSurfaceEnter(void *data, const QList ¶meters); - static void sendSurfaceLeave(void *data, const QList ¶meters); - static void sendShellSurfaceConfigure(void *data, const QList ¶meters); - static void sendIviSurfaceConfigure(void *data, const QList ¶meters); - static void sendXdgToplevelV6Configure(void *data, const QList ¶meters); - -public: - bool m_startDragSeen = false; - -private: - static void bindCompositor(wl_client *client, void *data, uint32_t version, uint32_t id); - static Surface *resolveSurface(const QVariant &v); - static Output *resolveOutput(const QVariant &v); - static IviSurface *resolveIviSurface(const QVariant &v); - static XdgToplevelV6 *resolveToplevel(const QVariant &v); - - void initShm(); - - QRect m_outputGeometry; - - wl_display *m_display = nullptr; - wl_event_loop *m_loop = nullptr; - int m_fd = -1; - - uint32_t m_time = 0; - - QScopedPointer m_seat; - Pointer *m_pointer = nullptr; - Keyboard *m_keyboard = nullptr; - Touch *m_touch = nullptr; - QScopedPointer m_data_device_manager; - QVector m_surfaces; - QVector m_outputs; - QScopedPointer m_iviApplication; - QScopedPointer m_wlShell; - QScopedPointer m_xdgShellV6; - QScopedPointer m_fullScreenShellV1; -}; - -void registerResource(wl_list *list, wl_resource *resource); - -} - -class MockSurface -{ -public: - Impl::Surface *handle() const { return m_surface; } - - QImage image; - -private: - MockSurface(Impl::Surface *surface); - friend class Impl::Compositor; - friend class Impl::Surface; - - Impl::Surface *m_surface = nullptr; -}; - -Q_DECLARE_METATYPE(QSharedPointer) - -class MockIviSurface -{ -public: - Impl::IviSurface *handle() const { return m_iviSurface; } - const uint iviId; - -private: - MockIviSurface(Impl::IviSurface *iviSurface) : iviId(iviSurface->iviId()), m_iviSurface(iviSurface) {} - friend class Impl::Compositor; - friend class Impl::IviSurface; - - Impl::IviSurface *m_iviSurface; -}; +#ifndef BTN_LEFT +// As defined in linux/input-event-codes.h +#define BTN_LEFT 0x110 +#endif -Q_DECLARE_METATYPE(QSharedPointer) +namespace MockCompositor { -class MockXdgToplevelV6 : public QObject +class DefaultCompositor : public CoreCompositor { - Q_OBJECT -public: - Impl::XdgToplevelV6 *handle() const { return m_toplevel; } - - void sendConfigure(const QSharedPointer toplevel); - -signals: - uint setMinimizedRequested(); - uint setMaximizedRequested(); - uint unsetMaximizedRequested(); - uint setFullscreenRequested(); - uint unsetFullscreenRequested(); - void windowGeometryRequested(QRect geometry); // NOTE: This is really an xdg surface event - -private: - MockXdgToplevelV6(Impl::XdgToplevelV6 *toplevel) : m_toplevel(toplevel) {} - friend class Impl::Compositor; - friend class Impl::XdgToplevelV6; - - Impl::XdgToplevelV6 *m_toplevel; -}; - -Q_DECLARE_METATYPE(QSharedPointer) - -class MockOutput { public: - Impl::Output *handle() const { return m_output; } - MockOutput(Impl::Output *output); -private: - Impl::Output *m_output = nullptr; + explicit DefaultCompositor(); + // Convenience functions + Surface *surface(int i = 0) { return get()->m_surfaces.value(i, nullptr); } + XdgSurface *xdgSurface(int i = 0) { return get()->m_xdgSurfaces.value(i, nullptr); } + XdgToplevel *xdgToplevel(int i = 0) { return get()->toplevel(i); } + XdgPopup *xdgPopup(int i = 0) { return get()->popup(i); } + Pointer *pointer() { auto *seat = get(); Q_ASSERT(seat); return seat->m_pointer; } + uint sendXdgShellPing(); + void xdgPingAndWaitForPong(); + // Things that can be changed run-time without confusing the client (i.e. don't require separate tests) + struct Config { + bool autoEnter = true; + bool autoRelease = true; + bool autoConfigure = false; + } m_config; + void resetConfig() { exec([&] { m_config = Config{}; }); } }; -Q_DECLARE_METATYPE(QSharedPointer) - -class MockCompositor -{ -public: - MockCompositor(); - ~MockCompositor(); - - void applicationInitialized(); - - int waylandFileDescriptor() const; - void processWaylandEvents(); - - void setOutputMode(const QSize &size); - void setKeyboardFocus(const QSharedPointer &surface); - void sendMousePress(const QSharedPointer &surface, const QPoint &pos); - void sendMouseRelease(const QSharedPointer &surface); - void sendKeyPress(const QSharedPointer &surface, uint code); - void sendKeyRelease(const QSharedPointer &surface, uint code); - void sendTouchDown(const QSharedPointer &surface, const QPoint &position, int id); - void sendTouchMotion(const QSharedPointer &surface, const QPoint &position, int id); - void sendTouchUp(const QSharedPointer &surface, int id); - void sendTouchFrame(const QSharedPointer &surface); - void sendDataDeviceDataOffer(const QSharedPointer &surface); - void sendDataDeviceEnter(const QSharedPointer &surface, const QPoint &position); - void sendDataDeviceMotion(const QPoint &position); - void sendDataDeviceDrop(const QSharedPointer &surface); - void sendDataDeviceLeave(const QSharedPointer &surface); - void sendAddOutput(); - void sendRemoveOutput(const QSharedPointer &output); - void sendOutputGeometry(const QSharedPointer &output, const QRect &geometry); - void sendSurfaceEnter(const QSharedPointer &surface, QSharedPointer &output); - void sendSurfaceLeave(const QSharedPointer &surface, QSharedPointer &output); - void sendShellSurfaceConfigure(const QSharedPointer surface, const QSize &size = QSize(0, 0)); - void sendIviSurfaceConfigure(const QSharedPointer iviSurface, const QSize &size); - void sendXdgToplevelV6Configure(const QSharedPointer toplevel, const QSize &size = QSize(0, 0), - const QVector &states = { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED }); - void waitForStartDrag(); - - QSharedPointer surface(); - QSharedPointer output(int index = 0); - QSharedPointer iviSurface(int index = 0); - QSharedPointer xdgToplevelV6(int index = 0); - QSharedPointer fullScreenShellV1Surface(int index = 0); - - void lock(); - void unlock(); - -private: - struct Command - { - typedef void (*Callback)(void *target, const QList ¶meters); - - Callback callback; - void *target = nullptr; - QList parameters; - }; - - static Command makeCommand(Command::Callback callback, void *target); - - void processCommand(const Command &command); - void dispatchCommands(); - - static void *run(void *data); - - bool m_alive = true; - bool m_ready = false; - pthread_t m_thread; - QMutex m_mutex; - QWaitCondition m_waitCondition; - - Impl::Compositor *m_compositor = nullptr; - - QList m_commandQueue; -}; +} // namespace MockCompositor + +#define QCOMPOSITOR_VERIFY(expr) QVERIFY(exec([&]{ return expr; })) +#define QCOMPOSITOR_TRY_VERIFY(expr) QTRY_VERIFY(exec([&]{ return expr; })) +#define QCOMPOSITOR_COMPARE(expr, expr2) QCOMPARE(exec([&]{ return expr; }), expr2) +#define QCOMPOSITOR_TRY_COMPARE(expr, expr2) QTRY_COMPARE(exec([&]{ return expr; }), expr2) + +#define QCOMPOSITOR_TEST_MAIN(test) \ +int main(int argc, char **argv) \ +{ \ + setenv("XDG_RUNTIME_DIR", ".", 1); \ + setenv("QT_QPA_PLATFORM", "wayland", 1); \ + test tc; \ + QGuiApplication app(argc, argv); \ + return QTest::qExec(&tc, argc, argv); \ +} \ #endif diff --git a/tests/auto/client/shared/mockfullscreenshellv1.cpp b/tests/auto/client/shared/mockfullscreenshellv1.cpp deleted file mode 100644 index 22c49cde6..000000000 --- a/tests/auto/client/shared/mockfullscreenshellv1.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2018 Pier Luigi Fiorini -** 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 "mockfullscreenshellv1.h" -#include "mocksurface.h" - -namespace Impl { - -void FullScreenShellV1::zwp_fullscreen_shell_v1_present_surface(Resource *resource, struct ::wl_resource *surface, uint32_t method, struct ::wl_resource *output) -{ - Q_UNUSED(resource) - Q_UNUSED(method) - Q_UNUSED(output) - - m_surfaces.append(Surface::fromResource(surface)); -} - -} // namespace Impl diff --git a/tests/auto/client/shared/mockfullscreenshellv1.h b/tests/auto/client/shared/mockfullscreenshellv1.h deleted file mode 100644 index 819bbc186..000000000 --- a/tests/auto/client/shared/mockfullscreenshellv1.h +++ /dev/null @@ -1,58 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2018 Pier Luigi Fiorini -** 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 MOCKFULLSCREENSHELLV1_H -#define MOCKFULLSCREENSHELLV1_H - -#include - -#include - -namespace Impl { - -class Surface; -class FullScreenShellV1; - -class FullScreenShellV1 : public QtWaylandServer::zwp_fullscreen_shell_v1 -{ -public: - explicit FullScreenShellV1(::wl_display *display) : zwp_fullscreen_shell_v1(display, 1) {} - - QVector surfaces() const { return m_surfaces; } - void removeSurface(Surface *surface) { m_surfaces.removeOne(surface); } - -protected: - void zwp_fullscreen_shell_v1_present_surface(Resource *resource, struct ::wl_resource *surface, uint32_t method, struct ::wl_resource *output) override; - -private: - QVector m_surfaces; -}; - -} // namespace Impl - -#endif // MOCKFULLSCREENSHELLV1_H diff --git a/tests/auto/client/shared/mockinput.cpp b/tests/auto/client/shared/mockinput.cpp deleted file mode 100644 index 8b7592824..000000000 --- a/tests/auto/client/shared/mockinput.cpp +++ /dev/null @@ -1,474 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "mockcompositor.h" -#include "mockinput.h" -#include "mocksurface.h" - -namespace Impl { - -void Compositor::setKeyboardFocus(void *data, const QList ¶meters) -{ - Compositor *compositor = static_cast(data); - compositor->m_keyboard->setFocus(resolveSurface(parameters.first())); -} - -void Compositor::sendMousePress(void *data, const QList ¶meters) -{ - Compositor *compositor = static_cast(data); - Surface *surface = resolveSurface(parameters.first()); - if (!surface) - return; - - QPoint pos = parameters.last().toPoint(); - compositor->m_pointer->setFocus(surface, pos); - compositor->m_pointer->sendMotion(pos); - compositor->m_pointer->sendButton(0x110, 1); -} - -void Compositor::sendMouseRelease(void *data, const QList ¶meters) -{ - Compositor *compositor = static_cast(data); - Surface *surface = resolveSurface(parameters.first()); - if (!surface) - return; - - compositor->m_pointer->sendButton(0x110, 0); -} - -void Compositor::sendKeyPress(void *data, const QList ¶meters) -{ - Compositor *compositor = static_cast(data); - Surface *surface = resolveSurface(parameters.first()); - if (!surface) - return; - - compositor->m_keyboard->sendKey(parameters.last().toUInt() - 8, 1); -} - -void Compositor::sendKeyRelease(void *data, const QList ¶meters) -{ - Compositor *compositor = static_cast(data); - Surface *surface = resolveSurface(parameters.first()); - if (!surface) - return; - - compositor->m_keyboard->sendKey(parameters.last().toUInt() - 8, 0); -} - -void Compositor::sendTouchDown(void *data, const QList ¶meters) -{ - Compositor *compositor = static_cast(data); - Surface *surface = resolveSurface(parameters.first()); - - Q_ASSERT(compositor); - Q_ASSERT(surface); - - QPoint position = parameters.at(1).toPoint(); - int id = parameters.at(2).toInt(); - - compositor->m_touch->sendDown(surface, position, id); -} - -void Compositor::sendTouchUp(void *data, const QList ¶meters) -{ - Compositor *compositor = static_cast(data); - Surface *surface = resolveSurface(parameters.first()); - - Q_ASSERT(compositor); - Q_ASSERT(surface); - - int id = parameters.at(1).toInt(); - - compositor->m_touch->sendUp(surface, id); -} - -void Compositor::sendTouchMotion(void *data, const QList ¶meters) -{ - Compositor *compositor = static_cast(data); - Surface *surface = resolveSurface(parameters.first()); - - Q_ASSERT(compositor); - Q_ASSERT(surface); - - QPoint position = parameters.at(1).toPoint(); - int id = parameters.at(2).toInt(); - - compositor->m_touch->sendMotion(surface, position, id); -} - -void Compositor::sendTouchFrame(void *data, const QList ¶meters) -{ - Compositor *compositor = static_cast(data); - Surface *surface = resolveSurface(parameters.first()); - - Q_ASSERT(compositor); - Q_ASSERT(surface); - - compositor->m_touch->sendFrame(surface); -} - -void Compositor::sendDataDeviceDataOffer(void *data, const QList ¶meters) -{ - Compositor *compositor = static_cast(data); - Surface *surface = resolveSurface(parameters.first()); - - Q_ASSERT(compositor); - Q_ASSERT(surface); - - compositor->m_data_device_manager->dataDevice()->sendDataOffer(surface->resource()->client()); -} - -void Compositor::sendDataDeviceEnter(void *data, const QList ¶meters) -{ - Compositor *compositor = static_cast(data); - Surface *surface = resolveSurface(parameters.first()); - QPoint position = parameters.at(1).toPoint(); - - Q_ASSERT(compositor); - Q_ASSERT(surface); - - compositor->m_data_device_manager->dataDevice()->sendEnter(surface, position); -} - -void Compositor::sendDataDeviceMotion(void *data, const QList ¶meters) -{ - Compositor *compositor = static_cast(data); - Q_ASSERT(compositor); - QPoint position = parameters.first().toPoint(); - compositor->m_data_device_manager->dataDevice()->sendMotion(position); -} - -void Compositor::sendDataDeviceDrop(void *data, const QList ¶meters) -{ - Compositor *compositor = static_cast(data); - Surface *surface = resolveSurface(parameters.first()); - - Q_ASSERT(compositor); - Q_ASSERT(surface); - - compositor->m_data_device_manager->dataDevice()->sendDrop(surface); -} - -void Compositor::sendDataDeviceLeave(void *data, const QList ¶meters) -{ - Compositor *compositor = static_cast(data); - Surface *surface = resolveSurface(parameters.first()); - - Q_ASSERT(compositor); - Q_ASSERT(surface); - - compositor->m_data_device_manager->dataDevice()->sendLeave(surface); -} - -void Compositor::waitForStartDrag(void *data, const QList ¶meters) -{ - Q_UNUSED(parameters); - Compositor *compositor = static_cast(data); - Q_ASSERT(compositor); - while (!compositor->m_startDragSeen) { - wl_display_flush_clients(compositor->m_display); - wl_event_loop_dispatch(compositor->m_loop, 100); - } - compositor->m_startDragSeen = false; -} - -Seat::Seat(Compositor *compositor, struct ::wl_display *display) - : wl_seat(display, 2) - , m_compositor(compositor) - , m_keyboard(new Keyboard(compositor)) - , m_pointer(new Pointer(compositor)) - , m_touch(new Touch(compositor)) -{ -} - -Seat::~Seat() -{ -} - -void Seat::seat_bind_resource(Resource *resource) -{ - send_capabilities(resource->handle, capability_keyboard | capability_pointer | capability_touch); -} - -void Seat::seat_get_keyboard(Resource *resource, uint32_t id) -{ - m_keyboard->add(resource->client(), id, resource->version()); -} - -void Seat::seat_get_pointer(Resource *resource, uint32_t id) -{ - m_pointer->add(resource->client(), id, resource->version()); -} - -void Seat::seat_get_touch(Resource *resource, uint32_t id) -{ - m_touch->add(resource->client(), id, resource->version()); -} - -Keyboard::Keyboard(Compositor *compositor) - : m_compositor(compositor) -{ -} - -Keyboard::~Keyboard() -{ -} - -void Keyboard::setFocus(Surface *surface) -{ - if (m_focusResource && m_focus != surface) { - uint32_t serial = m_compositor->nextSerial(); - send_leave(m_focusResource->handle, serial, m_focus->resource()->handle); - } - - Resource *resource = surface ? resourceMap().value(surface->resource()->client()) : 0; - - if (resource && (m_focus != surface || m_focusResource != resource)) { - uint32_t serial = m_compositor->nextSerial(); - send_modifiers(resource->handle, serial, 0, 0, 0, 0); - send_enter(resource->handle, serial, surface->resource()->handle, QByteArray()); - } - - m_focusResource = resource; - m_focus = surface; -} - -void Keyboard::handleSurfaceDestroyed(Surface *surface) -{ - if (surface == m_focus) { - m_focusResource = nullptr; - m_focus = nullptr; - } -} - -void Keyboard::sendKey(uint32_t key, uint32_t state) -{ - if (m_focusResource) { - uint32_t serial = m_compositor->nextSerial(); - send_key(m_focusResource->handle, serial, m_compositor->time(), key, state); - } -} - - -void Keyboard::keyboard_destroy_resource(wl_keyboard::Resource *resource) -{ - if (m_focusResource == resource) - m_focusResource = 0; -} - -Pointer::Pointer(Compositor *compositor) - : m_compositor(compositor) -{ -} - -Pointer::~Pointer() -{ - -} - -void Pointer::setFocus(Surface *surface, const QPoint &pos) -{ - if (m_focusResource && m_focus != surface) { - uint32_t serial = m_compositor->nextSerial(); - send_leave(m_focusResource->handle, serial, m_focus->resource()->handle); - } - - Resource *resource = surface ? resourceMap().value(surface->resource()->client()) : 0; - - if (resource && (m_focus != surface || resource != m_focusResource)) { - uint32_t serial = m_compositor->nextSerial(); - send_enter(resource->handle, serial, surface->resource()->handle, - wl_fixed_from_int(pos.x()), wl_fixed_from_int(pos.y())); - } - - m_focusResource = resource; - m_focus = surface; -} - -void Pointer::handleSurfaceDestroyed(Surface *surface) -{ - if (m_focus == surface) { - m_focus = nullptr; - m_focusResource = nullptr; - } -} - -void Pointer::sendMotion(const QPoint &pos) -{ - if (m_focusResource) - send_motion(m_focusResource->handle, m_compositor->time(), - wl_fixed_from_int(pos.x()), wl_fixed_from_int(pos.y())); -} - -void Pointer::sendButton(uint32_t button, uint32_t state) -{ - if (m_focusResource) { - uint32_t serial = m_compositor->nextSerial(); - send_button(m_focusResource->handle, serial, m_compositor->time(), - button, state); - } -} - -void Pointer::pointer_destroy_resource(wl_pointer::Resource *resource) -{ - if (m_focusResource == resource) - m_focusResource = 0; -} - -Touch::Touch(Compositor *compositor) - : wl_touch() - , m_compositor(compositor) -{ -} - -void Touch::sendDown(Surface *surface, const QPoint &position, int id) -{ - uint32_t serial = m_compositor->nextSerial(); - uint32_t time = m_compositor->time(); - Q_ASSERT(surface); - Resource *resource = resourceMap().value(surface->resource()->client()); - Q_ASSERT(resource); - auto x = wl_fixed_from_int(position.x()); - auto y = wl_fixed_from_int(position.y()); - wl_touch_send_down(resource->handle, serial, time, surface->resource()->handle, id, x, y); -} - -void Touch::sendUp(Surface *surface, int id) -{ - Resource *resource = resourceMap().value(surface->resource()->client()); - wl_touch_send_up(resource->handle, m_compositor->nextSerial(), m_compositor->time(), id); -} - -void Touch::sendMotion(Surface *surface, const QPoint &position, int id) -{ - Resource *resource = resourceMap().value(surface->resource()->client()); - uint32_t time = m_compositor->time(); - auto x = wl_fixed_from_int(position.x()); - auto y = wl_fixed_from_int(position.y()); - wl_touch_send_motion(resource->handle, time, id, x, y); -} - -void Touch::sendFrame(Surface *surface) -{ - Resource *resource = resourceMap().value(surface->resource()->client()); - wl_touch_send_frame(resource->handle); -} - -DataOffer::DataOffer() - : wl_data_offer() -{ - -} - -DataDevice::DataDevice(Compositor *compositor) - : m_compositor(compositor) -{ - -} - -void DataDevice::sendDataOffer(wl_client *client) -{ - m_dataOffer = new QtWaylandServer::wl_data_offer(client, 0, 1); - Resource *resource = resourceMap().value(client); - send_data_offer(resource->handle, m_dataOffer->resource()->handle); -} - -void DataDevice::sendEnter(Surface *surface, const QPoint& position) -{ - uint serial = m_compositor->nextSerial(); - m_focus = surface; - Resource *resource = resourceMap().value(surface->resource()->client()); - send_enter(resource->handle, serial, surface->resource()->handle, position.x(), position.y(), m_dataOffer->resource()->handle); -} - -void DataDevice::sendMotion(const QPoint &position) -{ - uint32_t time = m_compositor->time(); - Resource *resource = resourceMap().value(m_focus->resource()->client()); - send_motion(resource->handle, time, position.x(), position.y()); -} - -void DataDevice::sendDrop(Surface *surface) -{ - Resource *resource = resourceMap().value(surface->resource()->client()); - send_drop(resource->handle); -} - -void DataDevice::sendLeave(Surface *surface) -{ - Resource *resource = resourceMap().value(surface->resource()->client()); - send_leave(resource->handle); -} - -DataDevice::~DataDevice() -{ - -} - -void DataDevice::data_device_start_drag(QtWaylandServer::wl_data_device::Resource *resource, wl_resource *source, wl_resource *origin, wl_resource *icon, uint32_t serial) -{ - Q_UNUSED(resource); - Q_UNUSED(source); - Q_UNUSED(origin); - Q_UNUSED(icon); - Q_UNUSED(serial); - m_compositor->m_startDragSeen = true; -} - -DataDeviceManager::DataDeviceManager(Compositor *compositor, wl_display *display) - : wl_data_device_manager(display, 1) - , m_compositor(compositor) -{ - -} - -DataDeviceManager::~DataDeviceManager() -{ - -} - -DataDevice *DataDeviceManager::dataDevice() const -{ - return m_data_device.data(); -} - -void DataDeviceManager::data_device_manager_get_data_device(Resource *resource, uint32_t id, struct ::wl_resource *seat) -{ - Q_UNUSED(seat); - if (!m_data_device) - m_data_device.reset(new DataDevice(m_compositor)); - m_data_device->add(resource->client(), id, 1); -} - -void DataDeviceManager::data_device_manager_create_data_source(QtWaylandServer::wl_data_device_manager::Resource *resource, uint32_t id) -{ - new QtWaylandServer::wl_data_source(resource->client(), id, 1); -} - -} diff --git a/tests/auto/client/shared/mockinput.h b/tests/auto/client/shared/mockinput.h deleted file mode 100644 index d9adb3621..000000000 --- a/tests/auto/client/shared/mockinput.h +++ /dev/null @@ -1,172 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Klarälvdalens Datakonsult AB (KDAB). -** 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 MOCKINPUT_H -#define MOCKINPUT_H - -#include - -#include "qwayland-server-wayland.h" - -#include "mockcompositor.h" - -namespace Impl { - -class Keyboard; -class Pointer; - -class Seat : public QtWaylandServer::wl_seat -{ -public: - Seat(Compositor *compositor, struct ::wl_display *display); - ~Seat(); - - Compositor *compositor() const { return m_compositor; } - - Keyboard *keyboard() const { return m_keyboard.data(); } - Pointer *pointer() const { return m_pointer.data(); } - Touch *touch() const { return m_touch.data(); } - -protected: - void seat_bind_resource(Resource *resource) override; - void seat_get_keyboard(Resource *resource, uint32_t id) override; - void seat_get_pointer(Resource *resource, uint32_t id) override; - void seat_get_touch(Resource *resource, uint32_t id) override; - -private: - Compositor *m_compositor = nullptr; - - QScopedPointer m_keyboard; - QScopedPointer m_pointer; - QScopedPointer m_touch; -}; - -class Keyboard : public QtWaylandServer::wl_keyboard -{ -public: - Keyboard(Compositor *compositor); - ~Keyboard(); - - Surface *focus() const { return m_focus; } - void setFocus(Surface *surface); - void handleSurfaceDestroyed(Surface *surface); - - void sendKey(uint32_t key, uint32_t state); - -protected: - void keyboard_destroy_resource(wl_keyboard::Resource *resource) override; - -private: - Compositor *m_compositor = nullptr; - - Resource *m_focusResource = nullptr; - Surface *m_focus = nullptr; -}; - -class Pointer : public QtWaylandServer::wl_pointer -{ -public: - Pointer(Compositor *compositor); - ~Pointer(); - - Surface *focus() const { return m_focus; } - - void setFocus(Surface *surface, const QPoint &pos); - void handleSurfaceDestroyed(Surface *surface); - void sendMotion(const QPoint &pos); - void sendButton(uint32_t button, uint32_t state); - -protected: - void pointer_destroy_resource(wl_pointer::Resource *resource) override; - -private: - Compositor *m_compositor = nullptr; - - Resource *m_focusResource = nullptr; - Surface *m_focus = nullptr; -}; - -class Touch : public QtWaylandServer::wl_touch -{ -public: - Touch(Compositor *compositor); - void sendDown(Surface *surface, const QPoint &position, int id); - void sendUp(Surface *surface, int id); - void sendMotion(Surface *surface, const QPoint &position, int id); - void sendFrame(Surface *surface); -private: - Compositor *m_compositor = nullptr; -}; - -class DataOffer : public QtWaylandServer::wl_data_offer -{ -public: - DataOffer(); -}; - -class DataDevice : public QtWaylandServer::wl_data_device -{ -public: - DataDevice(Compositor *compositor); - void sendDataOffer(wl_client *client); - void sendEnter(Surface *surface, const QPoint &position); - void sendMotion(const QPoint &position); - void sendDrop(Surface *surface); - void sendLeave(Surface *surface); - ~DataDevice(); - -protected: - void data_device_start_drag(Resource *resource, struct ::wl_resource *source, struct ::wl_resource *origin, struct ::wl_resource *icon, uint32_t serial) override; - -private: - Compositor *m_compositor = nullptr; - QtWaylandServer::wl_data_offer *m_dataOffer = nullptr; - Surface* m_focus = nullptr; -}; - -class DataDeviceManager : public QtWaylandServer::wl_data_device_manager -{ -public: - DataDeviceManager(Compositor *compositor, struct ::wl_display *display); - ~DataDeviceManager(); - DataDevice *dataDevice() const; - -protected: - void data_device_manager_get_data_device(Resource *resource, uint32_t id, struct ::wl_resource *seat) override; - void data_device_manager_create_data_source(Resource *resource, uint32_t id) override; - -private: - Compositor *m_compositor = nullptr; - - QScopedPointer m_data_device; -}; - -} - -#endif // MOCKINPUT_H diff --git a/tests/auto/client/shared/mockiviapplication.cpp b/tests/auto/client/shared/mockiviapplication.cpp deleted file mode 100644 index 29a308993..000000000 --- a/tests/auto/client/shared/mockiviapplication.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "mockiviapplication.h" -#include "mocksurface.h" -#include "mockcompositor.h" - -namespace Impl { - -void Compositor::sendIviSurfaceConfigure(void *data, const QList ¶meters) -{ - Q_UNUSED(data); - IviSurface *iviSurface = resolveIviSurface(parameters.at(0)); - Q_ASSERT(iviSurface && iviSurface->resource()); - QSize size = parameters.at(1).toSize(); - Q_ASSERT(!size.isEmpty()); - iviSurface->send_configure(size.width(), size.height()); -} - -IviSurface::IviSurface(IviApplication *iviApplication, Surface *surface, uint iviId, wl_client *client, uint32_t id) - : QtWaylandServer::ivi_surface(client, id, 1) - , m_surface(surface) - , m_iviApplication(iviApplication) - , m_iviId(iviId) - , m_mockIviSurface(new MockIviSurface(this)) -{ - iviApplication->addIviSurface(this); - surface->map(); -} - -IviSurface::~IviSurface() -{ - m_iviApplication->removeIviSurface(this); - m_mockIviSurface->m_iviSurface = nullptr; -} - -void IviSurface::ivi_surface_destroy(Resource *resource) -{ - wl_resource_destroy(resource->handle); -} - -void IviApplication::ivi_application_surface_create(Resource *resource, uint32_t ivi_id, ::wl_resource *surface, uint32_t id) -{ - new IviSurface(this, Surface::fromResource(surface), ivi_id, resource->client(), id); -} - -} // namespace Impl diff --git a/tests/auto/client/shared/mockiviapplication.h b/tests/auto/client/shared/mockiviapplication.h deleted file mode 100644 index 4d65eeaba..000000000 --- a/tests/auto/client/shared/mockiviapplication.h +++ /dev/null @@ -1,85 +0,0 @@ -/**************************************************************************** -** -** 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 MOCKIVIAPPLICATION_H -#define MOCKIVIAPPLICATION_H - -#include - -#include -#include - -class MockIviSurface; - -namespace Impl { - -class Surface; -class IviApplication; - -class IviSurface : public QtWaylandServer::ivi_surface -{ -public: - IviSurface(IviApplication *iviApplication, Surface *surface, uint iviId, wl_client *client, uint32_t id); - ~IviSurface() override; - IviApplication *iviApplication() const { return m_iviApplication; } - Surface *surface() const { return m_surface; } - uint iviId() const { return m_iviId; } - - QSharedPointer mockIviSurface() const { return m_mockIviSurface; } - -protected: - void ivi_surface_destroy_resource(Resource *) override { delete this; } - void ivi_surface_destroy(Resource *resource) override; - -private: - Surface *m_surface = nullptr; - IviApplication *m_iviApplication = nullptr; - const uint m_iviId = 0; - QSharedPointer m_mockIviSurface; -}; - -class IviApplication : public QtWaylandServer::ivi_application -{ -public: - explicit IviApplication(::wl_display *display) : ivi_application(display, 1) {} - QVector iviSurfaces() const { return m_iviSurfaces; } - -protected: - void ivi_application_surface_create(Resource *resource, uint32_t ivi_id, ::wl_resource *surface, uint32_t id) override; - -private: - void addIviSurface(IviSurface *iviSurface) { m_iviSurfaces.append(iviSurface); } - void removeIviSurface(IviSurface *iviSurface) { m_iviSurfaces.removeOne(iviSurface); } - QVector m_iviSurfaces; - - friend class IviSurface; -}; - -} // namespace Impl - -#endif // MOCKIVIAPPLICATION_H diff --git a/tests/auto/client/shared/mockoutput.cpp b/tests/auto/client/shared/mockoutput.cpp deleted file mode 100644 index 13e0524ad..000000000 --- a/tests/auto/client/shared/mockoutput.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "mockcompositor.h" -#include "mockoutput.h" - -#include - -namespace Impl { - -void Compositor::sendAddOutput(void *data, const QList ¶meters) { - Q_UNUSED(parameters); - Compositor *compositor = static_cast(data); - auto output = new Output(compositor->m_display, QSize(1920, 1200), QPoint(0, 0)); - compositor->m_outputs.append(output); - - // Wait for the client to bind to the output - while (output->resourceMap().isEmpty()) - compositor->dispatchEvents(); -} - -void Compositor::sendRemoveOutput(void *data, const QList ¶meters) { - Compositor *compositor = static_cast(data); - Q_ASSERT(compositor); - Output *output = resolveOutput(parameters.first()); - Q_ASSERT(output); - bool wasRemoved = compositor->m_outputs.removeOne(output); - Q_ASSERT(wasRemoved); - delete output; -} - -void Compositor::sendOutputGeometry(void *data, const QList ¶meters) -{ - Compositor *compositor = static_cast(data); - Q_ASSERT(compositor); - Output *output = resolveOutput(parameters.first()); - Q_ASSERT(output); - QRect geometry = parameters.at(1).toRect(); - output->sendGeometryAndMode(geometry); -} - -void Compositor::setOutputMode(void *data, const QList ¶meters) -{ - Compositor *compositor = static_cast(data); - QSize size = parameters.first().toSize(); - Output *output = compositor->m_outputs.first(); - Q_ASSERT(output); - output->setCurrentMode(size); -} - -Output::Output(wl_display *display, const QSize &resolution, const QPoint &position) - : wl_output(display, 2) - , m_size(resolution) - , m_position(position) - , m_physicalSize(520, 320) - , m_mockOutput(new MockOutput(this)) -{ -} - -void Output::setCurrentMode(const QSize &size) -{ - m_size = size; - for (Resource *resource : resourceMap()) { - sendCurrentMode(resource); - send_done(resource->handle); - } -} - -void Output::sendGeometryAndMode(const QRect &geometry) -{ - m_size = geometry.size(); - m_position = geometry.topLeft(); - for (Resource *resource : resourceMap()) { - sendGeometry(resource); - sendCurrentMode(resource); - send_done(resource->handle); - } -} - -void Output::output_bind_resource(QtWaylandServer::wl_output::Resource *resource) -{ - sendGeometry(resource); - sendCurrentMode(resource); - send_done(resource->handle); -} - -void Output::sendGeometry(Resource *resource) -{ - const int subPixel = 0; - const int transform = 0; - - send_geometry(resource->handle, - m_position.x(), m_position.y(), - m_physicalSize.width(), m_physicalSize.height(), - subPixel, "", "", transform ); -} - -void Output::sendCurrentMode(Resource *resource) -{ - send_mode(resource->handle, - WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED, - m_size.width(), m_size.height(), 60000); -} - -} // Impl - -MockOutput::MockOutput(Impl::Output *output) - : m_output(output) -{ -} diff --git a/tests/auto/client/shared/mockoutput.h b/tests/auto/client/shared/mockoutput.h deleted file mode 100644 index 9f261d5d7..000000000 --- a/tests/auto/client/shared/mockoutput.h +++ /dev/null @@ -1,63 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef MOCKOUTPUT_H -#define MOCKOUTPUT_H - -#include - -#include "qwayland-server-wayland.h" - -#include "mockcompositor.h" - -namespace Impl { - -class Output : public QtWaylandServer::wl_output -{ -public: - Output(::wl_display *display, const QSize &resolution, const QPoint &position); - - QSharedPointer mockOutput() const { return m_mockOutput; } - void setCurrentMode(const QSize &size); - void sendGeometryAndMode(const QRect &geometry); - -protected: - void output_bind_resource(Resource *resource) override; - -private: - void sendGeometry(Resource *resource); - void sendCurrentMode(Resource *resource); - QSize m_size; - QPoint m_position; - const QSize m_physicalSize; - QSharedPointer m_mockOutput; -}; - -} - -#endif // MOCKOUTPUT_H diff --git a/tests/auto/client/shared/mocksurface.cpp b/tests/auto/client/shared/mocksurface.cpp deleted file mode 100644 index 84dcda6b0..000000000 --- a/tests/auto/client/shared/mocksurface.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/**************************************************************************** -** -** 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 "mocksurface.h" -#include "mockoutput.h" -#include "mockcompositor.h" -#include "mockwlshell.h" - -#include - -namespace Impl { - -void Compositor::sendSurfaceEnter(void *data, const QList ¶meters) -{ - Q_UNUSED(data); - Surface *surface = resolveSurface(parameters.at(0)); - Output *output = resolveOutput(parameters.at(1)); - Q_ASSERT(surface && surface->resource()); - Q_ASSERT(output); - auto outputResources = output->resourceMap().values(surface->resource()->client()); - Q_ASSERT(!outputResources.isEmpty()); - - for (auto outputResource : outputResources) - surface->send_enter(outputResource->handle); -} - -void Compositor::sendSurfaceLeave(void *data, const QList ¶meters) -{ - Q_UNUSED(data); - Surface *surface = resolveSurface(parameters.at(0)); - Output *output = resolveOutput(parameters.at(1)); - Q_ASSERT(surface && surface->resource()); - Q_ASSERT(output); - auto outputResources = output->resourceMap().values(surface->resource()->client()); - Q_ASSERT(!outputResources.isEmpty()); - - for (auto outputResource : outputResources) - surface->send_leave(outputResource->handle); -} - -void Compositor::sendShellSurfaceConfigure(void *data, const QList ¶meters) -{ - Compositor *compositor = static_cast(data); - Surface *surface = resolveSurface(parameters.at(0)); - QSize size = parameters.at(1).toSize(); - Q_ASSERT(size.isValid()); - if (auto toplevel = surface->xdgToplevelV6()) { - QVector states = { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED }; - auto statesBytes = QByteArray::fromRawData(reinterpret_cast(states.data()), - states.size() * static_cast(sizeof(uint))); - toplevel->send_configure(size.width(), size.height(), statesBytes); - toplevel->xdgSurface()->sendConfigure(compositor->nextSerial()); - } else if (auto wlShellSurface = surface->wlShellSurface()) { - const uint edges = 0; - wlShellSurface->send_configure(edges, size.width(), size.height()); - } else { - qWarning() << "The mocking framework doesn't know how to send a configure event for this surface"; - } -} - -Surface::Surface(wl_client *client, uint32_t id, int v, Compositor *compositor) - : QtWaylandServer::wl_surface(client, id, v) - , m_compositor(compositor) - , m_mockSurface(new MockSurface(this)) -{ -} - -Surface::~Surface() -{ - m_mockSurface->m_surface = 0; -} - -void Surface::map() -{ - m_mapped = true; -} - -bool Surface::isMapped() const -{ - return m_mapped; -} - -Surface *Surface::fromResource(struct ::wl_resource *resource) -{ - if (auto *r = Resource::fromResource(resource)) - return static_cast(r->surface_object); - return nullptr; -} - -void Surface::surface_destroy_resource(Resource *) -{ - compositor()->removeSurface(this); - delete this; -} - -void Surface::surface_destroy(Resource *resource) -{ - if (m_wlShellSurface) // on wl-shell the shell surface is automatically destroyed with the surface - wl_resource_destroy(m_wlShellSurface->resource()->handle); - Q_ASSERT(!m_wlShellSurface); - Q_ASSERT(!m_xdgSurfaceV6); - wl_resource_destroy(resource->handle); -} - -void Surface::surface_attach(Resource *resource, struct wl_resource *buffer, int x, int y) -{ - if (m_xdgSurfaceV6) { - // It's a protocol error to attach a buffer to an xdgSurface that's not configured - Q_ASSERT(xdgSurfaceV6()->configureSent()); - } - - Q_UNUSED(resource); - Q_UNUSED(x); - Q_UNUSED(y); - m_buffer = buffer; - - if (!buffer) - m_mockSurface->image = QImage(); -} - -void Surface::surface_damage(Resource *resource, - int32_t x, int32_t y, int32_t width, int32_t height) -{ - Q_UNUSED(resource); - Q_UNUSED(x); - Q_UNUSED(y); - Q_UNUSED(width); - Q_UNUSED(height); -} - -void Surface::surface_frame(Resource *resource, - uint32_t callback) -{ - wl_resource *frameCallback = wl_resource_create(resource->client(), &wl_callback_interface, 1, callback); - m_frameCallbackList << frameCallback; -} - -void Surface::surface_commit(Resource *resource) -{ - Q_UNUSED(resource); - - if (m_buffer) { - struct ::wl_shm_buffer *shm_buffer = wl_shm_buffer_get(m_buffer); - if (shm_buffer) { - int stride = wl_shm_buffer_get_stride(shm_buffer); - uint format = wl_shm_buffer_get_format(shm_buffer); - Q_UNUSED(format); - void *data = wl_shm_buffer_get_data(shm_buffer); - const uchar *char_data = static_cast(data); - QImage img(char_data, wl_shm_buffer_get_width(shm_buffer), wl_shm_buffer_get_height(shm_buffer), stride, QImage::Format_ARGB32_Premultiplied); - m_mockSurface->image = img; - } - } - - foreach (wl_resource *frameCallback, m_frameCallbackList) { - wl_callback_send_done(frameCallback, m_compositor->time()); - wl_resource_destroy(frameCallback); - } - m_frameCallbackList.clear(); -} - -} -MockSurface::MockSurface(Impl::Surface *surface) - : m_surface(surface) -{ -} diff --git a/tests/auto/client/shared/mocksurface.h b/tests/auto/client/shared/mocksurface.h deleted file mode 100644 index 949dc23dd..000000000 --- a/tests/auto/client/shared/mocksurface.h +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef MOCKSURFACE_H -#define MOCKSURFACE_H - -#include - -#include "qwayland-server-wayland.h" - -#include "mockcompositor.h" - -namespace Impl { - -class XdgToplevelV6; -class WlShellSurface; - -class Surface : public QtWaylandServer::wl_surface -{ -public: - Surface(wl_client *client, uint32_t id, int v, Compositor *compositor); - ~Surface(); - - Compositor *compositor() const { return m_compositor; } - static Surface *fromResource(struct ::wl_resource *resource); - void map(); - bool isMapped() const; - XdgSurfaceV6 *xdgSurfaceV6() const { return m_xdgSurfaceV6; } - XdgToplevelV6 *xdgToplevelV6() const { return m_xdgSurfaceV6 ? m_xdgSurfaceV6->toplevel() : nullptr; } - WlShellSurface *wlShellSurface() const { return m_wlShellSurface; } - - QSharedPointer mockSurface() const { return m_mockSurface; } - -protected: - - void surface_destroy_resource(Resource *resource) override; - - void surface_destroy(Resource *resource) override; - void surface_attach(Resource *resource, - struct wl_resource *buffer, int x, int y) override; - void surface_damage(Resource *resource, - int32_t x, int32_t y, int32_t width, int32_t height) override; - void surface_frame(Resource *resource, - uint32_t callback) override; - void surface_commit(Resource *resource) override; -private: - wl_resource *m_buffer = nullptr; - XdgSurfaceV6 *m_xdgSurfaceV6 = nullptr; - WlShellSurface *m_wlShellSurface = nullptr; - - Compositor *m_compositor = nullptr; - QSharedPointer m_mockSurface; - QList m_frameCallbackList; - bool m_mapped = false; - - friend class XdgSurfaceV6; - friend class WlShellSurface; -}; - -} - -#endif // MOCKSURFACE_H diff --git a/tests/auto/client/shared/mockwlshell.cpp b/tests/auto/client/shared/mockwlshell.cpp deleted file mode 100644 index 50e539932..000000000 --- a/tests/auto/client/shared/mockwlshell.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/**************************************************************************** -** -** 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 "mockwlshell.h" -#include "mocksurface.h" - -namespace Impl { - -WlShellSurface::WlShellSurface(wl_client *client, int id, Surface *surface) - : QtWaylandServer::wl_shell_surface(client, id, 1) - , m_surface(surface) -{ - surface->m_wlShellSurface = this; - surface->map(); -} - -WlShellSurface::~WlShellSurface() -{ - m_surface->m_wlShellSurface = nullptr; -} - -void WlShell::shell_get_shell_surface(QtWaylandServer::wl_shell::Resource *resource, uint32_t id, wl_resource *surface) -{ - new WlShellSurface(resource->client(), id, Surface::fromResource(surface)); -} - -} // namespace Impl diff --git a/tests/auto/client/shared/mockwlshell.h b/tests/auto/client/shared/mockwlshell.h deleted file mode 100644 index 3da586ca8..000000000 --- a/tests/auto/client/shared/mockwlshell.h +++ /dev/null @@ -1,58 +0,0 @@ -/**************************************************************************** -** -** 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 - -#ifndef MOCKWLSHELL_H -#define MOCKWLSHELL_H - -namespace Impl { - -class Surface; - -class WlShellSurface : public QtWaylandServer::wl_shell_surface -{ -public: - explicit WlShellSurface(::wl_client *client, int id, Surface *surface); - ~WlShellSurface() override; - void shell_surface_destroy_resource(Resource *) override { delete this; } - -private: - Surface *m_surface = nullptr; -}; - -class WlShell : public QtWaylandServer::wl_shell -{ -public: - explicit WlShell(::wl_display *display) : wl_shell(display, 1) {} - void shell_get_shell_surface(Resource *resource, uint32_t id, ::wl_resource *surface) override; -}; - -} // namespace Impl - -#endif // MOCKWLSHELL_H diff --git a/tests/auto/client/shared/mockxdgshellv6.cpp b/tests/auto/client/shared/mockxdgshellv6.cpp deleted file mode 100644 index 05eff74ad..000000000 --- a/tests/auto/client/shared/mockxdgshellv6.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "mockxdgshellv6.h" -#include "mocksurface.h" -#include "mockcompositor.h" - -namespace Impl { - -void Compositor::sendXdgToplevelV6Configure(void *data, const QList ¶meters) -{ - Compositor *compositor = static_cast(data); - XdgToplevelV6 *toplevel = resolveToplevel(parameters.at(0)); - Q_ASSERT(toplevel && toplevel->resource()); - QSize size = parameters.at(1).toSize(); - Q_ASSERT(size.isValid()); - auto statesBytes = parameters.at(2).toByteArray(); - toplevel->send_configure(size.width(), size.height(), statesBytes); - toplevel->xdgSurface()->send_configure(compositor->nextSerial()); -} - -XdgSurfaceV6::XdgSurfaceV6(XdgShellV6 *shell, Surface *surface, wl_client *client, uint32_t id) - : QtWaylandServer::zxdg_surface_v6(client, id, 1) - , m_surface(surface) - , m_shell(shell) -{ - m_surface->m_xdgSurfaceV6 = this; -} - -XdgSurfaceV6::~XdgSurfaceV6() -{ - m_surface->m_xdgSurfaceV6 = nullptr; -} - -void XdgSurfaceV6::sendConfigure(uint32_t serial) -{ - send_configure(serial); - m_configureSent = true; -} - -void XdgSurfaceV6::zxdg_surface_v6_get_toplevel(QtWaylandServer::zxdg_surface_v6::Resource *resource, uint32_t id) -{ - int version = wl_resource_get_version(resource->handle); - m_toplevel = new XdgToplevelV6(this, resource->client(), id, version); -} - -void XdgSurfaceV6::zxdg_surface_v6_set_window_geometry(QtWaylandServer::zxdg_surface_v6::Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) -{ - Q_UNUSED(resource); - if (m_toplevel) { - QRect geometry(x, y, width, height); - emit m_toplevel->mockToplevel()->windowGeometryRequested(geometry); - } -} - -void XdgSurfaceV6::zxdg_surface_v6_destroy(QtWaylandServer::zxdg_surface_v6::Resource *resource) -{ - Q_ASSERT(!m_toplevel); - wl_resource_destroy(resource->handle); -} - -XdgToplevelV6::XdgToplevelV6(XdgSurfaceV6 *xdgSurface, wl_client *client, uint32_t id, int version) - : QtWaylandServer::zxdg_toplevel_v6(client, id, version) - , m_xdgSurface(xdgSurface) - , m_mockToplevel(new MockXdgToplevelV6(this)) -{ - auto *surface = m_xdgSurface->surface(); - m_xdgSurface->shell()->addToplevel(this); - surface->map(); -} - -XdgToplevelV6::~XdgToplevelV6() -{ - m_xdgSurface->shell()->removeToplevel(this); - m_mockToplevel->m_toplevel = nullptr; -} - -void XdgToplevelV6::zxdg_toplevel_v6_destroy(QtWaylandServer::zxdg_toplevel_v6::Resource *resource) -{ - m_xdgSurface->m_toplevel = nullptr; - wl_resource_destroy(resource->handle); -} - -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); -} - -} // namespace Impl diff --git a/tests/auto/client/shared/mockxdgshellv6.h b/tests/auto/client/shared/mockxdgshellv6.h deleted file mode 100644 index a238fa562..000000000 --- a/tests/auto/client/shared/mockxdgshellv6.h +++ /dev/null @@ -1,114 +0,0 @@ -/**************************************************************************** -** -** 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 - -#include -#include - -#ifndef MOCKXDGSHELLV6_H -#define MOCKXDGSHELLV6_H - -class MockXdgToplevelV6; - -namespace Impl { - -class XdgToplevelV6; -class XdgShellV6; -class Surface; - -class XdgSurfaceV6 : public QtWaylandServer::zxdg_surface_v6 -{ -public: - XdgSurfaceV6(XdgShellV6 *shell, Surface *surface, wl_client *client, uint32_t id); - ~XdgSurfaceV6() override; - XdgShellV6 *shell() const { return m_shell; } - Surface *surface() const { return m_surface; } - XdgToplevelV6 *toplevel() const { return m_toplevel; } - - void sendConfigure(uint32_t serial); - bool configureSent() const { return m_configureSent; } - -protected: - void zxdg_surface_v6_destroy_resource(Resource *) override { delete this; } - void zxdg_surface_v6_get_toplevel(Resource *resource, uint32_t id) override; - void zxdg_surface_v6_set_window_geometry(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) override; - void zxdg_surface_v6_destroy(Resource *resource) override; - -private: - Surface *m_surface = nullptr; - XdgToplevelV6 *m_toplevel = nullptr; - XdgShellV6 *m_shell = nullptr; - bool m_configureSent = false; - - friend class XdgToplevelV6; -}; - -class XdgToplevelV6 : public QtWaylandServer::zxdg_toplevel_v6 -{ -public: - XdgToplevelV6(XdgSurfaceV6 *xdgSurface, wl_client *client, uint32_t id, int version); - ~XdgToplevelV6() override; - XdgSurfaceV6 *xdgSurface() const { return m_xdgSurface; } - - QSharedPointer mockToplevel() const { return m_mockToplevel; } - -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; - QSharedPointer m_mockToplevel; -}; - -class XdgShellV6 : public QtWaylandServer::zxdg_shell_v6 -{ -public: - explicit XdgShellV6(::wl_display *display) : zxdg_shell_v6(display, 1) {} - QVector toplevels() const { return m_toplevels; } - -protected: - void zxdg_shell_v6_get_xdg_surface(Resource *resource, uint32_t id, ::wl_resource *surface) override; - -private: - void addToplevel(XdgToplevelV6 *toplevel) { m_toplevels.append(toplevel); } - void removeToplevel(XdgToplevelV6 *toplevel) { m_toplevels.removeOne(toplevel); } - QVector m_toplevels; - - friend class XdgToplevelV6; -}; - -} // namespace Impl - -#endif // MOCKXDGSHELLV6_H diff --git a/tests/auto/client/shared/shared.pri b/tests/auto/client/shared/shared.pri index db71de528..3376c73bc 100644 --- a/tests/auto/client/shared/shared.pri +++ b/tests/auto/client/shared/shared.pri @@ -1,34 +1,21 @@ -CONFIG += testcase link_pkgconfig -QT += testlib -QT += core-private gui-private waylandclient-private +QT += testlib waylandclient-private +CONFIG += testcase wayland-scanner +QMAKE_USE += wayland-server -QMAKE_USE += wayland-client wayland-server - -CONFIG += wayland-scanner WAYLANDSERVERSOURCES += \ - ../../../../src/3rdparty/protocol/ivi-application.xml \ - ../../../../src/3rdparty/protocol/wayland.xml \ - ../../../../src/3rdparty/protocol/xdg-shell-unstable-v6.xml \ - ../../../../src/3rdparty/protocol/fullscreen-shell-unstable-v1.xml + $$PWD/../../../../src/3rdparty/protocol/wayland.xml \ + $$PWD/../../../../src/3rdparty/protocol/xdg-shell.xml INCLUDEPATH += ../shared -SOURCES += \ - ../shared/mockcompositor.cpp \ - ../shared/mockfullscreenshellv1.cpp \ - ../shared/mockinput.cpp \ - ../shared/mockiviapplication.cpp \ - ../shared/mockwlshell.cpp \ - ../shared/mockxdgshellv6.cpp \ - ../shared/mocksurface.cpp \ - ../shared/mockoutput.cpp - HEADERS += \ - ../shared/mockcompositor.h \ - ../shared/mockfullscreenshellv1.h \ - ../shared/mockinput.h \ - ../shared/mockiviapplication.h \ - ../shared/mockwlshell.h \ - ../shared/mockxdgshellv6.h \ - ../shared/mocksurface.h \ - ../shared/mockoutput.h + $$PWD/corecompositor.h \ + $$PWD/coreprotocol.h \ + $$PWD/mockcompositor.h \ + $$PWD/xdgshell.h + +SOURCES += \ + $$PWD/corecompositor.cpp \ + $$PWD/coreprotocol.cpp \ + $$PWD/mockcompositor.cpp \ + $$PWD/xdgshell.cpp diff --git a/tests/auto/client/shared/xdgshell.cpp b/tests/auto/client/shared/xdgshell.cpp new file mode 100644 index 000000000..ebbcc2942 --- /dev/null +++ b/tests/auto/client/shared/xdgshell.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** 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 "xdgshell.h" + +namespace MockCompositor { + +XdgWmBase::XdgWmBase(CoreCompositor *compositor, int version) + : QtWaylandServer::xdg_wm_base(compositor->m_display, version) + , m_compositor(compositor) +{ +} + +XdgToplevel *XdgWmBase::toplevel(int i) +{ + int j = 0; + for (auto *xdgSurface : qAsConst(m_xdgSurfaces)) { + if (auto *toplevel = xdgSurface->m_toplevel) { + if (j == i) + return toplevel; + ++j; + } + } + return nullptr; +} + +XdgPopup *XdgWmBase::popup(int i) +{ + int j = 0; + for (auto *xdgSurface : qAsConst(m_xdgSurfaces)) { + if (auto *popup = xdgSurface->m_popup) { + if (j == i) + return popup; + ++j; + } + } + return nullptr; +} + +void XdgWmBase::xdg_wm_base_get_xdg_surface(Resource *resource, uint32_t id, wl_resource *surface) +{ + auto *s = fromResource(surface); + auto *xdgSurface = new XdgSurface(this, s, resource->client(), id, resource->version()); + m_xdgSurfaces << xdgSurface; + emit xdgSurfaceCreated(xdgSurface); +} + +void XdgWmBase::xdg_wm_base_pong(Resource *resource, uint32_t serial) +{ + Q_UNUSED(resource); + emit pong(serial); +} + +XdgSurface::XdgSurface(XdgWmBase *xdgWmBase, Surface *surface, wl_client *client, int id, int version) + : QtWaylandServer::xdg_surface(client, id, version) + , m_xdgWmBase(xdgWmBase) + , m_surface(surface) +{ + QVERIFY(!surface->m_pending.buffer); + QVERIFY(!surface->m_committed.buffer); + connect(this, &XdgSurface::toplevelCreated, xdgWmBase, &XdgWmBase::toplevelCreated); + connect(surface, &Surface::attach, this, &XdgSurface::verifyConfigured); + connect(surface, &Surface::commit, this, [this] { + if (m_ackedConfigureSerial != m_committedConfigureSerial) { + m_committedConfigureSerial = m_ackedConfigureSerial; + emit configureCommitted(m_committedConfigureSerial); + } + }); +} + +void XdgSurface::sendConfigure(uint serial) +{ + Q_ASSERT(serial); + m_pendingConfigureSerials.append(serial); + m_configureSent = true; + xdg_surface::send_configure(serial); +} + +uint XdgSurface::sendConfigure() +{ + const uint serial = m_xdgWmBase->m_compositor->nextSerial(); + sendConfigure(serial); + return serial; +} + +void XdgSurface::xdg_surface_get_toplevel(Resource *resource, uint32_t id) +{ + QVERIFY(!m_toplevel); + QVERIFY(!m_popup); + m_toplevel = new XdgToplevel(this, id, resource->version()); + emit toplevelCreated(m_toplevel); +} + +void XdgSurface::xdg_surface_get_popup(Resource *resource, uint32_t id, wl_resource *parent, wl_resource *positioner) +{ + Q_UNUSED(parent); + Q_UNUSED(positioner); + QVERIFY(!m_toplevel); + QVERIFY(!m_popup); + m_popup = new XdgPopup(this, id, resource->version()); +} + +void XdgSurface::xdg_surface_destroy_resource(Resource *resource) +{ + Q_UNUSED(resource); + bool removed = m_xdgWmBase->m_xdgSurfaces.removeOne(this); + Q_ASSERT(removed); + delete this; +} + +void XdgSurface::xdg_surface_ack_configure(Resource *resource, uint32_t serial) +{ + Q_UNUSED(resource); + QVERIFY2(m_pendingConfigureSerials.contains(serial), qPrintable(QString::number(serial))); + m_ackedConfigureSerial = serial; + while (!m_pendingConfigureSerials.empty()) { + uint s = m_pendingConfigureSerials.takeFirst(); + if (s == serial) + return; + } +} + +XdgToplevel::XdgToplevel(XdgSurface *xdgSurface, int id, int version) + : QtWaylandServer::xdg_toplevel(xdgSurface->resource()->client(), id, version) + , m_xdgSurface(xdgSurface) +{ +} + +void XdgToplevel::sendConfigure(const QSize &size, const QVector &states) +{ + send_configure(size.width(), size.height(), toByteArray(states)); +} + +uint XdgToplevel::sendCompleteConfigure(const QSize &size, const QVector &states) +{ + sendConfigure(size, states); + return m_xdgSurface->sendConfigure(); +} + +XdgPopup::XdgPopup(XdgSurface *xdgSurface, int id, int version) + : QtWaylandServer::xdg_popup(xdgSurface->resource()->client(), id, version) + , m_xdgSurface(xdgSurface) +{ +} + +void XdgPopup::sendConfigure(const QRect &geometry) +{ + send_configure(geometry.x(), geometry.y(), geometry.width(), geometry.height()); +} + +void XdgPopup::xdg_popup_grab(QtWaylandServer::xdg_popup::Resource *resource, wl_resource *seat, uint32_t serial) +{ + Q_UNUSED(resource); + Q_UNUSED(seat); // TODO: verify correct seat as well + //TODO: verify no other popup has grabbed + QVERIFY(!m_grabbed); + m_grabbed = true; + m_grabSerial = serial; +} + +} // namespace MockCompositor diff --git a/tests/auto/client/shared/xdgshell.h b/tests/auto/client/shared/xdgshell.h new file mode 100644 index 000000000..3fcec7983 --- /dev/null +++ b/tests/auto/client/shared/xdgshell.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** 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 MOCKCOMPOSITOR_XDGSHELL_H +#define MOCKCOMPOSITOR_XDGSHELL_H + +#include "coreprotocol.h" +#include + +namespace MockCompositor { + +class XdgSurface; +class XdgToplevel; +class XdgPopup; +using XdgPositioner = QtWaylandServer::xdg_positioner; + +class XdgWmBase : public Global, public QtWaylandServer::xdg_wm_base +{ + Q_OBJECT +public: + explicit XdgWmBase(CoreCompositor *compositor, int version = 1); + using QtWaylandServer::xdg_wm_base::send_ping; + void send_ping(uint32_t) = delete; // It's a global, use resource specific instead + bool isClean() override { return m_xdgSurfaces.empty(); } + QString dirtyMessage() override { return m_xdgSurfaces.empty() ? "clean" : "remaining xdg surfaces"; } + QVector m_xdgSurfaces; + XdgToplevel *toplevel(int i = 0); + XdgPopup *popup(int i = 0); + CoreCompositor *m_compositor = nullptr; + +signals: + void pong(uint serial); + void xdgSurfaceCreated(XdgSurface *xdgSurface); + void toplevelCreated(XdgToplevel *toplevel); + +protected: + void xdg_wm_base_get_xdg_surface(Resource *resource, uint32_t id, ::wl_resource *surface) override; + void xdg_wm_base_pong(Resource *resource, uint32_t serial) override; + void xdg_wm_base_create_positioner(Resource *resource, uint32_t id) override + { + new XdgPositioner(resource->client(), id, resource->version()); + } +}; + +class XdgSurface : public QObject, public QtWaylandServer::xdg_surface +{ + Q_OBJECT +public: + explicit XdgSurface(XdgWmBase *xdgWmBase, Surface *surface, wl_client *client, int id, int version); + void send_configure(uint serial) = delete; // Use the one below instead, as it tracks state + void sendConfigure(uint serial); + uint sendConfigure(); + XdgToplevel *m_toplevel = nullptr; + XdgPopup *m_popup = nullptr; + XdgWmBase *m_xdgWmBase = nullptr; + Surface *m_surface = nullptr; + bool m_configureSent = false; + QVector m_pendingConfigureSerials; + uint m_ackedConfigureSerial = 0; + uint m_committedConfigureSerial = 0; + +public slots: + void verifyConfigured() { QVERIFY(m_configureSent); } + +signals: + void configureCommitted(uint); + void toplevelCreated(XdgToplevel *toplevel); + +protected: + void xdg_surface_get_toplevel(Resource *resource, uint32_t id) override; + void xdg_surface_get_popup(Resource *resource, uint32_t id, ::wl_resource *parent, ::wl_resource *positioner) override; + void xdg_surface_destroy_resource(Resource *resource) override; + void xdg_surface_destroy(Resource *resource) override { wl_resource_destroy(resource->handle); } + void xdg_surface_ack_configure(Resource *resource, uint32_t serial) override; +}; + +class XdgToplevel : public QtWaylandServer::xdg_toplevel +{ +public: + explicit XdgToplevel(XdgSurface *xdgSurface, int id, int version = 1); + void sendConfigure(const QSize &size = {0, 0}, const QVector &states = {}); + uint sendCompleteConfigure(const QSize &size = {0, 0}, const QVector &states = {}); + Surface *surface() { return m_xdgSurface->m_surface; } + XdgSurface *m_xdgSurface = nullptr; +}; + +class XdgPopup : public QtWaylandServer::xdg_popup +{ +public: + explicit XdgPopup(XdgSurface *xdgSurface, int id, int version = 1); + void sendConfigure(const QRect &geometry); + Surface *surface() { return m_xdgSurface->m_surface; } + XdgSurface *m_xdgSurface = nullptr; + bool m_grabbed = false; + uint m_grabSerial = 0; +protected: + void xdg_popup_grab(Resource *resource, ::wl_resource *seat, uint32_t serial) override; +}; + +} // namespace MockCompositor + +#endif // MOCKCOMPOSITOR_XDGSHELL_H diff --git a/tests/auto/client/shared_old/mockcompositor.cpp b/tests/auto/client/shared_old/mockcompositor.cpp new file mode 100644 index 000000000..df24b4091 --- /dev/null +++ b/tests/auto/client/shared_old/mockcompositor.cpp @@ -0,0 +1,520 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mockcompositor.h" +#include "mockinput.h" +#include "mockoutput.h" +#include "mocksurface.h" +#include "mockwlshell.h" +#include "mockxdgshellv6.h" +#include "mockiviapplication.h" + +#include + +#include +MockCompositor::MockCompositor() +{ + pthread_create(&m_thread, 0, run, this); + + m_mutex.lock(); + m_waitCondition.wait(&m_mutex); + m_mutex.unlock(); +} + +MockCompositor::~MockCompositor() +{ + m_alive = false; + m_waitCondition.wakeOne(); + pthread_join(m_thread, 0); +} + +void MockCompositor::lock() +{ + m_mutex.lock(); +} + +void MockCompositor::unlock() +{ + m_mutex.unlock(); +} + +void MockCompositor::applicationInitialized() +{ + m_ready = true; +} + +int MockCompositor::waylandFileDescriptor() const +{ + return m_compositor->fileDescriptor(); +} + +void MockCompositor::processWaylandEvents() +{ + m_waitCondition.wakeOne(); +} + +void MockCompositor::setOutputMode(const QSize &size) +{ + Command command = makeCommand(Impl::Compositor::setOutputMode, m_compositor); + command.parameters << size; + processCommand(command); +} + +void MockCompositor::setKeyboardFocus(const QSharedPointer &surface) +{ + Command command = makeCommand(Impl::Compositor::setKeyboardFocus, m_compositor); + command.parameters << QVariant::fromValue(surface); + processCommand(command); +} + +void MockCompositor::sendMousePress(const QSharedPointer &surface, const QPoint &pos) +{ + Command command = makeCommand(Impl::Compositor::sendMousePress, m_compositor); + command.parameters << QVariant::fromValue(surface) << pos; + processCommand(command); +} + +void MockCompositor::sendMouseRelease(const QSharedPointer &surface) +{ + Command command = makeCommand(Impl::Compositor::sendMouseRelease, m_compositor); + command.parameters << QVariant::fromValue(surface); + processCommand(command); +} + +void MockCompositor::sendKeyPress(const QSharedPointer &surface, uint code) +{ + Command command = makeCommand(Impl::Compositor::sendKeyPress, m_compositor); + command.parameters << QVariant::fromValue(surface) << code; + processCommand(command); +} + +void MockCompositor::sendKeyRelease(const QSharedPointer &surface, uint code) +{ + Command command = makeCommand(Impl::Compositor::sendKeyRelease, m_compositor); + command.parameters << QVariant::fromValue(surface) << code; + processCommand(command); +} + +void MockCompositor::sendTouchDown(const QSharedPointer &surface, const QPoint &position, int id) +{ + Command command = makeCommand(Impl::Compositor::sendTouchDown, m_compositor); + command.parameters << QVariant::fromValue(surface) << position << id; + processCommand(command); +} + +void MockCompositor::sendTouchMotion(const QSharedPointer &surface, const QPoint &position, int id) +{ + Command command = makeCommand(Impl::Compositor::sendTouchMotion, m_compositor); + command.parameters << QVariant::fromValue(surface) << position << id; + processCommand(command); +} + +void MockCompositor::sendTouchUp(const QSharedPointer &surface, int id) +{ + Command command = makeCommand(Impl::Compositor::sendTouchUp, m_compositor); + command.parameters << QVariant::fromValue(surface) << id; + processCommand(command); +} + +void MockCompositor::sendTouchFrame(const QSharedPointer &surface) +{ + Command command = makeCommand(Impl::Compositor::sendTouchFrame, m_compositor); + command.parameters << QVariant::fromValue(surface); + processCommand(command); +} + +void MockCompositor::sendDataDeviceDataOffer(const QSharedPointer &surface) +{ + Command command = makeCommand(Impl::Compositor::sendDataDeviceDataOffer, m_compositor); + command.parameters << QVariant::fromValue(surface); + processCommand(command); +} + +void MockCompositor::sendDataDeviceEnter(const QSharedPointer &surface, const QPoint& position) +{ + Command command = makeCommand(Impl::Compositor::sendDataDeviceEnter, m_compositor); + command.parameters << QVariant::fromValue(surface) << QVariant::fromValue(position); + processCommand(command); +} + +void MockCompositor::sendDataDeviceMotion(const QPoint &position) +{ + Command command = makeCommand(Impl::Compositor::sendDataDeviceMotion, m_compositor); + command.parameters << QVariant::fromValue(position); + processCommand(command); +} + +void MockCompositor::sendDataDeviceDrop(const QSharedPointer &surface) +{ + Command command = makeCommand(Impl::Compositor::sendDataDeviceDrop, m_compositor); + command.parameters << QVariant::fromValue(surface); + processCommand(command); +} + +void MockCompositor::sendDataDeviceLeave(const QSharedPointer &surface) +{ + Command command = makeCommand(Impl::Compositor::sendDataDeviceLeave, m_compositor); + command.parameters << QVariant::fromValue(surface); + processCommand(command); +} + +void MockCompositor::sendAddOutput() +{ + Command command = makeCommand(Impl::Compositor::sendAddOutput, m_compositor); + processCommand(command); +} + +void MockCompositor::sendRemoveOutput(const QSharedPointer &output) +{ + Command command = makeCommand(Impl::Compositor::sendRemoveOutput, m_compositor); + command.parameters << QVariant::fromValue(output); + processCommand(command); +} + +void MockCompositor::sendOutputGeometry(const QSharedPointer &output, const QRect &geometry) +{ + Command command = makeCommand(Impl::Compositor::sendOutputGeometry, m_compositor); + command.parameters << QVariant::fromValue(output); + command.parameters << QVariant::fromValue(geometry); + processCommand(command); +} + +void MockCompositor::sendSurfaceEnter(const QSharedPointer &surface, QSharedPointer &output) +{ + Command command = makeCommand(Impl::Compositor::sendSurfaceEnter, m_compositor); + command.parameters << QVariant::fromValue(surface); + command.parameters << QVariant::fromValue(output); + processCommand(command); +} + +void MockCompositor::sendSurfaceLeave(const QSharedPointer &surface, QSharedPointer &output) +{ + Command command = makeCommand(Impl::Compositor::sendSurfaceLeave, m_compositor); + command.parameters << QVariant::fromValue(surface); + command.parameters << QVariant::fromValue(output); + processCommand(command); +} + +void MockCompositor::sendShellSurfaceConfigure(const QSharedPointer surface, const QSize &size) +{ + Command command = makeCommand(Impl::Compositor::sendShellSurfaceConfigure, m_compositor); + command.parameters << QVariant::fromValue(surface); + command.parameters << QVariant::fromValue(size); + processCommand(command); +} + +void MockCompositor::sendIviSurfaceConfigure(const QSharedPointer iviSurface, const QSize &size) +{ + Command command = makeCommand(Impl::Compositor::sendIviSurfaceConfigure, m_compositor); + command.parameters << QVariant::fromValue(iviSurface); + command.parameters << QVariant::fromValue(size); + processCommand(command); +} + +void MockCompositor::sendXdgToplevelV6Configure(const QSharedPointer toplevel, const QSize &size, const QVector &states) +{ + Command command = makeCommand(Impl::Compositor::sendXdgToplevelV6Configure, m_compositor); + command.parameters << QVariant::fromValue(toplevel); + command.parameters << QVariant::fromValue(size); + QByteArray statesBytes(reinterpret_cast(states.data()), + states.size() * static_cast(sizeof(uint))); + command.parameters << statesBytes; + processCommand(command); +} + +void MockCompositor::waitForStartDrag() +{ + Command command = makeCommand(Impl::Compositor::waitForStartDrag, m_compositor); + processCommand(command); +} + +QSharedPointer MockCompositor::surface() +{ + QSharedPointer result; + lock(); + QVector surfaces = m_compositor->surfaces(); + foreach (Impl::Surface *surface, surfaces) { + // we don't want to mistake the cursor surface for a window surface + if (surface->isMapped()) { + result = surface->mockSurface(); + break; + } + } + unlock(); + return result; +} + +QSharedPointer MockCompositor::output(int index) +{ + QSharedPointer result; + lock(); + if (Impl::Output *output = m_compositor->outputs().value(index, nullptr)) + result = output->mockOutput(); + unlock(); + return result; +} + +QSharedPointer MockCompositor::iviSurface(int index) +{ + QSharedPointer result; + lock(); + if (Impl::IviSurface *toplevel = m_compositor->iviApplication()->iviSurfaces().value(index, nullptr)) + result = toplevel->mockIviSurface(); + unlock(); + return result; +} + +QSharedPointer MockCompositor::xdgToplevelV6(int index) +{ + QSharedPointer result; + lock(); + if (Impl::XdgToplevelV6 *toplevel = m_compositor->xdgShellV6()->toplevels().value(index, nullptr)) + result = toplevel->mockToplevel(); + unlock(); + return result; +} + +QSharedPointer MockCompositor::fullScreenShellV1Surface(int index) +{ + QSharedPointer result; + lock(); + if (Impl::Surface *surface = m_compositor->fullScreenShellV1()->surfaces().value(index, nullptr)) + result = surface->mockSurface(); + unlock(); + return result; +} + +MockCompositor::Command MockCompositor::makeCommand(Command::Callback callback, void *target) +{ + Command command; + command.callback = callback; + command.target = target; + return command; +} + +void MockCompositor::processCommand(const Command &command) +{ + lock(); + m_commandQueue << command; + unlock(); + + m_waitCondition.wakeOne(); +} + +void MockCompositor::dispatchCommands() +{ + lock(); + int count = m_commandQueue.length(); + unlock(); + + for (int i = 0; i < count; ++i) { + lock(); + const Command command = m_commandQueue.takeFirst(); + unlock(); + command.callback(command.target, command.parameters); + } +} + +void *MockCompositor::run(void *data) +{ + MockCompositor *controller = static_cast(data); + + Impl::Compositor compositor; + + controller->m_compositor = &compositor; + controller->m_waitCondition.wakeOne(); + + while (!controller->m_ready) { + controller->dispatchCommands(); + compositor.dispatchEvents(20); + } + + while (controller->m_alive) { + { + QMutexLocker locker(&controller->m_mutex); + if (controller->m_commandQueue.isEmpty()) + controller->m_waitCondition.wait(&controller->m_mutex); + } + controller->dispatchCommands(); + compositor.dispatchEvents(20); + } + + return 0; +} + +namespace Impl { + +Compositor::Compositor() + : m_display(wl_display_create()) +{ + if (wl_display_add_socket(m_display, 0)) { + fprintf(stderr, "Fatal: Failed to open server socket\n"); + exit(EXIT_FAILURE); + } + + wl_global_create(m_display, &wl_compositor_interface, 1, this, bindCompositor); + + m_data_device_manager.reset(new DataDeviceManager(this, m_display)); + + wl_display_init_shm(m_display); + + m_seat.reset(new Seat(this, m_display)); + m_pointer = m_seat->pointer(); + m_keyboard = m_seat->keyboard(); + m_touch = m_seat->touch(); + + m_outputs.append(new Output(m_display, QSize(1920, 1080), QPoint(0, 0))); + m_iviApplication.reset(new IviApplication(m_display)); + m_wlShell.reset(new WlShell(m_display)); + m_xdgShellV6.reset(new XdgShellV6(m_display)); + m_fullScreenShellV1.reset(new FullScreenShellV1(m_display)); + + m_loop = wl_display_get_event_loop(m_display); + m_fd = wl_event_loop_get_fd(m_loop); +} + +Compositor::~Compositor() +{ + wl_display_destroy(m_display); +} + +void Compositor::dispatchEvents(int timeout) +{ + wl_display_flush_clients(m_display); + wl_event_loop_dispatch(m_loop, timeout); +} + +static void compositor_create_surface(wl_client *client, wl_resource *compositorResource, uint32_t id) +{ + Compositor *compositor = static_cast(wl_resource_get_user_data(compositorResource)); + compositor->addSurface(new Surface(client, id, wl_resource_get_version(compositorResource), compositor)); +} + +static void compositor_create_region(wl_client *client, wl_resource *compositorResource, uint32_t id) +{ + Q_UNUSED(client); + Q_UNUSED(compositorResource); + Q_UNUSED(id); +} + +void Compositor::bindCompositor(wl_client *client, void *compositorData, uint32_t version, uint32_t id) +{ + static const struct wl_compositor_interface compositorInterface = { + compositor_create_surface, + compositor_create_region + }; + + wl_resource *resource = wl_resource_create(client, &wl_compositor_interface, static_cast(version), id); + wl_resource_set_implementation(resource, &compositorInterface, compositorData, nullptr); +} + +static void unregisterResourceCallback(wl_listener *listener, void *data) +{ + struct wl_resource *resource = reinterpret_cast(data); + wl_list_remove(wl_resource_get_link(resource)); + delete listener; +} + +void registerResource(wl_list *list, wl_resource *resource) +{ + wl_list_insert(list, wl_resource_get_link(resource)); + + wl_listener *listener = new wl_listener; + listener->notify = unregisterResourceCallback; + + wl_resource_add_destroy_listener(resource, listener); +} + +QVector Compositor::surfaces() const +{ + return m_surfaces; +} + +QVector Compositor::outputs() const +{ + return m_outputs; +} + +IviApplication *Compositor::iviApplication() const +{ + return m_iviApplication.data(); +} + +XdgShellV6 *Compositor::xdgShellV6() const +{ + return m_xdgShellV6.data(); +} + +FullScreenShellV1 *Compositor::fullScreenShellV1() const +{ + return m_fullScreenShellV1.data(); +} + +uint32_t Compositor::nextSerial() +{ + return wl_display_next_serial(m_display); +} + +void Compositor::addSurface(Surface *surface) +{ + m_surfaces << surface; +} + +void Compositor::removeSurface(Surface *surface) +{ + m_surfaces.removeOne(surface); + m_keyboard->handleSurfaceDestroyed(surface); + m_pointer->handleSurfaceDestroyed(surface); + m_fullScreenShellV1->removeSurface(surface); +} + +Surface *Compositor::resolveSurface(const QVariant &v) +{ + QSharedPointer mockSurface = v.value >(); + return mockSurface ? mockSurface->handle() : nullptr; +} + +Output *Compositor::resolveOutput(const QVariant &v) +{ + QSharedPointer mockOutput = v.value >(); + return mockOutput ? mockOutput->handle() : nullptr; +} + +IviSurface *Compositor::resolveIviSurface(const QVariant &v) +{ + QSharedPointer mockIviSurface = v.value>(); + return mockIviSurface ? mockIviSurface->handle() : nullptr; +} + +XdgToplevelV6 *Compositor::resolveToplevel(const QVariant &v) +{ + QSharedPointer mockToplevel = v.value>(); + return mockToplevel ? mockToplevel->handle() : nullptr; +} + +} diff --git a/tests/auto/client/shared_old/mockcompositor.h b/tests/auto/client/shared_old/mockcompositor.h new file mode 100644 index 000000000..4bab1ed67 --- /dev/null +++ b/tests/auto/client/shared_old/mockcompositor.h @@ -0,0 +1,290 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef MOCKCOMPOSITOR_H +#define MOCKCOMPOSITOR_H + +#include "mockxdgshellv6.h" +#include "mockiviapplication.h" +#include "mockfullscreenshellv1.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace Impl { + +typedef void (**Implementation)(void); + +class Keyboard; +class Pointer; +class Touch; +class Seat; +class DataDeviceManager; +class Surface; +class Output; +class IviApplication; +class WlShell; +class XdgShellV6; + +class Compositor +{ +public: + Compositor(); + ~Compositor(); + + int fileDescriptor() const { return m_fd; } + void dispatchEvents(int timeout = 0); + + uint32_t nextSerial(); + uint32_t time() { return ++m_time; } + + QVector surfaces() const; + QVector outputs() const; + + IviApplication *iviApplication() const; + XdgShellV6 *xdgShellV6() const; + FullScreenShellV1 *fullScreenShellV1() const; + + void addSurface(Surface *surface); + void removeSurface(Surface *surface); + + static void setKeyboardFocus(void *data, const QList ¶meters); + static void sendMousePress(void *data, const QList ¶meters); + static void sendMouseRelease(void *data, const QList ¶meters); + static void sendKeyPress(void *data, const QList ¶meters); + static void sendKeyRelease(void *data, const QList ¶meters); + static void sendTouchDown(void *data, const QList ¶meters); + static void sendTouchUp(void *data, const QList ¶meters); + static void sendTouchMotion(void *data, const QList ¶meters); + static void sendTouchFrame(void *data, const QList ¶meters); + static void sendDataDeviceDataOffer(void *data, const QList ¶meters); + static void sendDataDeviceEnter(void *data, const QList ¶meters); + static void sendDataDeviceMotion(void *data, const QList ¶meters); + static void sendDataDeviceDrop(void *data, const QList ¶meters); + static void sendDataDeviceLeave(void *data, const QList ¶meters); + static void waitForStartDrag(void *data, const QList ¶meters); + static void setOutputMode(void *compositor, const QList ¶meters); + static void sendAddOutput(void *data, const QList ¶meters); + static void sendRemoveOutput(void *data, const QList ¶meters); + static void sendOutputGeometry(void *data, const QList ¶meters); + static void sendSurfaceEnter(void *data, const QList ¶meters); + static void sendSurfaceLeave(void *data, const QList ¶meters); + static void sendShellSurfaceConfigure(void *data, const QList ¶meters); + static void sendIviSurfaceConfigure(void *data, const QList ¶meters); + static void sendXdgToplevelV6Configure(void *data, const QList ¶meters); + +public: + bool m_startDragSeen = false; + +private: + static void bindCompositor(wl_client *client, void *data, uint32_t version, uint32_t id); + static Surface *resolveSurface(const QVariant &v); + static Output *resolveOutput(const QVariant &v); + static IviSurface *resolveIviSurface(const QVariant &v); + static XdgToplevelV6 *resolveToplevel(const QVariant &v); + + void initShm(); + + QRect m_outputGeometry; + + wl_display *m_display = nullptr; + wl_event_loop *m_loop = nullptr; + int m_fd = -1; + + uint32_t m_time = 0; + + QScopedPointer m_seat; + Pointer *m_pointer = nullptr; + Keyboard *m_keyboard = nullptr; + Touch *m_touch = nullptr; + QScopedPointer m_data_device_manager; + QVector m_surfaces; + QVector m_outputs; + QScopedPointer m_iviApplication; + QScopedPointer m_wlShell; + QScopedPointer m_xdgShellV6; + QScopedPointer m_fullScreenShellV1; +}; + +void registerResource(wl_list *list, wl_resource *resource); + +} + +class MockSurface +{ +public: + Impl::Surface *handle() const { return m_surface; } + + QImage image; + +private: + MockSurface(Impl::Surface *surface); + friend class Impl::Compositor; + friend class Impl::Surface; + + Impl::Surface *m_surface = nullptr; +}; + +Q_DECLARE_METATYPE(QSharedPointer) + +class MockIviSurface +{ +public: + Impl::IviSurface *handle() const { return m_iviSurface; } + const uint iviId; + +private: + MockIviSurface(Impl::IviSurface *iviSurface) : iviId(iviSurface->iviId()), m_iviSurface(iviSurface) {} + friend class Impl::Compositor; + friend class Impl::IviSurface; + + Impl::IviSurface *m_iviSurface; +}; + +Q_DECLARE_METATYPE(QSharedPointer) + +class MockXdgToplevelV6 : public QObject +{ + Q_OBJECT +public: + Impl::XdgToplevelV6 *handle() const { return m_toplevel; } + + void sendConfigure(const QSharedPointer toplevel); + +signals: + uint setMinimizedRequested(); + uint setMaximizedRequested(); + uint unsetMaximizedRequested(); + uint setFullscreenRequested(); + uint unsetFullscreenRequested(); + void windowGeometryRequested(QRect geometry); // NOTE: This is really an xdg surface event + +private: + MockXdgToplevelV6(Impl::XdgToplevelV6 *toplevel) : m_toplevel(toplevel) {} + friend class Impl::Compositor; + friend class Impl::XdgToplevelV6; + + Impl::XdgToplevelV6 *m_toplevel; +}; + +Q_DECLARE_METATYPE(QSharedPointer) + +class MockOutput { +public: + Impl::Output *handle() const { return m_output; } + MockOutput(Impl::Output *output); +private: + Impl::Output *m_output = nullptr; +}; + +Q_DECLARE_METATYPE(QSharedPointer) + +class MockCompositor +{ +public: + MockCompositor(); + ~MockCompositor(); + + void applicationInitialized(); + + int waylandFileDescriptor() const; + void processWaylandEvents(); + + void setOutputMode(const QSize &size); + void setKeyboardFocus(const QSharedPointer &surface); + void sendMousePress(const QSharedPointer &surface, const QPoint &pos); + void sendMouseRelease(const QSharedPointer &surface); + void sendKeyPress(const QSharedPointer &surface, uint code); + void sendKeyRelease(const QSharedPointer &surface, uint code); + void sendTouchDown(const QSharedPointer &surface, const QPoint &position, int id); + void sendTouchMotion(const QSharedPointer &surface, const QPoint &position, int id); + void sendTouchUp(const QSharedPointer &surface, int id); + void sendTouchFrame(const QSharedPointer &surface); + void sendDataDeviceDataOffer(const QSharedPointer &surface); + void sendDataDeviceEnter(const QSharedPointer &surface, const QPoint &position); + void sendDataDeviceMotion(const QPoint &position); + void sendDataDeviceDrop(const QSharedPointer &surface); + void sendDataDeviceLeave(const QSharedPointer &surface); + void sendAddOutput(); + void sendRemoveOutput(const QSharedPointer &output); + void sendOutputGeometry(const QSharedPointer &output, const QRect &geometry); + void sendSurfaceEnter(const QSharedPointer &surface, QSharedPointer &output); + void sendSurfaceLeave(const QSharedPointer &surface, QSharedPointer &output); + void sendShellSurfaceConfigure(const QSharedPointer surface, const QSize &size = QSize(0, 0)); + void sendIviSurfaceConfigure(const QSharedPointer iviSurface, const QSize &size); + void sendXdgToplevelV6Configure(const QSharedPointer toplevel, const QSize &size = QSize(0, 0), + const QVector &states = { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED }); + void waitForStartDrag(); + + QSharedPointer surface(); + QSharedPointer output(int index = 0); + QSharedPointer iviSurface(int index = 0); + QSharedPointer xdgToplevelV6(int index = 0); + QSharedPointer fullScreenShellV1Surface(int index = 0); + + void lock(); + void unlock(); + +private: + struct Command + { + typedef void (*Callback)(void *target, const QList ¶meters); + + Callback callback; + void *target = nullptr; + QList parameters; + }; + + static Command makeCommand(Command::Callback callback, void *target); + + void processCommand(const Command &command); + void dispatchCommands(); + + static void *run(void *data); + + bool m_alive = true; + bool m_ready = false; + pthread_t m_thread; + QMutex m_mutex; + QWaitCondition m_waitCondition; + + Impl::Compositor *m_compositor = nullptr; + + QList m_commandQueue; +}; + +#endif diff --git a/tests/auto/client/shared_old/mockfullscreenshellv1.cpp b/tests/auto/client/shared_old/mockfullscreenshellv1.cpp new file mode 100644 index 000000000..22c49cde6 --- /dev/null +++ b/tests/auto/client/shared_old/mockfullscreenshellv1.cpp @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Pier Luigi Fiorini +** 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 "mockfullscreenshellv1.h" +#include "mocksurface.h" + +namespace Impl { + +void FullScreenShellV1::zwp_fullscreen_shell_v1_present_surface(Resource *resource, struct ::wl_resource *surface, uint32_t method, struct ::wl_resource *output) +{ + Q_UNUSED(resource) + Q_UNUSED(method) + Q_UNUSED(output) + + m_surfaces.append(Surface::fromResource(surface)); +} + +} // namespace Impl diff --git a/tests/auto/client/shared_old/mockfullscreenshellv1.h b/tests/auto/client/shared_old/mockfullscreenshellv1.h new file mode 100644 index 000000000..819bbc186 --- /dev/null +++ b/tests/auto/client/shared_old/mockfullscreenshellv1.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Pier Luigi Fiorini +** 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 MOCKFULLSCREENSHELLV1_H +#define MOCKFULLSCREENSHELLV1_H + +#include + +#include + +namespace Impl { + +class Surface; +class FullScreenShellV1; + +class FullScreenShellV1 : public QtWaylandServer::zwp_fullscreen_shell_v1 +{ +public: + explicit FullScreenShellV1(::wl_display *display) : zwp_fullscreen_shell_v1(display, 1) {} + + QVector surfaces() const { return m_surfaces; } + void removeSurface(Surface *surface) { m_surfaces.removeOne(surface); } + +protected: + void zwp_fullscreen_shell_v1_present_surface(Resource *resource, struct ::wl_resource *surface, uint32_t method, struct ::wl_resource *output) override; + +private: + QVector m_surfaces; +}; + +} // namespace Impl + +#endif // MOCKFULLSCREENSHELLV1_H diff --git a/tests/auto/client/shared_old/mockinput.cpp b/tests/auto/client/shared_old/mockinput.cpp new file mode 100644 index 000000000..8b7592824 --- /dev/null +++ b/tests/auto/client/shared_old/mockinput.cpp @@ -0,0 +1,474 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mockcompositor.h" +#include "mockinput.h" +#include "mocksurface.h" + +namespace Impl { + +void Compositor::setKeyboardFocus(void *data, const QList ¶meters) +{ + Compositor *compositor = static_cast(data); + compositor->m_keyboard->setFocus(resolveSurface(parameters.first())); +} + +void Compositor::sendMousePress(void *data, const QList ¶meters) +{ + Compositor *compositor = static_cast(data); + Surface *surface = resolveSurface(parameters.first()); + if (!surface) + return; + + QPoint pos = parameters.last().toPoint(); + compositor->m_pointer->setFocus(surface, pos); + compositor->m_pointer->sendMotion(pos); + compositor->m_pointer->sendButton(0x110, 1); +} + +void Compositor::sendMouseRelease(void *data, const QList ¶meters) +{ + Compositor *compositor = static_cast(data); + Surface *surface = resolveSurface(parameters.first()); + if (!surface) + return; + + compositor->m_pointer->sendButton(0x110, 0); +} + +void Compositor::sendKeyPress(void *data, const QList ¶meters) +{ + Compositor *compositor = static_cast(data); + Surface *surface = resolveSurface(parameters.first()); + if (!surface) + return; + + compositor->m_keyboard->sendKey(parameters.last().toUInt() - 8, 1); +} + +void Compositor::sendKeyRelease(void *data, const QList ¶meters) +{ + Compositor *compositor = static_cast(data); + Surface *surface = resolveSurface(parameters.first()); + if (!surface) + return; + + compositor->m_keyboard->sendKey(parameters.last().toUInt() - 8, 0); +} + +void Compositor::sendTouchDown(void *data, const QList ¶meters) +{ + Compositor *compositor = static_cast(data); + Surface *surface = resolveSurface(parameters.first()); + + Q_ASSERT(compositor); + Q_ASSERT(surface); + + QPoint position = parameters.at(1).toPoint(); + int id = parameters.at(2).toInt(); + + compositor->m_touch->sendDown(surface, position, id); +} + +void Compositor::sendTouchUp(void *data, const QList ¶meters) +{ + Compositor *compositor = static_cast(data); + Surface *surface = resolveSurface(parameters.first()); + + Q_ASSERT(compositor); + Q_ASSERT(surface); + + int id = parameters.at(1).toInt(); + + compositor->m_touch->sendUp(surface, id); +} + +void Compositor::sendTouchMotion(void *data, const QList ¶meters) +{ + Compositor *compositor = static_cast(data); + Surface *surface = resolveSurface(parameters.first()); + + Q_ASSERT(compositor); + Q_ASSERT(surface); + + QPoint position = parameters.at(1).toPoint(); + int id = parameters.at(2).toInt(); + + compositor->m_touch->sendMotion(surface, position, id); +} + +void Compositor::sendTouchFrame(void *data, const QList ¶meters) +{ + Compositor *compositor = static_cast(data); + Surface *surface = resolveSurface(parameters.first()); + + Q_ASSERT(compositor); + Q_ASSERT(surface); + + compositor->m_touch->sendFrame(surface); +} + +void Compositor::sendDataDeviceDataOffer(void *data, const QList ¶meters) +{ + Compositor *compositor = static_cast(data); + Surface *surface = resolveSurface(parameters.first()); + + Q_ASSERT(compositor); + Q_ASSERT(surface); + + compositor->m_data_device_manager->dataDevice()->sendDataOffer(surface->resource()->client()); +} + +void Compositor::sendDataDeviceEnter(void *data, const QList ¶meters) +{ + Compositor *compositor = static_cast(data); + Surface *surface = resolveSurface(parameters.first()); + QPoint position = parameters.at(1).toPoint(); + + Q_ASSERT(compositor); + Q_ASSERT(surface); + + compositor->m_data_device_manager->dataDevice()->sendEnter(surface, position); +} + +void Compositor::sendDataDeviceMotion(void *data, const QList ¶meters) +{ + Compositor *compositor = static_cast(data); + Q_ASSERT(compositor); + QPoint position = parameters.first().toPoint(); + compositor->m_data_device_manager->dataDevice()->sendMotion(position); +} + +void Compositor::sendDataDeviceDrop(void *data, const QList ¶meters) +{ + Compositor *compositor = static_cast(data); + Surface *surface = resolveSurface(parameters.first()); + + Q_ASSERT(compositor); + Q_ASSERT(surface); + + compositor->m_data_device_manager->dataDevice()->sendDrop(surface); +} + +void Compositor::sendDataDeviceLeave(void *data, const QList ¶meters) +{ + Compositor *compositor = static_cast(data); + Surface *surface = resolveSurface(parameters.first()); + + Q_ASSERT(compositor); + Q_ASSERT(surface); + + compositor->m_data_device_manager->dataDevice()->sendLeave(surface); +} + +void Compositor::waitForStartDrag(void *data, const QList ¶meters) +{ + Q_UNUSED(parameters); + Compositor *compositor = static_cast(data); + Q_ASSERT(compositor); + while (!compositor->m_startDragSeen) { + wl_display_flush_clients(compositor->m_display); + wl_event_loop_dispatch(compositor->m_loop, 100); + } + compositor->m_startDragSeen = false; +} + +Seat::Seat(Compositor *compositor, struct ::wl_display *display) + : wl_seat(display, 2) + , m_compositor(compositor) + , m_keyboard(new Keyboard(compositor)) + , m_pointer(new Pointer(compositor)) + , m_touch(new Touch(compositor)) +{ +} + +Seat::~Seat() +{ +} + +void Seat::seat_bind_resource(Resource *resource) +{ + send_capabilities(resource->handle, capability_keyboard | capability_pointer | capability_touch); +} + +void Seat::seat_get_keyboard(Resource *resource, uint32_t id) +{ + m_keyboard->add(resource->client(), id, resource->version()); +} + +void Seat::seat_get_pointer(Resource *resource, uint32_t id) +{ + m_pointer->add(resource->client(), id, resource->version()); +} + +void Seat::seat_get_touch(Resource *resource, uint32_t id) +{ + m_touch->add(resource->client(), id, resource->version()); +} + +Keyboard::Keyboard(Compositor *compositor) + : m_compositor(compositor) +{ +} + +Keyboard::~Keyboard() +{ +} + +void Keyboard::setFocus(Surface *surface) +{ + if (m_focusResource && m_focus != surface) { + uint32_t serial = m_compositor->nextSerial(); + send_leave(m_focusResource->handle, serial, m_focus->resource()->handle); + } + + Resource *resource = surface ? resourceMap().value(surface->resource()->client()) : 0; + + if (resource && (m_focus != surface || m_focusResource != resource)) { + uint32_t serial = m_compositor->nextSerial(); + send_modifiers(resource->handle, serial, 0, 0, 0, 0); + send_enter(resource->handle, serial, surface->resource()->handle, QByteArray()); + } + + m_focusResource = resource; + m_focus = surface; +} + +void Keyboard::handleSurfaceDestroyed(Surface *surface) +{ + if (surface == m_focus) { + m_focusResource = nullptr; + m_focus = nullptr; + } +} + +void Keyboard::sendKey(uint32_t key, uint32_t state) +{ + if (m_focusResource) { + uint32_t serial = m_compositor->nextSerial(); + send_key(m_focusResource->handle, serial, m_compositor->time(), key, state); + } +} + + +void Keyboard::keyboard_destroy_resource(wl_keyboard::Resource *resource) +{ + if (m_focusResource == resource) + m_focusResource = 0; +} + +Pointer::Pointer(Compositor *compositor) + : m_compositor(compositor) +{ +} + +Pointer::~Pointer() +{ + +} + +void Pointer::setFocus(Surface *surface, const QPoint &pos) +{ + if (m_focusResource && m_focus != surface) { + uint32_t serial = m_compositor->nextSerial(); + send_leave(m_focusResource->handle, serial, m_focus->resource()->handle); + } + + Resource *resource = surface ? resourceMap().value(surface->resource()->client()) : 0; + + if (resource && (m_focus != surface || resource != m_focusResource)) { + uint32_t serial = m_compositor->nextSerial(); + send_enter(resource->handle, serial, surface->resource()->handle, + wl_fixed_from_int(pos.x()), wl_fixed_from_int(pos.y())); + } + + m_focusResource = resource; + m_focus = surface; +} + +void Pointer::handleSurfaceDestroyed(Surface *surface) +{ + if (m_focus == surface) { + m_focus = nullptr; + m_focusResource = nullptr; + } +} + +void Pointer::sendMotion(const QPoint &pos) +{ + if (m_focusResource) + send_motion(m_focusResource->handle, m_compositor->time(), + wl_fixed_from_int(pos.x()), wl_fixed_from_int(pos.y())); +} + +void Pointer::sendButton(uint32_t button, uint32_t state) +{ + if (m_focusResource) { + uint32_t serial = m_compositor->nextSerial(); + send_button(m_focusResource->handle, serial, m_compositor->time(), + button, state); + } +} + +void Pointer::pointer_destroy_resource(wl_pointer::Resource *resource) +{ + if (m_focusResource == resource) + m_focusResource = 0; +} + +Touch::Touch(Compositor *compositor) + : wl_touch() + , m_compositor(compositor) +{ +} + +void Touch::sendDown(Surface *surface, const QPoint &position, int id) +{ + uint32_t serial = m_compositor->nextSerial(); + uint32_t time = m_compositor->time(); + Q_ASSERT(surface); + Resource *resource = resourceMap().value(surface->resource()->client()); + Q_ASSERT(resource); + auto x = wl_fixed_from_int(position.x()); + auto y = wl_fixed_from_int(position.y()); + wl_touch_send_down(resource->handle, serial, time, surface->resource()->handle, id, x, y); +} + +void Touch::sendUp(Surface *surface, int id) +{ + Resource *resource = resourceMap().value(surface->resource()->client()); + wl_touch_send_up(resource->handle, m_compositor->nextSerial(), m_compositor->time(), id); +} + +void Touch::sendMotion(Surface *surface, const QPoint &position, int id) +{ + Resource *resource = resourceMap().value(surface->resource()->client()); + uint32_t time = m_compositor->time(); + auto x = wl_fixed_from_int(position.x()); + auto y = wl_fixed_from_int(position.y()); + wl_touch_send_motion(resource->handle, time, id, x, y); +} + +void Touch::sendFrame(Surface *surface) +{ + Resource *resource = resourceMap().value(surface->resource()->client()); + wl_touch_send_frame(resource->handle); +} + +DataOffer::DataOffer() + : wl_data_offer() +{ + +} + +DataDevice::DataDevice(Compositor *compositor) + : m_compositor(compositor) +{ + +} + +void DataDevice::sendDataOffer(wl_client *client) +{ + m_dataOffer = new QtWaylandServer::wl_data_offer(client, 0, 1); + Resource *resource = resourceMap().value(client); + send_data_offer(resource->handle, m_dataOffer->resource()->handle); +} + +void DataDevice::sendEnter(Surface *surface, const QPoint& position) +{ + uint serial = m_compositor->nextSerial(); + m_focus = surface; + Resource *resource = resourceMap().value(surface->resource()->client()); + send_enter(resource->handle, serial, surface->resource()->handle, position.x(), position.y(), m_dataOffer->resource()->handle); +} + +void DataDevice::sendMotion(const QPoint &position) +{ + uint32_t time = m_compositor->time(); + Resource *resource = resourceMap().value(m_focus->resource()->client()); + send_motion(resource->handle, time, position.x(), position.y()); +} + +void DataDevice::sendDrop(Surface *surface) +{ + Resource *resource = resourceMap().value(surface->resource()->client()); + send_drop(resource->handle); +} + +void DataDevice::sendLeave(Surface *surface) +{ + Resource *resource = resourceMap().value(surface->resource()->client()); + send_leave(resource->handle); +} + +DataDevice::~DataDevice() +{ + +} + +void DataDevice::data_device_start_drag(QtWaylandServer::wl_data_device::Resource *resource, wl_resource *source, wl_resource *origin, wl_resource *icon, uint32_t serial) +{ + Q_UNUSED(resource); + Q_UNUSED(source); + Q_UNUSED(origin); + Q_UNUSED(icon); + Q_UNUSED(serial); + m_compositor->m_startDragSeen = true; +} + +DataDeviceManager::DataDeviceManager(Compositor *compositor, wl_display *display) + : wl_data_device_manager(display, 1) + , m_compositor(compositor) +{ + +} + +DataDeviceManager::~DataDeviceManager() +{ + +} + +DataDevice *DataDeviceManager::dataDevice() const +{ + return m_data_device.data(); +} + +void DataDeviceManager::data_device_manager_get_data_device(Resource *resource, uint32_t id, struct ::wl_resource *seat) +{ + Q_UNUSED(seat); + if (!m_data_device) + m_data_device.reset(new DataDevice(m_compositor)); + m_data_device->add(resource->client(), id, 1); +} + +void DataDeviceManager::data_device_manager_create_data_source(QtWaylandServer::wl_data_device_manager::Resource *resource, uint32_t id) +{ + new QtWaylandServer::wl_data_source(resource->client(), id, 1); +} + +} diff --git a/tests/auto/client/shared_old/mockinput.h b/tests/auto/client/shared_old/mockinput.h new file mode 100644 index 000000000..d9adb3621 --- /dev/null +++ b/tests/auto/client/shared_old/mockinput.h @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2016 Klarälvdalens Datakonsult AB (KDAB). +** 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 MOCKINPUT_H +#define MOCKINPUT_H + +#include + +#include "qwayland-server-wayland.h" + +#include "mockcompositor.h" + +namespace Impl { + +class Keyboard; +class Pointer; + +class Seat : public QtWaylandServer::wl_seat +{ +public: + Seat(Compositor *compositor, struct ::wl_display *display); + ~Seat(); + + Compositor *compositor() const { return m_compositor; } + + Keyboard *keyboard() const { return m_keyboard.data(); } + Pointer *pointer() const { return m_pointer.data(); } + Touch *touch() const { return m_touch.data(); } + +protected: + void seat_bind_resource(Resource *resource) override; + void seat_get_keyboard(Resource *resource, uint32_t id) override; + void seat_get_pointer(Resource *resource, uint32_t id) override; + void seat_get_touch(Resource *resource, uint32_t id) override; + +private: + Compositor *m_compositor = nullptr; + + QScopedPointer m_keyboard; + QScopedPointer m_pointer; + QScopedPointer m_touch; +}; + +class Keyboard : public QtWaylandServer::wl_keyboard +{ +public: + Keyboard(Compositor *compositor); + ~Keyboard(); + + Surface *focus() const { return m_focus; } + void setFocus(Surface *surface); + void handleSurfaceDestroyed(Surface *surface); + + void sendKey(uint32_t key, uint32_t state); + +protected: + void keyboard_destroy_resource(wl_keyboard::Resource *resource) override; + +private: + Compositor *m_compositor = nullptr; + + Resource *m_focusResource = nullptr; + Surface *m_focus = nullptr; +}; + +class Pointer : public QtWaylandServer::wl_pointer +{ +public: + Pointer(Compositor *compositor); + ~Pointer(); + + Surface *focus() const { return m_focus; } + + void setFocus(Surface *surface, const QPoint &pos); + void handleSurfaceDestroyed(Surface *surface); + void sendMotion(const QPoint &pos); + void sendButton(uint32_t button, uint32_t state); + +protected: + void pointer_destroy_resource(wl_pointer::Resource *resource) override; + +private: + Compositor *m_compositor = nullptr; + + Resource *m_focusResource = nullptr; + Surface *m_focus = nullptr; +}; + +class Touch : public QtWaylandServer::wl_touch +{ +public: + Touch(Compositor *compositor); + void sendDown(Surface *surface, const QPoint &position, int id); + void sendUp(Surface *surface, int id); + void sendMotion(Surface *surface, const QPoint &position, int id); + void sendFrame(Surface *surface); +private: + Compositor *m_compositor = nullptr; +}; + +class DataOffer : public QtWaylandServer::wl_data_offer +{ +public: + DataOffer(); +}; + +class DataDevice : public QtWaylandServer::wl_data_device +{ +public: + DataDevice(Compositor *compositor); + void sendDataOffer(wl_client *client); + void sendEnter(Surface *surface, const QPoint &position); + void sendMotion(const QPoint &position); + void sendDrop(Surface *surface); + void sendLeave(Surface *surface); + ~DataDevice(); + +protected: + void data_device_start_drag(Resource *resource, struct ::wl_resource *source, struct ::wl_resource *origin, struct ::wl_resource *icon, uint32_t serial) override; + +private: + Compositor *m_compositor = nullptr; + QtWaylandServer::wl_data_offer *m_dataOffer = nullptr; + Surface* m_focus = nullptr; +}; + +class DataDeviceManager : public QtWaylandServer::wl_data_device_manager +{ +public: + DataDeviceManager(Compositor *compositor, struct ::wl_display *display); + ~DataDeviceManager(); + DataDevice *dataDevice() const; + +protected: + void data_device_manager_get_data_device(Resource *resource, uint32_t id, struct ::wl_resource *seat) override; + void data_device_manager_create_data_source(Resource *resource, uint32_t id) override; + +private: + Compositor *m_compositor = nullptr; + + QScopedPointer m_data_device; +}; + +} + +#endif // MOCKINPUT_H diff --git a/tests/auto/client/shared_old/mockiviapplication.cpp b/tests/auto/client/shared_old/mockiviapplication.cpp new file mode 100644 index 000000000..29a308993 --- /dev/null +++ b/tests/auto/client/shared_old/mockiviapplication.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mockiviapplication.h" +#include "mocksurface.h" +#include "mockcompositor.h" + +namespace Impl { + +void Compositor::sendIviSurfaceConfigure(void *data, const QList ¶meters) +{ + Q_UNUSED(data); + IviSurface *iviSurface = resolveIviSurface(parameters.at(0)); + Q_ASSERT(iviSurface && iviSurface->resource()); + QSize size = parameters.at(1).toSize(); + Q_ASSERT(!size.isEmpty()); + iviSurface->send_configure(size.width(), size.height()); +} + +IviSurface::IviSurface(IviApplication *iviApplication, Surface *surface, uint iviId, wl_client *client, uint32_t id) + : QtWaylandServer::ivi_surface(client, id, 1) + , m_surface(surface) + , m_iviApplication(iviApplication) + , m_iviId(iviId) + , m_mockIviSurface(new MockIviSurface(this)) +{ + iviApplication->addIviSurface(this); + surface->map(); +} + +IviSurface::~IviSurface() +{ + m_iviApplication->removeIviSurface(this); + m_mockIviSurface->m_iviSurface = nullptr; +} + +void IviSurface::ivi_surface_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +void IviApplication::ivi_application_surface_create(Resource *resource, uint32_t ivi_id, ::wl_resource *surface, uint32_t id) +{ + new IviSurface(this, Surface::fromResource(surface), ivi_id, resource->client(), id); +} + +} // namespace Impl diff --git a/tests/auto/client/shared_old/mockiviapplication.h b/tests/auto/client/shared_old/mockiviapplication.h new file mode 100644 index 000000000..4d65eeaba --- /dev/null +++ b/tests/auto/client/shared_old/mockiviapplication.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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 MOCKIVIAPPLICATION_H +#define MOCKIVIAPPLICATION_H + +#include + +#include +#include + +class MockIviSurface; + +namespace Impl { + +class Surface; +class IviApplication; + +class IviSurface : public QtWaylandServer::ivi_surface +{ +public: + IviSurface(IviApplication *iviApplication, Surface *surface, uint iviId, wl_client *client, uint32_t id); + ~IviSurface() override; + IviApplication *iviApplication() const { return m_iviApplication; } + Surface *surface() const { return m_surface; } + uint iviId() const { return m_iviId; } + + QSharedPointer mockIviSurface() const { return m_mockIviSurface; } + +protected: + void ivi_surface_destroy_resource(Resource *) override { delete this; } + void ivi_surface_destroy(Resource *resource) override; + +private: + Surface *m_surface = nullptr; + IviApplication *m_iviApplication = nullptr; + const uint m_iviId = 0; + QSharedPointer m_mockIviSurface; +}; + +class IviApplication : public QtWaylandServer::ivi_application +{ +public: + explicit IviApplication(::wl_display *display) : ivi_application(display, 1) {} + QVector iviSurfaces() const { return m_iviSurfaces; } + +protected: + void ivi_application_surface_create(Resource *resource, uint32_t ivi_id, ::wl_resource *surface, uint32_t id) override; + +private: + void addIviSurface(IviSurface *iviSurface) { m_iviSurfaces.append(iviSurface); } + void removeIviSurface(IviSurface *iviSurface) { m_iviSurfaces.removeOne(iviSurface); } + QVector m_iviSurfaces; + + friend class IviSurface; +}; + +} // namespace Impl + +#endif // MOCKIVIAPPLICATION_H diff --git a/tests/auto/client/shared_old/mockoutput.cpp b/tests/auto/client/shared_old/mockoutput.cpp new file mode 100644 index 000000000..13e0524ad --- /dev/null +++ b/tests/auto/client/shared_old/mockoutput.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mockcompositor.h" +#include "mockoutput.h" + +#include + +namespace Impl { + +void Compositor::sendAddOutput(void *data, const QList ¶meters) { + Q_UNUSED(parameters); + Compositor *compositor = static_cast(data); + auto output = new Output(compositor->m_display, QSize(1920, 1200), QPoint(0, 0)); + compositor->m_outputs.append(output); + + // Wait for the client to bind to the output + while (output->resourceMap().isEmpty()) + compositor->dispatchEvents(); +} + +void Compositor::sendRemoveOutput(void *data, const QList ¶meters) { + Compositor *compositor = static_cast(data); + Q_ASSERT(compositor); + Output *output = resolveOutput(parameters.first()); + Q_ASSERT(output); + bool wasRemoved = compositor->m_outputs.removeOne(output); + Q_ASSERT(wasRemoved); + delete output; +} + +void Compositor::sendOutputGeometry(void *data, const QList ¶meters) +{ + Compositor *compositor = static_cast(data); + Q_ASSERT(compositor); + Output *output = resolveOutput(parameters.first()); + Q_ASSERT(output); + QRect geometry = parameters.at(1).toRect(); + output->sendGeometryAndMode(geometry); +} + +void Compositor::setOutputMode(void *data, const QList ¶meters) +{ + Compositor *compositor = static_cast(data); + QSize size = parameters.first().toSize(); + Output *output = compositor->m_outputs.first(); + Q_ASSERT(output); + output->setCurrentMode(size); +} + +Output::Output(wl_display *display, const QSize &resolution, const QPoint &position) + : wl_output(display, 2) + , m_size(resolution) + , m_position(position) + , m_physicalSize(520, 320) + , m_mockOutput(new MockOutput(this)) +{ +} + +void Output::setCurrentMode(const QSize &size) +{ + m_size = size; + for (Resource *resource : resourceMap()) { + sendCurrentMode(resource); + send_done(resource->handle); + } +} + +void Output::sendGeometryAndMode(const QRect &geometry) +{ + m_size = geometry.size(); + m_position = geometry.topLeft(); + for (Resource *resource : resourceMap()) { + sendGeometry(resource); + sendCurrentMode(resource); + send_done(resource->handle); + } +} + +void Output::output_bind_resource(QtWaylandServer::wl_output::Resource *resource) +{ + sendGeometry(resource); + sendCurrentMode(resource); + send_done(resource->handle); +} + +void Output::sendGeometry(Resource *resource) +{ + const int subPixel = 0; + const int transform = 0; + + send_geometry(resource->handle, + m_position.x(), m_position.y(), + m_physicalSize.width(), m_physicalSize.height(), + subPixel, "", "", transform ); +} + +void Output::sendCurrentMode(Resource *resource) +{ + send_mode(resource->handle, + WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED, + m_size.width(), m_size.height(), 60000); +} + +} // Impl + +MockOutput::MockOutput(Impl::Output *output) + : m_output(output) +{ +} diff --git a/tests/auto/client/shared_old/mockoutput.h b/tests/auto/client/shared_old/mockoutput.h new file mode 100644 index 000000000..9f261d5d7 --- /dev/null +++ b/tests/auto/client/shared_old/mockoutput.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MOCKOUTPUT_H +#define MOCKOUTPUT_H + +#include + +#include "qwayland-server-wayland.h" + +#include "mockcompositor.h" + +namespace Impl { + +class Output : public QtWaylandServer::wl_output +{ +public: + Output(::wl_display *display, const QSize &resolution, const QPoint &position); + + QSharedPointer mockOutput() const { return m_mockOutput; } + void setCurrentMode(const QSize &size); + void sendGeometryAndMode(const QRect &geometry); + +protected: + void output_bind_resource(Resource *resource) override; + +private: + void sendGeometry(Resource *resource); + void sendCurrentMode(Resource *resource); + QSize m_size; + QPoint m_position; + const QSize m_physicalSize; + QSharedPointer m_mockOutput; +}; + +} + +#endif // MOCKOUTPUT_H diff --git a/tests/auto/client/shared_old/mocksurface.cpp b/tests/auto/client/shared_old/mocksurface.cpp new file mode 100644 index 000000000..84dcda6b0 --- /dev/null +++ b/tests/auto/client/shared_old/mocksurface.cpp @@ -0,0 +1,191 @@ +/**************************************************************************** +** +** 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 "mocksurface.h" +#include "mockoutput.h" +#include "mockcompositor.h" +#include "mockwlshell.h" + +#include + +namespace Impl { + +void Compositor::sendSurfaceEnter(void *data, const QList ¶meters) +{ + Q_UNUSED(data); + Surface *surface = resolveSurface(parameters.at(0)); + Output *output = resolveOutput(parameters.at(1)); + Q_ASSERT(surface && surface->resource()); + Q_ASSERT(output); + auto outputResources = output->resourceMap().values(surface->resource()->client()); + Q_ASSERT(!outputResources.isEmpty()); + + for (auto outputResource : outputResources) + surface->send_enter(outputResource->handle); +} + +void Compositor::sendSurfaceLeave(void *data, const QList ¶meters) +{ + Q_UNUSED(data); + Surface *surface = resolveSurface(parameters.at(0)); + Output *output = resolveOutput(parameters.at(1)); + Q_ASSERT(surface && surface->resource()); + Q_ASSERT(output); + auto outputResources = output->resourceMap().values(surface->resource()->client()); + Q_ASSERT(!outputResources.isEmpty()); + + for (auto outputResource : outputResources) + surface->send_leave(outputResource->handle); +} + +void Compositor::sendShellSurfaceConfigure(void *data, const QList ¶meters) +{ + Compositor *compositor = static_cast(data); + Surface *surface = resolveSurface(parameters.at(0)); + QSize size = parameters.at(1).toSize(); + Q_ASSERT(size.isValid()); + if (auto toplevel = surface->xdgToplevelV6()) { + QVector states = { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED }; + auto statesBytes = QByteArray::fromRawData(reinterpret_cast(states.data()), + states.size() * static_cast(sizeof(uint))); + toplevel->send_configure(size.width(), size.height(), statesBytes); + toplevel->xdgSurface()->sendConfigure(compositor->nextSerial()); + } else if (auto wlShellSurface = surface->wlShellSurface()) { + const uint edges = 0; + wlShellSurface->send_configure(edges, size.width(), size.height()); + } else { + qWarning() << "The mocking framework doesn't know how to send a configure event for this surface"; + } +} + +Surface::Surface(wl_client *client, uint32_t id, int v, Compositor *compositor) + : QtWaylandServer::wl_surface(client, id, v) + , m_compositor(compositor) + , m_mockSurface(new MockSurface(this)) +{ +} + +Surface::~Surface() +{ + m_mockSurface->m_surface = 0; +} + +void Surface::map() +{ + m_mapped = true; +} + +bool Surface::isMapped() const +{ + return m_mapped; +} + +Surface *Surface::fromResource(struct ::wl_resource *resource) +{ + if (auto *r = Resource::fromResource(resource)) + return static_cast(r->surface_object); + return nullptr; +} + +void Surface::surface_destroy_resource(Resource *) +{ + compositor()->removeSurface(this); + delete this; +} + +void Surface::surface_destroy(Resource *resource) +{ + if (m_wlShellSurface) // on wl-shell the shell surface is automatically destroyed with the surface + wl_resource_destroy(m_wlShellSurface->resource()->handle); + Q_ASSERT(!m_wlShellSurface); + Q_ASSERT(!m_xdgSurfaceV6); + wl_resource_destroy(resource->handle); +} + +void Surface::surface_attach(Resource *resource, struct wl_resource *buffer, int x, int y) +{ + if (m_xdgSurfaceV6) { + // It's a protocol error to attach a buffer to an xdgSurface that's not configured + Q_ASSERT(xdgSurfaceV6()->configureSent()); + } + + Q_UNUSED(resource); + Q_UNUSED(x); + Q_UNUSED(y); + m_buffer = buffer; + + if (!buffer) + m_mockSurface->image = QImage(); +} + +void Surface::surface_damage(Resource *resource, + int32_t x, int32_t y, int32_t width, int32_t height) +{ + Q_UNUSED(resource); + Q_UNUSED(x); + Q_UNUSED(y); + Q_UNUSED(width); + Q_UNUSED(height); +} + +void Surface::surface_frame(Resource *resource, + uint32_t callback) +{ + wl_resource *frameCallback = wl_resource_create(resource->client(), &wl_callback_interface, 1, callback); + m_frameCallbackList << frameCallback; +} + +void Surface::surface_commit(Resource *resource) +{ + Q_UNUSED(resource); + + if (m_buffer) { + struct ::wl_shm_buffer *shm_buffer = wl_shm_buffer_get(m_buffer); + if (shm_buffer) { + int stride = wl_shm_buffer_get_stride(shm_buffer); + uint format = wl_shm_buffer_get_format(shm_buffer); + Q_UNUSED(format); + void *data = wl_shm_buffer_get_data(shm_buffer); + const uchar *char_data = static_cast(data); + QImage img(char_data, wl_shm_buffer_get_width(shm_buffer), wl_shm_buffer_get_height(shm_buffer), stride, QImage::Format_ARGB32_Premultiplied); + m_mockSurface->image = img; + } + } + + foreach (wl_resource *frameCallback, m_frameCallbackList) { + wl_callback_send_done(frameCallback, m_compositor->time()); + wl_resource_destroy(frameCallback); + } + m_frameCallbackList.clear(); +} + +} +MockSurface::MockSurface(Impl::Surface *surface) + : m_surface(surface) +{ +} diff --git a/tests/auto/client/shared_old/mocksurface.h b/tests/auto/client/shared_old/mocksurface.h new file mode 100644 index 000000000..949dc23dd --- /dev/null +++ b/tests/auto/client/shared_old/mocksurface.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef MOCKSURFACE_H +#define MOCKSURFACE_H + +#include + +#include "qwayland-server-wayland.h" + +#include "mockcompositor.h" + +namespace Impl { + +class XdgToplevelV6; +class WlShellSurface; + +class Surface : public QtWaylandServer::wl_surface +{ +public: + Surface(wl_client *client, uint32_t id, int v, Compositor *compositor); + ~Surface(); + + Compositor *compositor() const { return m_compositor; } + static Surface *fromResource(struct ::wl_resource *resource); + void map(); + bool isMapped() const; + XdgSurfaceV6 *xdgSurfaceV6() const { return m_xdgSurfaceV6; } + XdgToplevelV6 *xdgToplevelV6() const { return m_xdgSurfaceV6 ? m_xdgSurfaceV6->toplevel() : nullptr; } + WlShellSurface *wlShellSurface() const { return m_wlShellSurface; } + + QSharedPointer mockSurface() const { return m_mockSurface; } + +protected: + + void surface_destroy_resource(Resource *resource) override; + + void surface_destroy(Resource *resource) override; + void surface_attach(Resource *resource, + struct wl_resource *buffer, int x, int y) override; + void surface_damage(Resource *resource, + int32_t x, int32_t y, int32_t width, int32_t height) override; + void surface_frame(Resource *resource, + uint32_t callback) override; + void surface_commit(Resource *resource) override; +private: + wl_resource *m_buffer = nullptr; + XdgSurfaceV6 *m_xdgSurfaceV6 = nullptr; + WlShellSurface *m_wlShellSurface = nullptr; + + Compositor *m_compositor = nullptr; + QSharedPointer m_mockSurface; + QList m_frameCallbackList; + bool m_mapped = false; + + friend class XdgSurfaceV6; + friend class WlShellSurface; +}; + +} + +#endif // MOCKSURFACE_H diff --git a/tests/auto/client/shared_old/mockwlshell.cpp b/tests/auto/client/shared_old/mockwlshell.cpp new file mode 100644 index 000000000..50e539932 --- /dev/null +++ b/tests/auto/client/shared_old/mockwlshell.cpp @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** 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 "mockwlshell.h" +#include "mocksurface.h" + +namespace Impl { + +WlShellSurface::WlShellSurface(wl_client *client, int id, Surface *surface) + : QtWaylandServer::wl_shell_surface(client, id, 1) + , m_surface(surface) +{ + surface->m_wlShellSurface = this; + surface->map(); +} + +WlShellSurface::~WlShellSurface() +{ + m_surface->m_wlShellSurface = nullptr; +} + +void WlShell::shell_get_shell_surface(QtWaylandServer::wl_shell::Resource *resource, uint32_t id, wl_resource *surface) +{ + new WlShellSurface(resource->client(), id, Surface::fromResource(surface)); +} + +} // namespace Impl diff --git a/tests/auto/client/shared_old/mockwlshell.h b/tests/auto/client/shared_old/mockwlshell.h new file mode 100644 index 000000000..3da586ca8 --- /dev/null +++ b/tests/auto/client/shared_old/mockwlshell.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** 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 + +#ifndef MOCKWLSHELL_H +#define MOCKWLSHELL_H + +namespace Impl { + +class Surface; + +class WlShellSurface : public QtWaylandServer::wl_shell_surface +{ +public: + explicit WlShellSurface(::wl_client *client, int id, Surface *surface); + ~WlShellSurface() override; + void shell_surface_destroy_resource(Resource *) override { delete this; } + +private: + Surface *m_surface = nullptr; +}; + +class WlShell : public QtWaylandServer::wl_shell +{ +public: + explicit WlShell(::wl_display *display) : wl_shell(display, 1) {} + void shell_get_shell_surface(Resource *resource, uint32_t id, ::wl_resource *surface) override; +}; + +} // namespace Impl + +#endif // MOCKWLSHELL_H diff --git a/tests/auto/client/shared_old/mockxdgshellv6.cpp b/tests/auto/client/shared_old/mockxdgshellv6.cpp new file mode 100644 index 000000000..05eff74ad --- /dev/null +++ b/tests/auto/client/shared_old/mockxdgshellv6.cpp @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mockxdgshellv6.h" +#include "mocksurface.h" +#include "mockcompositor.h" + +namespace Impl { + +void Compositor::sendXdgToplevelV6Configure(void *data, const QList ¶meters) +{ + Compositor *compositor = static_cast(data); + XdgToplevelV6 *toplevel = resolveToplevel(parameters.at(0)); + Q_ASSERT(toplevel && toplevel->resource()); + QSize size = parameters.at(1).toSize(); + Q_ASSERT(size.isValid()); + auto statesBytes = parameters.at(2).toByteArray(); + toplevel->send_configure(size.width(), size.height(), statesBytes); + toplevel->xdgSurface()->send_configure(compositor->nextSerial()); +} + +XdgSurfaceV6::XdgSurfaceV6(XdgShellV6 *shell, Surface *surface, wl_client *client, uint32_t id) + : QtWaylandServer::zxdg_surface_v6(client, id, 1) + , m_surface(surface) + , m_shell(shell) +{ + m_surface->m_xdgSurfaceV6 = this; +} + +XdgSurfaceV6::~XdgSurfaceV6() +{ + m_surface->m_xdgSurfaceV6 = nullptr; +} + +void XdgSurfaceV6::sendConfigure(uint32_t serial) +{ + send_configure(serial); + m_configureSent = true; +} + +void XdgSurfaceV6::zxdg_surface_v6_get_toplevel(QtWaylandServer::zxdg_surface_v6::Resource *resource, uint32_t id) +{ + int version = wl_resource_get_version(resource->handle); + m_toplevel = new XdgToplevelV6(this, resource->client(), id, version); +} + +void XdgSurfaceV6::zxdg_surface_v6_set_window_geometry(QtWaylandServer::zxdg_surface_v6::Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) +{ + Q_UNUSED(resource); + if (m_toplevel) { + QRect geometry(x, y, width, height); + emit m_toplevel->mockToplevel()->windowGeometryRequested(geometry); + } +} + +void XdgSurfaceV6::zxdg_surface_v6_destroy(QtWaylandServer::zxdg_surface_v6::Resource *resource) +{ + Q_ASSERT(!m_toplevel); + wl_resource_destroy(resource->handle); +} + +XdgToplevelV6::XdgToplevelV6(XdgSurfaceV6 *xdgSurface, wl_client *client, uint32_t id, int version) + : QtWaylandServer::zxdg_toplevel_v6(client, id, version) + , m_xdgSurface(xdgSurface) + , m_mockToplevel(new MockXdgToplevelV6(this)) +{ + auto *surface = m_xdgSurface->surface(); + m_xdgSurface->shell()->addToplevel(this); + surface->map(); +} + +XdgToplevelV6::~XdgToplevelV6() +{ + m_xdgSurface->shell()->removeToplevel(this); + m_mockToplevel->m_toplevel = nullptr; +} + +void XdgToplevelV6::zxdg_toplevel_v6_destroy(QtWaylandServer::zxdg_toplevel_v6::Resource *resource) +{ + m_xdgSurface->m_toplevel = nullptr; + wl_resource_destroy(resource->handle); +} + +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); +} + +} // namespace Impl diff --git a/tests/auto/client/shared_old/mockxdgshellv6.h b/tests/auto/client/shared_old/mockxdgshellv6.h new file mode 100644 index 000000000..a238fa562 --- /dev/null +++ b/tests/auto/client/shared_old/mockxdgshellv6.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** 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 + +#include +#include + +#ifndef MOCKXDGSHELLV6_H +#define MOCKXDGSHELLV6_H + +class MockXdgToplevelV6; + +namespace Impl { + +class XdgToplevelV6; +class XdgShellV6; +class Surface; + +class XdgSurfaceV6 : public QtWaylandServer::zxdg_surface_v6 +{ +public: + XdgSurfaceV6(XdgShellV6 *shell, Surface *surface, wl_client *client, uint32_t id); + ~XdgSurfaceV6() override; + XdgShellV6 *shell() const { return m_shell; } + Surface *surface() const { return m_surface; } + XdgToplevelV6 *toplevel() const { return m_toplevel; } + + void sendConfigure(uint32_t serial); + bool configureSent() const { return m_configureSent; } + +protected: + void zxdg_surface_v6_destroy_resource(Resource *) override { delete this; } + void zxdg_surface_v6_get_toplevel(Resource *resource, uint32_t id) override; + void zxdg_surface_v6_set_window_geometry(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) override; + void zxdg_surface_v6_destroy(Resource *resource) override; + +private: + Surface *m_surface = nullptr; + XdgToplevelV6 *m_toplevel = nullptr; + XdgShellV6 *m_shell = nullptr; + bool m_configureSent = false; + + friend class XdgToplevelV6; +}; + +class XdgToplevelV6 : public QtWaylandServer::zxdg_toplevel_v6 +{ +public: + XdgToplevelV6(XdgSurfaceV6 *xdgSurface, wl_client *client, uint32_t id, int version); + ~XdgToplevelV6() override; + XdgSurfaceV6 *xdgSurface() const { return m_xdgSurface; } + + QSharedPointer mockToplevel() const { return m_mockToplevel; } + +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; + QSharedPointer m_mockToplevel; +}; + +class XdgShellV6 : public QtWaylandServer::zxdg_shell_v6 +{ +public: + explicit XdgShellV6(::wl_display *display) : zxdg_shell_v6(display, 1) {} + QVector toplevels() const { return m_toplevels; } + +protected: + void zxdg_shell_v6_get_xdg_surface(Resource *resource, uint32_t id, ::wl_resource *surface) override; + +private: + void addToplevel(XdgToplevelV6 *toplevel) { m_toplevels.append(toplevel); } + void removeToplevel(XdgToplevelV6 *toplevel) { m_toplevels.removeOne(toplevel); } + QVector m_toplevels; + + friend class XdgToplevelV6; +}; + +} // namespace Impl + +#endif // MOCKXDGSHELLV6_H diff --git a/tests/auto/client/shared_old/shared_old.pri b/tests/auto/client/shared_old/shared_old.pri new file mode 100644 index 000000000..467e98115 --- /dev/null +++ b/tests/auto/client/shared_old/shared_old.pri @@ -0,0 +1,34 @@ +CONFIG += testcase link_pkgconfig +QT += testlib +QT += core-private gui-private waylandclient-private + +QMAKE_USE += wayland-client wayland-server + +CONFIG += wayland-scanner +WAYLANDSERVERSOURCES += \ + ../../../../src/3rdparty/protocol/ivi-application.xml \ + ../../../../src/3rdparty/protocol/wayland.xml \ + ../../../../src/3rdparty/protocol/xdg-shell-unstable-v6.xml \ + ../../../../src/3rdparty/protocol/fullscreen-shell-unstable-v1.xml + +INCLUDEPATH += ../shared_old + +SOURCES += \ + ../shared_old/mockcompositor.cpp \ + ../shared_old/mockfullscreenshellv1.cpp \ + ../shared_old/mockinput.cpp \ + ../shared_old/mockiviapplication.cpp \ + ../shared_old/mockwlshell.cpp \ + ../shared_old/mockxdgshellv6.cpp \ + ../shared_old/mocksurface.cpp \ + ../shared_old/mockoutput.cpp + +HEADERS += \ + ../shared_old/mockcompositor.h \ + ../shared_old/mockfullscreenshellv1.h \ + ../shared_old/mockinput.h \ + ../shared_old/mockiviapplication.h \ + ../shared_old/mockwlshell.h \ + ../shared_old/mockxdgshellv6.h \ + ../shared_old/mocksurface.h \ + ../shared_old/mockoutput.h diff --git a/tests/auto/client/surface/surface.pro b/tests/auto/client/surface/surface.pro new file mode 100644 index 000000000..36882aa2d --- /dev/null +++ b/tests/auto/client/surface/surface.pro @@ -0,0 +1,5 @@ +include (../shared/shared.pri) + +TARGET = tst_surface +SOURCES += tst_surface.cpp + diff --git a/tests/auto/client/surface/tst_surface.cpp b/tests/auto/client/surface/tst_surface.cpp new file mode 100644 index 000000000..dddff0866 --- /dev/null +++ b/tests/auto/client/surface/tst_surface.cpp @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** 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 "mockcompositor.h" +#include +#include + +using namespace MockCompositor; + +class tst_surface : public QObject, private DefaultCompositor +{ + Q_OBJECT +private slots: + void cleanup() { QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage())); } + void createDestroySurface(); + void waitForFrameCallbackRaster(); + void waitForFrameCallbackGl(); + void negotiateShmFormat(); +}; + +void tst_surface::createDestroySurface() +{ + QWindow window; + window.show(); + + QCOMPOSITOR_TRY_VERIFY(surface()); + + window.destroy(); + QCOMPOSITOR_TRY_VERIFY(!surface()); +} + +void tst_surface::waitForFrameCallbackRaster() +{ + QSKIP("TODO: This currently fails, needs a fix"); + class TestWindow : public QRasterWindow { + public: + explicit TestWindow() { resize(40, 40); } + void paintEvent(QPaintEvent *event) override + { + Q_UNUSED(event); + update(); + } + }; + TestWindow window; + window.show(); + QCOMPOSITOR_TRY_VERIFY(xdgToplevel()); + QSignalSpy bufferSpy(exec([=] { return xdgSurface()->m_surface; }), &Surface::bufferCommitted); + exec([=] { xdgToplevel()->sendCompleteConfigure(); }); + + // We should get the first buffer without waiting for a frame callback + QTRY_COMPARE(bufferSpy.count(), 1); + bufferSpy.removeFirst(); + + // Make sure we follow frame callbacks for some frames + for (int i = 0; i < 5; ++i) { + xdgPingAndWaitForPong(); // Make sure things have happened on the client + exec([&] { + QVERIFY(bufferSpy.empty()); // Make sure no extra buffers have arrived + QVERIFY(!xdgToplevel()->surface()->m_waitingFrameCallbacks.empty()); + xdgToplevel()->surface()->sendFrameCallbacks(); + }); + QTRY_COMPARE(bufferSpy.count(), 1); + bufferSpy.removeFirst(); + } +} + +void tst_surface::waitForFrameCallbackGl() +{ + QSKIP("TODO: This currently fails, needs a fix"); + class TestWindow : public QOpenGLWindow { + public: + explicit TestWindow() + { + resize(40, 40); + connect(this, &QOpenGLWindow::frameSwapped, + this, QOverload<>::of(&QPaintDeviceWindow::update)); + update(); + } + void paintGL() override + { + glClearColor(1, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + } + }; + TestWindow window; + window.show(); + QCOMPOSITOR_TRY_VERIFY(xdgToplevel()); + QSignalSpy bufferSpy(exec([=] { return xdgSurface()->m_surface; }), &Surface::bufferCommitted); + exec([=] { xdgToplevel()->sendCompleteConfigure(); }); + + // We should get the first buffer without waiting for a frame callback + QTRY_COMPARE(bufferSpy.count(), 1); + bufferSpy.removeFirst(); + + // Make sure we follow frame callbacks for some frames + for (int i = 0; i < 5; ++i) { + xdgPingAndWaitForPong(); // Make sure things have happened on the client + exec([&] { + QVERIFY(bufferSpy.empty()); // Make sure no extra buffers have arrived + QVERIFY(!xdgToplevel()->surface()->m_waitingFrameCallbacks.empty()); + xdgToplevel()->surface()->sendFrameCallbacks(); + }); + QTRY_COMPARE(bufferSpy.count(), 1); + bufferSpy.removeFirst(); + } +} + +void tst_surface::negotiateShmFormat() +{ + QSKIP("TODO: I'm not sure why we're choosing xrgb over argb in this case..."); + QRasterWindow window; + window.setFlag(Qt::FramelessWindowHint); // decorations force alpha + QSurfaceFormat format; + format.setAlphaBufferSize(0); + window.setFormat(format); + window.resize(64, 48); + window.show(); + QCOMPOSITOR_TRY_VERIFY(xdgToplevel()); + QSignalSpy bufferSpy(exec([=] { return xdgSurface()->m_surface; }), &Surface::bufferCommitted); + const uint serial = exec([=] { return xdgToplevel()->sendCompleteConfigure(); }); + QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, serial); + exec([&] { + Buffer *buffer = xdgToplevel()->surface()->m_committed.buffer; + QVERIFY(buffer); + auto *shmBuffer = ShmBuffer::fromBuffer(buffer); + QVERIFY(shmBuffer); + qDebug() << "shmBuffer->m_format" << shmBuffer->m_format; + QCOMPARE(shmBuffer->m_format, Shm::format_xrgb8888); + }); +} + +QCOMPOSITOR_TEST_MAIN(tst_surface) +#include "tst_surface.moc" diff --git a/tests/auto/client/xdgshell/tst_xdgshell.cpp b/tests/auto/client/xdgshell/tst_xdgshell.cpp new file mode 100644 index 000000000..55e994b06 --- /dev/null +++ b/tests/auto/client/xdgshell/tst_xdgshell.cpp @@ -0,0 +1,269 @@ +/**************************************************************************** +** +** 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 "mockcompositor.h" +#include +#include + +using namespace MockCompositor; + +class tst_xdgshell : public QObject, private DefaultCompositor +{ + Q_OBJECT +private slots: + void cleanup() { QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage())); } + void showMinimized(); + void basicConfigure(); + void configureSize(); + void configureStates(); + void popup(); + void pongs(); +}; + +void tst_xdgshell::showMinimized() +{ + QSKIP("TODO: This currently fails, needs a fix"); + // On xdg-shell 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. + QWindow window; + window.showMinimized(); + QCOMPARE(window.windowStates(), Qt::WindowMinimized); // should return minimized until + QTRY_COMPARE(window.windowStates(), Qt::WindowNoState); // rejected by handleWindowStateChanged + + // Make sure the window on the compositor side is/was created here, and not after the test + // finishes, as that may mess up for later tests. + QCOMPOSITOR_TRY_VERIFY(surface()); + QVERIFY(!window.isExposed()); +} + +void tst_xdgshell::basicConfigure() +{ + QRasterWindow window; + window.resize(64, 48); + window.show(); + QCOMPOSITOR_TRY_VERIFY(xdgToplevel()); + + QSignalSpy configureSpy(exec([=] { return xdgSurface(); }), &XdgSurface::configureCommitted); + + QTRY_VERIFY(window.isVisible()); + // The window should not be exposed before the first xdg_surface configure event + QTRY_VERIFY(!window.isExposed()); + + exec([=] { + xdgToplevel()->sendConfigure({0, 0}, {}); // Let the window decide the size + }); + + // Nothing should happen before the *xdg_surface* configure + QTRY_VERIFY(!window.isExposed()); //Window should not be exposed before the first configure event + QVERIFY(configureSpy.isEmpty()); + + const uint serial = exec([=] { return nextSerial(); }); + + exec([=] { + xdgSurface()->sendConfigure(serial); + }); + + // Finally, we're exposed + QTRY_VERIFY(window.isExposed()); + + // The client is now going to ack the configure + QTRY_COMPARE(configureSpy.count(), 1); + QCOMPARE(configureSpy.takeFirst().at(0).toUInt(), serial); + + // And attach a buffer + exec([&] { + Buffer *buffer = xdgToplevel()->surface()->m_committed.buffer; + QVERIFY(buffer); + QCOMPARE(buffer->size(), window.frameGeometry().size()); + }); +} + +void tst_xdgshell::configureSize() +{ + QRasterWindow window; + window.resize(64, 48); + window.show(); + QCOMPOSITOR_TRY_VERIFY(xdgToplevel()); + + QSignalSpy configureSpy(exec([=] { return xdgSurface(); }), &XdgSurface::configureCommitted); + + const QSize configureSize(60, 40); + + exec([=] { + xdgToplevel()->sendCompleteConfigure(configureSize); + }); + + QTRY_COMPARE(configureSpy.count(), 1); + + exec([=] { + Buffer *buffer = xdgToplevel()->surface()->m_committed.buffer; + QVERIFY(buffer); + QCOMPARE(buffer->size(), configureSize); + }); +} + +void tst_xdgshell::configureStates() +{ + QRasterWindow window; + window.resize(64, 48); + window.show(); + QCOMPOSITOR_TRY_VERIFY(xdgToplevel()); + + const QSize windowedSize(320, 240); + const uint windowedSerial = exec([=] { + return xdgToplevel()->sendCompleteConfigure(windowedSize, { XdgToplevel::state_activated }); + }); + QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, windowedSerial); + QCOMPARE(window.visibility(), QWindow::Windowed); + QCOMPARE(window.windowStates(), Qt::WindowNoState); + QCOMPARE(window.frameGeometry().size(), windowedSize); + // Toplevel windows don't know their position on xdg-shell +// QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled + +// QEXPECT_FAIL("", "configure has already been acked, we shouldn't have to wait for isActive", Continue); +// QVERIFY(window.isActive()); + QTRY_VERIFY(window.isActive()); // Just make sure it eventually get's set correctly + + const QSize screenSize(640, 480); + const uint maximizedSerial = exec([=] { + return xdgToplevel()->sendCompleteConfigure(screenSize, { XdgToplevel::state_activated, XdgToplevel::state_maximized }); + }); + QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, maximizedSerial); + QCOMPARE(window.visibility(), QWindow::Maximized); + QCOMPARE(window.windowStates(), Qt::WindowMaximized); + QCOMPARE(window.frameGeometry().size(), screenSize); +// QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled + + const uint fullscreenSerial = exec([=] { + return xdgToplevel()->sendCompleteConfigure(screenSize, { XdgToplevel::state_activated, XdgToplevel::state_fullscreen }); + }); + QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, fullscreenSerial); + QCOMPARE(window.visibility(), QWindow::FullScreen); + QCOMPARE(window.windowStates(), Qt::WindowFullScreen); + QCOMPARE(window.frameGeometry().size(), screenSize); +// QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled + + // The window should remember its original size + const uint restoreSerial = exec([=] { + return xdgToplevel()->sendCompleteConfigure({0, 0}, { XdgToplevel::state_activated }); + }); + QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, restoreSerial); + QCOMPARE(window.visibility(), QWindow::Windowed); + QCOMPARE(window.windowStates(), Qt::WindowNoState); + QCOMPARE(window.frameGeometry().size(), windowedSize); +// QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled +} + +void tst_xdgshell::popup() +{ + class Window : public QRasterWindow { + public: + void mousePressEvent(QMouseEvent *event) override + { + QRasterWindow::mousePressEvent(event); + m_popup.reset(new QRasterWindow); + m_popup->setTransientParent(this); + m_popup->setFlags(Qt::Popup); + m_popup->resize(100, 100); + m_popup->show(); + } + QScopedPointer m_popup; + }; + Window window; + window.resize(200, 200); + window.show(); + + QCOMPOSITOR_TRY_VERIFY(xdgToplevel()); + QSignalSpy toplevelConfigureSpy(exec([=] { return xdgSurface(); }), &XdgSurface::configureCommitted); + exec([=] { xdgToplevel()->sendCompleteConfigure(); }); + QTRY_COMPARE(toplevelConfigureSpy.count(), 1); + + uint clickSerial = exec([=] { + auto *surface = xdgToplevel()->surface(); + auto *p = pointer(); + p->sendEnter(surface, {100, 100}); +// p->sendFrame(); //TODO: uncomment when we support seat v5 + uint serial = p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed); + p->sendButton(client(), BTN_LEFT, Pointer::button_state_released); + return serial; +// p->sendFrame(); //TODO: uncomment when we support seat v5 + }); + + QTRY_VERIFY(window.m_popup); + QCOMPOSITOR_TRY_VERIFY(xdgPopup()); + QSignalSpy popupConfigureSpy(exec([=] { return xdgPopup()->m_xdgSurface; }), &XdgSurface::configureCommitted); + QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_grabbed); + QCOMPOSITOR_TRY_COMPARE(xdgPopup()->m_grabSerial, clickSerial); + + QRasterWindow *popup = window.m_popup.get(); + QVERIFY(!popup->isExposed()); // wait for configure + + //TODO: Verify it works with a different configure window geometry + exec([=] { xdgPopup()->sendConfigure(QRect(100, 100, 100, 100)); }); + + // Nothing should happen before the *xdg_surface* configure + QTRY_VERIFY(!popup->isExposed()); // Popup shouldn't be exposed before the first configure event + QVERIFY(popupConfigureSpy.isEmpty()); + + const uint configureSerial = exec([=] { + return xdgPopup()->m_xdgSurface->sendConfigure(); + }); + + // Finally, we're exposed + QTRY_VERIFY(popup->isExposed()); + + // The client is now going to ack the configure + QTRY_COMPARE(popupConfigureSpy.count(), 1); + QCOMPARE(popupConfigureSpy.takeFirst().at(0).toUInt(), configureSerial); + + // And attach a buffer + exec([&] { + Buffer *buffer = xdgPopup()->surface()->m_committed.buffer; + QVERIFY(buffer); + QCOMPARE(buffer->size(), popup->frameGeometry().size()); + }); +} + +void tst_xdgshell::pongs() +{ + QSignalSpy pongSpy(exec([=] { return get(); }), &XdgWmBase::pong); + // Verify that the client has bound to the global + QCOMPOSITOR_TRY_COMPARE(get()->resourceMap().size(), 1); + const uint serial = exec([=] { return nextSerial(); }); + exec([=] { + auto *base = get(); + wl_resource *resource = base->resourceMap().first()->handle; + base->send_ping(resource, serial); + }); + QTRY_COMPARE(pongSpy.count(), 1); + QCOMPARE(pongSpy.first().at(0).toUInt(), serial); +} + +QCOMPOSITOR_TEST_MAIN(tst_xdgshell) +#include "tst_xdgshell.moc" diff --git a/tests/auto/client/xdgshell/xdgshell.pro b/tests/auto/client/xdgshell/xdgshell.pro new file mode 100644 index 000000000..d7c3f9df6 --- /dev/null +++ b/tests/auto/client/xdgshell/xdgshell.pro @@ -0,0 +1,5 @@ +include (../shared/shared.pri) + +TARGET = tst_xdgshell +SOURCES += tst_xdgshell.cpp + diff --git a/tests/auto/client/xdgshellv6/xdgshellv6.pro b/tests/auto/client/xdgshellv6/xdgshellv6.pro index 4fec593df..cc8a22d83 100644 --- a/tests/auto/client/xdgshellv6/xdgshellv6.pro +++ b/tests/auto/client/xdgshellv6/xdgshellv6.pro @@ -1,4 +1,4 @@ -include (../shared/shared.pri) +include (../shared_old/shared_old.pri) TARGET = tst_client_xdgshellv6 SOURCES += tst_xdgshellv6.cpp -- cgit v1.2.3