cache svg icons from icon theme

cache as well svg icons from the icon theme
(invalidating as well when the icon theme is updated)

REVIEW:127260
This commit is contained in:
Marco Martin 2016-04-01 15:06:31 +02:00
parent ca98250d0c
commit 944c7e60dc
8 changed files with 288 additions and 3 deletions

View File

@ -45,6 +45,7 @@ PLASMA_UNIT_TESTS(
pluginloadertest
framesvgtest
iconitemtest
themetest
# plasmoidpackagetest
)

View File

@ -0,0 +1,72 @@
<?xml version="1.0"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="22" height="22" id="svg2" version="1.1" inkscape:version="0.91pre2 r" viewBox="0 0 22 22" sodipodi:docname="plasma.svg">
<defs id="defs4">
<style type="text/css" id="current-color-scheme">
.ColorScheme-Text {
color:#4d4d4d;
}
.ColorScheme-Background {
color:#eff0f1;
}
.ColorScheme-Highlight {
color:#3daee9;
}
.ColorScheme-ViewText {
color:#31363b;
}
.ColorScheme-ViewBackground {
color:#fcfcfc;
}
.ColorScheme-ViewHover {
color:#93cee9;
}
.ColorScheme-ViewFocus{
color:#3daee9;
}
.ColorScheme-ButtonText {
color:#31363b;
}
.ColorScheme-ButtonBackground {
color:#eff0f1;
}
.ColorScheme-ButtonHover {
color:#93cee9;
}
.ColorScheme-ButtonFocus{
color:#3daee9;
}
</style>
</defs>
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="22.627417" inkscape:cx="7.6662963" inkscape:cy="11.508125" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" units="px" inkscape:showpageshadow="false" inkscape:window-width="1366" inkscape:window-height="669" inkscape:window-x="-4" inkscape:window-y="25" inkscape:window-maximized="1" showguides="true">
<inkscape:grid type="xygrid" id="grid4101"/>
<sodipodi:guide position="2,20.000017" orientation="18,0" id="guide4107"/>
<sodipodi:guide position="2,2.0000174" orientation="0,18" id="guide4109"/>
<sodipodi:guide position="20,2.0000174" orientation="-18,0" id="guide4111"/>
<sodipodi:guide position="20,20.000017" orientation="0,-18" id="guide4113"/>
<sodipodi:guide position="3,19.000017" orientation="16,0" id="guide4115"/>
<sodipodi:guide position="3,3.0000174" orientation="0,16" id="guide4117"/>
<sodipodi:guide position="19,3.0000174" orientation="-16,0" id="guide4119"/>
<sodipodi:guide position="19,19.000017" orientation="0,-16" id="guide4121"/>
<sodipodi:guide position="10,6.0000174" orientation="-7,0" id="guide4162"/>
<sodipodi:guide position="11,12.000017" orientation="5,0" id="guide4280"/>
<sodipodi:guide position="11,7.0000174" orientation="0,5" id="guide4282"/>
<sodipodi:guide position="16,7.0000174" orientation="-5,0" id="guide4284"/>
<sodipodi:guide position="16,12.000017" orientation="0,-5" id="guide4286"/>
<sodipodi:guide position="5,13.000017" orientation="6,0" id="guide4294"/>
<sodipodi:guide position="5,7.0000174" orientation="0,6" id="guide4296"/>
<sodipodi:guide position="11,7.0000174" orientation="-6,0" id="guide4298"/>
</sodipodi:namedview>
<metadata id="metadata7">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<g inkscape:label="Capa 1" inkscape:groupmode="layer" id="layer1" transform="translate(0,-1030.3622)">
<path style="opacity:1;fill:currentColor;fill-opacity:1;stroke:none" d="M 7 3 C 6.446 3 6 3.446 6 4 C 6 4.554 6.446 5 7 5 C 7.554 5 8 4.554 8 4 C 8 3.446 7.554 3 7 3 z M 14 3 L 12 5 L 15 8 L 12 11 L 14 13 L 17 10 L 19 8 L 14 3 z M 4.5 9 C 3.669 9 3 9.669 3 10.5 C 3 11.331 3.669 12 4.5 12 C 5.331 12 6 11.331 6 10.5 C 6 9.669 5.331 9 4.5 9 z M 9 15 C 7.892 15 7 15.892 7 17 C 7 18.108 7.892 19 9 19 C 10.108 19 11 18.108 11 17 C 11 15.892 10.108 15 9 15 z " transform="translate(0,1030.3622)" id="rect4231" class="ColorScheme-Text"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -0,0 +1,28 @@
[Icon Theme]
Name=Unittest Theme two
DisplayDepth=32
DesktopDefault=48
DesktopSizes=16,22,32,48,64,128,256
ToolbarDefault=22
ToolbarSizes=16,22,32,48
MainToolbarDefault=22
MainToolbarSizes=16,22,32,48
SmallDefault=16
SmallSizes=16,22,32,48
PanelDefault=32
PanelSizes=16,22,32,48,64,128,256
DialogDefault=32
DialogSizes=16,22,32,48,64,128,256
########## Directories
########## ordered by category and alphabetically
Directories=apps/22
[apps/22]
Size=22
Context=Applications
Type=Fixed

99
autotests/themetest.cpp Normal file
View File

@ -0,0 +1,99 @@
/********************************************************************************
* Copyright 2016 Marco Martin <mart@kde.org> *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public License *
* along with this library; see the file COPYING.LIB. If not, write to *
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301, USA. *
*********************************************************************************/
#include "themetest.h"
#include <QStandardPaths>
#include <QApplication>
#include <KIconLoader>
#include <KIconTheme>
#define QLSEP QLatin1Char('_')
#define CACHE_ID_WITH_SIZE(size, id, devicePixelRatio) QString::number(int(size.width())) % QLSEP % QString::number(int(size.height())) % QLSEP % id % QLSEP % QLSEP % QString::number(int(devicePixelRatio))
void ThemeTest::initTestCase()
{
// make our theme in search path
qputenv("XDG_DATA_DIRS",
qgetenv("XDG_DATA_DIRS") + ":" + QFINDTESTDATA("data").toLocal8Bit());
// set default icon theme to test-theme
QStandardPaths::setTestModeEnabled(true);
QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
if(!QDir(configPath).mkpath(QStringLiteral("."))) {
qFatal("Failed to create test configuration directory.");
}
QFile::remove(configPath);
QIcon::setThemeSearchPaths(QStringList()<<QFINDTESTDATA("data/icons"));
KConfigGroup cg(KSharedConfig::openConfig("kdeglobals"), "Icons");
cg.writeEntry("Theme", "test-theme");
KConfigGroup plasmaConfig(KSharedConfig::openConfig("plasmarc"), "Theme");
plasmaConfig.writeEntry("name", "default");
m_svg = new Plasma::Svg();
}
void ThemeTest::cleanupTestCase()
{
// m_testIconsDir.removeRecursively();
delete m_svg;
}
void ThemeTest::loadSvgIcon()
{
const auto *iconTheme = KIconLoader::global()->theme();
QString iconPath;
if (iconTheme) {
iconPath = iconTheme->iconPath(QLatin1String("konversation.svg"), 48, KIconLoader::MatchBest);
}
m_svg->setImagePath(iconPath);
QVERIFY(m_svg->isValid());
m_svg->pixmap(); //trigger the SVG being loaded
QString cacheId = CACHE_ID_WITH_SIZE(QSize(48, 48), iconPath, m_svg->devicePixelRatio()) % QLSEP % QString::number(m_svg->colorGroup());
QPixmap result;
QVERIFY(m_svg->theme()->findInCache(cacheId, result));
QSignalSpy spy(m_svg, SIGNAL(repaintNeeded()));
QVERIFY(spy.isValid());
KConfigGroup cg(KSharedConfig::openConfig("kdeglobals"), "Icons");
cg.writeEntry("Theme", "test-theme-two");
cg.sync();
// KIconloader needs changesto be emitted manually, ouch.
for (int i=0; i < KIconLoader::LastGroup; i++) {
KIconLoader::emitChange(KIconLoader::Group(i));
}
spy.wait();
//Svg emitting repaintNeeded when something changes in KIconLoader means the svg loaded an icon
QVERIFY(spy.count() == 1);
QVERIFY(!m_svg->theme()->findInCache(cacheId, result));
}
QTEST_MAIN(ThemeTest)

43
autotests/themetest.h Normal file
View File

@ -0,0 +1,43 @@
/******************************************************************************
* Copyright 2016 Marco Martin <mart@kde.org> *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public License *
* along with this library; see the file COPYING.LIB. If not, write to *
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301, USA. *
*******************************************************************************/
#ifndef THEMETEST_H
#define THEMETEST_H
#include <QtTest/QtTest>
#include "plasma/theme.h"
#include "plasma/svg.h"
class ThemeTest : public QObject
{
Q_OBJECT
public Q_SLOTS:
void initTestCase();
void cleanupTestCase();
private Q_SLOTS:
void loadSvgIcon();
private:
Plasma::Svg *m_svg;
};
#endif

View File

@ -30,6 +30,8 @@
#include <kdirwatch.h>
#include <kwindoweffects.h>
#include <KIconLoader>
#include <KIconTheme>
namespace Plasma
{
@ -120,6 +122,11 @@ ThemePrivate::ThemePrivate(QObject *parent)
// ... but also remove/recreate cycles, like KConfig does it
connect(KDirWatch::self(), &KDirWatch::created, this, &ThemePrivate::settingsFileChanged);
QObject::connect(KIconLoader::global(), &KIconLoader::iconChanged,
this, [this]() {
scheduleThemeChangeNotification(PixmapCache|SvgElementsCache);
});
connect(KWindowSystem::self(), &KWindowSystem::compositingChanged, this, &ThemePrivate::compositingChanged);
}
@ -172,6 +179,8 @@ bool ThemePrivate::useCache()
}
if (isRegularTheme) {
themeMetadataPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1Literal(PLASMA_RELATIVE_DATA_INSTALL_DIR "/desktoptheme/") % themeName % QLatin1Literal("/metadata.desktop"));
const auto *iconTheme = KIconLoader::global()->theme();
iconThemeMetadataPath = iconTheme->dir() + "index.theme";
Q_ASSERT(!themeMetadataPath.isEmpty() || themeName.isEmpty());
const QString cacheFileBase = cacheFile + QLatin1String("*.kcache");
@ -194,6 +203,10 @@ bool ThemePrivate::useCache()
QObject::connect(KDirWatch::self(), SIGNAL(dirty(QString)),
this, SLOT(settingsFileChanged(QString)),
Qt::UniqueConnection);
if (!iconThemeMetadataPath.isEmpty()) {
KDirWatch::self()->addFile(iconThemeMetadataPath);
}
}
// now we check for, and remove if necessary, old caches
@ -220,7 +233,10 @@ bool ThemePrivate::useCache()
if (!cacheFilePath.isEmpty()) {
const QFileInfo cacheFileInfo(cacheFilePath);
const QFileInfo metadataFileInfo(themeMetadataPath);
cachesTooOld = cacheFileInfo.lastModified().toTime_t() < metadataFileInfo.lastModified().toTime_t();
const QFileInfo iconThemeMetadataFileInfo(iconThemeMetadataPath);
cachesTooOld = (cacheFileInfo.lastModified().toTime_t() < metadataFileInfo.lastModified().toTime_t()) ||
(cacheFileInfo.lastModified().toTime_t() < iconThemeMetadataFileInfo.lastModified().toTime_t());
}
}
@ -248,6 +264,18 @@ bool ThemePrivate::useCache()
const QString svgElementsFile = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + '/' + svgElementsFileName;
svgElementsCache = KSharedConfig::openConfig(svgElementsFile);
QString currentIconThemePath;
const auto *iconTheme = KIconLoader::global()->theme();
if (iconTheme) {
currentIconThemePath = iconTheme->dir();
}
KConfigGroup globalGroup(svgElementsCache, QLatin1String("Global"));
const QString oldIconThemePath = globalGroup.readEntry("currentIconThemePath", QString());
if (oldIconThemePath != currentIconThemePath) {
discardCache(PixmapCache | SvgElementsCache);
globalGroup.writeEntry("currentIconThemePath", currentIconThemePath);
svgElementsCache = KSharedConfig::openConfig(svgElementsFile);
}
}
return cacheTheme;

View File

@ -140,6 +140,7 @@ public:
CacheTypes cachesToDiscard;
QString themeVersion;
QString themeMetadataPath;
QString iconThemeMetadataPath;
bool locolor : 1;
bool compositingActive : 1;

View File

@ -36,6 +36,8 @@
#include <QDebug>
#include <kfilterdev.h>
#include <kiconeffect.h>
#include <KIconLoader>
#include <KIconTheme>
#include "applet.h"
#include "package.h"
@ -182,8 +184,15 @@ bool SvgPrivate::setImagePath(const QString &imagePath)
//length of file://
actualPath = actualPath.mid(7);
}
const bool isThemed = !QDir::isAbsolutePath(actualPath);
bool isThemed = !QDir::isAbsolutePath(actualPath);
bool inIconTheme = false;
//an absolute path.. let's try if this actually an *icon* theme
if (!isThemed) {
const auto *iconTheme = KIconLoader::global()->theme();
isThemed = inIconTheme = iconTheme && actualPath.startsWith(iconTheme->dir());
}
// lets check to see if we're already set to this file
if (isThemed == themed &&
((themed && themePath == actualPath) ||
@ -216,7 +225,11 @@ bool SvgPrivate::setImagePath(const QString &imagePath)
emit q->fromCurrentThemeChanged(fromCurrentTheme);
}
if (themed) {
if (inIconTheme) {
themePath = actualPath;
path = actualPath;
QObject::connect(actualTheme(), SIGNAL(themeChanged()), q, SLOT(themeChanged()));
} else if (themed) {
themePath = actualPath;
path = actualTheme()->imagePath(themePath);
themeFailed = path.isEmpty();