diff --git a/autotests/integration/CMakeLists.txt b/autotests/integration/CMakeLists.txt --- a/autotests/integration/CMakeLists.txt +++ b/autotests/integration/CMakeLists.txt @@ -59,6 +59,7 @@ integrationTest(WAYLAND_ONLY NAME testDontCrashCursorPhysicalSizeEmpty SRCS dont_crash_cursor_physical_size_empty.cpp) integrationTest(WAYLAND_ONLY NAME testDontCrashReinitializeCompositor SRCS dont_crash_reinitialize_compositor.cpp) integrationTest(WAYLAND_ONLY NAME testNoGlobalShortcuts SRCS no_global_shortcuts_test.cpp) +integrationTest(WAYLAND_ONLY NAME testBufferSizeChange SRCS buffer_size_change_test.cpp generic_scene_opengl_test.cpp) if (XCB_ICCCM_FOUND) integrationTest(NAME testMoveResize SRCS move_resize_window_test.cpp LIBS XCB::ICCCM) diff --git a/autotests/integration/buffer_size_change_test.cpp b/autotests/integration/buffer_size_change_test.cpp new file mode 100644 --- /dev/null +++ b/autotests/integration/buffer_size_change_test.cpp @@ -0,0 +1,128 @@ +/******************************************************************** +KWin - the KDE window manager +This file is part of the KDE project. + +Copyright 2019 Roman Gilg + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#include "generic_scene_opengl_test.h" + +#include "composite.h" +#include "shell_client.h" +#include "wayland_server.h" + +#include +#include +#include + +namespace KWin +{ + +static const QString s_socketName = QStringLiteral("wayland_test_buffer_size_change-0"); + +class BufferSizeChangeTest : public GenericSceneOpenGLTest +{ + Q_OBJECT +public: + BufferSizeChangeTest() : GenericSceneOpenGLTest(QByteArrayLiteral("O2")) {} +private Q_SLOTS: + void init(); + void testShmBufferSizeChange(); + void testShmBufferSizeChangeOnSubSurface(); +}; + +void BufferSizeChangeTest::init() +{ + QVERIFY(Test::setupWaylandConnection()); +} + +void BufferSizeChangeTest::testShmBufferSizeChange() +{ + // This test verifies that an SHM buffer size change is handled correctly + + using namespace KWayland::Client; + + QScopedPointer surface(Test::createSurface()); + QVERIFY(!surface.isNull()); + + QScopedPointer shellSurface(Test::createXdgShellStableSurface(surface.data())); + QVERIFY(!shellSurface.isNull()); + Test::flushWaylandConnection(); + + // set buffer size + ShellClient *client = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue); + QVERIFY(client); + + // add a first repaint + QSignalSpy swapSpy(Compositor::self(), &Compositor::bufferSwapCompleted); + QVERIFY(swapSpy.isValid()); + Compositor::self()->addRepaintFull(); + QVERIFY(swapSpy.wait()); + + // now change buffer size + Test::render(surface.data(), QSize(30, 10), Qt::red); + Test::flushWaylandConnection(); + + QSignalSpy damagedSpy(client, &ShellClient::damaged); + QVERIFY(damagedSpy.isValid()); + QVERIFY(damagedSpy.wait()); + KWin::Compositor::self()->addRepaintFull(); + QVERIFY(swapSpy.wait()); +} + +void BufferSizeChangeTest::testShmBufferSizeChangeOnSubSurface() +{ + using namespace KWayland::Client; + + // setup parent surface + QScopedPointer parentSurface(Test::createSurface()); + QVERIFY(!parentSurface.isNull()); + QScopedPointer shellSurface(Test::createXdgShellStableSurface(parentSurface.data())); + QVERIFY(!shellSurface.isNull()); + + // setup sub surface + QScopedPointer surface(Test::createSurface()); + QVERIFY(!surface.isNull()); + QScopedPointer subSurface(Test::createSubSurface(surface.data(), parentSurface.data())); + QVERIFY(!subSurface.isNull()); + + // set buffer sizes + Test::render(surface.data(), QSize(30, 10), Qt::red); + ShellClient *parent = Test::renderAndWaitForShown(parentSurface.data(), QSize(100, 50), Qt::blue); + QVERIFY(parent); + + // add a first repaint + QSignalSpy swapSpy(Compositor::self(), &Compositor::bufferSwapCompleted); + QVERIFY(swapSpy.isValid()); + Compositor::self()->addRepaintFull(); + QVERIFY(swapSpy.wait()); + + // change buffer size of sub surface + QSignalSpy damagedParentSpy(parent, &ShellClient::damaged); + QVERIFY(damagedParentSpy.isValid()); + Test::render(surface.data(), QSize(20, 10), Qt::red); + parentSurface->commit(Surface::CommitFlag::None); + + QVERIFY(damagedParentSpy.wait()); + + // add a second repaint + KWin::Compositor::self()->addRepaintFull(); + QVERIFY(swapSpy.wait()); +} + +} + +WAYLANDTEST_MAIN(KWin::BufferSizeChangeTest) +#include "buffer_size_change_test.moc" diff --git a/autotests/integration/kwin_wayland_test.h b/autotests/integration/kwin_wayland_test.h --- a/autotests/integration/kwin_wayland_test.h +++ b/autotests/integration/kwin_wayland_test.h @@ -45,6 +45,8 @@ class Shell; class ShellSurface; class ShmPool; +class SubCompositor; +class SubSurface; class Surface; class XdgDecorationManager; } @@ -112,6 +114,7 @@ KWayland::Client::ConnectionThread *waylandConnection(); KWayland::Client::Compositor *waylandCompositor(); +KWayland::Client::SubCompositor *waylandSubCompositor(); KWayland::Client::ShadowManager *waylandShadowManager(); KWayland::Client::Shell *waylandShell(); KWayland::Client::ShmPool *waylandShmPool(); @@ -131,6 +134,8 @@ void flushWaylandConnection(); KWayland::Client::Surface *createSurface(QObject *parent = nullptr); +KWayland::Client::SubSurface *createSubSurface(KWayland::Client::Surface *surface, + KWayland::Client::Surface *parentSurface, QObject *parent = nullptr); enum class ShellSurfaceType { WlShell, XdgShellV5, diff --git a/autotests/integration/test_helpers.cpp b/autotests/integration/test_helpers.cpp --- a/autotests/integration/test_helpers.cpp +++ b/autotests/integration/test_helpers.cpp @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include #include #include @@ -63,6 +65,7 @@ ConnectionThread *connection = nullptr; EventQueue *queue = nullptr; Compositor *compositor = nullptr; + SubCompositor *subCompositor = nullptr; ServerSideDecorationManager *decoration = nullptr; ShadowManager *shadowManager = nullptr; Shell *shell = nullptr; @@ -146,6 +149,10 @@ if (!s_waylandConnection.compositor->isValid()) { return false; } + s_waylandConnection.subCompositor = registry->createSubCompositor(registry->interface(Registry::Interface::SubCompositor).name, registry->interface(Registry::Interface::SubCompositor).version); + if (!s_waylandConnection.subCompositor->isValid()) { + return false; + } s_waylandConnection.shm = registry->createShmPool(registry->interface(Registry::Interface::Shm).name, registry->interface(Registry::Interface::Shm).version); if (!s_waylandConnection.shm->isValid()) { return false; @@ -234,6 +241,8 @@ { delete s_waylandConnection.compositor; s_waylandConnection.compositor = nullptr; + delete s_waylandConnection.subCompositor; + s_waylandConnection.subCompositor = nullptr; delete s_waylandConnection.windowManagement; s_waylandConnection.windowManagement = nullptr; delete s_waylandConnection.plasmaShell; @@ -292,6 +301,11 @@ return s_waylandConnection.compositor; } +SubCompositor *waylandSubCompositor() +{ + return s_waylandConnection.subCompositor; +} + ShadowManager *waylandShadowManager() { return s_waylandConnection.shadowManager; @@ -444,6 +458,19 @@ return s; } +SubSurface *createSubSurface(Surface *surface, Surface *parentSurface, QObject *parent) +{ + if (!s_waylandConnection.subCompositor) { + return nullptr; + } + auto s = s_waylandConnection.subCompositor->createSubSurface(surface, parentSurface, parent); + if (!s->isValid()) { + delete s; + return nullptr; + } + return s; +} + ShellSurface *createShellSurface(Surface *surface, QObject *parent) { if (!s_waylandConnection.shell) { diff --git a/composite.h b/composite.h --- a/composite.h +++ b/composite.h @@ -178,6 +178,7 @@ void aboutToDestroy(); void aboutToToggleCompositing(); void sceneCreated(); + void bufferSwapCompleted(); protected: void timerEvent(QTimerEvent *te); diff --git a/composite.cpp b/composite.cpp --- a/composite.cpp +++ b/composite.cpp @@ -655,6 +655,8 @@ assert(m_bufferSwapPending); m_bufferSwapPending = false; + emit bufferSwapCompleted(); + if (m_composeAtSwapCompletion) { m_composeAtSwapCompletion = false; performCompositing();