1 /*
2     SPDX-FileCopyrightText: 2016 Marco Martin <mart@kde.org>
3 
4     SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "themetest.h"
8 #include "../src/plasma/private/svg_p.h"
9 #include <QApplication>
10 #include <QSignalSpy>
11 #include <QStandardPaths>
12 
13 #include <KIconLoader>
14 #include <KIconTheme>
15 #include <KWindowSystem>
16 
17 #include <config-plasma.h>
18 #if HAVE_X11
19 #include <KSelectionOwner>
20 #endif
21 #include <array>
22 
cacheIdHash(const Plasma::SvgPrivate::CacheId & id)23 QString cacheIdHash(const Plasma::SvgPrivate::CacheId &id)
24 {
25     static const uint seed = 0x9e3779b9;
26     std::array<uint, 10> parts = {::qHash(id.width),
27                                   ::qHash(id.height),
28                                   ::qHash(id.elementName),
29                                   ::qHash(id.filePath),
30                                   ::qHash(id.status),
31                                   ::qHash(id.devicePixelRatio),
32                                   ::qHash(id.scaleFactor),
33                                   ::qHash(id.colorGroup),
34                                   ::qHash(id.extraFlags),
35                                   ::qHash(id.lastModified)};
36     return QString::number(qHashRange(parts.begin(), parts.end(), seed));
37 }
38 
initTestCase()39 void ThemeTest::initTestCase()
40 {
41     // make our theme in search path
42     qputenv("XDG_DATA_DIRS", qgetenv("XDG_DATA_DIRS") + ":" + QFINDTESTDATA("data").toLocal8Bit());
43 
44     // set default icon theme to test-theme
45     QStandardPaths::setTestModeEnabled(true);
46 
47     m_theme = new Plasma::Theme("testtheme", this);
48     QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
49 
50     if (!QDir(configPath).mkpath(QStringLiteral("."))) {
51         qFatal("Failed to create test configuration directory.");
52     }
53 
54     QFile::remove(configPath);
55 
56     QIcon::setThemeSearchPaths(QStringList() << QFINDTESTDATA("data/icons"));
57 
58     KConfigGroup plasmaConfig(KSharedConfig::openConfig("plasmarc"), "Theme");
59     plasmaConfig.writeEntry("name", "default");
60     m_svg = new Plasma::Svg();
61 
62     KIconTheme::forceThemeForTests("test-theme");
63     KSharedConfig::openConfig()->reparseConfiguration();
64     KIconTheme::reconfigure();
65     KIconLoader::global()->reconfigure(QString());
66 }
67 
cleanupTestCase()68 void ThemeTest::cleanupTestCase()
69 {
70     //    m_testIconsDir.removeRecursively();
71     delete m_svg;
72 }
73 
loadSvgIcon()74 void ThemeTest::loadSvgIcon()
75 {
76     const auto *iconTheme = KIconLoader::global()->theme();
77     QString iconPath;
78     if (iconTheme) {
79         iconPath = iconTheme->iconPath(QLatin1String("konversation.svg"), 48, KIconLoader::MatchBest);
80     }
81 
82     QVERIFY(iconTheme);
83     QVERIFY(iconTheme->isValid());
84     QVERIFY2(QFile::exists(iconPath), qPrintable(iconPath));
85     m_svg->setImagePath(iconPath);
86     QVERIFY(m_svg->isValid());
87 
88     m_svg->pixmap(); // trigger the SVG being loaded
89 
90     QFileInfo info(iconPath);
91 
92     QString cacheId = cacheIdHash(Plasma::SvgPrivate::CacheId{48,
93                                                               48,
94                                                               iconPath,
95                                                               QString(),
96                                                               m_svg->status(),
97                                                               m_svg->devicePixelRatio(),
98                                                               m_svg->scaleFactor(),
99                                                               m_svg->colorGroup(),
100                                                               0,
101                                                               static_cast<uint>(info.lastModified().toSecsSinceEpoch())});
102 
103     QPixmap result;
104     QVERIFY(m_svg->theme()->findInCache(cacheId, result, info.lastModified().toSecsSinceEpoch()));
105 
106     QSignalSpy spy(m_svg, SIGNAL(repaintNeeded()));
107     QVERIFY(spy.isValid());
108 
109     KIconTheme::forceThemeForTests("test-theme-two");
110     // KIconloader needs changesto be emitted manually, ouch.
111     for (int i = 0; i < KIconLoader::LastGroup; i++) {
112         KIconLoader::emitChange(KIconLoader::Group(i));
113     }
114 
115     spy.wait();
116     // Svg emitting repaintNeeded when something changes in KIconLoader means the svg loaded an icon
117     QVERIFY(spy.count() == 1);
118 
119     QVERIFY(!m_svg->theme()->findInCache(cacheId, result));
120 }
121 
testColors()122 void ThemeTest::testColors()
123 {
124     QCOMPARE(m_theme->color(Plasma::Theme::TextColor, Plasma::Theme::NormalColorGroup), QColor(49, 54, 59));
125     QCOMPARE(m_theme->color(Plasma::Theme::BackgroundColor, Plasma::Theme::NormalColorGroup), QColor(239, 240, 241));
126     QCOMPARE(m_theme->color(Plasma::Theme::HighlightColor, Plasma::Theme::NormalColorGroup), QColor(61, 174, 230));
127     QCOMPARE(m_theme->color(Plasma::Theme::HoverColor, Plasma::Theme::NormalColorGroup), QColor(61, 174, 230));
128     QCOMPARE(m_theme->color(Plasma::Theme::FocusColor, Plasma::Theme::NormalColorGroup), QColor(30, 146, 255));
129     QCOMPARE(m_theme->color(Plasma::Theme::LinkColor, Plasma::Theme::NormalColorGroup), QColor(61, 174, 230));
130     QCOMPARE(m_theme->color(Plasma::Theme::VisitedLinkColor, Plasma::Theme::NormalColorGroup), QColor(61, 174, 230));
131     QCOMPARE(m_theme->color(Plasma::Theme::HighlightedTextColor, Plasma::Theme::NormalColorGroup), QColor(252, 252, 252));
132     QCOMPARE(m_theme->color(Plasma::Theme::PositiveTextColor, Plasma::Theme::NormalColorGroup), QColor(17, 209, 22));
133     QCOMPARE(m_theme->color(Plasma::Theme::NeutralTextColor, Plasma::Theme::NormalColorGroup), QColor(201, 206, 59));
134     QCOMPARE(m_theme->color(Plasma::Theme::NegativeTextColor, Plasma::Theme::NormalColorGroup), QColor(237, 21, 21));
135 
136     QCOMPARE(m_theme->color(Plasma::Theme::TextColor, Plasma::Theme::ButtonColorGroup), QColor(49, 54, 59));
137     QCOMPARE(m_theme->color(Plasma::Theme::BackgroundColor, Plasma::Theme::ButtonColorGroup), QColor(239, 240, 241));
138     QCOMPARE(m_theme->color(Plasma::Theme::HighlightColor, Plasma::Theme::ButtonColorGroup), QColor(61, 174, 230));
139     QCOMPARE(m_theme->color(Plasma::Theme::HoverColor, Plasma::Theme::ButtonColorGroup), QColor(61, 174, 230));
140     QCOMPARE(m_theme->color(Plasma::Theme::FocusColor, Plasma::Theme::ButtonColorGroup), QColor(30, 146, 255));
141     QCOMPARE(m_theme->color(Plasma::Theme::LinkColor, Plasma::Theme::ButtonColorGroup), QColor(61, 174, 230));
142     QCOMPARE(m_theme->color(Plasma::Theme::VisitedLinkColor, Plasma::Theme::ButtonColorGroup), QColor(61, 174, 230));
143     QCOMPARE(m_theme->color(Plasma::Theme::HighlightedTextColor, Plasma::Theme::ButtonColorGroup), QColor(252, 252, 252));
144     QCOMPARE(m_theme->color(Plasma::Theme::PositiveTextColor, Plasma::Theme::ButtonColorGroup), QColor(17, 209, 23));
145     QCOMPARE(m_theme->color(Plasma::Theme::NeutralTextColor, Plasma::Theme::ButtonColorGroup), QColor(201, 206, 60));
146     QCOMPARE(m_theme->color(Plasma::Theme::NegativeTextColor, Plasma::Theme::ButtonColorGroup), QColor(237, 21, 22));
147 
148     QCOMPARE(m_theme->color(Plasma::Theme::TextColor, Plasma::Theme::ViewColorGroup), QColor(49, 54, 59));
149     QCOMPARE(m_theme->color(Plasma::Theme::BackgroundColor, Plasma::Theme::ViewColorGroup), QColor(252, 252, 252));
150     QCOMPARE(m_theme->color(Plasma::Theme::HighlightColor, Plasma::Theme::ViewColorGroup), QColor(61, 174, 230));
151     QCOMPARE(m_theme->color(Plasma::Theme::HoverColor, Plasma::Theme::ViewColorGroup), QColor(61, 174, 230));
152     QCOMPARE(m_theme->color(Plasma::Theme::FocusColor, Plasma::Theme::ViewColorGroup), QColor(30, 146, 255));
153     QCOMPARE(m_theme->color(Plasma::Theme::LinkColor, Plasma::Theme::ViewColorGroup), QColor(61, 174, 230));
154     QCOMPARE(m_theme->color(Plasma::Theme::VisitedLinkColor, Plasma::Theme::ViewColorGroup), QColor(61, 174, 230));
155     QCOMPARE(m_theme->color(Plasma::Theme::HighlightedTextColor, Plasma::Theme::ViewColorGroup), QColor(252, 252, 252));
156     QCOMPARE(m_theme->color(Plasma::Theme::PositiveTextColor, Plasma::Theme::ViewColorGroup), QColor(17, 209, 24));
157     QCOMPARE(m_theme->color(Plasma::Theme::NeutralTextColor, Plasma::Theme::ViewColorGroup), QColor(201, 206, 61));
158     QCOMPARE(m_theme->color(Plasma::Theme::NegativeTextColor, Plasma::Theme::ViewColorGroup), QColor(237, 21, 23));
159 
160     QCOMPARE(m_theme->color(Plasma::Theme::TextColor, Plasma::Theme::ComplementaryColorGroup), QColor(239, 240, 241));
161     QCOMPARE(m_theme->color(Plasma::Theme::BackgroundColor, Plasma::Theme::ComplementaryColorGroup), QColor(49, 54, 59));
162     QCOMPARE(m_theme->color(Plasma::Theme::HighlightColor, Plasma::Theme::ComplementaryColorGroup), QColor(61, 174, 230));
163     QCOMPARE(m_theme->color(Plasma::Theme::HoverColor, Plasma::Theme::ComplementaryColorGroup), QColor(71, 174, 230));
164     QCOMPARE(m_theme->color(Plasma::Theme::FocusColor, Plasma::Theme::ComplementaryColorGroup), QColor(40, 146, 255));
165     QCOMPARE(m_theme->color(Plasma::Theme::LinkColor, Plasma::Theme::ComplementaryColorGroup), QColor(71, 174, 230));
166     QCOMPARE(m_theme->color(Plasma::Theme::VisitedLinkColor, Plasma::Theme::ComplementaryColorGroup), QColor(71, 174, 230));
167     QCOMPARE(m_theme->color(Plasma::Theme::HighlightedTextColor, Plasma::Theme::ComplementaryColorGroup), QColor(252, 252, 252));
168     QCOMPARE(m_theme->color(Plasma::Theme::PositiveTextColor, Plasma::Theme::ComplementaryColorGroup), QColor(17, 209, 25));
169     QCOMPARE(m_theme->color(Plasma::Theme::NeutralTextColor, Plasma::Theme::ComplementaryColorGroup), QColor(201, 206, 62));
170     QCOMPARE(m_theme->color(Plasma::Theme::NegativeTextColor, Plasma::Theme::ComplementaryColorGroup), QColor(237, 21, 24));
171 }
172 
testCompositingChange()173 void ThemeTest::testCompositingChange()
174 {
175     // this test simulates the compositing change on X11
176 #if HAVE_X11
177     if (!KWindowSystem::isPlatformX11()) {
178         QSKIP("Test is only for X11");
179     }
180     QVERIFY(!KWindowSystem::compositingActive());
181 
182     // image path should give us an opaque variant
183     QVERIFY(m_theme->imagePath(QStringLiteral("element")).endsWith(QLatin1String("/desktoptheme/testtheme/opaque/element.svg")));
184 
185     QSignalSpy themeChangedSpy(m_theme, &Plasma::Theme::themeChanged);
186     QVERIFY(themeChangedSpy.isValid());
187 
188     // fake the compositor
189     QSignalSpy compositingChangedSpy(KWindowSystem::self(), &KWindowSystem::compositingChanged);
190     QVERIFY(compositingChangedSpy.isValid());
191     QScopedPointer<KSelectionOwner> compositorSelection(new KSelectionOwner("_NET_WM_CM_S0"));
192     QSignalSpy claimedSpy(compositorSelection.data(), &KSelectionOwner::claimedOwnership);
193     QVERIFY(claimedSpy.isValid());
194     compositorSelection->claim(true);
195     QVERIFY(claimedSpy.wait());
196 
197     QCOMPARE(compositingChangedSpy.count(), 1);
198     QVERIFY(KWindowSystem::compositingActive());
199     QVERIFY(themeChangedSpy.wait());
200     QCOMPARE(themeChangedSpy.count(), 1);
201     QVERIFY(m_theme->imagePath(QStringLiteral("element")).endsWith(QLatin1String("/desktoptheme/testtheme/element.svg")));
202 
203     // remove compositor again
204     compositorSelection.reset();
205     QVERIFY(compositingChangedSpy.wait());
206     QCOMPARE(compositingChangedSpy.count(), 2);
207     QVERIFY(!KWindowSystem::compositingActive());
208     QVERIFY(themeChangedSpy.wait());
209     QCOMPARE(themeChangedSpy.count(), 2);
210     QVERIFY(m_theme->imagePath(QStringLiteral("element")).endsWith(QLatin1String("/desktoptheme/testtheme/opaque/element.svg")));
211 #endif
212 }
213 
214 QTEST_MAIN(ThemeTest)
215