diff --git a/autotests/test_builtin_effectloader.cpp b/autotests/test_builtin_effectloader.cpp index dc741bdc0..cf6a1219a 100644 --- a/autotests/test_builtin_effectloader.cpp +++ b/autotests/test_builtin_effectloader.cpp @@ -1,575 +1,579 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2014 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 "../effectloader.h" #include "../effects/effect_builtins.h" #include "mock_effectshandler.h" #include "../scripting/scriptedeffect.h" // for mocking ScriptedEffect::create #include "testutils.h" // KDE #include #include // Qt #include #include Q_DECLARE_METATYPE(KWin::CompositingType) Q_DECLARE_METATYPE(KWin::LoadEffectFlag) Q_DECLARE_METATYPE(KWin::LoadEffectFlags) Q_DECLARE_METATYPE(KWin::BuiltInEffect) Q_DECLARE_METATYPE(KWin::Effect*) Q_LOGGING_CATEGORY(KWIN_CORE, "kwin_core") namespace KWin { ScriptedEffect *ScriptedEffect::create(const KPluginMetaData&) { return nullptr; } bool ScriptedEffect::supported() { return true; } } class TestBuiltInEffectLoader : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void testHasEffect_data(); void testHasEffect(); void testKnownEffects(); void testSupported_data(); void testSupported(); void testLoadEffect_data(); void testLoadEffect(); void testLoadBuiltInEffect_data(); void testLoadBuiltInEffect(); void testLoadAllEffects(); }; void TestBuiltInEffectLoader::initTestCase() { qApp->setProperty("x11Connection", QVariant::fromValue(QX11Info::connection())); } void TestBuiltInEffectLoader::testHasEffect_data() { QTest::addColumn("name"); QTest::addColumn("expected"); QTest::newRow("blur") << QStringLiteral("blur") << true; QTest::newRow("with kwin4_effect_ prefix") << QStringLiteral("kwin4_effect_blur") << false; QTest::newRow("case sensitive") << QStringLiteral("BlUR") << true; QTest::newRow("Colorpicker") << QStringLiteral("colorpicker") << true; QTest::newRow("Contrast") << QStringLiteral("contrast") << true; QTest::newRow("CoverSwitch") << QStringLiteral("coverswitch") << true; QTest::newRow("Cube") << QStringLiteral("cube") << true; QTest::newRow("CubeSlide") << QStringLiteral("cubeslide") << true; QTest::newRow("DesktopGrid") << QStringLiteral("desktopgrid") << true; QTest::newRow("DimInactive") << QStringLiteral("diminactive") << true; QTest::newRow("DimScreen") << QStringLiteral("dimscreen") << true; QTest::newRow("FallApart") << QStringLiteral("fallapart") << true; QTest::newRow("FlipSwitch") << QStringLiteral("flipswitch") << true; QTest::newRow("Glide") << QStringLiteral("glide") << true; QTest::newRow("HighlightWindow") << QStringLiteral("highlightwindow") << true; QTest::newRow("Invert") << QStringLiteral("invert") << true; QTest::newRow("Kscreen") << QStringLiteral("kscreen") << true; QTest::newRow("LookingGlass") << QStringLiteral("lookingglass") << true; QTest::newRow("MagicLamp") << QStringLiteral("magiclamp") << true; QTest::newRow("Magnifier") << QStringLiteral("magnifier") << true; QTest::newRow("MinimizeAnimation") << QStringLiteral("minimizeanimation") << true; QTest::newRow("MouseClick") << QStringLiteral("mouseclick") << true; QTest::newRow("MouseMark") << QStringLiteral("mousemark") << true; QTest::newRow("PresentWindows") << QStringLiteral("presentwindows") << true; QTest::newRow("Resize") << QStringLiteral("resize") << true; + QTest::newRow("Scale") << QStringLiteral("scale") << true; QTest::newRow("ScreenEdge") << QStringLiteral("screenedge") << true; QTest::newRow("ScreenShot") << QStringLiteral("screenshot") << true; QTest::newRow("Sheet") << QStringLiteral("sheet") << true; QTest::newRow("ShowFps") << QStringLiteral("showfps") << true; QTest::newRow("ShowPaint") << QStringLiteral("showpaint") << true; QTest::newRow("Slide") << QStringLiteral("slide") << true; QTest::newRow("SlideBack") << QStringLiteral("slideback") << true; QTest::newRow("SlidingPopups") << QStringLiteral("slidingpopups") << true; QTest::newRow("SnapHelper") << QStringLiteral("snaphelper") << true; QTest::newRow("StartupFeedback") << QStringLiteral("startupfeedback") << true; QTest::newRow("ThumbnailAside") << QStringLiteral("thumbnailaside") << true; QTest::newRow("Touchpoints") << QStringLiteral("touchpoints") << true; QTest::newRow("TrackMouse") << QStringLiteral("trackmouse") << true; QTest::newRow("WindowGeometry") << QStringLiteral("windowgeometry") << true; QTest::newRow("WobblyWindows") << QStringLiteral("wobblywindows") << true; QTest::newRow("Zoom") << QStringLiteral("zoom") << true; QTest::newRow("Non Existing") << QStringLiteral("InvalidName") << false; QTest::newRow("Fade - Scripted") << QStringLiteral("fade") << false; QTest::newRow("Fade - Scripted + kwin4_effect") << QStringLiteral("kwin4_effect_fade") << false; } void TestBuiltInEffectLoader::testHasEffect() { QFETCH(QString, name); QFETCH(bool, expected); KWin::BuiltInEffectLoader loader; QCOMPARE(loader.hasEffect(name), expected); } void TestBuiltInEffectLoader::testKnownEffects() { QStringList expectedEffects; expectedEffects << QStringLiteral("blur") << QStringLiteral("colorpicker") << QStringLiteral("contrast") << QStringLiteral("coverswitch") << QStringLiteral("cube") << QStringLiteral("cubeslide") << QStringLiteral("desktopgrid") << QStringLiteral("diminactive") << QStringLiteral("dimscreen") << QStringLiteral("fallapart") << QStringLiteral("flipswitch") << QStringLiteral("glide") << QStringLiteral("highlightwindow") << QStringLiteral("invert") << QStringLiteral("kscreen") << QStringLiteral("lookingglass") << QStringLiteral("magiclamp") << QStringLiteral("magnifier") << QStringLiteral("minimizeanimation") << QStringLiteral("mouseclick") << QStringLiteral("mousemark") << QStringLiteral("presentwindows") << QStringLiteral("resize") + << QStringLiteral("scale") << QStringLiteral("screenedge") << QStringLiteral("screenshot") << QStringLiteral("sheet") << QStringLiteral("showfps") << QStringLiteral("showpaint") << QStringLiteral("slide") << QStringLiteral("slideback") << QStringLiteral("slidingpopups") << QStringLiteral("snaphelper") << QStringLiteral("startupfeedback") << QStringLiteral("thumbnailaside") << QStringLiteral("touchpoints") << QStringLiteral("trackmouse") << QStringLiteral("windowgeometry") << QStringLiteral("wobblywindows") << QStringLiteral("zoom"); KWin::BuiltInEffectLoader loader; QStringList result = loader.listOfKnownEffects(); QCOMPARE(result.size(), expectedEffects.size()); qSort(result); for (int i = 0; i < expectedEffects.size(); ++i) { QCOMPARE(result.at(i), expectedEffects.at(i)); } } void TestBuiltInEffectLoader::testSupported_data() { QTest::addColumn("name"); QTest::addColumn("expected"); QTest::addColumn("type"); QTest::addColumn("animationsSupported"); const KWin::CompositingType xc = KWin::XRenderCompositing; const KWin::CompositingType oc = KWin::OpenGL2Compositing; QTest::newRow("blur") << QStringLiteral("blur") << false << xc << true; // fails for GL as it does proper tests on what's supported and doesn't just check whether it's GL QTest::newRow("blur-GL") << QStringLiteral("blur") << false << oc << true; QTest::newRow("Colorpicker") << QStringLiteral("colorpicker") << false << xc << true; QTest::newRow("Colorpicker-GL") << QStringLiteral("colorpicker") << true << oc << true; QTest::newRow("Contrast") << QStringLiteral("contrast") << false << xc << true; // fails for GL as it does proper tests on what's supported and doesn't just check whether it's GL QTest::newRow("Contrast-GL") << QStringLiteral("contrast") << false << oc << true; QTest::newRow("CoverSwitch") << QStringLiteral("coverswitch") << false << xc << true; QTest::newRow("CoverSwitch-GL") << QStringLiteral("coverswitch") << true << oc << true; QTest::newRow("CoverSwitch-GL-no-anim") << QStringLiteral("coverswitch") << false << oc << false; QTest::newRow("Cube") << QStringLiteral("cube") << false << xc << true; QTest::newRow("Cube-GL") << QStringLiteral("cube") << true << oc << true; QTest::newRow("CubeSlide") << QStringLiteral("cubeslide") << false << xc << true; QTest::newRow("CubeSlide-GL") << QStringLiteral("cubeslide") << true << oc << true; QTest::newRow("CubeSlide-GL-no-anim") << QStringLiteral("cubeslide") << false << oc << false; QTest::newRow("DesktopGrid") << QStringLiteral("desktopgrid") << true << xc << true; QTest::newRow("DimInactive") << QStringLiteral("diminactive") << true << xc << true; QTest::newRow("DimScreen") << QStringLiteral("dimscreen") << true << xc << true; QTest::newRow("FallApart") << QStringLiteral("fallapart") << false << xc << true; QTest::newRow("FallApart-GL") << QStringLiteral("fallapart") << true << oc << true; QTest::newRow("FlipSwitch") << QStringLiteral("flipswitch") << false << xc << true; QTest::newRow("FlipSwitch-GL") << QStringLiteral("flipswitch") << true << oc << true; QTest::newRow("FlipSwitch-GL-no-anim") << QStringLiteral("flipswitch") << false << oc << false; QTest::newRow("Glide") << QStringLiteral("glide") << false << xc << true; QTest::newRow("Glide-GL") << QStringLiteral("glide") << true << oc << true; QTest::newRow("Glide-GL-no-anim") << QStringLiteral("glide") << false << oc << false; QTest::newRow("HighlightWindow") << QStringLiteral("highlightwindow") << true << xc << true; QTest::newRow("Invert") << QStringLiteral("invert") << false << xc << true; QTest::newRow("Invert-GL") << QStringLiteral("invert") << true << oc << true; QTest::newRow("Kscreen") << QStringLiteral("kscreen") << true << xc << true; QTest::newRow("LookingGlass") << QStringLiteral("lookingglass") << false << xc << true; QTest::newRow("LookingGlass-GL") << QStringLiteral("lookingglass") << true << oc << true; QTest::newRow("MagicLamp") << QStringLiteral("magiclamp") << false << xc << true; QTest::newRow("MagicLamp-GL") << QStringLiteral("magiclamp") << true << oc << true; QTest::newRow("MagicLamp-GL-no-anim") << QStringLiteral("magiclamp") << false << oc << false; QTest::newRow("Magnifier") << QStringLiteral("magnifier") << true << xc << true; QTest::newRow("MinimizeAnimation") << QStringLiteral("minimizeanimation") << true << xc << true; QTest::newRow("MouseClick") << QStringLiteral("mouseclick") << true << xc << true; QTest::newRow("MouseMark") << QStringLiteral("mousemark") << true << xc << true; QTest::newRow("PresentWindows") << QStringLiteral("presentwindows") << true << xc << true; QTest::newRow("Resize") << QStringLiteral("resize") << true << xc << true; + QTest::newRow("Scale") << QStringLiteral("scale") << true << xc << true; QTest::newRow("ScreenEdge") << QStringLiteral("screenedge") << true << xc << true; QTest::newRow("ScreenShot") << QStringLiteral("screenshot") << true << xc << true; QTest::newRow("Sheet") << QStringLiteral("sheet") << false << xc << true; QTest::newRow("Sheet-GL") << QStringLiteral("sheet") << true << oc << true; QTest::newRow("Sheet-GL-no-anim") << QStringLiteral("sheet") << false << oc << false; QTest::newRow("ShowFps") << QStringLiteral("showfps") << true << xc << true; QTest::newRow("ShowPaint") << QStringLiteral("showpaint") << true << xc << true; QTest::newRow("Slide") << QStringLiteral("slide") << true << xc << true; QTest::newRow("SlideBack") << QStringLiteral("slideback") << true << xc << true; QTest::newRow("SlidingPopups") << QStringLiteral("slidingpopups") << true << xc << true; QTest::newRow("SnapHelper") << QStringLiteral("snaphelper") << true << xc << true; QTest::newRow("StartupFeedback") << QStringLiteral("startupfeedback") << false << xc << true; QTest::newRow("StartupFeedback-GL") << QStringLiteral("startupfeedback") << true << oc << true; QTest::newRow("ThumbnailAside") << QStringLiteral("thumbnailaside") << true << xc << true; QTest::newRow("TouchPoints") << QStringLiteral("touchpoints") << true << xc << true; QTest::newRow("TrackMouse") << QStringLiteral("trackmouse") << true << xc << true; QTest::newRow("WindowGeometry") << QStringLiteral("windowgeometry") << true << xc << true; QTest::newRow("WobblyWindows") << QStringLiteral("wobblywindows") << false << xc << true; QTest::newRow("WobblyWindows-GL") << QStringLiteral("wobblywindows") << true << oc << true; QTest::newRow("WobblyWindows-GL-no-anim") << QStringLiteral("wobblywindows") << false << oc << false; QTest::newRow("Zoom") << QStringLiteral("zoom") << true << xc << true; QTest::newRow("Non Existing") << QStringLiteral("InvalidName") << false << xc << true; QTest::newRow("Fade - Scripted") << QStringLiteral("fade") << false << xc << true; QTest::newRow("Fade - Scripted + kwin4_effect") << QStringLiteral("kwin4_effect_fade") << false << xc << true; } void TestBuiltInEffectLoader::testSupported() { QFETCH(QString, name); QFETCH(bool, expected); QFETCH(KWin::CompositingType, type); QFETCH(bool, animationsSupported); MockEffectsHandler mockHandler(type); mockHandler.setAnimationsSupported(animationsSupported); QCOMPARE(mockHandler.animationsSupported(), animationsSupported); KWin::BuiltInEffectLoader loader; QCOMPARE(loader.isEffectSupported(name), expected); } void TestBuiltInEffectLoader::testLoadEffect_data() { QTest::addColumn("name"); QTest::addColumn("expected"); QTest::addColumn("type"); const KWin::CompositingType xc = KWin::XRenderCompositing; const KWin::CompositingType oc = KWin::OpenGL2Compositing; QTest::newRow("blur") << QStringLiteral("blur") << false << xc; // fails for GL as it does proper tests on what's supported and doesn't just check whether it's GL QTest::newRow("blur-GL") << QStringLiteral("blur") << false << oc; QTest::newRow("Colorpicker") << QStringLiteral("colorpicker") << false << xc; QTest::newRow("Colorpicker-GL") << QStringLiteral("colorpicker") << true << oc; QTest::newRow("Contrast") << QStringLiteral("contrast") << false << xc; // fails for GL as it does proper tests on what's supported and doesn't just check whether it's GL QTest::newRow("Contrast-GL") << QStringLiteral("contrast") << false << oc; QTest::newRow("CoverSwitch") << QStringLiteral("coverswitch") << false << xc; // TODO: needs GL mocking // QTest::newRow("CoverSwitch-GL") << QStringLiteral("coverswitch") << true << oc; QTest::newRow("Cube") << QStringLiteral("cube") << false << xc; // TODO: needs GL mocking // QTest::newRow("Cube-GL") << QStringLiteral("cube") << true << oc; QTest::newRow("CubeSlide") << QStringLiteral("cubeslide") << false << xc; QTest::newRow("CubeSlide-GL") << QStringLiteral("cubeslide") << true << oc; QTest::newRow("DesktopGrid") << QStringLiteral("desktopgrid") << true << xc; QTest::newRow("DimInactive") << QStringLiteral("diminactive") << true << xc; QTest::newRow("DimScreen") << QStringLiteral("dimScreen") << true << xc; QTest::newRow("FallApart") << QStringLiteral("fallapart") << false << xc; QTest::newRow("FallApart-GL") << QStringLiteral("fallapart") << true << oc; QTest::newRow("FlipSwitch") << QStringLiteral("flipswitch") << false << xc; QTest::newRow("FlipSwitch-GL") << QStringLiteral("flipswitch") << true << oc; QTest::newRow("Glide") << QStringLiteral("glide") << false << xc; QTest::newRow("Glide-GL") << QStringLiteral("glide") << true << oc; QTest::newRow("HighlightWindow") << QStringLiteral("highlightwindow") << true << xc; QTest::newRow("Invert") << QStringLiteral("invert") << false << xc; QTest::newRow("Invert-GL") << QStringLiteral("invert") << true << oc; QTest::newRow("Kscreen") << QStringLiteral("kscreen") << true << xc; QTest::newRow("LookingGlass") << QStringLiteral("lookingglass") << false << xc; QTest::newRow("LookingGlass-GL") << QStringLiteral("lookingglass") << true << oc; QTest::newRow("MagicLamp") << QStringLiteral("magiclamp") << false << xc; QTest::newRow("MagicLamp-GL") << QStringLiteral("magiclamp") << true << oc; QTest::newRow("Magnifier") << QStringLiteral("magnifier") << true << xc; QTest::newRow("MinimizeAnimation") << QStringLiteral("minimizeanimation") << true << xc; QTest::newRow("MouseClick") << QStringLiteral("mouseclick") << true << xc; QTest::newRow("MouseMark") << QStringLiteral("mousemark") << true << xc; QTest::newRow("PresentWindows") << QStringLiteral("presentwindows") << true << xc; QTest::newRow("Resize") << QStringLiteral("resize") << true << xc; + QTest::newRow("Scale") << QStringLiteral("scale") << true << xc; QTest::newRow("ScreenEdge") << QStringLiteral("screenedge") << true << xc; QTest::newRow("ScreenShot") << QStringLiteral("screenshot") << true << xc; QTest::newRow("Sheet") << QStringLiteral("sheet") << false << xc; QTest::newRow("Sheet-GL") << QStringLiteral("sheet") << true << oc; // TODO: Accesses EffectFrame and crashes // QTest::newRow("ShowFps") << QStringLiteral("showfps") << true << xc; QTest::newRow("ShowPaint") << QStringLiteral("showpaint") << true << xc; QTest::newRow("Slide") << QStringLiteral("slide") << true << xc; QTest::newRow("SlideBack") << QStringLiteral("slideback") << true << xc; QTest::newRow("SlidingPopups") << QStringLiteral("slidingpopups") << true << xc; QTest::newRow("SnapHelper") << QStringLiteral("snaphelper") << true << xc; QTest::newRow("StartupFeedback") << QStringLiteral("startupfeedback") << false << xc; // Tries to load shader and makes our test abort // QTest::newRow("StartupFeedback-GL") << QStringLiteral("startupfeedback") << true << oc; QTest::newRow("ThumbnailAside") << QStringLiteral("thumbnailaside") << true << xc; QTest::newRow("Touchpoints") << QStringLiteral("touchpoints") << true << xc; QTest::newRow("TrackMouse") << QStringLiteral("trackmouse") << true << xc; // TODO: Accesses EffectFrame and crashes // QTest::newRow("WindowGeometry") << QStringLiteral("windowgeometry") << true << xc; QTest::newRow("WobblyWindows") << QStringLiteral("wobblywindows") << false << xc; QTest::newRow("WobblyWindows-GL") << QStringLiteral("wobblywindows") << true << oc; QTest::newRow("Zoom") << QStringLiteral("zoom") << true << xc; QTest::newRow("Non Existing") << QStringLiteral("InvalidName") << false << xc; QTest::newRow("Fade - Scripted") << QStringLiteral("fade") << false << xc; QTest::newRow("Fade - Scripted + kwin4_effect") << QStringLiteral("kwin4_effect_fade") << false << xc; } void TestBuiltInEffectLoader::testLoadEffect() { QFETCH(QString, name); QFETCH(bool, expected); QFETCH(KWin::CompositingType, type); MockEffectsHandler mockHandler(type); KWin::BuiltInEffectLoader loader; KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); loader.setConfig(config); qRegisterMetaType(); QSignalSpy spy(&loader, SIGNAL(effectLoaded(KWin::Effect*,QString))); // connect to signal to ensure that we delete the Effect again as the Effect doesn't have a parent connect(&loader, &KWin::BuiltInEffectLoader::effectLoaded, [&name](KWin::Effect *effect, const QString &effectName) { QCOMPARE(effectName, name); effect->deleteLater(); } ); // try to load the Effect QCOMPARE(loader.loadEffect(name), expected); // loading again should fail QVERIFY(!loader.loadEffect(name)); // signal spy should have got the signal if it was expected QCOMPARE(spy.isEmpty(), !expected); if (!spy.isEmpty()) { QCOMPARE(spy.count(), 1); // if we caught a signal it should have the effect name we passed in QList arguments = spy.takeFirst(); QCOMPARE(arguments.count(), 2); QCOMPARE(arguments.at(1).toString(), name); } spy.clear(); QVERIFY(spy.isEmpty()); // now if we wait for the events being processed, the effect will get deleted and it should load again QTest::qWait(1); QCOMPARE(loader.loadEffect(name), expected); // signal spy should have got the signal if it was expected QCOMPARE(spy.isEmpty(), !expected); if (!spy.isEmpty()) { QCOMPARE(spy.count(), 1); // if we caught a signal it should have the effect name we passed in QList arguments = spy.takeFirst(); QCOMPARE(arguments.count(), 2); QCOMPARE(arguments.at(1).toString(), name); } } void TestBuiltInEffectLoader::testLoadBuiltInEffect_data() { // TODO: this test cannot yet test the checkEnabledByDefault functionality as that requires // mocking enough of GL to get the blur effect to think it's supported and enabled by default QTest::addColumn("effect"); QTest::addColumn("name"); QTest::addColumn("expected"); QTest::addColumn("type"); QTest::addColumn("loadFlags"); const KWin::CompositingType xc = KWin::XRenderCompositing; const KWin::CompositingType oc = KWin::OpenGL2Compositing; const KWin::LoadEffectFlags checkDefault = KWin::LoadEffectFlag::Load | KWin::LoadEffectFlag::CheckDefaultFunction; const KWin::LoadEffectFlags forceFlags = KWin::LoadEffectFlag::Load; const KWin::LoadEffectFlags dontLoadFlags = KWin::LoadEffectFlags(); // enabled by default, but not supported QTest::newRow("blur") << KWin::BuiltInEffect::Blur << QStringLiteral("blur") << false << oc << checkDefault; // enabled by default QTest::newRow("HighlightWindow") << KWin::BuiltInEffect::HighlightWindow << QStringLiteral("highlightwindow") << true << xc << checkDefault; // supported but not enabled by default QTest::newRow("LookingGlass-GL") << KWin::BuiltInEffect::LookingGlass << QStringLiteral("lookingglass") << true << oc << checkDefault; // not enabled by default QTest::newRow("MouseClick") << KWin::BuiltInEffect::MouseClick << QStringLiteral("mouseclick") << true << xc << checkDefault; // Force an Effect which will load QTest::newRow("MouseClick-Force") << KWin::BuiltInEffect::MouseClick << QStringLiteral("mouseclick") << true << xc << forceFlags; // Force an Effect which is not supported QTest::newRow("LookingGlass-Force") << KWin::BuiltInEffect::LookingGlass << QStringLiteral("lookingglass") << false << xc << forceFlags; // Force the Effect as supported QTest::newRow("LookingGlass-Force-GL") << KWin::BuiltInEffect::LookingGlass << QStringLiteral("lookingglass") << true << oc << forceFlags; // Enforce no load of effect which is enabled by default QTest::newRow("HighlightWindow-DontLoad") << KWin::BuiltInEffect::HighlightWindow << QStringLiteral("highlightwindow") << false << xc << dontLoadFlags; // Enforce no load of effect which is not enabled by default, but enforced QTest::newRow("MouseClick-DontLoad") << KWin::BuiltInEffect::MouseClick << QStringLiteral("mouseclick") << false << xc << dontLoadFlags; } void TestBuiltInEffectLoader::testLoadBuiltInEffect() { QFETCH(KWin::BuiltInEffect, effect); QFETCH(QString, name); QFETCH(bool, expected); QFETCH(KWin::CompositingType, type); QFETCH(KWin::LoadEffectFlags, loadFlags); MockEffectsHandler mockHandler(type); KWin::BuiltInEffectLoader loader; KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); loader.setConfig(config); qRegisterMetaType(); QSignalSpy spy(&loader, SIGNAL(effectLoaded(KWin::Effect*,QString))); // connect to signal to ensure that we delete the Effect again as the Effect doesn't have a parent connect(&loader, &KWin::BuiltInEffectLoader::effectLoaded, [&name](KWin::Effect *effect, const QString &effectName) { QCOMPARE(effectName, name); effect->deleteLater(); } ); // try to load the Effect QCOMPARE(loader.loadEffect(effect, loadFlags), expected); // loading again should fail QVERIFY(!loader.loadEffect(effect, loadFlags)); // signal spy should have got the signal if it was expected QCOMPARE(spy.isEmpty(), !expected); if (!spy.isEmpty()) { QCOMPARE(spy.count(), 1); // if we caught a signal it should have the effect name we passed in QList arguments = spy.takeFirst(); QCOMPARE(arguments.count(), 2); QCOMPARE(arguments.at(1).toString(), name); } spy.clear(); QVERIFY(spy.isEmpty()); // now if we wait for the events being processed, the effect will get deleted and it should load again QTest::qWait(1); QCOMPARE(loader.loadEffect(effect, loadFlags), expected); // signal spy should have got the signal if it was expected QCOMPARE(spy.isEmpty(), !expected); if (!spy.isEmpty()) { QCOMPARE(spy.count(), 1); // if we caught a signal it should have the effect name we passed in QList arguments = spy.takeFirst(); QCOMPARE(arguments.count(), 2); QCOMPARE(arguments.at(1).toString(), name); } } void TestBuiltInEffectLoader::testLoadAllEffects() { MockEffectsHandler mockHandler(KWin::XRenderCompositing); KWin::BuiltInEffectLoader loader; KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); // prepare the configuration to hard enable/disable the effects we want to load KConfigGroup plugins = config->group("Plugins"); plugins.writeEntry(QStringLiteral("desktopgridEnabled"), false); plugins.writeEntry(QStringLiteral("highlightwindowEnabled"), false); plugins.writeEntry(QStringLiteral("kscreenEnabled"), false); plugins.writeEntry(QStringLiteral("minimizeanimationEnabled"), false); plugins.writeEntry(QStringLiteral("presentwindowsEnabled"), false); plugins.writeEntry(QStringLiteral("screenedgeEnabled"), false); plugins.writeEntry(QStringLiteral("screenshotEnabled"), false); plugins.writeEntry(QStringLiteral("slideEnabled"), false); plugins.writeEntry(QStringLiteral("slidingpopupsEnabled"), false); plugins.writeEntry(QStringLiteral("startupfeedbackEnabled"), false); plugins.writeEntry(QStringLiteral("zoomEnabled"), false); // enable lookingglass as it's not supported plugins.writeEntry(QStringLiteral("lookingglassEnabled"), true); plugins.sync(); loader.setConfig(config); qRegisterMetaType(); QSignalSpy spy(&loader, SIGNAL(effectLoaded(KWin::Effect*,QString))); // connect to signal to ensure that we delete the Effect again as the Effect doesn't have a parent connect(&loader, &KWin::BuiltInEffectLoader::effectLoaded, [](KWin::Effect *effect) { effect->deleteLater(); } ); // the config is prepared so that no Effect gets loaded! loader.queryAndLoadAll(); // we need to wait some time because it's queued QVERIFY(!spy.wait(10)); // now let's prepare a config which has one effect explicitly enabled plugins.writeEntry(QStringLiteral("mouseclickEnabled"), true); plugins.sync(); loader.queryAndLoadAll(); // should load one effect in first go QVERIFY(spy.wait(10)); // and afterwards it should not load another one QVERIFY(!spy.wait(10)); QCOMPARE(spy.size(), 1); // if we caught a signal it should have the effect name we passed in QList arguments = spy.takeFirst(); QCOMPARE(arguments.count(), 2); QCOMPARE(arguments.at(1).toString(), QStringLiteral("mouseclick")); spy.clear(); // let's delete one of the default entries plugins.deleteEntry(QStringLiteral("kscreenEnabled")); plugins.sync(); QVERIFY(spy.isEmpty()); loader.queryAndLoadAll(); // let's use qWait as we need to wait for two signals to be emitted QTest::qWait(100); QCOMPARE(spy.size(), 2); QStringList loadedEffects; for (auto &list : spy) { QCOMPARE(list.size(), 2); loadedEffects << list.at(1).toString(); } qSort(loadedEffects); QCOMPARE(loadedEffects.at(0), QStringLiteral("kscreen")); QCOMPARE(loadedEffects.at(1), QStringLiteral("mouseclick")); } Q_CONSTRUCTOR_FUNCTION(forceXcb) QTEST_MAIN(TestBuiltInEffectLoader) #include "test_builtin_effectloader.moc" diff --git a/autotests/test_plugin_effectloader.cpp b/autotests/test_plugin_effectloader.cpp index 59e295b9d..5143ee08a 100644 --- a/autotests/test_plugin_effectloader.cpp +++ b/autotests/test_plugin_effectloader.cpp @@ -1,419 +1,420 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2014 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 "../effectloader.h" #include "mock_effectshandler.h" #include "../scripting/scriptedeffect.h" // for mocking ScriptedEffect::create // KDE #include #include #include // Qt #include #include Q_DECLARE_METATYPE(KWin::CompositingType) Q_DECLARE_METATYPE(KWin::LoadEffectFlag) Q_DECLARE_METATYPE(KWin::LoadEffectFlags) Q_DECLARE_METATYPE(KWin::Effect*) Q_LOGGING_CATEGORY(KWIN_CORE, "kwin_core") namespace KWin { ScriptedEffect *ScriptedEffect::create(const KPluginMetaData&) { return nullptr; } bool ScriptedEffect::supported() { return true; } } class TestPluginEffectLoader : public QObject { Q_OBJECT private Q_SLOTS: void testHasEffect_data(); void testHasEffect(); void testKnownEffects(); void testSupported_data(); void testSupported(); void testLoadEffect_data(); void testLoadEffect(); void testLoadPluginEffect_data(); void testLoadPluginEffect(); void testLoadAllEffects(); void testCancelLoadAllEffects(); }; void TestPluginEffectLoader::testHasEffect_data() { QTest::addColumn("name"); QTest::addColumn("expected"); // all the built-in effects should fail QTest::newRow("blur") << QStringLiteral("blur") << false; QTest::newRow("ColorPicker") << QStringLiteral("colorpicker") << false; QTest::newRow("Contrast") << QStringLiteral("contrast") << false; QTest::newRow("CoverSwitch") << QStringLiteral("coverswitch") << false; QTest::newRow("Cube") << QStringLiteral("cube") << false; QTest::newRow("CubeSlide") << QStringLiteral("cubeslide") << false; QTest::newRow("DesktopGrid") << QStringLiteral("desktopgrid") << false; QTest::newRow("DimInactive") << QStringLiteral("diminactive") << false; QTest::newRow("DimScreen") << QStringLiteral("dimscreen") << false; QTest::newRow("FallApart") << QStringLiteral("fallapart") << false; QTest::newRow("FlipSwitch") << QStringLiteral("flipswitch") << false; QTest::newRow("Glide") << QStringLiteral("glide") << false; QTest::newRow("HighlightWindow") << QStringLiteral("highlightwindow") << false; QTest::newRow("Invert") << QStringLiteral("invert") << false; QTest::newRow("Kscreen") << QStringLiteral("kscreen") << false; QTest::newRow("LookingGlass") << QStringLiteral("lookingglass") << false; QTest::newRow("MagicLamp") << QStringLiteral("magiclamp") << false; QTest::newRow("Magnifier") << QStringLiteral("magnifier") << false; QTest::newRow("MinimizeAnimation") << QStringLiteral("minimizeanimation") << false; QTest::newRow("MouseClick") << QStringLiteral("mouseclick") << false; QTest::newRow("MouseMark") << QStringLiteral("mousemark") << false; QTest::newRow("PresentWindows") << QStringLiteral("presentwindows") << false; QTest::newRow("Resize") << QStringLiteral("resize") << false; + QTest::newRow("Scale") << QStringLiteral("scale") << false; QTest::newRow("ScreenEdge") << QStringLiteral("screenedge") << false; QTest::newRow("ScreenShot") << QStringLiteral("screenshot") << false; QTest::newRow("Sheet") << QStringLiteral("sheet") << false; QTest::newRow("ShowFps") << QStringLiteral("showfps") << false; QTest::newRow("ShowPaint") << QStringLiteral("showpaint") << false; QTest::newRow("Slide") << QStringLiteral("slide") << false; QTest::newRow("SlideBack") << QStringLiteral("slideback") << false; QTest::newRow("SlidingPopups") << QStringLiteral("slidingpopups") << false; QTest::newRow("SnapHelper") << QStringLiteral("snaphelper") << false; QTest::newRow("StartupFeedback") << QStringLiteral("startupfeedback") << false; QTest::newRow("ThumbnailAside") << QStringLiteral("thumbnailaside") << false; QTest::newRow("TrackMouse") << QStringLiteral("trackmouse") << false; QTest::newRow("WindowGeometry") << QStringLiteral("windowgeometry") << false; QTest::newRow("WobblyWindows") << QStringLiteral("wobblywindows") << false; QTest::newRow("Zoom") << QStringLiteral("zoom") << false; QTest::newRow("Non Existing") << QStringLiteral("InvalidName") << false; // all the scripted effects should fail QTest::newRow("Fade") << QStringLiteral("kwin4_effect_fade") << false; QTest::newRow("FadeDesktop") << QStringLiteral("kwin4_effect_fadedesktop") << false; QTest::newRow("DialogParent") << QStringLiteral("kwin4_effect_dialogparent") << false; QTest::newRow("Login") << QStringLiteral("kwin4_effect_login") << false; QTest::newRow("Logout") << QStringLiteral("kwin4_effect_logout") << false; QTest::newRow("Maximize") << QStringLiteral("kwin4_effect_maximize") << false; QTest::newRow("ScaleIn") << QStringLiteral("kwin4_effect_scalein") << false; QTest::newRow("Translucency") << QStringLiteral("kwin4_effect_translucency") << false; // and the fake effects we use here QTest::newRow("fakeeffectplugin") << QStringLiteral("fakeeffectplugin") << true; QTest::newRow("fakeeffectplugin CS") << QStringLiteral("fakeEffectPlugin") << true; QTest::newRow("effectversion") << QStringLiteral("effectversion") << true; } void TestPluginEffectLoader::testHasEffect() { QFETCH(QString, name); QFETCH(bool, expected); KWin::PluginEffectLoader loader; loader.setPluginSubDirectory(QString()); QCOMPARE(loader.hasEffect(name), expected); } void TestPluginEffectLoader::testKnownEffects() { QStringList expectedEffects; expectedEffects << QStringLiteral("fakeeffectplugin") << QStringLiteral("effectversion"); KWin::PluginEffectLoader loader; loader.setPluginSubDirectory(QString()); QStringList result = loader.listOfKnownEffects(); // at least as many effects as we expect - system running the test could have more effects QVERIFY(result.size() >= expectedEffects.size()); for (const QString &effect : expectedEffects) { QVERIFY(result.contains(effect)); } } void TestPluginEffectLoader::testSupported_data() { QTest::addColumn("name"); QTest::addColumn("expected"); QTest::addColumn("type"); const KWin::CompositingType xc = KWin::XRenderCompositing; const KWin::CompositingType oc = KWin::OpenGL2Compositing; QTest::newRow("invalid") << QStringLiteral("blur") << false << xc; QTest::newRow("fake - xrender") << QStringLiteral("fakeeffectplugin") << false << xc; QTest::newRow("fake - opengl") << QStringLiteral("fakeeffectplugin") << true << oc; QTest::newRow("fake - CS") << QStringLiteral("fakeEffectPlugin") << true << oc; QTest::newRow("version") << QStringLiteral("effectversion") << false << xc; } void TestPluginEffectLoader::testSupported() { QFETCH(QString, name); QFETCH(bool, expected); QFETCH(KWin::CompositingType, type); MockEffectsHandler mockHandler(type); KWin::PluginEffectLoader loader; loader.setPluginSubDirectory(QString()); QCOMPARE(loader.isEffectSupported(name), expected); } void TestPluginEffectLoader::testLoadEffect_data() { QTest::addColumn("name"); QTest::addColumn("expected"); QTest::addColumn("type"); const KWin::CompositingType xc = KWin::XRenderCompositing; const KWin::CompositingType oc = KWin::OpenGL2Compositing; QTest::newRow("invalid") << QStringLiteral("slide") << false << xc; QTest::newRow("fake - xrender") << QStringLiteral("fakeeffectplugin") << false << xc; QTest::newRow("fake - opengl") << QStringLiteral("fakeeffectplugin") << true << oc; QTest::newRow("fake - CS") << QStringLiteral("fakeEffectPlugin") << true << oc; QTest::newRow("version") << QStringLiteral("effectversion") << false << xc; } void TestPluginEffectLoader::testLoadEffect() { QFETCH(QString, name); QFETCH(bool, expected); QFETCH(KWin::CompositingType, type); MockEffectsHandler mockHandler(type); KWin::PluginEffectLoader loader; loader.setPluginSubDirectory(QString()); KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); loader.setConfig(config); qRegisterMetaType(); QSignalSpy spy(&loader, SIGNAL(effectLoaded(KWin::Effect*,QString))); // connect to signal to ensure that we delete the Effect again as the Effect doesn't have a parent connect(&loader, &KWin::PluginEffectLoader::effectLoaded, [&name](KWin::Effect *effect, const QString &effectName) { QCOMPARE(effectName, name.toLower()); effect->deleteLater(); } ); // try to load the Effect QCOMPARE(loader.loadEffect(name), expected); // loading again should fail QVERIFY(!loader.loadEffect(name)); // signal spy should have got the signal if it was expected QCOMPARE(spy.isEmpty(), !expected); if (!spy.isEmpty()) { QCOMPARE(spy.count(), 1); // if we caught a signal it should have the effect name we passed in QList arguments = spy.takeFirst(); QCOMPARE(arguments.count(), 2); QCOMPARE(arguments.at(1).toString(), name.toLower()); } spy.clear(); QVERIFY(spy.isEmpty()); // now if we wait for the events being processed, the effect will get deleted and it should load again QTest::qWait(1); QCOMPARE(loader.loadEffect(name), expected); // signal spy should have got the signal if it was expected QCOMPARE(spy.isEmpty(), !expected); if (!spy.isEmpty()) { QCOMPARE(spy.count(), 1); // if we caught a signal it should have the effect name we passed in QList arguments = spy.takeFirst(); QCOMPARE(arguments.count(), 2); QCOMPARE(arguments.at(1).toString(), name.toLower()); } } void TestPluginEffectLoader::testLoadPluginEffect_data() { QTest::addColumn("name"); QTest::addColumn("expected"); QTest::addColumn("type"); QTest::addColumn("loadFlags"); QTest::addColumn("enabledByDefault"); const KWin::CompositingType xc = KWin::XRenderCompositing; const KWin::CompositingType oc = KWin::OpenGL2Compositing; const KWin::LoadEffectFlags checkDefault = KWin::LoadEffectFlag::Load | KWin::LoadEffectFlag::CheckDefaultFunction; const KWin::LoadEffectFlags forceFlags = KWin::LoadEffectFlag::Load; const KWin::LoadEffectFlags dontLoadFlags = KWin::LoadEffectFlags(); // enabled by default, but not supported QTest::newRow("fakeeffectplugin") << QStringLiteral("fakeeffectplugin") << false << xc << checkDefault << false; // enabled by default, check default false QTest::newRow("supported, check default error") << QStringLiteral("fakeeffectplugin") << false << oc << checkDefault << false; // enabled by default, check default true QTest::newRow("supported, check default") << QStringLiteral("fakeeffectplugin") << true << oc << checkDefault << true; // enabled by default, check default false QTest::newRow("supported, check default error, forced") << QStringLiteral("fakeeffectplugin") << true << oc << forceFlags << false; // enabled by default, check default true QTest::newRow("supported, check default, don't load") << QStringLiteral("fakeeffectplugin") << false << oc << dontLoadFlags << true; // incorrect version QTest::newRow("Version") << QStringLiteral("effectversion") << false << xc << forceFlags << true; } void TestPluginEffectLoader::testLoadPluginEffect() { QFETCH(QString, name); QFETCH(bool, expected); QFETCH(KWin::CompositingType, type); QFETCH(KWin::LoadEffectFlags, loadFlags); QFETCH(bool, enabledByDefault); MockEffectsHandler mockHandler(type); mockHandler.setProperty("testEnabledByDefault", enabledByDefault); KWin::PluginEffectLoader loader; loader.setPluginSubDirectory(QString()); KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); loader.setConfig(config); const auto plugins = KPluginLoader::findPlugins(QString(), [name] (const KPluginMetaData &data) { return data.pluginId().compare(name, Qt::CaseInsensitive) == 0 && data.serviceTypes().contains(QStringLiteral("KWin/Effect")); } ); QCOMPARE(plugins.size(), 1); qRegisterMetaType(); QSignalSpy spy(&loader, SIGNAL(effectLoaded(KWin::Effect*,QString))); // connect to signal to ensure that we delete the Effect again as the Effect doesn't have a parent connect(&loader, &KWin::PluginEffectLoader::effectLoaded, [&name](KWin::Effect *effect, const QString &effectName) { QCOMPARE(effectName, name); effect->deleteLater(); } ); // try to load the Effect QCOMPARE(loader.loadEffect(plugins.first(), loadFlags), expected); // loading again should fail QVERIFY(!loader.loadEffect(plugins.first(), loadFlags)); // signal spy should have got the signal if it was expected QCOMPARE(spy.isEmpty(), !expected); if (!spy.isEmpty()) { QCOMPARE(spy.count(), 1); // if we caught a signal it should have the effect name we passed in QList arguments = spy.takeFirst(); QCOMPARE(arguments.count(), 2); QCOMPARE(arguments.at(1).toString(), name); } spy.clear(); QVERIFY(spy.isEmpty()); // now if we wait for the events being processed, the effect will get deleted and it should load again QTest::qWait(1); QCOMPARE(loader.loadEffect(plugins.first(), loadFlags), expected); // signal spy should have got the signal if it was expected QCOMPARE(spy.isEmpty(), !expected); if (!spy.isEmpty()) { QCOMPARE(spy.count(), 1); // if we caught a signal it should have the effect name we passed in QList arguments = spy.takeFirst(); QCOMPARE(arguments.count(), 2); QCOMPARE(arguments.at(1).toString(), name); } } void TestPluginEffectLoader::testLoadAllEffects() { MockEffectsHandler mockHandler(KWin::OpenGL2Compositing); mockHandler.setProperty("testEnabledByDefault", true); KWin::PluginEffectLoader loader; loader.setPluginSubDirectory(QString()); KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); // prepare the configuration to hard enable/disable the effects we want to load KConfigGroup plugins = config->group("Plugins"); plugins.writeEntry(QStringLiteral("fakeeffectpluginEnabled"), false); plugins.sync(); loader.setConfig(config); qRegisterMetaType(); QSignalSpy spy(&loader, SIGNAL(effectLoaded(KWin::Effect*,QString))); // connect to signal to ensure that we delete the Effect again as the Effect doesn't have a parent connect(&loader, &KWin::PluginEffectLoader::effectLoaded, [](KWin::Effect *effect) { effect->deleteLater(); } ); // the config is prepared so that no Effect gets loaded! loader.queryAndLoadAll(); // we need to wait some time because it's queued and in a thread QVERIFY(!spy.wait(100)); // now let's prepare a config which has one effect explicitly enabled plugins.writeEntry(QStringLiteral("fakeeffectpluginEnabled"), true); plugins.sync(); loader.queryAndLoadAll(); // should load one effect in first go QVERIFY(spy.wait(100)); // and afterwards it should not load another one QVERIFY(!spy.wait(10)); QCOMPARE(spy.size(), 1); // if we caught a signal it should have the effect name we passed in QList arguments = spy.takeFirst(); QCOMPARE(arguments.count(), 2); QCOMPARE(arguments.at(1).toString(), QStringLiteral("fakeeffectplugin")); spy.clear(); } void TestPluginEffectLoader::testCancelLoadAllEffects() { // this test verifies that no test gets loaded when the loader gets cleared MockEffectsHandler mockHandler(KWin::OpenGL2Compositing); KWin::PluginEffectLoader loader; loader.setPluginSubDirectory(QString()); // prepare the configuration to hard enable/disable the effects we want to load KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); KConfigGroup plugins = config->group("Plugins"); plugins.writeEntry(QStringLiteral("fakeeffectpluginEnabled"), true); plugins.sync(); loader.setConfig(config); qRegisterMetaType(); QSignalSpy spy(&loader, &KWin::PluginEffectLoader::effectLoaded); QVERIFY(spy.isValid()); loader.queryAndLoadAll(); loader.clear(); // Should not load any effect QVERIFY(!spy.wait(100)); QVERIFY(spy.isEmpty()); } QTEST_MAIN(TestPluginEffectLoader) #include "test_plugin_effectloader.moc" diff --git a/autotests/test_scripted_effectloader.cpp b/autotests/test_scripted_effectloader.cpp index b308dc7f2..16e970b53 100644 --- a/autotests/test_scripted_effectloader.cpp +++ b/autotests/test_scripted_effectloader.cpp @@ -1,453 +1,454 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2014 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 "../effectloader.h" #include "mock_effectshandler.h" #include "../scripting/scriptedeffect.h" // for mocking #include "../cursor.h" #include "../input.h" #include "../screenedge.h" // KDE #include #include #include // Qt #include #include Q_DECLARE_METATYPE(KWin::LoadEffectFlag) Q_DECLARE_METATYPE(KWin::LoadEffectFlags) Q_DECLARE_METATYPE(KWin::Effect*) Q_DECLARE_METATYPE(KSharedConfigPtr) Q_LOGGING_CATEGORY(KWIN_CORE, "kwin_core") namespace KWin { ScreenEdges *ScreenEdges::s_self = nullptr; void ScreenEdges::reserve(ElectricBorder, QObject *, const char *) { } void ScreenEdges::reserveTouch(ElectricBorder, QAction *) { } InputRedirection *InputRedirection::s_self = nullptr; void InputRedirection::registerShortcut(const QKeySequence &, QAction *) { } namespace MetaScripting { void registration(QScriptEngine *) { } } static QPoint s_cursorPos = QPoint(); QPoint Cursor::pos() { return s_cursorPos; } } class TestScriptedEffectLoader : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void testHasEffect_data(); void testHasEffect(); void testKnownEffects(); void testLoadEffect_data(); void testLoadEffect(); void testLoadScriptedEffect_data(); void testLoadScriptedEffect(); void testLoadAllEffects(); void testCancelLoadAllEffects(); }; void TestScriptedEffectLoader::initTestCase() { auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); QCoreApplication::instance()->setProperty("config", QVariant::fromValue(config)); } void TestScriptedEffectLoader::testHasEffect_data() { QTest::addColumn("name"); QTest::addColumn("expected"); // all the built-in effects should fail QTest::newRow("blur") << QStringLiteral("blur") << false; QTest::newRow("Colorpicker") << QStringLiteral("colorpicker") << false; QTest::newRow("Contrast") << QStringLiteral("contrast") << false; QTest::newRow("CoverSwitch") << QStringLiteral("coverswitch") << false; QTest::newRow("Cube") << QStringLiteral("cube") << false; QTest::newRow("CubeSlide") << QStringLiteral("cubeslide") << false; QTest::newRow("DesktopGrid") << QStringLiteral("desktopgrid") << false; QTest::newRow("DimInactive") << QStringLiteral("diminactive") << false; QTest::newRow("DimScreen") << QStringLiteral("dimscreen") << false; QTest::newRow("FallApart") << QStringLiteral("fallapart") << false; QTest::newRow("FlipSwitch") << QStringLiteral("flipswitch") << false; QTest::newRow("Glide") << QStringLiteral("glide") << false; QTest::newRow("HighlightWindow") << QStringLiteral("highlightwindow") << false; QTest::newRow("Invert") << QStringLiteral("invert") << false; QTest::newRow("Kscreen") << QStringLiteral("kscreen") << false; QTest::newRow("Logout") << QStringLiteral("logout") << false; QTest::newRow("LookingGlass") << QStringLiteral("lookingglass") << false; QTest::newRow("MagicLamp") << QStringLiteral("magiclamp") << false; QTest::newRow("Magnifier") << QStringLiteral("magnifier") << false; QTest::newRow("MinimizeAnimation") << QStringLiteral("minimizeanimation") << false; QTest::newRow("MouseClick") << QStringLiteral("mouseclick") << false; QTest::newRow("MouseMark") << QStringLiteral("mousemark") << false; QTest::newRow("PresentWindows") << QStringLiteral("presentwindows") << false; QTest::newRow("Resize") << QStringLiteral("resize") << false; + QTest::newRow("Scale") << QStringLiteral("scale") << false; QTest::newRow("ScreenEdge") << QStringLiteral("screenedge") << false; QTest::newRow("ScreenShot") << QStringLiteral("screenshot") << false; QTest::newRow("Sheet") << QStringLiteral("sheet") << false; QTest::newRow("ShowFps") << QStringLiteral("showfps") << false; QTest::newRow("ShowPaint") << QStringLiteral("showpaint") << false; QTest::newRow("Slide") << QStringLiteral("slide") << false; QTest::newRow("SlideBack") << QStringLiteral("slideback") << false; QTest::newRow("SlidingPopups") << QStringLiteral("slidingpopups") << false; QTest::newRow("SnapHelper") << QStringLiteral("snaphelper") << false; QTest::newRow("StartupFeedback") << QStringLiteral("startupfeedback") << false; QTest::newRow("ThumbnailAside") << QStringLiteral("thumbnailaside") << false; QTest::newRow("TrackMouse") << QStringLiteral("trackmouse") << false; QTest::newRow("WindowGeometry") << QStringLiteral("windowgeometry") << false; QTest::newRow("WobblyWindows") << QStringLiteral("wobblywindows") << false; QTest::newRow("Zoom") << QStringLiteral("zoom") << false; QTest::newRow("Non Existing") << QStringLiteral("InvalidName") << false; QTest::newRow("Fade - without kwin4_effect") << QStringLiteral("fade") << false; QTest::newRow("Fade + kwin4_effect") << QStringLiteral("kwin4_effect_fade") << true; QTest::newRow("Fade + kwin4_effect + CS") << QStringLiteral("kwin4_eFfect_fAde") << true; QTest::newRow("FadeDesktop") << QStringLiteral("kwin4_effect_fadedesktop") << true; QTest::newRow("FrozenApp") << QStringLiteral("kwin4_effect_frozenapp") << true; QTest::newRow("DialogParent") << QStringLiteral("kwin4_effect_dialogparent") << true; QTest::newRow("Login") << QStringLiteral("kwin4_effect_login") << true; QTest::newRow("Logout") << QStringLiteral("kwin4_effect_logout") << true; QTest::newRow("Maximize") << QStringLiteral("kwin4_effect_maximize") << true; QTest::newRow("ScaleIn") << QStringLiteral("kwin4_effect_scalein") << true; QTest::newRow("Translucency") << QStringLiteral("kwin4_effect_translucency") << true; } void TestScriptedEffectLoader::testHasEffect() { QFETCH(QString, name); QFETCH(bool, expected); MockEffectsHandler mockHandler(KWin::XRenderCompositing); KWin::ScriptedEffectLoader loader; QCOMPARE(loader.hasEffect(name), expected); // each available effect should also be supported QCOMPARE(loader.isEffectSupported(name), expected); if (expected) { mockHandler.setAnimationsSupported(false); QVERIFY(!loader.isEffectSupported(name)); } } void TestScriptedEffectLoader::testKnownEffects() { QStringList expectedEffects; expectedEffects << QStringLiteral("kwin4_effect_dialogparent") << QStringLiteral("kwin4_effect_fade") << QStringLiteral("kwin4_effect_fadedesktop") << QStringLiteral("kwin4_effect_frozenapp") << QStringLiteral("kwin4_effect_login") << QStringLiteral("kwin4_effect_logout") << QStringLiteral("kwin4_effect_maximize") << QStringLiteral("kwin4_effect_scalein") << QStringLiteral("kwin4_effect_translucency"); KWin::ScriptedEffectLoader loader; QStringList result = loader.listOfKnownEffects(); // at least as many effects as we expect - system running the test could have more effects QVERIFY(result.size() >= expectedEffects.size()); for (const QString &effect : expectedEffects) { QVERIFY(result.contains(effect)); } } void TestScriptedEffectLoader::testLoadEffect_data() { QTest::addColumn("name"); QTest::addColumn("expected"); QTest::newRow("Non Existing") << QStringLiteral("InvalidName") << false; QTest::newRow("Fade - without kwin4_effect") << QStringLiteral("fade") << false; QTest::newRow("Fade + kwin4_effect") << QStringLiteral("kwin4_effect_fade") << true; QTest::newRow("Fade + kwin4_effect + CS") << QStringLiteral("kwin4_eFfect_fAde") << true; QTest::newRow("FadeDesktop") << QStringLiteral("kwin4_effect_fadedesktop") << true; QTest::newRow("FrozenApp") << QStringLiteral("kwin4_effect_frozenapp") << true; QTest::newRow("DialogParent") << QStringLiteral("kwin4_effect_dialogparent") << true; QTest::newRow("Login") << QStringLiteral("kwin4_effect_login") << true; QTest::newRow("Logout") << QStringLiteral("kwin4_effect_logout") << true; QTest::newRow("Maximize") << QStringLiteral("kwin4_effect_maximize") << true; QTest::newRow("ScaleIn") << QStringLiteral("kwin4_effect_scalein") << true; QTest::newRow("Translucency") << QStringLiteral("kwin4_effect_translucency") << true; } void TestScriptedEffectLoader::testLoadEffect() { QFETCH(QString, name); QFETCH(bool, expected); MockEffectsHandler mockHandler(KWin::XRenderCompositing); KWin::ScriptedEffectLoader loader; KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); loader.setConfig(config); qRegisterMetaType(); QSignalSpy spy(&loader, SIGNAL(effectLoaded(KWin::Effect*,QString))); // connect to signal to ensure that we delete the Effect again as the Effect doesn't have a parent connect(&loader, &KWin::ScriptedEffectLoader::effectLoaded, [&name](KWin::Effect *effect, const QString &effectName) { QCOMPARE(effectName, name.toLower()); effect->deleteLater(); } ); // try to load the Effect QCOMPARE(loader.loadEffect(name), expected); // loading again should fail QVERIFY(!loader.loadEffect(name)); // signal spy should have got the signal if it was expected QCOMPARE(spy.isEmpty(), !expected); if (!spy.isEmpty()) { QCOMPARE(spy.count(), 1); // if we caught a signal it should have the effect name we passed in QList arguments = spy.takeFirst(); QCOMPARE(arguments.count(), 2); QCOMPARE(arguments.at(1).toString(), name.toLower()); } spy.clear(); QVERIFY(spy.isEmpty()); // now if we wait for the events being processed, the effect will get deleted and it should load again QTest::qWait(1); QCOMPARE(loader.loadEffect(name), expected); // signal spy should have got the signal if it was expected QCOMPARE(spy.isEmpty(), !expected); if (!spy.isEmpty()) { QCOMPARE(spy.count(), 1); // if we caught a signal it should have the effect name we passed in QList arguments = spy.takeFirst(); QCOMPARE(arguments.count(), 2); QCOMPARE(arguments.at(1).toString(), name.toLower()); } } void TestScriptedEffectLoader::testLoadScriptedEffect_data() { QTest::addColumn("name"); QTest::addColumn("expected"); QTest::addColumn("loadFlags"); const KWin::LoadEffectFlags checkDefault = KWin::LoadEffectFlag::Load | KWin::LoadEffectFlag::CheckDefaultFunction; const KWin::LoadEffectFlags forceFlags = KWin::LoadEffectFlag::Load; const KWin::LoadEffectFlags dontLoadFlags = KWin::LoadEffectFlags(); // enabled by default QTest::newRow("Fade") << QStringLiteral("kwin4_effect_fade") << true << checkDefault; // not enabled by default QTest::newRow("Scalein") << QStringLiteral("kwin4_effect_scalein") << true << checkDefault; // Force an Effect which will load QTest::newRow("Scalein-Force") << QStringLiteral("kwin4_effect_scalein") << true << forceFlags; // Enforce no load of effect which is enabled by default QTest::newRow("Fade-DontLoad") << QStringLiteral("kwin4_effect_fade") << false << dontLoadFlags; // Enforce no load of effect which is not enabled by default, but enforced QTest::newRow("Scalein-DontLoad") << QStringLiteral("kwin4_effect_scalein") << false << dontLoadFlags; } void TestScriptedEffectLoader::testLoadScriptedEffect() { QFETCH(QString, name); QFETCH(bool, expected); QFETCH(KWin::LoadEffectFlags, loadFlags); MockEffectsHandler mockHandler(KWin::XRenderCompositing); KWin::ScriptedEffectLoader loader; KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); loader.setConfig(config); const auto services = KPackage::PackageLoader::self()->findPackages(QStringLiteral("KWin/Effect"), QStringLiteral("kwin/effects"), [name] (const KPluginMetaData &metadata) { return metadata.pluginId().compare(name, Qt::CaseInsensitive) == 0; } ); QCOMPARE(services.count(), 1); qRegisterMetaType(); QSignalSpy spy(&loader, SIGNAL(effectLoaded(KWin::Effect*,QString))); // connect to signal to ensure that we delete the Effect again as the Effect doesn't have a parent connect(&loader, &KWin::ScriptedEffectLoader::effectLoaded, [&name](KWin::Effect *effect, const QString &effectName) { QCOMPARE(effectName, name.toLower()); effect->deleteLater(); } ); // try to load the Effect QCOMPARE(loader.loadEffect(services.first(), loadFlags), expected); // loading again should fail QVERIFY(!loader.loadEffect(services.first(), loadFlags)); // signal spy should have got the signal if it was expected QCOMPARE(spy.isEmpty(), !expected); if (!spy.isEmpty()) { QCOMPARE(spy.count(), 1); // if we caught a signal it should have the effect name we passed in QList arguments = spy.takeFirst(); QCOMPARE(arguments.count(), 2); QCOMPARE(arguments.at(1).toString(), name.toLower()); } spy.clear(); QVERIFY(spy.isEmpty()); // now if we wait for the events being processed, the effect will get deleted and it should load again QTest::qWait(1); QCOMPARE(loader.loadEffect(services.first(), loadFlags), expected); // signal spy should have got the signal if it was expected QCOMPARE(spy.isEmpty(), !expected); if (!spy.isEmpty()) { QCOMPARE(spy.count(), 1); // if we caught a signal it should have the effect name we passed in QList arguments = spy.takeFirst(); QCOMPARE(arguments.count(), 2); QCOMPARE(arguments.at(1).toString(), name.toLower()); } } void TestScriptedEffectLoader::testLoadAllEffects() { MockEffectsHandler mockHandler(KWin::XRenderCompositing); KWin::ScriptedEffectLoader loader; KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); const QString kwin4 = QStringLiteral("kwin4_effect_"); // prepare the configuration to hard enable/disable the effects we want to load KConfigGroup plugins = config->group("Plugins"); plugins.writeEntry(kwin4 + QStringLiteral("dialogparentEnabled"), false); plugins.writeEntry(kwin4 + QStringLiteral("fadeEnabled"), false); plugins.writeEntry(kwin4 + QStringLiteral("fadedesktopEnabled"), false); plugins.writeEntry(kwin4 + QStringLiteral("frozenappEnabled"), false); plugins.writeEntry(kwin4 + QStringLiteral("loginEnabled"), false); plugins.writeEntry(kwin4 + QStringLiteral("logoutEnabled"), false); plugins.writeEntry(kwin4 + QStringLiteral("maximizeEnabled"), false); plugins.writeEntry(kwin4 + QStringLiteral("minimizeanimationEnabled"), false); plugins.writeEntry(kwin4 + QStringLiteral("scaleinEnabled"), false); plugins.writeEntry(kwin4 + QStringLiteral("translucencyEnabled"), false); plugins.writeEntry(kwin4 + QStringLiteral("eyeonscreenEnabled"), false); plugins.writeEntry(kwin4 + QStringLiteral("windowapertureEnabled"), false); plugins.writeEntry(kwin4 + QStringLiteral("morphingpopupsEnabled"), false); plugins.sync(); loader.setConfig(config); qRegisterMetaType(); QSignalSpy spy(&loader, SIGNAL(effectLoaded(KWin::Effect*,QString))); // connect to signal to ensure that we delete the Effect again as the Effect doesn't have a parent connect(&loader, &KWin::ScriptedEffectLoader::effectLoaded, [](KWin::Effect *effect) { effect->deleteLater(); } ); // the config is prepared so that no Effect gets loaded! loader.queryAndLoadAll(); // we need to wait some time because it's queued and in a thread QVERIFY(!spy.wait(100)); // now let's prepare a config which has one effect explicitly enabled plugins.writeEntry(kwin4 + QStringLiteral("scaleinEnabled"), true); plugins.sync(); loader.queryAndLoadAll(); // should load one effect in first go QVERIFY(spy.wait(100)); // and afterwards it should not load another one QVERIFY(!spy.wait(10)); QCOMPARE(spy.size(), 1); // if we caught a signal it should have the effect name we passed in QList arguments = spy.takeFirst(); QCOMPARE(arguments.count(), 2); QCOMPARE(arguments.at(1).toString(), kwin4 + QStringLiteral("scalein")); spy.clear(); // let's delete one of the default entries plugins.deleteEntry(kwin4 + QStringLiteral("fadeEnabled")); plugins.sync(); QVERIFY(spy.isEmpty()); loader.queryAndLoadAll(); // let's use qWait as we need to wait for two signals to be emitted QTRY_COMPARE(spy.size(), 2); QStringList loadedEffects; for (auto &list : spy) { QCOMPARE(list.size(), 2); loadedEffects << list.at(1).toString(); } qSort(loadedEffects); QCOMPARE(loadedEffects.at(0), kwin4 + QStringLiteral("fade")); QCOMPARE(loadedEffects.at(1), kwin4 + QStringLiteral("scalein")); } void TestScriptedEffectLoader::testCancelLoadAllEffects() { // this test verifies that no test gets loaded when the loader gets cleared MockEffectsHandler mockHandler(KWin::XRenderCompositing); KWin::ScriptedEffectLoader loader; // prepare the configuration to hard enable/disable the effects we want to load KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); const QString kwin4 = QStringLiteral("kwin4_effect_"); KConfigGroup plugins = config->group("Plugins"); plugins.writeEntry(kwin4 + QStringLiteral("scaleinEnabled"), true); plugins.sync(); loader.setConfig(config); qRegisterMetaType(); QSignalSpy spy(&loader, &KWin::ScriptedEffectLoader::effectLoaded); QVERIFY(spy.isValid()); loader.queryAndLoadAll(); loader.clear(); // Should not load any effect QVERIFY(!spy.wait(100)); QVERIFY(spy.isEmpty()); } QTEST_MAIN(TestScriptedEffectLoader) #include "test_scripted_effectloader.moc" diff --git a/effects/CMakeLists.txt b/effects/CMakeLists.txt index 30b731352..71e011e77 100644 --- a/effects/CMakeLists.txt +++ b/effects/CMakeLists.txt @@ -1,192 +1,195 @@ # KI18N Translation Domain for this library add_definitions(-DTRANSLATION_DOMAIN=\"kwin_effects\" -DEFFECT_BUILTINS) include_directories(${KWIN_SOURCE_DIR}) # for xcbutils.h set(kwin_effect_OWN_LIBS kwineffects ) if( KWIN_HAVE_XRENDER_COMPOSITING ) set(kwin_effect_OWN_LIBS ${kwin_effect_OWN_LIBS} kwinxrenderutils) endif() set(kwin_effect_KDE_LIBS KF5::ConfigGui KF5::ConfigWidgets KF5::GlobalAccel KF5::I18n KF5::WindowSystem KF5::Plasma # screenedge effect KF5::IconThemes KF5::Service KF5::Notifications # screenshot effect ) set(kwin_effect_QT_LIBS Qt5::Concurrent Qt5::DBus Qt5::Quick Qt5::X11Extras ) set(kwin_effect_XLIB_LIBS ${X11_X11_LIB} ) set(kwin_effect_XCB_LIBS XCB::XCB XCB::IMAGE XCB::XFIXES ) if( KWIN_HAVE_XRENDER_COMPOSITING ) set(kwin_effect_XCB_LIBS ${kwin_effect_XCB_LIBS} XCB::RENDER) endif() set(kwin_effect_OWN_LIBS ${kwin_effect_OWN_LIBS} kwinglutils) macro( KWIN4_ADD_EFFECT_BACKEND name ) add_library( ${name} SHARED ${ARGN} ) target_link_libraries( ${name} PRIVATE ${kwin_effect_OWN_LIBS} ${kwin_effect_KDE_LIBS} ${kwin_effect_QT_LIBS} ${kwin_effect_XLIB_LIBS} ${kwin_effect_XCB_LIBS}) endmacro() # Adds effect plugin with given name. Sources are given after the name macro( KWIN4_ADD_EFFECT name ) kwin4_add_effect_backend(kwin4_effect_${name} ${ARGN}) set_target_properties(kwin4_effect_${name} PROPERTIES VERSION 1.0.0 SOVERSION 1 ) set_target_properties(kwin4_effect_${name} PROPERTIES OUTPUT_NAME ${KWIN_NAME}4_effect_${name}) install(TARGETS kwin4_effect_${name} ${INSTALL_TARGETS_DEFAULT_ARGS} ) endmacro() # Install the KWin/Effect service type install( FILES kwineffect.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR} ) # Create initial variables set( kwin4_effect_include_directories ) set( kwin4_effect_builtins_sources logging.cpp effect_builtins.cpp blur/blur.cpp blur/blurshader.cpp colorpicker/colorpicker.cpp cube/cube.cpp cube/cube_proxy.cpp cube/cubeslide.cpp coverswitch/coverswitch.cpp desktopgrid/desktopgrid.cpp diminactive/diminactive.cpp flipswitch/flipswitch.cpp glide/glide.cpp invert/invert.cpp lookingglass/lookingglass.cpp magiclamp/magiclamp.cpp magnifier/magnifier.cpp mouseclick/mouseclick.cpp mousemark/mousemark.cpp presentwindows/presentwindows.cpp presentwindows/presentwindows_proxy.cpp resize/resize.cpp + scale/scale.cpp showfps/showfps.cpp slide/slide.cpp thumbnailaside/thumbnailaside.cpp touchpoints/touchpoints.cpp trackmouse/trackmouse.cpp windowgeometry/windowgeometry.cpp wobblywindows/wobblywindows.cpp zoom/zoom.cpp ) qt5_add_resources( kwin4_effect_builtins_sources shaders.qrc ) kconfig_add_kcfg_files(kwin4_effect_builtins_sources blur/blurconfig.kcfgc cube/cubeslideconfig.kcfgc cube/cubeconfig.kcfgc coverswitch/coverswitchconfig.kcfgc desktopgrid/desktopgridconfig.kcfgc diminactive/diminactiveconfig.kcfgc fallapart/fallapartconfig.kcfgc flipswitch/flipswitchconfig.kcfgc glide/glideconfig.kcfgc lookingglass/lookingglassconfig.kcfgc magiclamp/magiclampconfig.kcfgc magnifier/magnifierconfig.kcfgc mouseclick/mouseclickconfig.kcfgc mousemark/mousemarkconfig.kcfgc presentwindows/presentwindowsconfig.kcfgc resize/resizeconfig.kcfgc + scale/scaleconfig.kcfgc showfps/showfpsconfig.kcfgc slide/slideconfig.kcfgc slidingpopups/slidingpopupsconfig.kcfgc thumbnailaside/thumbnailasideconfig.kcfgc trackmouse/trackmouseconfig.kcfgc windowgeometry/windowgeometryconfig.kcfgc wobblywindows/wobblywindowsconfig.kcfgc zoom/zoomconfig.kcfgc ) # scripted effects add_subdirectory( dialogparent ) add_subdirectory( eyeonscreen ) add_subdirectory( fade ) add_subdirectory( fadedesktop ) add_subdirectory( frozenapp ) add_subdirectory( login ) add_subdirectory( logout ) add_subdirectory( maximize ) add_subdirectory( morphingpopups ) add_subdirectory( scalein ) add_subdirectory( translucency ) add_subdirectory( windowaperture ) ############################################################################### # Built-in effects go here # Common effects add_subdirectory( desktopgrid ) add_subdirectory( diminactive ) include( dimscreen/CMakeLists.txt ) include( fallapart/CMakeLists.txt ) include( highlightwindow/CMakeLists.txt ) include( kscreen/CMakeLists.txt ) add_subdirectory( magiclamp ) include( minimizeanimation/CMakeLists.txt ) add_subdirectory( presentwindows ) add_subdirectory( resize ) include( screenedge/CMakeLists.txt ) add_subdirectory( showfps ) include( showpaint/CMakeLists.txt ) add_subdirectory( slide ) include( slideback/CMakeLists.txt ) include( slidingpopups/CMakeLists.txt ) add_subdirectory( thumbnailaside ) add_subdirectory( windowgeometry ) add_subdirectory( zoom ) # OpenGL-specific effects add_subdirectory( blur ) include( backgroundcontrast/CMakeLists.txt ) add_subdirectory( coverswitch ) add_subdirectory( cube ) add_subdirectory( flipswitch ) add_subdirectory( glide ) add_subdirectory( invert ) add_subdirectory( lookingglass ) add_subdirectory( magnifier ) add_subdirectory( mouseclick ) add_subdirectory( mousemark ) +add_subdirectory( scale ) include( screenshot/CMakeLists.txt ) include( sheet/CMakeLists.txt ) include( snaphelper/CMakeLists.txt ) include( startupfeedback/CMakeLists.txt ) add_subdirectory( trackmouse ) add_subdirectory( wobblywindows ) ############################################################################### # Add the builtins plugin kwin4_add_effect( builtins ${kwin4_effect_builtins_sources} ) diff --git a/effects/effect_builtins.cpp b/effects/effect_builtins.cpp index 30587e77c..bd3630b3b 100644 --- a/effects/effect_builtins.cpp +++ b/effects/effect_builtins.cpp @@ -1,787 +1,803 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2014 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 "effect_builtins.h" #ifdef EFFECT_BUILTINS // common effects #include "backgroundcontrast/contrast.h" #include "blur/blur.h" #include "colorpicker/colorpicker.h" #include "kscreen/kscreen.h" #include "presentwindows/presentwindows.h" #include "screenedge/screenedgeeffect.h" #include "screenshot/screenshot.h" #include "slidingpopups/slidingpopups.h" // Common effects only relevant to desktop #include "desktopgrid/desktopgrid.h" #include "diminactive/diminactive.h" #include "dimscreen/dimscreen.h" #include "fallapart/fallapart.h" #include "highlightwindow/highlightwindow.h" #include "magiclamp/magiclamp.h" #include "minimizeanimation/minimizeanimation.h" #include "resize/resize.h" +#include "scale/scale.h" #include "showfps/showfps.h" #include "showpaint/showpaint.h" #include "slide/slide.h" #include "slideback/slideback.h" #include "thumbnailaside/thumbnailaside.h" #include "touchpoints/touchpoints.h" #include "windowgeometry/windowgeometry.h" #include "zoom/zoom.h" // OpenGL-specific effects for desktop #include "coverswitch/coverswitch.h" #include "cube/cube.h" #include "cube/cubeslide.h" #include "flipswitch/flipswitch.h" #include "glide/glide.h" #include "invert/invert.h" #include "lookingglass/lookingglass.h" #include "magnifier/magnifier.h" #include "mouseclick/mouseclick.h" #include "mousemark/mousemark.h" #include "sheet/sheet.h" #include "snaphelper/snaphelper.h" #include "startupfeedback/startupfeedback.h" #include "trackmouse/trackmouse.h" #include "wobblywindows/wobblywindows.h" #endif #include #include #ifndef EFFECT_BUILTINS #define EFFECT_FALLBACK nullptr, nullptr, nullptr #else #define EFFECT_FALLBACK #endif namespace KWin { namespace BuiltInEffects { template inline Effect *createHelper() { return new T(); } static const QVector s_effectData = { { QString(), QString(), QString(), QString(), QString(), QUrl(), false, false, nullptr, nullptr, nullptr }, { QStringLiteral("blur"), i18ndc("kwin_effects", "Name of a KWin Effect", "Blur"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Blurs the background behind semi-transparent windows"), QStringLiteral("Appearance"), QString(), QUrl(), true, false, #ifdef EFFECT_BUILTINS &createHelper, &BlurEffect::supported, &BlurEffect::enabledByDefault #endif EFFECT_FALLBACK }, { QStringLiteral("colorpicker"), i18ndc("kwin_effects", "Name of a KWin Effect", "Color Picker"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Supports picking a color"), QStringLiteral("Accessibility"), QString(), QUrl(), true, true, #ifdef EFFECT_BUILTINS &createHelper, &ColorPickerEffect::supported, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("contrast"), i18ndc("kwin_effects", "Name of a KWin Effect", "Background contrast"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Improve contrast and readability behind semi-transparent windows"), QStringLiteral("Appearance"), QString(), QUrl(), true, false, #ifdef EFFECT_BUILTINS &createHelper, &ContrastEffect::supported, &ContrastEffect::enabledByDefault #endif EFFECT_FALLBACK }, { QStringLiteral("coverswitch"), i18ndc("kwin_effects", "Name of a KWin Effect", "Cover Switch"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Display a Cover Flow effect for the alt+tab window switcher"), QStringLiteral("Window Management"), QString(), QUrl(QStringLiteral("http://files.kde.org/plasma/kwin/effect-videos/cover_switch.mp4")), false, true, #ifdef EFFECT_BUILTINS &createHelper, &CoverSwitchEffect::supported, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("cube"), i18ndc("kwin_effects", "Name of a KWin Effect", "Desktop Cube"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Display each virtual desktop on a side of a cube"), QStringLiteral("Window Management"), QString(), QUrl(QStringLiteral("http://files.kde.org/plasma/kwin/effect-videos/desktop_cube.ogv")), false, false, #ifdef EFFECT_BUILTINS &createHelper, &CubeEffect::supported, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("cubeslide"), i18ndc("kwin_effects", "Name of a KWin Effect", "Desktop Cube Animation"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Animate desktop switching with a cube"), QStringLiteral("Virtual Desktop Switching Animation"), QStringLiteral("desktop-animations"), QUrl(QStringLiteral("http://files.kde.org/plasma/kwin/effect-videos/desktop_cube_animation.ogv")), false, false, #ifdef EFFECT_BUILTINS &createHelper, &CubeSlideEffect::supported, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("desktopgrid"), i18ndc("kwin_effects", "Name of a KWin Effect", "Desktop Grid"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Zoom out so all desktops are displayed side-by-side in a grid"), QStringLiteral("Window Management"), QString(), QUrl(QStringLiteral("http://files.kde.org/plasma/kwin/effect-videos/desktop_grid.mp4")), true, false, #ifdef EFFECT_BUILTINS &createHelper, nullptr, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("diminactive"), i18ndc("kwin_effects", "Name of a KWin Effect", "Dim Inactive"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Darken inactive windows"), QStringLiteral("Focus"), QString(), QUrl(QStringLiteral("http://files.kde.org/plasma/kwin/effect-videos/dim_inactive.mp4")), false, false, #ifdef EFFECT_BUILTINS &createHelper, nullptr, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("dimscreen"), i18ndc("kwin_effects", "Name of a KWin Effect", "Dim Screen for Administrator Mode"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Darkens the entire screen when requesting root privileges"), QStringLiteral("Focus"), QString(), QUrl(QStringLiteral("http://files.kde.org/plasma/kwin/effect-videos/dim_administration.mp4")), false, false, #ifdef EFFECT_BUILTINS &createHelper, nullptr, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("fallapart"), i18ndc("kwin_effects", "Name of a KWin Effect", "Fall Apart"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Closed windows fall into pieces"), QStringLiteral("Candy"), QString(), QUrl(), false, false, #ifdef EFFECT_BUILTINS &createHelper, &FallApartEffect::supported, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("flipswitch"), i18ndc("kwin_effects", "Name of a KWin Effect", "Flip Switch"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Flip through windows that are in a stack for the alt+tab window switcher"), QStringLiteral("Window Management"), QString(), QUrl(QStringLiteral("http://files.kde.org/plasma/kwin/effect-videos/flip_switch.mp4")), false, false, #ifdef EFFECT_BUILTINS &createHelper, &FlipSwitchEffect::supported, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("glide"), i18ndc("kwin_effects", "Name of a KWin Effect", "Glide"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Glide windows as they appear or disappear"), QStringLiteral("Appearance"), QString(), QUrl(), false, false, #ifdef EFFECT_BUILTINS &createHelper, &GlideEffect::supported, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("highlightwindow"), i18ndc("kwin_effects", "Name of a KWin Effect", "Highlight Window"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Highlight the appropriate window when hovering over taskbar entries"), QStringLiteral("Appearance"), QString(), QUrl(), true, true, #ifdef EFFECT_BUILTINS &createHelper, nullptr, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("invert"), i18ndc("kwin_effects", "Name of a KWin Effect", "Invert"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Inverts the color of the desktop and windows"), QStringLiteral("Accessibility"), QString(), QUrl(QStringLiteral("http://files.kde.org/plasma/kwin/effect-videos/invert.mp4")), false, false, #ifdef EFFECT_BUILTINS &createHelper, &InvertEffect::supported, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("kscreen"), i18ndc("kwin_effects", "Name of a KWin Effect", "Kscreen"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Helper Effect for KScreen"), QStringLiteral("Appearance"), QString(), QUrl(), true, true, #ifdef EFFECT_BUILTINS &createHelper, nullptr, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("lookingglass"), i18ndc("kwin_effects", "Name of a KWin Effect", "Looking Glass"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "A screen magnifier that looks like a fisheye lens"), QStringLiteral("Accessibility"), QStringLiteral("magnifiers"), QUrl(QStringLiteral("http://files.kde.org/plasma/kwin/effect-videos/looking_glass.ogv")), false, false, #ifdef EFFECT_BUILTINS &createHelper, &LookingGlassEffect::supported, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("magiclamp"), i18ndc("kwin_effects", "Name of a KWin Effect", "Magic Lamp"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Simulate a magic lamp when minimizing windows"), QStringLiteral("Appearance"), QStringLiteral("minimize"), QUrl(QStringLiteral("http://files.kde.org/plasma/kwin/effect-videos/magic_lamp.ogv")), false, false, #ifdef EFFECT_BUILTINS &createHelper, &MagicLampEffect::supported, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("magnifier"), i18ndc("kwin_effects", "Name of a KWin Effect", "Magnifier"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Magnify the section of the screen that is near the mouse cursor"), QStringLiteral("Accessibility"), QStringLiteral("magnifiers"), QUrl(QStringLiteral("http://files.kde.org/plasma/kwin/effect-videos/magnifier.ogv")), false, false, #ifdef EFFECT_BUILTINS &createHelper, &MagnifierEffect::supported, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("minimizeanimation"), i18ndc("kwin_effects", "Name of a KWin Effect", "Minimize Animation"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Animate the minimizing of windows"), QStringLiteral("Appearance"), QStringLiteral("minimize"), QUrl(QStringLiteral("http://files.kde.org/plasma/kwin/effect-videos/minimize.ogv")), true, false, #ifdef EFFECT_BUILTINS &createHelper, &MinimizeAnimationEffect::supported, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("mouseclick"), i18ndc("kwin_effects", "Name of a KWin Effect", "Mouse Click Animation"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Creates an animation whenever a mouse button is clicked. This is useful for screenrecordings/presentations"), QStringLiteral("Accessibility"), QString(), QUrl(QStringLiteral("http://files.kde.org/plasma/kwin/effect-videos/mouse_click.mp4")), false, false, #ifdef EFFECT_BUILTINS &createHelper, nullptr, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("mousemark"), i18ndc("kwin_effects", "Name of a KWin Effect", "Mouse Mark"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Allows you to draw lines on the desktop"), QStringLiteral("Appearance"), QString(), QUrl(), false, false, #ifdef EFFECT_BUILTINS &createHelper, nullptr, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("presentwindows"), i18ndc("kwin_effects", "Name of a KWin Effect", "Present Windows"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Zoom out until all opened windows can be displayed side-by-side"), QStringLiteral("Window Management"), QString(), QUrl(QStringLiteral("http://files.kde.org/plasma/kwin/effect-videos/present_windows.mp4")), true, false, #ifdef EFFECT_BUILTINS &createHelper, nullptr, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("resize"), i18ndc("kwin_effects", "Name of a KWin Effect", "Resize Window"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Resizes windows with a fast texture scale instead of updating contents"), QStringLiteral("Window Management"), QString(), QUrl(), false, false, #ifdef EFFECT_BUILTINS &createHelper, nullptr, nullptr #endif +EFFECT_FALLBACK + }, { + QStringLiteral("scale"), + i18ndc("kwin_effects", "Name of a KWin Effect", "Scale"), + i18ndc("kwin_effects", "Comment describing the KWin Effect", "Make windows smoothly scale in and out when they are shown or hidden"), + QStringLiteral("Appearance"), + QString(), + QUrl(), + false, + false, +#ifdef EFFECT_BUILTINS + &createHelper, + &ScaleEffect::supported, + nullptr +#endif EFFECT_FALLBACK }, { QStringLiteral("screenedge"), i18ndc("kwin_effects", "Name of a KWin Effect", "Screen Edge"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Highlights a screen edge when approaching"), QStringLiteral("Appearance"), QString(), QUrl(), true, false, #ifdef EFFECT_BUILTINS &createHelper, nullptr, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("screenshot"), i18ndc("kwin_effects", "Name of a KWin Effect", "Screenshot"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Helper effect for KSnapshot"), QStringLiteral("Appearance"), QString(), QUrl(), true, true, #ifdef EFFECT_BUILTINS &createHelper, &ScreenShotEffect::supported, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("sheet"), i18ndc("kwin_effects", "Name of a KWin Effect", "Sheet"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Make modal dialogs smoothly fly in and out when they are shown or hidden"), QStringLiteral("Candy"), QString(), QUrl(), false, false, #ifdef EFFECT_BUILTINS &createHelper, &SheetEffect::supported, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("showfps"), i18ndc("kwin_effects", "Name of a KWin Effect", "Show FPS"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Display KWin's performance in the corner of the screen"), QStringLiteral("Tools"), QString(), QUrl(), false, false, #ifdef EFFECT_BUILTINS &createHelper, nullptr, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("showpaint"), i18ndc("kwin_effects", "Name of a KWin Effect", "Show Paint"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Highlight areas of the desktop that have been recently updated"), QStringLiteral("Tools"), QString(), QUrl(), false, false, #ifdef EFFECT_BUILTINS &createHelper, nullptr, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("slide"), i18ndc("kwin_effects", "Name of a KWin Effect", "Slide"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Slide desktops when switching virtual desktops"), QStringLiteral("Virtual Desktop Switching Animation"), QStringLiteral("desktop-animations"), QUrl(QStringLiteral("http://files.kde.org/plasma/kwin/effect-videos/slide.ogv")), true, false, #ifdef EFFECT_BUILTINS &createHelper, &SlideEffect::supported, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("slideback"), i18ndc("kwin_effects", "Name of a KWin Effect", "Slide Back"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Slide back windows when another window is raised"), QStringLiteral("Focus"), QString(), QUrl(), false, false, #ifdef EFFECT_BUILTINS &createHelper, nullptr, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("slidingpopups"), i18ndc("kwin_effects", "Name of a KWin Effect", "Sliding popups"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Sliding animation for Plasma popups"), QStringLiteral("Appearance"), QString(), QUrl(QStringLiteral("http://files.kde.org/plasma/kwin/effect-videos/sliding_popups.mp4")), true, false, #ifdef EFFECT_BUILTINS &createHelper, &SlidingPopupsEffect::supported, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("snaphelper"), i18ndc("kwin_effects", "Name of a KWin Effect", "Snap Helper"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Help you locate the center of the screen when moving a window"), QStringLiteral("Accessibility"), QString(), QUrl(QStringLiteral("http://files.kde.org/plasma/kwin/effect-videos/snap_helper.mp4")), false, false, #ifdef EFFECT_BUILTINS &createHelper, nullptr, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("startupfeedback"), i18ndc("kwin_effects", "Name of a KWin Effect", "Startup Feedback"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Helper effect for startup feedback"), QStringLiteral("Candy"), QString(), QUrl(), true, true, #ifdef EFFECT_BUILTINS &createHelper, &StartupFeedbackEffect::supported, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("thumbnailaside"), i18ndc("kwin_effects", "Name of a KWin Effect", "Thumbnail Aside"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Display window thumbnails on the edge of the screen"), QStringLiteral("Appearance"), QString(), QUrl(), false, false, #ifdef EFFECT_BUILTINS &createHelper, nullptr, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("touchpoints"), i18ndc("kwin_effects", "Name of a KWin Effect", "Touch Points"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Visualize touch points"), QStringLiteral("Appearance"), QString(), QUrl(), false, false, #ifdef EFFECT_BUILTINS &createHelper, nullptr, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("trackmouse"), i18ndc("kwin_effects", "Name of a KWin Effect", "Track Mouse"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Display a mouse cursor locating effect when activated"), QStringLiteral("Accessibility"), QString(), QUrl(QStringLiteral("http://files.kde.org/plasma/kwin/effect-videos/track_mouse.mp4")), false, false, #ifdef EFFECT_BUILTINS &createHelper, nullptr, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("windowgeometry"), i18ndc("kwin_effects", "Name of a KWin Effect", "Window Geometry"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Display window geometries on move/resize"), QStringLiteral("Appearance"), QString(), QUrl(), false, true, #ifdef EFFECT_BUILTINS &createHelper, nullptr, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("wobblywindows"), i18ndc("kwin_effects", "Name of a KWin Effect", "Wobbly Windows"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Deform windows while they are moving"), QStringLiteral("Candy"), QString(), QUrl(QStringLiteral("http://files.kde.org/plasma/kwin/effect-videos/wobbly_windows.ogv")), false, false, #ifdef EFFECT_BUILTINS &createHelper, &WobblyWindowsEffect::supported, nullptr #endif EFFECT_FALLBACK }, { QStringLiteral("zoom"), i18ndc("kwin_effects", "Name of a KWin Effect", "Zoom"), i18ndc("kwin_effects", "Comment describing the KWin Effect", "Magnify the entire desktop"), QStringLiteral("Accessibility"), QStringLiteral("magnifiers"), QUrl(QStringLiteral("http://files.kde.org/plasma/kwin/effect-videos/zoom.ogv")), true, false, #ifdef EFFECT_BUILTINS &createHelper, nullptr, nullptr #endif EFFECT_FALLBACK } }; static inline int index(BuiltInEffect effect) { return static_cast(effect); } Effect *create(BuiltInEffect effect) { const EffectData &data = effectData(effect); if (data.createFunction == nullptr) { return nullptr; } return data.createFunction(); } bool available(const QString &name) { auto it = std::find_if(s_effectData.begin(), s_effectData.end(), [name](const EffectData &data) { return data.name == name; } ); return it != s_effectData.end(); } bool supported(BuiltInEffect effect) { if (effect == BuiltInEffect::Invalid) { return false; } const EffectData &data = effectData(effect); if (data.supportedFunction == nullptr) { return true; } return data.supportedFunction(); } bool checkEnabledByDefault(BuiltInEffect effect) { if (effect == BuiltInEffect::Invalid) { return false; } const EffectData &data = effectData(effect); if (data.enabledFunction == nullptr) { return true; } return data.enabledFunction(); } bool enabledByDefault(BuiltInEffect effect) { return effectData(effect).enabled; } QStringList availableEffectNames() { QStringList result; for (const EffectData &data : s_effectData) { if (data.name.isEmpty()) { continue; } result << data.name; } return result; } QList< BuiltInEffect > availableEffects() { QList result; for (int i = index(BuiltInEffect::Invalid) + 1; i <= index(BuiltInEffect::Zoom); ++i) { result << BuiltInEffect(i); } return result; } BuiltInEffect builtInForName(const QString &name) { auto it = std::find_if(s_effectData.begin(), s_effectData.end(), [name](const EffectData &data) { return data.name == name; } ); if (it == s_effectData.end()) { return BuiltInEffect::Invalid; } return BuiltInEffect(std::distance(s_effectData.begin(), it)); } QString nameForEffect(BuiltInEffect effect) { return effectData(effect).name; } const EffectData &effectData(BuiltInEffect effect) { return s_effectData.at(index(effect)); } } // BuiltInEffects } // namespace diff --git a/effects/effect_builtins.h b/effects/effect_builtins.h index 77e18c605..7abf4ac3c 100644 --- a/effects/effect_builtins.h +++ b/effects/effect_builtins.h @@ -1,109 +1,110 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2014 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 . *********************************************************************/ #ifndef KWIN_EFFECT_BUILTINS_H #define KWIN_EFFECT_BUILTINS_H #include #include #include #include namespace KWin { class Effect; /** * Defines all the built in effects. **/ enum class BuiltInEffect { Invalid, ///< not a valid Effect Blur, ColorPicker, Contrast, CoverSwitch, Cube, CubeSlide, DesktopGrid, DimInactive, DimScreen, FallApart, FlipSwitch, Glide, HighlightWindow, Invert, Kscreen, LookingGlass, MagicLamp, Magnifier, MinimizeAnimation, MouseClick, MouseMark, PresentWindows, Resize, + Scale, ScreenEdge, ScreenShot, Sheet, ShowFps, ShowPaint, Slide, SlideBack, SlidingPopups, SnapHelper, StartupFeedback, ThumbnailAside, TouchPoints, TrackMouse, WindowGeometry, WobblyWindows, Zoom }; namespace BuiltInEffects { struct EffectData { QString name; QString displayName; QString comment; QString category; QString exclusiveCategory; QUrl video; bool enabled; bool internal; std::function createFunction; std::function supportedFunction; std::function enabledFunction; }; KWINEFFECTS_EXPORT Effect *create(BuiltInEffect effect); KWINEFFECTS_EXPORT bool available(const QString &name); KWINEFFECTS_EXPORT bool supported(BuiltInEffect effect); KWINEFFECTS_EXPORT bool checkEnabledByDefault(BuiltInEffect effect); KWINEFFECTS_EXPORT bool enabledByDefault(BuiltInEffect effect); KWINEFFECTS_EXPORT QString nameForEffect(BuiltInEffect effect); KWINEFFECTS_EXPORT BuiltInEffect builtInForName(const QString &name); KWINEFFECTS_EXPORT QStringList availableEffectNames(); KWINEFFECTS_EXPORT QList availableEffects(); KWINEFFECTS_EXPORT const EffectData &effectData(BuiltInEffect effect); } } #endif diff --git a/effects/scale/CMakeLists.txt b/effects/scale/CMakeLists.txt new file mode 100644 index 000000000..016b2f6fc --- /dev/null +++ b/effects/scale/CMakeLists.txt @@ -0,0 +1,25 @@ +####################################### +# Config +set(kwin_scale_config_SRCS scale_config.cpp) +ki18n_wrap_ui(kwin_scale_config_SRCS scale_config.ui) +qt5_add_dbus_interface(kwin_scale_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) +kconfig_add_kcfg_files(kwin_scale_config_SRCS scaleconfig.kcfgc) + +add_library(kwin_scale_config MODULE ${kwin_scale_config_SRCS}) + +target_link_libraries(kwin_scale_config + Qt5::DBus + KF5::ConfigWidgets + KF5::I18n + KF5::Service +) + +kcoreaddons_desktop_to_json(kwin_scale_config scale_config.desktop SERVICE_TYPES kcmodule.desktop) + +install( + TARGETS + kwin_scale_config + DESTINATION + ${PLUGIN_INSTALL_DIR}/kwin/effects/configs +) + diff --git a/effects/scale/scale.cpp b/effects/scale/scale.cpp new file mode 100644 index 000000000..9a06b8bf3 --- /dev/null +++ b/effects/scale/scale.cpp @@ -0,0 +1,284 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + + Copyright (C) 2018 Vlad Zagorodniy + +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 . +*********************************************************************/ + +// own +#include "scale.h" + +// KConfigSkeleton +#include "scaleconfig.h" + +// Qt +#include + +namespace KWin +{ + +static const QSet s_blacklist { + // The logout screen has to be animated only by the logout effect. + QStringLiteral("ksmserver ksmserver"), + + // KDE Plasma splash screen has to be animated only by the login effect. + QStringLiteral("ksplashqml ksplashqml"), + QStringLiteral("ksplashsimple ksplashsimple"), + QStringLiteral("ksplashx ksplashx") +}; + +ScaleEffect::ScaleEffect() +{ + initConfig(); + reconfigure(ReconfigureAll); + + connect(effects, &EffectsHandler::windowAdded, this, &ScaleEffect::windowAdded); + connect(effects, &EffectsHandler::windowClosed, this, &ScaleEffect::windowClosed); + connect(effects, &EffectsHandler::windowDeleted, this, &ScaleEffect::windowDeleted); + connect(effects, &EffectsHandler::windowDataChanged, this, &ScaleEffect::windowDataChanged); +} + +ScaleEffect::~ScaleEffect() +{ +} + +void ScaleEffect::reconfigure(ReconfigureFlags flags) +{ + Q_UNUSED(flags) + + ScaleConfig::self()->read(); + m_duration = std::chrono::milliseconds(animationTime(160)); + + m_inParams.scale.from = ScaleConfig::inScale(); + m_inParams.scale.to = 1.0; + m_inParams.opacity.from = ScaleConfig::inOpacity(); + m_inParams.opacity.to = 1.0; + + m_outParams.scale.from = 1.0; + m_outParams.scale.to = ScaleConfig::outScale(); + m_outParams.opacity.from = 1.0; + m_outParams.opacity.to = ScaleConfig::outOpacity(); +} + +void ScaleEffect::prePaintScreen(ScreenPrePaintData &data, int time) +{ + const std::chrono::milliseconds delta(time); + + auto animationIt = m_animations.begin(); + while (animationIt != m_animations.end()) { + (*animationIt).update(delta); + ++animationIt; + } + + effects->prePaintScreen(data, time); +} + +void ScaleEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) +{ + if (m_animations.contains(w)) { + data.setTransformed(); + w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DELETE); + } + + effects->prePaintWindow(w, data, time); +} + +void ScaleEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) +{ + auto animationIt = m_animations.constFind(w); + if (animationIt == m_animations.constEnd()) { + effects->paintWindow(w, mask, region, data); + return; + } + + const ScaleParams params = w->isDeleted() ? m_outParams : m_inParams; + const qreal t = (*animationIt).value(); + const qreal scale = interpolate(params.scale.from, params.scale.to, t); + + data.setXScale(scale); + data.setYScale(scale); + data.setXTranslation(0.5 * (1.0 - scale) * w->width()); + data.setYTranslation(0.5 * (1.0 - scale) * w->height()); + data.multiplyOpacity(interpolate(params.opacity.from, params.opacity.to, t)); + + effects->paintWindow(w, mask, region, data); +} + +void ScaleEffect::postPaintScreen() +{ + auto animationIt = m_animations.begin(); + while (animationIt != m_animations.end()) { + EffectWindow *w = animationIt.key(); + + const QRect geo = w->expandedGeometry(); + const ScaleParams params = w->isDeleted() ? m_outParams : m_inParams; + const qreal scale = qMax(params.scale.from, params.scale.to); + const QRect repaintRect( + geo.topLeft() + 0.5 * (1.0 - scale) * QPoint(geo.width(), geo.height()), + geo.size() * scale); + effects->addRepaint(repaintRect); + + if ((*animationIt).done()) { + if (w->isDeleted()) { + w->unrefWindow(); + } else { + w->setData(WindowForceBackgroundContrastRole, QVariant()); + w->setData(WindowForceBlurRole, QVariant()); + } + animationIt = m_animations.erase(animationIt); + } else { + ++animationIt; + } + } + + effects->postPaintScreen(); +} + +bool ScaleEffect::isActive() const +{ + return !m_animations.isEmpty(); +} + +bool ScaleEffect::supported() +{ + return effects->animationsSupported(); +} + +void ScaleEffect::windowAdded(EffectWindow *w) +{ + if (effects->activeFullScreenEffect()) { + return; + } + + if (!isScaleWindow(w)) { + return; + } + + if (!w->isVisible()) { + return; + } + + const void *addGrab = w->data(WindowAddedGrabRole).value(); + if (addGrab && addGrab != this) { + return; + } + + TimeLine &timeLine = m_animations[w]; + timeLine.reset(); + timeLine.setDirection(TimeLine::Forward); + timeLine.setDuration(m_duration); + timeLine.setEasingCurve(QEasingCurve::InCurve); + + w->setData(WindowAddedGrabRole, QVariant::fromValue(static_cast(this))); + w->setData(WindowForceBackgroundContrastRole, QVariant(true)); + w->setData(WindowForceBlurRole, QVariant(true)); + + w->addRepaintFull(); +} + +void ScaleEffect::windowClosed(EffectWindow *w) +{ + if (effects->activeFullScreenEffect()) { + return; + } + + if (!isScaleWindow(w)) { + return; + } + + if (!w->isVisible()) { + return; + } + + const void *closeGrab = w->data(WindowClosedGrabRole).value(); + if (closeGrab && closeGrab != this) { + return; + } + + w->refWindow(); + + TimeLine &timeLine = m_animations[w]; + timeLine.reset(); + timeLine.setDirection(TimeLine::Forward); + timeLine.setDuration(m_duration); + timeLine.setEasingCurve(QEasingCurve::OutCurve); + + w->setData(WindowClosedGrabRole, QVariant::fromValue(static_cast(this))); + w->setData(WindowForceBackgroundContrastRole, QVariant(true)); + w->setData(WindowForceBlurRole, QVariant(true)); + + w->addRepaintFull(); +} + +void ScaleEffect::windowDeleted(EffectWindow *w) +{ + m_animations.remove(w); +} + +void ScaleEffect::windowDataChanged(EffectWindow *w, int role) +{ + if (role != WindowAddedGrabRole && role != WindowClosedGrabRole) { + return; + } + + if (w->data(role).value() == this) { + return; + } + + auto animationIt = m_animations.find(w); + if (animationIt == m_animations.end()) { + return; + } + + if (w->isDeleted() && role == WindowClosedGrabRole) { + w->unrefWindow(); + } + + m_animations.erase(animationIt); + + w->setData(WindowForceBackgroundContrastRole, QVariant()); + w->setData(WindowForceBlurRole, QVariant()); +} + +bool ScaleEffect::isScaleWindow(EffectWindow *w) const +{ + // We don't want to animate most of plasmashell's windows, yet, some + // of them we want to, for example, Task Manager Settings window. + // The problem is that all those window share single window class. + // So, the only way to decide whether a window should be animated is + // to use a heuristic: if a window has decoration, then it's most + // likely a dialog or a settings window so we have to animate it. + if (w->windowClass() == QLatin1String("plasmashell plasmashell")) { + return w->hasDecoration(); + } + + if (s_blacklist.contains(w->windowClass())) { + return false; + } + + if (w->hasDecoration()) { + return true; + } + + if (!w->isManaged()) { + return false; + } + + return w->isNormalWindow() + || w->isDialog(); +} + +} // namespace KWin diff --git a/effects/scale/scale.h b/effects/scale/scale.h new file mode 100644 index 000000000..68f3cff11 --- /dev/null +++ b/effects/scale/scale.h @@ -0,0 +1,116 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + + Copyright (C) 2018 Vlad Zagorodniy + +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 . +*********************************************************************/ + +#ifndef KWIN_SCALE_H +#define KWIN_SCALE_H + +// kwineffects +#include + +namespace KWin +{ + +class ScaleEffect : public Effect +{ + Q_OBJECT + Q_PROPERTY(int duration READ duration) + Q_PROPERTY(qreal inScale READ inScale) + Q_PROPERTY(qreal inOpacity READ inOpacity) + Q_PROPERTY(qreal outScale READ outScale) + Q_PROPERTY(qreal outOpacity READ outOpacity) + +public: + ScaleEffect(); + ~ScaleEffect() override; + + void reconfigure(ReconfigureFlags flags) override; + + void prePaintScreen(ScreenPrePaintData &data, int time) override; + void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) override; + void paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) override; + void postPaintScreen() override; + + bool isActive() const override; + int requestedEffectChainPosition() const override; + + static bool supported(); + + int duration() const; + qreal inScale() const; + qreal inOpacity() const; + qreal outScale() const; + qreal outOpacity() const; + +private Q_SLOTS: + void windowAdded(EffectWindow *w); + void windowClosed(EffectWindow *w); + void windowDeleted(EffectWindow *w); + void windowDataChanged(EffectWindow *w, int role); + +private: + bool isScaleWindow(EffectWindow *w) const; + + std::chrono::milliseconds m_duration; + QHash m_animations; + + struct ScaleParams { + struct { + qreal from; + qreal to; + } scale, opacity; + }; + + ScaleParams m_inParams; + ScaleParams m_outParams; +}; + +inline int ScaleEffect::requestedEffectChainPosition() const +{ + return 50; +} + +inline int ScaleEffect::duration() const +{ + return m_duration.count(); +} + +inline qreal ScaleEffect::inScale() const +{ + return m_inParams.scale.from; +} + +inline qreal ScaleEffect::inOpacity() const +{ + return m_inParams.opacity.from; +} + +inline qreal ScaleEffect::outScale() const +{ + return m_outParams.scale.to; +} + +inline qreal ScaleEffect::outOpacity() const +{ + return m_outParams.opacity.to; +} + +} // namespace KWin + +#endif diff --git a/effects/scale/scale.kcfg b/effects/scale/scale.kcfg new file mode 100644 index 000000000..2b77c303c --- /dev/null +++ b/effects/scale/scale.kcfg @@ -0,0 +1,28 @@ + + + + + + 0 + + + 0.96 + + + 0.4 + 0.0 + 1.0 + + + 0.96 + + + 0.0 + 0.0 + 1.0 + + + diff --git a/effects/scale/scale_config.cpp b/effects/scale/scale_config.cpp new file mode 100644 index 000000000..8b078add8 --- /dev/null +++ b/effects/scale/scale_config.cpp @@ -0,0 +1,62 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + + Copyright (C) 2018 Vlad Zagorodniy + +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 "scale_config.h" + +// KConfigSkeleton +#include "scaleconfig.h" +#include + +#include +#include +#include + +K_PLUGIN_FACTORY_WITH_JSON(ScaleEffectConfigFactory, + "scale_config.json", + registerPlugin();) + +namespace KWin +{ + +ScaleEffectConfig::ScaleEffectConfig(QWidget *parent, const QVariantList &args) + : KCModule(KAboutData::pluginData(QStringLiteral("scale")), parent, args) +{ + ui.setupUi(this); + ScaleConfig::instance(KWIN_CONFIG); + addConfig(ScaleConfig::self(), this); + load(); +} + +ScaleEffectConfig::~ScaleEffectConfig() +{ +} + +void ScaleEffectConfig::save() +{ + KCModule::save(); + OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"), + QStringLiteral("/Effects"), + QDBusConnection::sessionBus()); + interface.reconfigureEffect(QStringLiteral("scale")); +} + +} // namespace KWin + +#include "scale_config.moc" diff --git a/effects/scale/scale_config.desktop b/effects/scale/scale_config.desktop new file mode 100644 index 000000000..b018be93e --- /dev/null +++ b/effects/scale/scale_config.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KCModule + +X-KDE-Library=kwin_scale_config +X-KDE-ParentComponents=scale + +Name=Scale diff --git a/effects/scale/scale_config.h b/effects/scale/scale_config.h new file mode 100644 index 000000000..d26f361f1 --- /dev/null +++ b/effects/scale/scale_config.h @@ -0,0 +1,48 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + + Copyright (C) 2018 Vlad Zagorodniy + +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 . +*********************************************************************/ + +#ifndef SCALE_CONFIG_H +#define SCALE_CONFIG_H + +#include "ui_scale_config.h" + +#include + +namespace KWin +{ + +class ScaleEffectConfig : public KCModule +{ + Q_OBJECT + +public: + explicit ScaleEffectConfig(QWidget *parent = nullptr, const QVariantList &args = QVariantList()); + ~ScaleEffectConfig() override; + + void save() override; + +private: + ::Ui::ScaleEffectConfig ui; +}; + +} // namespace KWin + +#endif + diff --git a/effects/scale/scale_config.ui b/effects/scale/scale_config.ui new file mode 100644 index 000000000..97b43b57f --- /dev/null +++ b/effects/scale/scale_config.ui @@ -0,0 +1,93 @@ + + + ScaleEffectConfig + + + + 0 + 0 + 455 + 177 + + + + + + + Duration: + + + + + + + + 0 + 0 + + + + Default + + + milliseconds + + + 9999 + + + 5 + + + + + + + Window open scale: + + + + + + + Window close scale: + + + + + + + + 0 + 0 + + + + 9.990000000000000 + + + 0.050000000000000 + + + + + + + + 0 + 0 + + + + 9.990000000000000 + + + 0.050000000000000 + + + + + + + + diff --git a/effects/scale/scaleconfig.kcfgc b/effects/scale/scaleconfig.kcfgc new file mode 100644 index 000000000..2b9bc9911 --- /dev/null +++ b/effects/scale/scaleconfig.kcfgc @@ -0,0 +1,5 @@ +File=scale.kcfg +ClassName=ScaleConfig +NameSpace=KWin +Singleton=true +Mutators=true