kwin/autotests/integration/effects/translucency_test.cpp
Martin Gräßlin 671740dc70 Ensure that EffectsHandlerImpl::slotClientShown is only invoked once per Window
Summary:
This fixes a regression introduced with a1afeded6a.
The connections were setup every the windowShown signal got emitted.
This caused effects to get multiple singals and start multiple animations
which then do not get cancelled correctly.

The incorrect behavior was most visible in the translucency effect which
did not cancel the move animation and the window stayed translucent.

BUG: 366081

Test Plan:
New test case which simulates the behavior of the translucency
effect.

Reviewers: #kwin, #plasma, sebas

Subscribers: kwin

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D2346
2016-08-03 16:16:00 +02:00

185 lines
6.6 KiB
C++

/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2016 Martin Gräßlin <mgraesslin@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "kwin_wayland_test.h"
#include "composite.h"
#include "effects.h"
#include "effectloader.h"
#include "cursor.h"
#include "platform.h"
#include "scene_qpainter.h"
#include "shell_client.h"
#include "wayland_server.h"
#include "workspace.h"
#include "effect_builtins.h"
#include <KConfigGroup>
#include <netwm.h>
#include <xcb/xcb_icccm.h>
using namespace KWin;
static const QString s_socketName = QStringLiteral("wayland_test_effects_translucency-0");
class TranslucencyTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void init();
void cleanup();
void testMoveAfterDesktopChange();
private:
Effect *m_translucencyEffect = nullptr;
};
void TranslucencyTest::initTestCase()
{
qRegisterMetaType<KWin::ShellClient*>();
qRegisterMetaType<KWin::AbstractClient*>();
qRegisterMetaType<KWin::Effect*>();
QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated);
QVERIFY(workspaceCreatedSpy.isValid());
kwinApp()->platform()->setInitialWindowSize(QSize(1280, 1024));
QVERIFY(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->group("Outline").writeEntry(QStringLiteral("QmlPath"), QString("/does/not/exist.qml"));
config->sync();
kwinApp()->setConfig(config);
kwinApp()->start();
QVERIFY(workspaceCreatedSpy.wait());
QVERIFY(Compositor::self());
}
void TranslucencyTest::init()
{
// load the translucency effect
EffectsHandlerImpl *e = static_cast<EffectsHandlerImpl*>(effects);
// find the effectsloader
auto effectloader = e->findChild<AbstractEffectLoader*>();
QVERIFY(effectloader);
QSignalSpy effectLoadedSpy(effectloader, &AbstractEffectLoader::effectLoaded);
QVERIFY(effectLoadedSpy.isValid());
QVERIFY(!e->isEffectLoaded(QStringLiteral("kwin4_effect_translucency")));
QVERIFY(e->loadEffect(QStringLiteral("kwin4_effect_translucency")));
QVERIFY(e->isEffectLoaded(QStringLiteral("kwin4_effect_translucency")));
QCOMPARE(effectLoadedSpy.count(), 1);
m_translucencyEffect = effectLoadedSpy.first().first().value<Effect*>();
QVERIFY(m_translucencyEffect);
}
void TranslucencyTest::cleanup()
{
EffectsHandlerImpl *e = static_cast<EffectsHandlerImpl*>(effects);
if (e->isEffectLoaded(QStringLiteral("kwin4_effect_translucency"))) {
e->unloadEffect(QStringLiteral("kwin4_effect_translucency"));
}
QVERIFY(!e->isEffectLoaded(QStringLiteral("kwin4_effect_translucency")));
m_translucencyEffect = nullptr;
}
void TranslucencyTest::testMoveAfterDesktopChange()
{
// test tries to simulate the condition of bug 366081
QVERIFY(!m_translucencyEffect->isActive());
QSignalSpy windowAddedSpy(effects, &EffectsHandler::windowAdded);
QVERIFY(windowAddedSpy.isValid());
// create an xcb window
struct XcbConnectionDeleter
{
static inline void cleanup(xcb_connection_t *pointer)
{
xcb_disconnect(pointer);
}
};
QScopedPointer<xcb_connection_t, XcbConnectionDeleter> c(xcb_connect(nullptr, nullptr));
QVERIFY(!xcb_connection_has_error(c.data()));
const QRect windowGeometry(0, 0, 100, 200);
xcb_window_t w = xcb_generate_id(c.data());
xcb_create_window(c.data(), XCB_COPY_FROM_PARENT, w, rootWindow(),
windowGeometry.x(),
windowGeometry.y(),
windowGeometry.width(),
windowGeometry.height(),
0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr);
xcb_size_hints_t hints;
memset(&hints, 0, sizeof(hints));
xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
xcb_icccm_set_wm_normal_hints(c.data(), w, &hints);
xcb_map_window(c.data(), w);
xcb_flush(c.data());
// we should get a client for it
QSignalSpy windowCreatedSpy(workspace(), &Workspace::clientAdded);
QVERIFY(windowCreatedSpy.isValid());
QVERIFY(windowCreatedSpy.wait());
Client *client = windowCreatedSpy.first().first().value<Client*>();
QVERIFY(client);
QCOMPARE(client->window(), w);
QVERIFY(client->isDecorated());
QVERIFY(windowAddedSpy.wait());
QVERIFY(!m_translucencyEffect->isActive());
// let's send the window to desktop 2
effects->setNumberOfDesktops(2);
QCOMPARE(effects->numberOfDesktops(), 2);
workspace()->sendClientToDesktop(client, 2, false);
effects->setCurrentDesktop(2);
QVERIFY(!m_translucencyEffect->isActive());
KWin::Cursor::setPos(client->geometry().center());
workspace()->performWindowOperation(client, Options::MoveOp);
QVERIFY(m_translucencyEffect->isActive());
QTest::qWait(200);
QVERIFY(m_translucencyEffect->isActive());
// now end move resize
client->endMoveResize();
QVERIFY(m_translucencyEffect->isActive());
QTest::qWait(500);
QVERIFY(!m_translucencyEffect->isActive());
// and destroy the window again
xcb_unmap_window(c.data(), w);
xcb_flush(c.data());
QSignalSpy windowClosedSpy(client, &Client::windowClosed);
QVERIFY(windowClosedSpy.isValid());
QVERIFY(windowClosedSpy.wait());
xcb_destroy_window(c.data(), w);
c.reset();
}
WAYLANDTEST_MAIN(TranslucencyTest)
#include "translucency_test.moc"