diff --git a/autotests/integration/CMakeLists.txt b/autotests/integration/CMakeLists.txt --- a/autotests/integration/CMakeLists.txt +++ b/autotests/integration/CMakeLists.txt @@ -235,3 +235,12 @@ target_link_libraries( testXClipboardSync kwin Qt5::Test) add_test(kwin-testXClipboardSync testXClipboardSync) ecm_mark_as_test(testXClipboardSync) + +######################################################## +# SceneQPainter Test +######################################################## +set( testSceneQPainter_SRCS scene_qpainter_test.cpp kwin_wayland_test.cpp ) +add_executable(testSceneQPainter ${testSceneQPainter_SRCS}) +target_link_libraries( testSceneQPainter kwin Qt5::Test) +add_test(kwin-testSceneQPainter testSceneQPainter) +ecm_mark_as_test(testSceneQPainter) diff --git a/autotests/integration/scene_qpainter_test.cpp b/autotests/integration/scene_qpainter_test.cpp new file mode 100644 --- /dev/null +++ b/autotests/integration/scene_qpainter_test.cpp @@ -0,0 +1,122 @@ +/******************************************************************** +KWin - the KDE window manager +This file is part of the KDE project. + +Copyright (C) 2016 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#include "kwin_wayland_test.h" +#include "composite.h" +#include "effectloader.h" +#include "cursor.h" +#include "platform.h" +#include "scene_qpainter.h" +#include "wayland_server.h" +#include "effect_builtins.h" + +#include + +#include + +using namespace KWin; +static const QString s_socketName = QStringLiteral("wayland_test_kwin_scene_qpainter-0"); + +class SceneQPainterTest : public QObject +{ +Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void testStartFrame(); + void testCursorMoving(); +}; + +void SceneQPainterTest::initTestCase() +{ + QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated); + QVERIFY(workspaceCreatedSpy.isValid()); + kwinApp()->platform()->setInitialWindowSize(QSize(1280, 1024)); + waylandServer()->init(s_socketName.toLocal8Bit()); + + // disable all effects - we don't want to have it interact with the rendering + auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); + KConfigGroup plugins(config, QStringLiteral("Plugins")); + ScriptedEffectLoader loader; + const auto builtinNames = BuiltInEffects::availableEffectNames() << loader.listOfKnownEffects(); + for (QString name : builtinNames) { + plugins.writeEntry(name + QStringLiteral("Enabled"), false); + } + + config->sync(); + kwinApp()->setConfig(config); + + qputenv("XCURSOR_THEME", QByteArrayLiteral("DMZ-White")); + qputenv("XCURSOR_SIZE", QByteArrayLiteral("24")); + qputenv("KWIN_COMPOSE", QByteArrayLiteral("Q")); + + kwinApp()->start(); + QVERIFY(workspaceCreatedSpy.wait()); + QVERIFY(Compositor::self()); +} + +void SceneQPainterTest::testStartFrame() +{ + // this test verifies that the initial rendering is correct + Compositor::self()->addRepaintFull(); + auto scene = qobject_cast(Compositor::self()->scene()); + QVERIFY(scene); + QSignalSpy frameRenderedSpy(scene, &Scene::frameRendered); + QVERIFY(frameRenderedSpy.isValid()); + QVERIFY(frameRenderedSpy.wait()); + // now let's render a reference image for comparison + QImage referenceImage(QSize(1280, 1024), QImage::Format_RGB32); + referenceImage.fill(Qt::black); + QPainter p(&referenceImage); + const QImage cursorImage = kwinApp()->platform()->softwareCursor(); + QVERIFY(!cursorImage.isNull()); + p.drawImage(KWin::Cursor::pos() - kwinApp()->platform()->softwareCursorHotspot(), cursorImage); + QCOMPARE(referenceImage, *scene->backend()->buffer()); +} + +void SceneQPainterTest::testCursorMoving() +{ + // this test verifies that rendering is correct also after moving the cursor a few times + auto scene = qobject_cast(Compositor::self()->scene()); + QVERIFY(scene); + QSignalSpy frameRenderedSpy(scene, &Scene::frameRendered); + QVERIFY(frameRenderedSpy.isValid()); + KWin::Cursor::setPos(0, 0); + QVERIFY(frameRenderedSpy.wait()); + KWin::Cursor::setPos(10, 0); + QVERIFY(frameRenderedSpy.wait()); + KWin::Cursor::setPos(10, 12); + QVERIFY(frameRenderedSpy.wait()); + KWin::Cursor::setPos(12, 14); + QVERIFY(frameRenderedSpy.wait()); + KWin::Cursor::setPos(50, 60); + QVERIFY(frameRenderedSpy.wait()); + KWin::Cursor::setPos(45, 45); + QVERIFY(frameRenderedSpy.wait()); + // now let's render a reference image for comparison + QImage referenceImage(QSize(1280, 1024), QImage::Format_RGB32); + referenceImage.fill(Qt::black); + QPainter p(&referenceImage); + const QImage cursorImage = kwinApp()->platform()->softwareCursor(); + QVERIFY(!cursorImage.isNull()); + p.drawImage(QPoint(45, 45) - kwinApp()->platform()->softwareCursorHotspot(), cursorImage); + QCOMPARE(referenceImage, *scene->backend()->buffer()); +} + +WAYLANDTEST_MAIN(SceneQPainterTest) +#include "scene_qpainter_test.moc" diff --git a/effectloader.h b/effectloader.h --- a/effectloader.h +++ b/effectloader.h @@ -19,6 +19,7 @@ *********************************************************************/ #ifndef KWIN_EFFECT_LOADER_H #define KWIN_EFFECT_LOADER_H +#include // KDE #include #include @@ -302,7 +303,7 @@ * @brief Can load scripted Effects * */ -class ScriptedEffectLoader : public AbstractEffectLoader +class KWIN_EXPORT ScriptedEffectLoader : public AbstractEffectLoader { Q_OBJECT public: diff --git a/scene.h b/scene.h --- a/scene.h +++ b/scene.h @@ -57,7 +57,7 @@ class WindowPixmap; // The base class for compositing backends. -class Scene : public QObject +class KWIN_EXPORT Scene : public QObject { Q_OBJECT public: @@ -149,6 +149,9 @@ virtual Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedClientImpl *) = 0; +Q_SIGNALS: + void frameRendered(); + public Q_SLOTS: // a window has been destroyed void windowDeleted(KWin::Deleted*); diff --git a/scene_qpainter.h b/scene_qpainter.h --- a/scene_qpainter.h +++ b/scene_qpainter.h @@ -102,7 +102,7 @@ bool m_failed; }; -class SceneQPainter : public Scene +class KWIN_EXPORT SceneQPainter : public Scene { Q_OBJECT @@ -121,6 +121,10 @@ QPainter *painter(); + QPainterBackend *backend() const { + return m_backend.data(); + } + static SceneQPainter *createScene(QObject *parent); protected: diff --git a/scene_qpainter.cpp b/scene_qpainter.cpp --- a/scene_qpainter.cpp +++ b/scene_qpainter.cpp @@ -186,6 +186,8 @@ // do cleanup clearStackingOrder(); + emit frameRendered(); + return renderTimer.nsecsElapsed(); }