diff options
Diffstat (limited to 'tests/auto/client/shared')
28 files changed, 1216 insertions, 436 deletions
diff --git a/tests/auto/client/shared/CMakeLists.txt b/tests/auto/client/shared/CMakeLists.txt new file mode 100644 index 000000000..1d64f2956 --- /dev/null +++ b/tests/auto/client/shared/CMakeLists.txt @@ -0,0 +1,73 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +##Client test shared components: +##################################################################### + +qt_manual_moc(moc_files + mockcompositor.h + coreprotocol.h + corecompositor.h + datadevice.h + fullscreenshellv1.h + fractionalscalev1.h + iviapplication.h + textinput.h + qttextinput.h + viewport.h + xdgdialog.h + xdgoutputv1.h + xdgshell.h +) + +add_library(SharedClientTest + OBJECT + corecompositor.cpp corecompositor.h + coreprotocol.cpp coreprotocol.h + datadevice.cpp datadevice.h + fullscreenshellv1.cpp fullscreenshellv1.h + fractionalscalev1.cpp fractionalscalev1.h + iviapplication.cpp iviapplication.h + mockcompositor.cpp mockcompositor.h + textinput.cpp textinput.h + qttextinput.cpp qttextinput.h + xdgoutputv1.cpp xdgoutputv1.h + xdgshell.cpp xdgshell.h + xdgdialog.cpp xdgdialog.h + viewport.cpp viewport.h + ${moc_files} +) + +qt6_generate_wayland_protocol_server_sources(SharedClientTest + FILES + ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/cursor-shape-v1.xml + ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/fullscreen-shell-unstable-v1.xml + ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/ivi-application.xml + ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/wp-primary-selection-unstable-v1.xml + ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/tablet-unstable-v2.xml + ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/text-input-unstable-v2.xml + ${PROJECT_SOURCE_DIR}/src/extensions/qt-text-input-method-unstable-v1.xml + ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/fractional-scale-v1.xml + ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/viewporter.xml + ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/wayland.xml + ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/xdg-decoration-unstable-v1.xml + ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/xdg-dialog-v1.xml + ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/xdg-output-unstable-v1.xml + ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/xdg-shell.xml +) + +if(QT_FEATURE_opengl) + set(optional_libraries Qt::OpenGL) +endif() + +target_link_libraries(SharedClientTest + PUBLIC + Qt::Gui + ${optional_libraries} + Qt::WaylandClientPrivate + Wayland::Server + Threads::Threads # special case +) + +target_include_directories(SharedClientTest PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/tests/auto/client/shared/corecompositor.cpp b/tests/auto/client/shared/corecompositor.cpp index 7edb1c2d4..d110768ec 100644 --- a/tests/auto/client/shared/corecompositor.cpp +++ b/tests/auto/client/shared/corecompositor.cpp @@ -1,38 +1,14 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "corecompositor.h" +#include <thread> namespace MockCompositor { -CoreCompositor::CoreCompositor() - : m_display(wl_display_create()) - , m_socketName(wl_display_add_socket_auto(m_display)) +CoreCompositor::CoreCompositor(CompositorType t, int socketFd) + : m_type(t) + , m_display(wl_display_create()) , m_eventLoop(wl_display_get_event_loop(m_display)) // Start dispatching @@ -43,6 +19,12 @@ CoreCompositor::CoreCompositor() } }) { + if (socketFd == -1) { + QByteArray socketName = wl_display_add_socket_auto(m_display); + qputenv("WAYLAND_DISPLAY", socketName); + } else { + wl_display_add_socket_fd(m_display, socketFd); + } m_timer.start(); Q_ASSERT(isClean()); } @@ -51,13 +33,15 @@ CoreCompositor::~CoreCompositor() { m_running = false; m_dispatchThread.join(); + wl_display_destroy_clients(m_display); wl_display_destroy(m_display); + qDebug() << "cleanup"; } bool CoreCompositor::isClean() { Lock lock(this); - for (auto *global : qAsConst(m_globals)) { + for (auto *global : std::as_const(m_globals)) { if (!global->isClean()) return false; } @@ -68,18 +52,17 @@ QString CoreCompositor::dirtyMessage() { Lock lock(this); QStringList messages; - for (auto *global : qAsConst(m_globals)) { + for (auto *global : std::as_const(m_globals)) { if (!global->isClean()) messages << (global->metaObject()->className() % QLatin1String(": ") % global->dirtyMessage()); } return messages.join(", "); } -void CoreCompositor::dispatch() +void CoreCompositor::dispatch(int timeout) { Lock lock(this); wl_display_flush_clients(m_display); - constexpr int timeout = 0; // immediate return wl_event_loop_dispatch(m_eventLoop, timeout); } diff --git a/tests/auto/client/shared/corecompositor.h b/tests/auto/client/shared/corecompositor.h index 254465ee6..2df1b5758 100644 --- a/tests/auto/client/shared/corecompositor.h +++ b/tests/auto/client/shared/corecompositor.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef MOCKCOMPOSITOR_CORECOMPOSITOR_H #define MOCKCOMPOSITOR_CORECOMPOSITOR_H @@ -48,11 +23,18 @@ public: class CoreCompositor { public: - explicit CoreCompositor(); + enum CompositorType { + Default, + Legacy // wl-shell + }; + + CompositorType m_type = Default; + explicit CoreCompositor(CompositorType t = Default, int socketFd = -1); + ~CoreCompositor(); bool isClean(); QString dirtyMessage(); - void dispatch(); + void dispatch(int timeout = 0); template<typename function_type, typename... arg_types> auto exec(function_type func, arg_types&&... args) -> decltype(func()) @@ -117,7 +99,7 @@ public: global_type *get() { warnIfNotLockedByThread(Q_FUNC_INFO); - for (auto *global : qAsConst(m_globals)) { + for (auto *global : std::as_const(m_globals)) { if (auto *casted = qobject_cast<global_type *>(global)) return casted; } @@ -131,7 +113,7 @@ public: global_type *get(int index) { warnIfNotLockedByThread(Q_FUNC_INFO); - for (auto *global : qAsConst(m_globals)) { + for (auto *global : std::as_const(m_globals)) { if (auto *casted = qobject_cast<global_type *>(global)) { if (index--) continue; @@ -145,11 +127,11 @@ public: * \brief Returns all globals with the given type, if any */ template<typename global_type> - QVector<global_type *> getAll() + QList<global_type *> getAll() { warnIfNotLockedByThread(Q_FUNC_INFO); - QVector<global_type *> matching; - for (auto *global : qAsConst(m_globals)) { + QList<global_type *> matching; + for (auto *global : std::as_const(m_globals)) { if (auto *casted = qobject_cast<global_type *>(global)) matching.append(casted); } @@ -164,6 +146,7 @@ public: public: // Only use this carefully from the test thread (i.e. lock first) wl_display *m_display = nullptr; + protected: class Lock { public: @@ -196,10 +179,9 @@ protected: CoreCompositor *m_compositor = nullptr; std::thread::id m_threadId; }; - QByteArray m_socketName; wl_event_loop *m_eventLoop = nullptr; bool m_running = true; - QVector<Global *> m_globals; + QList<Global *> m_globals; QElapsedTimer m_timer; private: diff --git a/tests/auto/client/shared/coreprotocol.cpp b/tests/auto/client/shared/coreprotocol.cpp index b0be2cb4e..833ad4b09 100644 --- a/tests/auto/client/shared/coreprotocol.cpp +++ b/tests/auto/client/shared/coreprotocol.cpp @@ -1,36 +1,26 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "coreprotocol.h" #include "datadevice.h" namespace MockCompositor { +Surface::Surface(WlCompositor *wlCompositor, wl_client *client, int id, int version) + : QtWaylandServer::wl_surface(client, id, version) + , m_wlCompositor(wlCompositor) + , m_wlshell(wlCompositor->m_compositor->m_type == CoreCompositor::CompositorType::Legacy) +{ +} + +Surface::~Surface() +{ + // TODO: maybe make sure buffers are released? + qDeleteAll(m_commits); + if (m_wlShellSurface) + m_wlShellSurface->m_surface = nullptr; +} + void Surface::sendFrameCallbacks() { uint time = m_wlCompositor->m_compositor->currentTimeMilliseconds(); @@ -55,6 +45,11 @@ void Surface::sendLeave(Output *output) wl_surface::send_leave(resource()->handle, outputResource->handle); } +void Surface::map() +{ + m_mapped = true; +} + void Surface::surface_destroy_resource(Resource *resource) { Q_UNUSED(resource); @@ -65,14 +60,29 @@ void Surface::surface_destroy_resource(Resource *resource) 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); + wl_resource_destroy(resource->handle); +} + 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>(buffer); - m_pending.commitSpecific.attachOffset = offset; - m_pending.commitSpecific.attached = true; - emit attach(buffer, offset); + if (m_wlshell) { + m_buffer = buffer; + if (!buffer) + m_image = QImage(); + } else { + QPoint offset(x, y); + m_pending.buffer = fromResource<Buffer>(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) @@ -84,32 +94,63 @@ void Surface::surface_set_buffer_scale(QtWaylandServer::wl_surface::Resource *re 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); + if (m_wlshell) { + 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<const uchar *>(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_image = img; + } + } + + for (wl_resource *frameCallback : std::exchange(m_frameCallbackList, {})) { + auto time = m_wlCompositor->m_compositor->currentTimeMilliseconds(); + wl_callback_send_done(frameCallback, time); + wl_resource_destroy(frameCallback); + } + } else { + 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(); + 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); + if (m_wlshell) { + wl_resource *frameCallback = wl_resource_create(resource->client(), &wl_callback_interface, 1, callback); + m_frameCallbackList << frameCallback; + } else { + // 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; + 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; + for (auto *surface : std::as_const(m_surfaces)) { + if (!CursorRole::fromSurface(surface)) { + if (m_compositor->m_type != CoreCompositor::CompositorType::Legacy) + return false; + if (surface->isMapped()) + return false; + } } return true; } @@ -119,7 +160,7 @@ QString WlCompositor::dirtyMessage() if (isClean()) return "clean"; QStringList messages; - for (auto *s : qAsConst(m_surfaces)) { + for (auto *s : std::as_const(m_surfaces)) { QString role = s->m_role ? s->m_role->staticMetaObject.className(): "none/unknown"; messages << "Surface with role: " + role; } @@ -158,6 +199,14 @@ void Output::sendScale(Resource *resource) wl_output::send_scale(resource->handle, m_data.scale); } +void Output::sendDone(wl_client *client) +{ + Q_ASSERT(m_version >= WL_OUTPUT_DONE_SINCE_VERSION); + auto resources = resourceMap().values(client); + for (auto *r : resources) + wl_output::send_done(r->handle); +} + void Output::sendDone() { Q_ASSERT(m_version >= WL_OUTPUT_DONE_SINCE_VERSION); @@ -177,6 +226,8 @@ void Output::output_bind_resource(QtWaylandServer::wl_output::Resource *resource if (m_version >= WL_OUTPUT_DONE_SINCE_VERSION) wl_output::send_done(resource->handle); + + Q_EMIT outputBound(resource); } // Seat stuff @@ -287,12 +338,13 @@ uint Pointer::sendEnter(Surface *surface, const QPointF &position) uint serial = m_seat->m_compositor->nextSerial(); m_enterSerials << serial; - m_cursorRole = nullptr; // According to the protocol, the pointer image is undefined after enter + m_cursorRole.clear(); // According to the protocol, the pointer image is undefined after enter wl_client *client = surface->resource()->client(); const auto pointerResources = resourceMap().values(client); - for (auto *r : pointerResources) + for (auto *r : pointerResources) { wl_pointer::send_enter(r->handle, serial, surface->resource()->handle, x ,y); + } return serial; } @@ -373,18 +425,36 @@ void Pointer::sendFrame(wl_client *client) send_frame(r->handle); } +void Pointer::sendAxisValue120(wl_client *client, QtWaylandServer::wl_pointer::axis axis, int value120) +{ + const auto pointerResources = resourceMap().values(client); + for (auto *r : pointerResources) + send_axis_value120(r->handle, axis, value120); +} + +void Pointer::sendAxisRelativeDirection(wl_client *client, QtWaylandServer::wl_pointer::axis axis, QtWaylandServer::wl_pointer::axis_relative_direction direction) +{ + const auto pointerResources = resourceMap().values(client); + for (auto *r : pointerResources) + send_axis_relative_direction(r->handle, axis, direction); +} + void Pointer::pointer_set_cursor(Resource *resource, uint32_t serial, wl_resource *surface, int32_t hotspot_x, int32_t hotspot_y) { Q_UNUSED(resource); - auto *s = fromResource<Surface>(surface); - QVERIFY(s); - if (s->m_role) { - m_cursorRole = CursorRole::fromSurface(s); - QVERIFY(m_cursorRole); + if (!surface) { + m_cursorRole = nullptr; } else { - m_cursorRole = new CursorRole(s); //TODO: make sure we don't leak CursorRole - s->m_role = m_cursorRole; + auto *s = fromResource<Surface>(surface); + QVERIFY(s); + if (s->m_role) { + m_cursorRole = CursorRole::fromSurface(s); + QVERIFY(m_cursorRole); + } else { + m_cursorRole = new CursorRole(s); //TODO: make sure we don't leak CursorRole + s->m_role = m_cursorRole; + } } // Directly checking the last serial would be racy, we may just have sent leaves/enters which @@ -443,6 +513,13 @@ void Touch::sendFrame(wl_client *client) send_frame(r->handle); } +void Touch::sendCancel(wl_client *client) +{ + const auto touchResources = resourceMap().values(client); + for (auto *r : touchResources) + send_cancel(r->handle); +} + uint Keyboard::sendEnter(Surface *surface) { auto serial = m_seat->m_compositor->nextSerial(); @@ -471,13 +548,14 @@ uint Keyboard::sendKey(wl_client *client, uint key, uint state) auto time = m_seat->m_compositor->currentTimeMilliseconds(); uint serial = m_seat->m_compositor->nextSerial(); const auto pointerResources = resourceMap().values(client); - for (auto *r : pointerResources) + for (auto *r : pointerResources) { send_key(r->handle, serial, time, key, state); + } return serial; } // Shm implementation -Shm::Shm(CoreCompositor *compositor, QVector<format> formats, int version) +Shm::Shm(CoreCompositor *compositor, QList<format> formats, int version) : QtWaylandServer::wl_shm(compositor->m_display, version) , m_compositor(compositor) , m_formats(formats) @@ -489,7 +567,7 @@ Shm::Shm(CoreCompositor *compositor, QVector<format> formats, int version) bool Shm::isClean() { -// for (ShmPool *pool : qAsConst(m_pools)) { +// for (ShmPool *pool : std::as_const(m_pools)) { // //TODO: return false if not cursor buffer // if (pool->m_buffers.isEmpty()) { // return false; @@ -526,4 +604,38 @@ void ShmPool::shm_pool_destroy_resource(Resource *resource) delete this; } +WlShell::WlShell(CoreCompositor *compositor, int version) + : QtWaylandServer::wl_shell(compositor->m_display, version) + , m_compositor(compositor) +{ +} + +void WlShell::shell_get_shell_surface(Resource *resource, uint32_t id, wl_resource *surface) +{ + auto *s = fromResource<Surface>(surface); + auto *wlShellSurface = new WlShellSurface(this, resource->client(), id, s); + m_wlShellSurfaces << wlShellSurface; + emit wlShellSurfaceCreated(wlShellSurface); +} + +WlShellSurface::WlShellSurface(WlShell *wlShell, wl_client *client, int id, Surface *surface) + : QtWaylandServer::wl_shell_surface(client, id, 1) + , m_wlShell(wlShell) + , m_surface(surface) +{ + surface->m_wlShellSurface = this; + surface->map(); +} + +WlShellSurface::~WlShellSurface() +{ + if (m_surface) + m_surface->m_wlShellSurface = nullptr; +} + +void WlShellSurface::sendConfigure(uint32_t edges, int32_t width, int32_t height) +{ + wl_shell_surface::send_configure(edges, width, height); +} + } // namespace MockCompositor diff --git a/tests/auto/client/shared/coreprotocol.h b/tests/auto/client/shared/coreprotocol.h index fe8202ad1..0f59441a3 100644 --- a/tests/auto/client/shared/coreprotocol.h +++ b/tests/auto/client/shared/coreprotocol.h @@ -1,41 +1,20 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef MOCKCOMPOSITOR_COREPROTOCOL_H #define MOCKCOMPOSITOR_COREPROTOCOL_H #include "corecompositor.h" +#include <QtCore/qpointer.h> + #include <qwayland-server-wayland.h> namespace MockCompositor { class WlCompositor; +class WlShell; +class WlShellSurface; class Output; class Pointer; class Touch; @@ -96,18 +75,18 @@ 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? + explicit Surface(WlCompositor *wlCompositor, wl_client *client, int id, int version); + ~Surface() override; void sendFrameCallbacks(); void sendEnter(Output *output); void send_enter(::wl_resource *output) = delete; void sendLeave(Output *output); void send_leave(::wl_resource *output) = delete; + void map(); + bool isMapped() const { return m_mapped; } + WlShellSurface *wlShellSurface() const { return m_wlShellSurface; } + WlCompositor *m_wlCompositor; struct PerCommitData { Callback *frame = nullptr; @@ -120,11 +99,19 @@ public: uint configureSerial = 0; int bufferScale = 1; } m_pending, m_committed; - QVector<DoubleBufferedState *> m_commits; - QVector<Callback *> m_waitingFrameCallbacks; - QVector<Output *> m_outputs; + QList<DoubleBufferedState *> m_commits; + QList<Callback *> m_waitingFrameCallbacks; + QList<Output *> m_outputs; SurfaceRole *m_role = nullptr; + WlShellSurface *m_wlShellSurface = nullptr; + bool m_mapped = false; + QList<wl_resource *> m_frameCallbackList; + + wl_resource *m_buffer = nullptr; + QImage m_image; // checking backingStore + bool m_wlshell = false; + signals: void attach(void *buffer, QPoint offset); void commit(); @@ -132,24 +119,39 @@ signals: protected: void surface_destroy_resource(Resource *resource) override; - void surface_destroy(Resource *resource) override { wl_resource_destroy(resource->handle); } + void surface_destroy(Resource *resource) override; 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 Region : public QtWaylandServer::wl_region +{ +public: + explicit Region(wl_client *client, int id, int version) + : QtWaylandServer::wl_region(client, id, version) + { + } + + void region_destroy_resource(Resource *resource) override + { + Q_UNUSED(resource); + delete this; + } +}; + class WlCompositor : public Global, public QtWaylandServer::wl_compositor { Q_OBJECT public: - explicit WlCompositor(CoreCompositor *compositor, int version = 3) + explicit WlCompositor(CoreCompositor *compositor, int version = 4) : QtWaylandServer::wl_compositor(compositor->m_display, version) , m_compositor(compositor) {} bool isClean() override; QString dirtyMessage() override; - QVector<Surface *> m_surfaces; + QList<Surface *> m_surfaces; CoreCompositor *m_compositor = nullptr; signals: @@ -162,6 +164,51 @@ protected: m_surfaces.append(surface); emit surfaceCreated(surface); } + + void compositor_create_region(Resource *resource, uint32_t id) override + { + new Region(resource->client(), id, resource->version()); + } +}; + +class WlShell : public Global, public QtWaylandServer::wl_shell +{ + Q_OBJECT +public: + explicit WlShell(CoreCompositor *compositor, int version = 1); + QList<WlShellSurface *> m_wlShellSurfaces; + CoreCompositor *m_compositor = nullptr; + +signals: + void wlShellSurfaceCreated(WlShellSurface *wlShellSurface); + +protected: + void shell_get_shell_surface(Resource *resource, uint32_t id, ::wl_resource *surface) override; +}; + +class WlShellSurface : public QObject, public QtWaylandServer::wl_shell_surface +{ + Q_OBJECT +public: + explicit WlShellSurface(WlShell *wlShell, wl_client *client, int id, Surface *surface); + ~WlShellSurface() override; + void sendConfigure(uint32_t edges, int32_t width, int32_t height); + void send_configure(uint32_t edges, int32_t width, int32_t height) = delete; + + void shell_surface_destroy_resource(Resource *) override { delete this; } + + WlShell *m_wlShell = nullptr; + Surface *m_surface = nullptr; +}; + +class Subsurface : public QObject, public QtWaylandServer::wl_subsurface +{ + Q_OBJECT +public: + explicit Subsurface(wl_client *client, int id, int version) + : QtWaylandServer::wl_subsurface(client, id, version) + { + } }; class SubCompositor : public Global, public QtWaylandServer::wl_subcompositor @@ -171,7 +218,20 @@ public: explicit SubCompositor(CoreCompositor *compositor, int version = 1) : QtWaylandServer::wl_subcompositor(compositor->m_display, version) {} - // TODO + QList<Subsurface *> m_subsurfaces; + +signals: + void subsurfaceCreated(Subsurface *subsurface); + +protected: + void subcompositor_get_subsurface(Resource *resource, uint32_t id, ::wl_resource *surface, ::wl_resource *parent) override + { + QTRY_VERIFY(parent); + QTRY_VERIFY(surface); + auto *subsurface = new Subsurface(resource->client(), id, resource->version()); + m_subsurfaces.append(subsurface); // TODO: clean up? + emit subsurfaceCreated(subsurface); + } }; struct OutputMode { @@ -222,6 +282,7 @@ public: void sendScale(int factor); void sendScale(Resource *resource); // Sends current scale to only one client + void sendDone(wl_client *client); void sendDone(); int scale() const { return m_data.scale; } @@ -229,6 +290,9 @@ public: OutputData m_data; int m_version = 1; // TODO: remove on libwayland upgrade +Q_SIGNALS: + void outputBound(Resource *resource); + protected: void output_bind_resource(Resource *resource) override; }; @@ -237,7 +301,7 @@ class Seat : public Global, public QtWaylandServer::wl_seat { Q_OBJECT public: - explicit Seat(CoreCompositor *compositor, uint capabilities = Seat::capability_pointer | Seat::capability_keyboard | Seat::capability_touch, int version = 5); + explicit Seat(CoreCompositor *compositor, uint capabilities = Seat::capability_pointer | Seat::capability_keyboard | Seat::capability_touch, int version = 9); ~Seat() override; void send_capabilities(Resource *resource, uint capabilities) = delete; // Use wrapper instead void send_capabilities(uint capabilities) = delete; // Use wrapper instead @@ -246,13 +310,13 @@ public: CoreCompositor *m_compositor = nullptr; Pointer* m_pointer = nullptr; - QVector<Pointer *> m_oldPointers; + QList<Pointer *> m_oldPointers; Touch* m_touch = nullptr; - QVector<Touch *> m_oldTouchs; + QList<Touch *> m_oldTouchs; Keyboard* m_keyboard = nullptr; - QVector<Keyboard *> m_oldKeyboards; + QList<Keyboard *> m_oldKeyboards; uint m_capabilities = 0; @@ -275,7 +339,7 @@ class Pointer : public QObject, public QtWaylandServer::wl_pointer public: explicit Pointer(Seat *seat) : m_seat(seat) {} Surface *cursorSurface(); - CursorRole* m_cursorRole = nullptr; //TODO: cleanup + QPointer<CursorRole> m_cursorRole; void send_enter() = delete; uint sendEnter(Surface *surface, const QPointF &position); void send_leave() = delete; @@ -287,9 +351,11 @@ public: void sendAxisSource(wl_client *client, axis_source source); void sendAxisStop(wl_client *client, axis axis); void sendFrame(wl_client *client); + void sendAxisValue120(wl_client *client, axis axis, int value120); + void sendAxisRelativeDirection(wl_client *client, axis axis, axis_relative_direction direction); Seat *m_seat = nullptr; - QVector<uint> m_enterSerials; + QList<uint> m_enterSerials; QPoint m_hotspot; signals: @@ -306,6 +372,7 @@ public: explicit CursorRole(Surface *surface) // TODO: needs some more args : m_surface(surface) { + connect(m_surface, &QObject::destroyed, this, &QObject::deleteLater); } static CursorRole *fromSurface(Surface *surface) { return qobject_cast<CursorRole *>(surface->m_role); } Surface *m_surface = nullptr; @@ -320,6 +387,7 @@ public: uint sendUp(wl_client *client, int id); void sendMotion(wl_client *client, const QPointF &position, int id); void sendFrame(wl_client *client); + void sendCancel(wl_client *client); Seat *m_seat = nullptr; }; @@ -341,17 +409,17 @@ class Shm : public Global, public QtWaylandServer::wl_shm { Q_OBJECT public: - explicit Shm(CoreCompositor *compositor, QVector<format> formats = {format_argb8888, format_xrgb8888, format_rgb888}, int version = 1); + explicit Shm(CoreCompositor *compositor, QList<format> formats = {format_argb8888, format_xrgb8888, format_rgb888}, int version = 1); bool isClean() override; CoreCompositor *m_compositor = nullptr; - QVector<ShmPool *> m_pools; - const QVector<format> m_formats; + QList<ShmPool *> m_pools; + const QList<format> 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)) + for (auto format : std::as_const(m_formats)) send_format(resource->handle, format); } }; @@ -362,7 +430,7 @@ class ShmPool : QObject, public QtWaylandServer::wl_shm_pool public: explicit ShmPool(Shm *shm, wl_client *client, int id, int version = 1); Shm *m_shm = nullptr; - QVector<ShmBuffer *> m_buffers; + QList<ShmBuffer *> 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; diff --git a/tests/auto/client/shared/datadevice.cpp b/tests/auto/client/shared/datadevice.cpp index dfa18952c..efb88d0b1 100644 --- a/tests/auto/client/shared/datadevice.cpp +++ b/tests/auto/client/shared/datadevice.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "datadevice.h" @@ -32,7 +7,7 @@ namespace MockCompositor { bool DataDeviceManager::isClean() { - for (auto *device : qAsConst(m_dataDevices)) { + for (auto *device : std::as_const(m_dataDevices)) { // The client should not leak selection offers, i.e. if this fails, there is a missing // data_offer.destroy request if (!device->m_sentSelectionOffers.empty()) @@ -60,6 +35,11 @@ void DataDeviceManager::data_device_manager_get_data_device(Resource *resource, device->add(resource->client(), id, resource->version()); } +void DataDeviceManager::data_device_manager_create_data_source(Resource *resource, uint32_t id) +{ + new QtWaylandServer::wl_data_source(resource->client(), id, 1); +} + DataDevice::~DataDevice() { // If the client(s) hasn't deleted the wayland object, just ignore subsequent events @@ -71,6 +51,7 @@ DataOffer *DataDevice::sendDataOffer(wl_client *client, const QStringList &mimeT { Q_ASSERT(client); auto *offer = new DataOffer(this, client, m_manager->m_version); + m_offer = offer; for (auto *resource : resourceMap().values(client)) wl_data_device::send_data_offer(resource->handle, offer->resource()->handle); for (const auto &mimeType : mimeTypes) @@ -86,6 +67,33 @@ void DataDevice::sendSelection(DataOffer *offer) m_sentSelectionOffers << offer; } +void DataDevice::sendEnter(Surface *surface, const QPoint &position) +{ + uint serial = m_manager->m_compositor->nextSerial(); + Resource *resource = resourceMap().value(surface->resource()->client()); + if (m_offer) + wl_data_device::send_enter(resource->handle, serial, surface->resource()->handle, position.x(), position.y(), m_offer->resource()->handle); +} + +void DataDevice::sendMotion(Surface *surface, const QPoint &position) +{ + uint32_t time = m_manager->m_compositor->nextSerial(); + Resource *resource = resourceMap().value(surface->resource()->client()); + wl_data_device::send_motion(resource->handle, time, position.x(), position.y()); +} + +void DataDevice::sendDrop(Surface *surface) +{ + Resource *resource = resourceMap().value(surface->resource()->client()); + wl_data_device::send_drop(resource->handle); +} + +void DataDevice::sendLeave(Surface *surface) +{ + Resource *resource = resourceMap().value(surface->resource()->client()); + wl_data_device::send_leave(resource->handle); +} + void DataOffer::data_offer_destroy_resource(Resource *resource) { Q_UNUSED(resource); @@ -100,8 +108,7 @@ void DataOffer::data_offer_receive(Resource *resource, const QString &mime_type, void DataOffer::data_offer_destroy(QtWaylandServer::wl_data_offer::Resource *resource) { - bool removed = m_dataDevice->m_sentSelectionOffers.removeOne(this); - QVERIFY(removed); + m_dataDevice->m_sentSelectionOffers.removeOne(this); wl_resource_destroy(resource->handle); } diff --git a/tests/auto/client/shared/datadevice.h b/tests/auto/client/shared/datadevice.h index a96da86f0..356dfa74a 100644 --- a/tests/auto/client/shared/datadevice.h +++ b/tests/auto/client/shared/datadevice.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef MOCKCOMPOSITOR_DATADEVICE_H #define MOCKCOMPOSITOR_DATADEVICE_H @@ -43,6 +18,7 @@ public: explicit DataDeviceManager(CoreCompositor *compositor, int version = 1) : QtWaylandServer::wl_data_device_manager(compositor->m_display, version) , m_version(version) + , m_compositor(compositor) {} ~DataDeviceManager() override { qDeleteAll(m_dataDevices); } bool isClean() override; @@ -50,13 +26,16 @@ public: int m_version = 1; // TODO: remove on libwayland upgrade QMap<Seat *, DataDevice *> m_dataDevices; + CoreCompositor *m_compositor; protected: void data_device_manager_get_data_device(Resource *resource, uint32_t id, ::wl_resource *seatResource) override; + void data_device_manager_create_data_source(Resource *resource, uint32_t id) override; }; -class DataDevice : public QtWaylandServer::wl_data_device +class DataDevice : public QObject, public QtWaylandServer::wl_data_device { + Q_OBJECT public: explicit DataDevice(DataDeviceManager *manager, Seat *seat) : m_manager(manager) @@ -65,16 +44,41 @@ public: ~DataDevice() override; void send_data_offer(::wl_resource *resource) = delete; DataOffer *sendDataOffer(::wl_client *client, const QStringList &mimeTypes = {}); - DataOffer *sendDataOffer(const QStringList &mimeTypes = {}); void send_selection(::wl_resource *resource) = delete; void sendSelection(DataOffer *offer); + void send_enter(uint32_t serial, ::wl_resource *surface, wl_fixed_t x, wl_fixed_t y, ::wl_resource *id) = delete; + void sendEnter(Surface *surface, const QPoint& position); + + void send_motion(uint32_t time, wl_fixed_t x, wl_fixed_t y) = delete; + void sendMotion(Surface *surface, const QPoint &position); + + void send_drop(::wl_resource *resource) = delete; + void sendDrop(Surface *surface); + + void send_leave(::wl_resource *resource) = delete; + void sendLeave(Surface *surface); + DataDeviceManager *m_manager = nullptr; Seat *m_seat = nullptr; - QVector<DataOffer *> m_sentSelectionOffers; + QList<DataOffer *> m_sentSelectionOffers; + QPointer<DataOffer> m_offer; + +signals: + void dragStarted(); protected: + void data_device_start_drag(Resource *resource, ::wl_resource *source, ::wl_resource *origin, ::wl_resource *icon, uint32_t serial) override + { + Q_UNUSED(resource); + Q_UNUSED(source); + Q_UNUSED(origin); + Q_UNUSED(icon); + Q_UNUSED(serial); + emit dragStarted(); + } + void data_device_release(Resource *resource) override { int removed = m_manager->m_dataDevices.remove(m_seat); diff --git a/tests/auto/client/shared/fractionalscalev1.cpp b/tests/auto/client/shared/fractionalscalev1.cpp new file mode 100644 index 000000000..28c778025 --- /dev/null +++ b/tests/auto/client/shared/fractionalscalev1.cpp @@ -0,0 +1,40 @@ +// Copyright (C) 2022 David Edmundson <davidedmundson@kde.org> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "fractionalscalev1.h" + +namespace MockCompositor { + +FractionalScaleManager::FractionalScaleManager(CoreCompositor *compositor, int version) + : QtWaylandServer::wp_fractional_scale_manager_v1(compositor->m_display, version) +{ +} + +void FractionalScaleManager::wp_fractional_scale_manager_v1_get_fractional_scale(Resource *resource, uint32_t id, wl_resource *surface) +{ + auto *s = fromResource<Surface>(surface); + auto *scaler = new FractionalScale(s, resource->client(), id, resource->version()); + connect(scaler, &QObject::destroyed, this, [this, scaler]() { + m_fractionalScales.removeOne(scaler); + }); + m_fractionalScales << scaler; +} + +FractionalScale::FractionalScale(Surface *surface, wl_client *client, int id, int version) + : QtWaylandServer::wp_fractional_scale_v1(client, id, version) + , m_surface(surface) +{ +} + +void FractionalScale::wp_fractional_scale_v1_destroy_resource(Resource *resource) +{ + Q_UNUSED(resource) + delete this; +} + +void FractionalScale::wp_fractional_scale_v1_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +} diff --git a/tests/auto/client/shared/fractionalscalev1.h b/tests/auto/client/shared/fractionalscalev1.h new file mode 100644 index 000000000..1ae2fad1f --- /dev/null +++ b/tests/auto/client/shared/fractionalscalev1.h @@ -0,0 +1,39 @@ +// Copyright (C) 2022 David Edmundson <davidedmundson@kde.org> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef MOCKCOMPOSITOR_FRACTIONALSCALE_H +#define MOCKCOMPOSITOR_FRACTIONALSCALE_H + +#include "coreprotocol.h" +#include <qwayland-server-fractional-scale-v1.h> + +namespace MockCompositor { + +class FractionalScale; + +class FractionalScaleManager : public Global, public QtWaylandServer::wp_fractional_scale_manager_v1 +{ + Q_OBJECT +public: + explicit FractionalScaleManager(CoreCompositor *compositor, int version = 1); + QList<FractionalScale *> m_fractionalScales; + +protected: + void wp_fractional_scale_manager_v1_get_fractional_scale(Resource *resource, uint32_t id, wl_resource *surface) override; +}; + +class FractionalScale : public QObject, public QtWaylandServer::wp_fractional_scale_v1 +{ + Q_OBJECT +public: + explicit FractionalScale(Surface *surface, wl_client *client, int id, int version); + Surface *m_surface; + +protected: + void wp_fractional_scale_v1_destroy_resource(Resource *resource) override; + void wp_fractional_scale_v1_destroy(Resource *resource) override; +}; + +} + +#endif diff --git a/tests/auto/client/shared/fullscreenshellv1.cpp b/tests/auto/client/shared/fullscreenshellv1.cpp new file mode 100644 index 000000000..24468e14b --- /dev/null +++ b/tests/auto/client/shared/fullscreenshellv1.cpp @@ -0,0 +1,22 @@ +// Copyright (C) 2021 David Edmundson <davidedmundson@kde.org> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "fullscreenshellv1.h" + +namespace MockCompositor { + +FullScreenShellV1::FullScreenShellV1(CoreCompositor *compositor) +{ + init(compositor->m_display, 1); +} + +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(fromResource<Surface>(surface)); +} + +} // namespace MockCompositor diff --git a/tests/auto/client/shared/fullscreenshellv1.h b/tests/auto/client/shared/fullscreenshellv1.h new file mode 100644 index 000000000..02ebf1e0c --- /dev/null +++ b/tests/auto/client/shared/fullscreenshellv1.h @@ -0,0 +1,34 @@ +// Copyright (C) 2021 David Edmundson <davidedmundson@kde.org> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef MOCKCOMPOSITOR_FULLSCREENSHELLV1_H +#define MOCKCOMPOSITOR_FULLSCREENSHELLV1_H + +#include "coreprotocol.h" +#include <qwayland-server-fullscreen-shell-unstable-v1.h> + +#include <QList> + +namespace MockCompositor { + +class Surface; +class FullScreenShellV1; + +class FullScreenShellV1 : public Global, public QtWaylandServer::zwp_fullscreen_shell_v1 +{ + Q_OBJECT +public: + explicit FullScreenShellV1(CoreCompositor *compositor); + + QList<Surface *> surfaces() const { return m_surfaces; } + +protected: + void zwp_fullscreen_shell_v1_present_surface(Resource *resource, struct ::wl_resource *surface, uint32_t method, struct ::wl_resource *output) override; + +private: + QList<Surface *> m_surfaces; +}; + +} // namespace MockCompositor + +#endif // MOCKCOMPOSITOR_FULLSCREENSHELLV1_H diff --git a/tests/auto/client/shared/iviapplication.cpp b/tests/auto/client/shared/iviapplication.cpp new file mode 100644 index 000000000..f4f167600 --- /dev/null +++ b/tests/auto/client/shared/iviapplication.cpp @@ -0,0 +1,45 @@ +// Copyright (C) 2021 David Edmundson <davidedmundson@kde.org> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "iviapplication.h" + +namespace MockCompositor { + +IviApplication::IviApplication(CoreCompositor *compositor) +{ + init(compositor->m_display, 1); +} + +void IviApplication::ivi_application_surface_create(Resource *resource, uint32_t ivi_id, struct ::wl_resource *surface, uint32_t id) +{ + auto *s = fromResource<Surface>(surface); + auto *iviSurface = new IviSurface(this, s, ivi_id, resource->client(), id, resource->version()); + m_iviSurfaces << iviSurface; + qDebug() << "count is " << m_iviSurfaces.size(); +} + +IviSurface::IviSurface(IviApplication *iviApplication, Surface *surface, uint32_t ivi_id, wl_client *client, int id, int version) + : QtWaylandServer::ivi_surface(client, id, version) + , m_iviId(ivi_id) + , m_iviApplication(iviApplication) + , m_surface(surface) +{ + surface->map(); +} + +void IviSurface::ivi_surface_destroy_resource(Resource *resource) +{ + Q_UNUSED(resource); + bool removed = m_iviApplication->m_iviSurfaces.removeOne(this); + Q_ASSERT(removed); + qDebug() << "destroy"; + + delete this; +} + +void IviSurface::ivi_surface_destroy(QtWaylandServer::ivi_surface::Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +} // namespace MockCompositor diff --git a/tests/auto/client/shared/iviapplication.h b/tests/auto/client/shared/iviapplication.h new file mode 100644 index 000000000..1644d0cfd --- /dev/null +++ b/tests/auto/client/shared/iviapplication.h @@ -0,0 +1,50 @@ +// Copyright (C) 2021 David Edmundson <davidedmundson@kde.org> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef MOCKCOMPOSITOR_IVIAPPLICATION_H +#define MOCKCOMPOSITOR_IVIAPPLICATION_H + +#include "coreprotocol.h" +#include <qwayland-server-ivi-application.h> + +#include <QList> + +namespace MockCompositor { + +class Surface; +class IviApplication; +class IviSurface; + +class IviApplication : public Global, public QtWaylandServer::ivi_application +{ + Q_OBJECT +public: + explicit IviApplication(CoreCompositor *compositor); + + QList<IviSurface *> m_iviSurfaces; +protected: + void ivi_application_surface_create(Resource *resource, uint32_t ivi_id, struct ::wl_resource *surface, uint32_t id) override; + +}; + +class IviSurface : public QObject, public QtWaylandServer::ivi_surface +{ + Q_OBJECT +public: + IviSurface(IviApplication *iviApplication, Surface *surface, uint32_t ivi_id, wl_client *client, int id, int version); + + Surface *surface() const { return m_surface; } + + void ivi_surface_destroy_resource(Resource *resource) override; + void ivi_surface_destroy(Resource *resource) override; + + const uint m_iviId = 0; +private: + IviApplication *m_iviApplication; + Surface *m_surface = nullptr; +}; + + +} // namespace MockCompositor + +#endif // MOCKCOMPOSITOR_IVIAPPLICATION_H diff --git a/tests/auto/client/shared/mockcompositor.cpp b/tests/auto/client/shared/mockcompositor.cpp index 5f2d89078..bbf406d64 100644 --- a/tests/auto/client/shared/mockcompositor.cpp +++ b/tests/auto/client/shared/mockcompositor.cpp @@ -1,36 +1,13 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2021 David Edmundson <davidedmundson@kde.org> +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "mockcompositor.h" namespace MockCompositor { -DefaultCompositor::DefaultCompositor() +DefaultCompositor::DefaultCompositor(CompositorType t, int socketFd) + : CoreCompositor(t, socketFd) { { Lock l(this); @@ -42,33 +19,71 @@ DefaultCompositor::DefaultCompositor() auto *output = add<Output>(); output->m_data.physicalSize = output->m_data.mode.physicalSizeForDpi(96); add<Seat>(Seat::capability_pointer | Seat::capability_keyboard | Seat::capability_touch); + add<WlShell>(); add<XdgWmBase>(); - add<Shm>(); + add<FractionalScaleManager>(); + add<Viewporter>(); + add<XdgWmDialog>(); + + switch (m_type) { + case CompositorType::Default: + add<Shm>(); + break; + case CompositorType::Legacy: + wl_display_init_shm(m_display); + break; + } + add<FullScreenShellV1>(); + add<IviApplication>(); + // TODO: other shells, viewporter, xdgoutput etc - QObject::connect(get<WlCompositor>(), &WlCompositor::surfaceCreated, [&] (Surface *surface){ - QObject::connect(surface, &Surface::bufferCommitted, [=] { + QObject::connect(get<WlCompositor>(), &WlCompositor::surfaceCreated, [this] (Surface *surface){ + QObject::connect(surface, &Surface::bufferCommitted, [this, surface] { 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()) + if (m_config.autoFrameCallback) { + surface->sendFrameCallbacks(); + } + if (m_config.autoEnter && get<Output>() && surface->m_outputs.empty()) surface->sendEnter(get<Output>()); wl_display_flush_clients(m_display); }); }); - QObject::connect(get<XdgWmBase>(), &XdgWmBase::toplevelCreated, [&] (XdgToplevel *toplevel) { - // Needed because lambdas don't support Qt::DirectConnection - exec([&]{ - if (m_config.autoConfigure) - toplevel->sendCompleteConfigure(); - }); - }); + QObject::connect(get<XdgWmBase>(), &XdgWmBase::toplevelCreated, get<XdgWmBase>(), [this] (XdgToplevel *toplevel) { + if (m_config.autoConfigure) + toplevel->sendCompleteConfigure(); + }, Qt::DirectConnection); } Q_ASSERT(isClean()); } +Surface *DefaultCompositor::surface(int i) +{ + QList<Surface *> surfaces; + switch (m_type) { + case CompositorType::Default: + return get<WlCompositor>()->m_surfaces.value(i, nullptr); + case CompositorType::Legacy: { + QList<Surface *> msurfaces = get<WlCompositor>()->m_surfaces; + for (Surface *surface : msurfaces) { + if (surface->isMapped()) { + surfaces << surface; + } + } + } + break; + } + + if (i >= 0 && i < surfaces.size()) + return surfaces[i]; + + return nullptr; +} + uint DefaultCompositor::sendXdgShellPing() { warnIfNotLockedByThread(Q_FUNC_INFO); @@ -82,10 +97,47 @@ uint DefaultCompositor::sendXdgShellPing() void DefaultCompositor::xdgPingAndWaitForPong() { - QSignalSpy pongSpy(exec([=] { return get<XdgWmBase>(); }), &XdgWmBase::pong); - uint serial = exec([=] { return sendXdgShellPing(); }); - QTRY_COMPARE(pongSpy.count(), 1); + QSignalSpy pongSpy(exec([&] { return get<XdgWmBase>(); }), &XdgWmBase::pong); + uint serial = exec([&] { return sendXdgShellPing(); }); + QTRY_COMPARE(pongSpy.size(), 1); QTRY_COMPARE(pongSpy.first().at(0).toUInt(), serial); } +void DefaultCompositor::sendShellSurfaceConfigure(Surface *surface) +{ + switch (m_type) { + case CompositorType::Default: + break; + case CompositorType::Legacy: { + if (auto wlShellSurface = surface->wlShellSurface()) { + wlShellSurface->sendConfigure(0, 0, 0); + return; + } + break; + } + } + + qWarning() << "The mocking framework doesn't know how to send a configure event for this surface"; +} + +WlShellCompositor::WlShellCompositor(CompositorType t) + : DefaultCompositor(t) +{ +} + +Surface *DefaultCompositor::wlSurface(int i) +{ + QList<Surface *> surfaces, msurfaces; + msurfaces = get<WlCompositor>()->m_surfaces; + for (Surface *surface : msurfaces) { + if (surface->isMapped()) + surfaces << surface; + } + + if (i >=0 && i < surfaces.size()) + return surfaces[i]; + + return nullptr; +} + } // namespace MockCompositor diff --git a/tests/auto/client/shared/mockcompositor.h b/tests/auto/client/shared/mockcompositor.h index fc4d7cc46..9a2c06a17 100644 --- a/tests/auto/client/shared/mockcompositor.h +++ b/tests/auto/client/shared/mockcompositor.h @@ -1,30 +1,6 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2021 David Edmundson <davidedmundson@kde.org> +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef MOCKCOMPOSITOR_H #define MOCKCOMPOSITOR_H @@ -32,7 +8,12 @@ #include "corecompositor.h" #include "coreprotocol.h" #include "datadevice.h" +#include "fullscreenshellv1.h" +#include "iviapplication.h" #include "xdgshell.h" +#include "viewport.h" +#include "fractionalscalev1.h" +#include "xdgdialog.h" #include <QtGui/QGuiApplication> @@ -52,10 +33,13 @@ namespace MockCompositor { class DefaultCompositor : public CoreCompositor { public: - explicit DefaultCompositor(); + explicit DefaultCompositor(CompositorType t = CompositorType::Default, int socketFd = -1); // Convenience functions Output *output(int i = 0) { return getAll<Output>().value(i, nullptr); } - Surface *surface(int i = 0) { return get<WlCompositor>()->m_surfaces.value(i, nullptr); } + Surface *surface(int i = 0); + Subsurface *subSurface(int i = 0) { return get<SubCompositor>()->m_subsurfaces.value(i, nullptr); } + WlShellSurface *wlShellSurface(int i = 0) { return get<WlShell>()->m_wlShellSurfaces.value(i, nullptr); } + Surface *wlSurface(int i = 0); XdgSurface *xdgSurface(int i = 0) { return get<XdgWmBase>()->m_xdgSurfaces.value(i, nullptr); } XdgToplevel *xdgToplevel(int i = 0) { return get<XdgWmBase>()->toplevel(i); } XdgPopup *xdgPopup(int i = 0) { return get<XdgWmBase>()->popup(i); } @@ -63,17 +47,33 @@ public: Touch *touch() { auto *seat = get<Seat>(); Q_ASSERT(seat); return seat->m_touch; } Surface *cursorSurface() { auto *p = pointer(); return p ? p->cursorSurface() : nullptr; } Keyboard *keyboard() { auto *seat = get<Seat>(); Q_ASSERT(seat); return seat->m_keyboard; } + FullScreenShellV1 *fullScreenShellV1() {return get<FullScreenShellV1>();}; + IviSurface *iviSurface(int i = 0) { return get<IviApplication>()->m_iviSurfaces.value(i, nullptr); } + FractionalScale *fractionalScale(int i = 0) {return get<FractionalScaleManager>()->m_fractionalScales.value(i, nullptr); } + Viewport *viewport(int i = 0) {return get<Viewporter>()->m_viewports.value(i, nullptr); } + XdgDialog *xdgDialog(int i = 0) { return get<XdgWmDialog>()->m_dialogs.value(i, nullptr); } + uint sendXdgShellPing(); void xdgPingAndWaitForPong(); + + void sendShellSurfaceConfigure(Surface *surface); + // 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; + bool autoFrameCallback = true; } m_config; void resetConfig() { exec([&] { m_config = Config{}; }); } }; +class WlShellCompositor : public DefaultCompositor +{ +public: + explicit WlShellCompositor(CompositorType t = CompositorType::Legacy); +}; + } // namespace MockCompositor #define QCOMPOSITOR_VERIFY(expr) QVERIFY(exec([&]{ return expr; })) @@ -84,11 +84,13 @@ public: #define QCOMPOSITOR_TEST_MAIN(test) \ int main(int argc, char **argv) \ { \ - setenv("XDG_RUNTIME_DIR", ".", 1); \ + QTemporaryDir tmpRuntimeDir; \ + setenv("XDG_RUNTIME_DIR", tmpRuntimeDir.path().toLocal8Bit(), 1); \ setenv("XDG_CURRENT_DESKTOP", "qtwaylandtests", 1); \ setenv("QT_QPA_PLATFORM", "wayland", 1); \ test tc; \ QGuiApplication app(argc, argv); \ + QTEST_SET_MAIN_SOURCE_PATH \ return QTest::qExec(&tc, argc, argv); \ } \ diff --git a/tests/auto/client/shared/qttextinput.cpp b/tests/auto/client/shared/qttextinput.cpp new file mode 100644 index 000000000..1fb5ef1c4 --- /dev/null +++ b/tests/auto/client/shared/qttextinput.cpp @@ -0,0 +1,20 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "qttextinput.h" + +namespace MockCompositor { + +QtTextInputManager::QtTextInputManager(CoreCompositor *compositor) +{ + init(compositor->m_display, 1); +} + +void QtTextInputManager::text_input_method_manager_v1_get_text_input_method(Resource *resource, uint32_t id, wl_resource *seatResource) +{ + Q_UNUSED(resource); + Q_UNUSED(id); + Q_UNUSED(seatResource); +} + +} // namespace MockCompositor diff --git a/tests/auto/client/shared/qttextinput.h b/tests/auto/client/shared/qttextinput.h new file mode 100644 index 000000000..047cec7d3 --- /dev/null +++ b/tests/auto/client/shared/qttextinput.h @@ -0,0 +1,26 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef MOCKCOMPOSITOR_QTTEXTINPUT_H +#define MOCKCOMPOSITOR_QTTEXTINPUT_H + +#include "coreprotocol.h" +#include <qwayland-server-qt-text-input-method-unstable-v1.h> + +#include <QtGui/qpa/qplatformnativeinterface.h> + +namespace MockCompositor { + +class QtTextInputManager : public Global, public QtWaylandServer::qt_text_input_method_manager_v1 +{ + Q_OBJECT +public: + QtTextInputManager(CoreCompositor *compositor); + +protected: + void text_input_method_manager_v1_get_text_input_method(Resource *resource, uint32_t id, struct ::wl_resource *seatResource) override; +}; + +} // namespace MockCompositor + +#endif // MOCKCOMPOSITOR_QTTEXTINPUT_H diff --git a/tests/auto/client/shared/shared.pri b/tests/auto/client/shared/shared.pri index c86183b3d..97202e787 100644 --- a/tests/auto/client/shared/shared.pri +++ b/tests/auto/client/shared/shared.pri @@ -1,9 +1,10 @@ -QT += testlib waylandclient-private +QT += testlib waylandclient-private opengl CONFIG += testcase wayland-scanner QMAKE_USE += wayland-server WAYLANDSERVERSOURCES += \ $$PWD/../../../../src/3rdparty/protocol/wayland.xml \ + $$PWD/../../../../src/3rdparty/protocol/xdg-output-unstable-v1.xml \ $$PWD/../../../../src/3rdparty/protocol/xdg-shell.xml \ $$PWD/../../../../src/3rdparty/protocol/text-input-unstable-v2.xml @@ -14,6 +15,7 @@ HEADERS += \ $$PWD/coreprotocol.h \ $$PWD/datadevice.h \ $$PWD/mockcompositor.h \ + $$PWD/xdgoutputv1.h \ $$PWD/xdgshell.h \ $$PWD/textinput.h @@ -22,5 +24,6 @@ SOURCES += \ $$PWD/coreprotocol.cpp \ $$PWD/datadevice.cpp \ $$PWD/mockcompositor.cpp \ + $$PWD/xdgoutputv1.cpp \ $$PWD/xdgshell.cpp \ $$PWD/textinput.cpp diff --git a/tests/auto/client/shared/textinput.cpp b/tests/auto/client/shared/textinput.cpp index f9fd287bb..fc4865d71 100644 --- a/tests/auto/client/shared/textinput.cpp +++ b/tests/auto/client/shared/textinput.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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$ -** -****************************************************************************/ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "textinput.h" @@ -37,9 +12,8 @@ TextInputManager::TextInputManager(CoreCompositor *compositor) void TextInputManager::zwp_text_input_manager_v2_get_text_input(Resource *resource, uint32_t id, wl_resource *seatResource) { - Q_UNUSED(resource); - Q_UNUSED(id); Q_UNUSED(seatResource); + add(resource->client(), id, resource->version()); } } // namespace MockCompositor diff --git a/tests/auto/client/shared/textinput.h b/tests/auto/client/shared/textinput.h index 85072e74b..ca20ddbad 100644 --- a/tests/auto/client/shared/textinput.h +++ b/tests/auto/client/shared/textinput.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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$ -** -****************************************************************************/ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef MOCKCOMPOSITOR_TEXTINPUT_H #define MOCKCOMPOSITOR_TEXTINPUT_H diff --git a/tests/auto/client/shared/viewport.cpp b/tests/auto/client/shared/viewport.cpp new file mode 100644 index 000000000..df6bbb336 --- /dev/null +++ b/tests/auto/client/shared/viewport.cpp @@ -0,0 +1,58 @@ +// Copyright (C) 2022 David Edmundson <davidedmundson@kde.org> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "viewport.h" + +namespace MockCompositor { + +Viewporter::Viewporter(CoreCompositor *compositor, int version) + : QtWaylandServer::wp_viewporter(compositor->m_display, version) +{ +} + +void Viewporter::wp_viewporter_get_viewport(Resource *resource, uint32_t id, wl_resource *surface) +{ + auto *s = fromResource<Surface>(surface); + auto *viewport = new Viewport(s, resource->client(), id, resource->version()); + connect(viewport, &QObject::destroyed, this, [this, viewport]() { + m_viewports.removeOne(viewport); + }); + m_viewports << viewport; +} + +Viewport::Viewport(Surface *surface, wl_client *client, int id, int version) + : QtWaylandServer::wp_viewport(client, id, version) + , m_surface(surface) +{ +} + +void Viewport::wp_viewport_set_source(Resource *resource, wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height) +{ + Q_UNUSED(resource) + m_source = QRectF(wl_fixed_to_double(x), + wl_fixed_to_double(y), + wl_fixed_to_double(width), + wl_fixed_to_double(height)); + Q_EMIT sourceChanged(); +} + +void Viewport::wp_viewport_set_destination(Resource *resource, int32_t width, int32_t height) +{ + Q_UNUSED(resource) + + m_destination = QSize(width, height); + Q_EMIT destinationChanged(); +} + +void Viewport::wp_viewport_destroy_resource(Resource *resource) +{ + Q_UNUSED(resource) + delete this; +} + +void Viewport::wp_viewport_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +} diff --git a/tests/auto/client/shared/viewport.h b/tests/auto/client/shared/viewport.h new file mode 100644 index 000000000..ddc4297db --- /dev/null +++ b/tests/auto/client/shared/viewport.h @@ -0,0 +1,50 @@ +// Copyright (C) 2022 David Edmundson <davidedmundson@kde.org> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef MOCKCOMPOSITOR_VIEWPORT_H +#define MOCKCOMPOSITOR_VIEWPORT_H + +#include "coreprotocol.h" +#include <qwayland-server-viewporter.h> + +namespace MockCompositor { + +class Viewport; + +class Viewporter : public Global, public QtWaylandServer::wp_viewporter +{ + Q_OBJECT +public: + explicit Viewporter(CoreCompositor *compositor, int version = 1); + QList<Viewport *> m_viewports; + +protected: + void wp_viewporter_get_viewport(Resource *resource, uint32_t id, wl_resource *surface) override; +}; + +class Viewport : public QObject, public QtWaylandServer::wp_viewport +{ + Q_OBJECT +public: + explicit Viewport(Surface *surface, wl_client *client, int id, int version); + + QRectF m_source; + QSize m_destination; + + Surface* m_surface; + +Q_SIGNALS: + void sourceChanged(); + void destinationChanged(); + +protected: + void wp_viewport_set_source(Resource *resource, wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height) override; + void wp_viewport_set_destination(Resource *resource, int32_t width, int32_t height) override; + + void wp_viewport_destroy_resource(Resource *resource) override; + void wp_viewport_destroy(Resource *resource) override; +}; + +} + +#endif diff --git a/tests/auto/client/shared/xdgdialog.cpp b/tests/auto/client/shared/xdgdialog.cpp new file mode 100644 index 000000000..b973415bd --- /dev/null +++ b/tests/auto/client/shared/xdgdialog.cpp @@ -0,0 +1,59 @@ +// Copyright (C) 2024 David Redondo <kde@david-redondo.de> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only +#include "xdgdialog.h" + +#include "xdgshell.h" + +namespace MockCompositor { + +XdgDialog::XdgDialog(XdgWmDialog *wm, XdgToplevel *toplevel, wl_client *client, int id, int version) + : QtWaylandServer::xdg_dialog_v1(client, id, version), + toplevel(toplevel), + modal(false), + m_wm(wm) +{ +} + +void XdgDialog::xdg_dialog_v1_set_modal(Resource *resource) +{ + Q_UNUSED(resource) + modal = true; +} + +void XdgDialog::xdg_dialog_v1_unset_modal(Resource *resource) +{ + Q_UNUSED(resource) + modal = false; +} + +void XdgDialog::xdg_dialog_v1_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +void XdgDialog::xdg_dialog_v1_destroy_resource(Resource *resource) +{ + Q_UNUSED(resource) + m_wm->m_dialogs.removeOne(this); + delete this; +} + +XdgWmDialog::XdgWmDialog(CoreCompositor *compositor, int version) + : QtWaylandServer::xdg_wm_dialog_v1(compositor->m_display, version) +{ +} + +void XdgWmDialog::xdg_wm_dialog_v1_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +void XdgWmDialog::xdg_wm_dialog_v1_get_xdg_dialog(Resource *resource, uint32_t id, + struct ::wl_resource *toplevel) +{ + auto *t = fromResource<XdgToplevel>(toplevel); + auto *dialog = new XdgDialog(this, t, resource->client(), id, resource->version()); + m_dialogs.push_back(dialog); +} + +} // namespace MockCompositor diff --git a/tests/auto/client/shared/xdgdialog.h b/tests/auto/client/shared/xdgdialog.h new file mode 100644 index 000000000..d9e3de996 --- /dev/null +++ b/tests/auto/client/shared/xdgdialog.h @@ -0,0 +1,49 @@ +// Copyright (C) 2024 David Redondo <kde@david-redondo.de> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef MOCKCOMPOSITOR_XDG_DIALOG_H +#define MOCKCOMPOSITOR_XDG_DIALOG_H + +#include "corecompositor.h" +#include <qwayland-server-xdg-dialog-v1.h> + +namespace MockCompositor { + +class XdgToplevel; +class XdgWmDialog; + +class XdgDialog : public QtWaylandServer::xdg_dialog_v1 +{ +public: + explicit XdgDialog(XdgWmDialog *wm, XdgToplevel *toplevel, wl_client *client, int id, + int version); + XdgToplevel *toplevel; + bool modal; + +protected: + void xdg_dialog_v1_set_modal(Resource *resource) override; + void xdg_dialog_v1_unset_modal(Resource *resource) override; + void xdg_dialog_v1_destroy(Resource *resource) override; + void xdg_dialog_v1_destroy_resource(Resource *resource) override; + +private: + XdgWmDialog *m_wm; +}; + +class XdgWmDialog : public Global, public QtWaylandServer::xdg_wm_dialog_v1 +{ + Q_OBJECT +public: + explicit XdgWmDialog(CoreCompositor *compositor, int version = 1); + ~XdgWmDialog() = default; + QList<XdgDialog *> m_dialogs; + +protected: + void xdg_wm_dialog_v1_destroy(Resource *resource) override; + void xdg_wm_dialog_v1_get_xdg_dialog(Resource *resource, uint32_t id, + struct ::wl_resource *toplevel) override; +}; + +} // namespace MockCompositor + +#endif diff --git a/tests/auto/client/shared/xdgoutputv1.cpp b/tests/auto/client/shared/xdgoutputv1.cpp new file mode 100644 index 000000000..af72ae2eb --- /dev/null +++ b/tests/auto/client/shared/xdgoutputv1.cpp @@ -0,0 +1,34 @@ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "xdgoutputv1.h" + +namespace MockCompositor { + +int XdgOutputV1::s_nextId = 1; + +void XdgOutputV1::sendLogicalSize(const QSize &size) +{ + m_logicalGeometry.setSize(size); + for (auto *resource : resourceMap()) + zxdg_output_v1::send_logical_size(resource->handle, size.width(), size.height()); +} + +void XdgOutputV1::addResource(wl_client *client, int id, int version) +{ + auto *resource = add(client, id, version)->handle; + zxdg_output_v1::send_logical_size(resource, m_logicalGeometry.width(), m_logicalGeometry.height()); + send_logical_position(resource, m_logicalGeometry.x(), m_logicalGeometry.y()); + if (version >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) + send_name(resource, m_name); + if (version >= ZXDG_OUTPUT_V1_DESCRIPTION_SINCE_VERSION) + send_description(resource, m_description); + + if (version < 3) // zxdg_output_v1.done has been deprecated + zxdg_output_v1::send_done(resource); + else { + m_output->sendDone(client); + } +} + +} // namespace MockCompositor diff --git a/tests/auto/client/shared/xdgoutputv1.h b/tests/auto/client/shared/xdgoutputv1.h new file mode 100644 index 000000000..8c6276741 --- /dev/null +++ b/tests/auto/client/shared/xdgoutputv1.h @@ -0,0 +1,63 @@ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef MOCKCOMPOSITOR_XDGOUTPUTV1_H +#define MOCKCOMPOSITOR_XDGOUTPUTV1_H + +#include "coreprotocol.h" + +#include <qwayland-server-xdg-output-unstable-v1.h> + +namespace MockCompositor { + +class XdgOutputV1 : public QObject, public QtWaylandServer::zxdg_output_v1 +{ +public: + explicit XdgOutputV1(Output *output) + : m_output(output) + , m_logicalGeometry(m_output->m_data.position, QSize(m_output->m_data.mode.resolution / m_output->m_data.scale)) + , m_name(QString("WL-%1").arg(s_nextId++)) + {} + + void send_logical_size(int32_t width, int32_t height) = delete; + void sendLogicalSize(const QSize &size); + + void send_done() = delete; // zxdg_output_v1.done has been deprecated (in protocol version 3) + + void addResource(wl_client *client, int id, int version); + Output *m_output = nullptr; + QRect m_logicalGeometry; + QString m_name; + QString m_description = "This is an Xdg Output description"; + static int s_nextId; +}; + +class XdgOutputManagerV1 : public Global, public QtWaylandServer::zxdg_output_manager_v1 +{ + Q_OBJECT +public: + explicit XdgOutputManagerV1(CoreCompositor *compositor, int version = 3) + : QtWaylandServer::zxdg_output_manager_v1(compositor->m_display, version) + , m_version(version) + {} + int m_version = 1; // TODO: remove on libwayland upgrade + QMap<Output *, XdgOutputV1 *> m_xdgOutputs; + XdgOutputV1 *getXdgOutput(Output *output) + { + if (auto *xdgOutput = m_xdgOutputs.value(output)) + return xdgOutput; + return m_xdgOutputs[output] = new XdgOutputV1(output); // TODO: free memory + } + +protected: + void zxdg_output_manager_v1_get_xdg_output(Resource *resource, uint32_t id, wl_resource *outputResource) override + { + auto *output = fromResource<Output>(outputResource); + auto *xdgOutput = getXdgOutput(output); + xdgOutput->addResource(resource->client(), id, resource->version()); + } +}; + +} // namespace MockCompositor + +#endif // MOCKCOMPOSITOR_XDGOUTPUTV1_H diff --git a/tests/auto/client/shared/xdgshell.cpp b/tests/auto/client/shared/xdgshell.cpp index 13acc01e2..2c1639851 100644 --- a/tests/auto/client/shared/xdgshell.cpp +++ b/tests/auto/client/shared/xdgshell.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "xdgshell.h" @@ -39,7 +14,7 @@ XdgWmBase::XdgWmBase(CoreCompositor *compositor, int version) XdgToplevel *XdgWmBase::toplevel(int i) { int j = 0; - for (auto *xdgSurface : qAsConst(m_xdgSurfaces)) { + for (auto *xdgSurface : std::as_const(m_xdgSurfaces)) { if (auto *toplevel = xdgSurface->m_toplevel) { if (j == i) return toplevel; @@ -52,7 +27,7 @@ XdgToplevel *XdgWmBase::toplevel(int i) XdgPopup *XdgWmBase::popup(int i) { int j = 0; - for (auto *xdgSurface : qAsConst(m_xdgSurfaces)) { + for (auto *xdgSurface : std::as_const(m_xdgSurfaces)) { if (auto *popup = xdgSurface->m_popup) { if (j == i) return popup; @@ -83,7 +58,7 @@ XdgSurface::XdgSurface(XdgWmBase *xdgWmBase, Surface *surface, wl_client *client { QVERIFY(!surface->m_pending.buffer); QVERIFY(!surface->m_committed.buffer); - connect(this, &XdgSurface::toplevelCreated, xdgWmBase, &XdgWmBase::toplevelCreated); + connect(this, &XdgSurface::toplevelCreated, xdgWmBase, &XdgWmBase::toplevelCreated, Qt::DirectConnection); connect(surface, &Surface::attach, this, &XdgSurface::verifyConfigured); connect(surface, &Surface::commit, this, [this] { m_committed = m_pending; @@ -168,12 +143,17 @@ XdgToplevel::XdgToplevel(XdgSurface *xdgSurface, int id, int version) connect(surface(), &Surface::commit, this, [this] { m_committed = m_pending; }); } -void XdgToplevel::sendConfigure(const QSize &size, const QVector<uint> &states) +void XdgToplevel::sendConfigureBounds(const QSize &size) +{ + send_configure_bounds(size.width(), size.height()); +} + +void XdgToplevel::sendConfigure(const QSize &size, const QList<uint> &states) { send_configure(size.width(), size.height(), toByteArray(states)); } -uint XdgToplevel::sendCompleteConfigure(const QSize &size, const QVector<uint> &states) +uint XdgToplevel::sendCompleteConfigure(const QSize &size, const QList<uint> &states) { sendConfigure(size, states); return m_xdgSurface->sendConfigure(); diff --git a/tests/auto/client/shared/xdgshell.h b/tests/auto/client/shared/xdgshell.h index 618babde7..3959e0668 100644 --- a/tests/auto/client/shared/xdgshell.h +++ b/tests/auto/client/shared/xdgshell.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef MOCKCOMPOSITOR_XDGSHELL_H #define MOCKCOMPOSITOR_XDGSHELL_H @@ -43,12 +18,12 @@ class XdgWmBase : public Global, public QtWaylandServer::xdg_wm_base { Q_OBJECT public: - explicit XdgWmBase(CoreCompositor *compositor, int version = 1); + explicit XdgWmBase(CoreCompositor *compositor, int version = 4); 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<XdgSurface *> m_xdgSurfaces; + QList<XdgSurface *> m_xdgSurfaces; XdgToplevel *toplevel(int i = 0); XdgPopup *popup(int i = 0); XdgPopup *m_topmostGrabbingPopup = nullptr; @@ -86,13 +61,13 @@ public: XdgWmBase *m_xdgWmBase = nullptr; Surface *m_surface = nullptr; bool m_configureSent = false; - QVector<uint> m_pendingConfigureSerials; + QList<uint> m_pendingConfigureSerials; uint m_ackedConfigureSerial = 0; uint m_committedConfigureSerial = 0; struct DoubleBufferedState { QRect windowGeometry = {0, 0, 0, 0}; } m_pending, m_committed; - QVector<XdgPopup *> m_popups; + QList<XdgPopup *> m_popups; public slots: void verifyConfigured() { QVERIFY(m_configureSent); } @@ -115,8 +90,9 @@ class XdgToplevel : public QObject, public QtWaylandServer::xdg_toplevel Q_OBJECT public: explicit XdgToplevel(XdgSurface *xdgSurface, int id, int version = 1); - void sendConfigure(const QSize &size = {0, 0}, const QVector<uint> &states = {}); - uint sendCompleteConfigure(const QSize &size = {0, 0}, const QVector<uint> &states = {}); + void sendConfigureBounds(const QSize &size); + void sendConfigure(const QSize &size = {0, 0}, const QList<uint> &states = {}); + uint sendCompleteConfigure(const QSize &size = {0, 0}, const QList<uint> &states = {}); Surface *surface() { return m_xdgSurface->m_surface; } XdgSurface *m_xdgSurface = nullptr; |