summaryrefslogtreecommitdiffstats
path: root/src/gui/image/qiconloader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/image/qiconloader.cpp')
-rw-r--r--src/gui/image/qiconloader.cpp102
1 files changed, 90 insertions, 12 deletions
diff --git a/src/gui/image/qiconloader.cpp b/src/gui/image/qiconloader.cpp
index 349e0dfbe3..1ea4f1340b 100644
--- a/src/gui/image/qiconloader.cpp
+++ b/src/gui/image/qiconloader.cpp
@@ -95,6 +95,16 @@ static inline QStringList systemIconSearchPaths()
return QStringList();
}
+static inline QStringList systemFallbackSearchPaths()
+{
+ if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
+ const QVariant themeHint = theme->themeHint(QPlatformTheme::IconFallbackSearchPaths);
+ if (themeHint.isValid())
+ return themeHint.toStringList();
+ }
+ return QStringList();
+}
+
extern QFactoryLoader *qt_iconEngineFactoryLoader(); // qicon.cpp
void QIconLoader::ensureInitialized()
@@ -158,6 +168,20 @@ QStringList QIconLoader::themeSearchPaths() const
return m_iconDirs;
}
+void QIconLoader::setFallbackSearchPaths(const QStringList &searchPaths)
+{
+ m_fallbackDirs = searchPaths;
+ invalidateKey();
+}
+
+QStringList QIconLoader::fallbackSearchPaths() const
+{
+ if (m_fallbackDirs.isEmpty()) {
+ m_fallbackDirs = systemFallbackSearchPaths();
+ }
+ return m_fallbackDirs;
+}
+
/*!
\internal
Helper class that reads and looks up into the icon-theme.cache generated with
@@ -481,11 +505,54 @@ QThemeIconInfo QIconLoader::findIconHelper(const QString &themeName,
return info;
}
+QThemeIconInfo QIconLoader::lookupFallbackIcon(const QString &iconName) const
+{
+ QThemeIconInfo info;
+
+ const QString pngIconName = iconName + QLatin1String(".png");
+ const QString xpmIconName = iconName + QLatin1String(".xpm");
+ const QString svgIconName = iconName + QLatin1String(".svg");
+
+ const auto searchPaths = QIcon::fallbackSearchPaths();
+ for (const QString &iconDir: searchPaths) {
+ QDir currentDir(iconDir);
+ if (currentDir.exists(pngIconName)) {
+ PixmapEntry *iconEntry = new PixmapEntry;
+ iconEntry->dir.type = QIconDirInfo::Fallback;
+ iconEntry->filename = currentDir.filePath(pngIconName);
+ info.entries.append(iconEntry);
+ break;
+ } else if (currentDir.exists(xpmIconName)) {
+ PixmapEntry *iconEntry = new PixmapEntry;
+ iconEntry->dir.type = QIconDirInfo::Fallback;
+ iconEntry->filename = currentDir.filePath(xpmIconName);
+ info.entries.append(iconEntry);
+ break;
+ } else if (m_supportsSvg &&
+ currentDir.exists(svgIconName)) {
+ ScalableEntry *iconEntry = new ScalableEntry;
+ iconEntry->dir.type = QIconDirInfo::Fallback;
+ iconEntry->filename = currentDir.filePath(svgIconName);
+ info.entries.append(iconEntry);
+ break;
+ }
+ }
+
+ if (!info.entries.isEmpty())
+ info.iconName = iconName;
+
+ return info;
+}
+
QThemeIconInfo QIconLoader::loadIcon(const QString &name) const
{
if (!themeName().isEmpty()) {
QStringList visited;
- return findIconHelper(themeName(), name, visited);
+ const QThemeIconInfo iconInfo = findIconHelper(themeName(), name, visited);
+ if (!iconInfo.entries.isEmpty())
+ return iconInfo;
+
+ return lookupFallbackIcon(name);
}
return QThemeIconInfo();
@@ -573,6 +640,8 @@ static bool directoryMatchesSize(const QIconDirInfo &dir, int iconsize, int icon
} else if (dir.type == QIconDirInfo::Threshold) {
return iconsize >= dir.size - dir.threshold &&
iconsize <= dir.size + dir.threshold;
+ } else if (dir.type == QIconDirInfo::Fallback) {
+ return true;
}
Q_ASSERT(1); // Not a valid value
@@ -603,24 +672,26 @@ static int directorySizeDistance(const QIconDirInfo &dir, int iconsize, int icon
else if (scaledIconSize > (dir.size + dir.threshold) * dir.scale)
return scaledIconSize - dir.maxSize * dir.scale;
else return 0;
+ } else if (dir.type == QIconDirInfo::Fallback) {
+ return 0;
}
Q_ASSERT(1); // Not a valid value
return INT_MAX;
}
-QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size, int scale)
+QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QThemeIconInfo &info, const QSize &size, int scale)
{
int iconsize = qMin(size.width(), size.height());
// Note that m_info.entries are sorted so that png-files
// come first
- const int numEntries = m_info.entries.size();
+ const int numEntries = info.entries.size();
// Search for exact matches first
for (int i = 0; i < numEntries; ++i) {
- QIconLoaderEngineEntry *entry = m_info.entries.at(i);
+ QIconLoaderEngineEntry *entry = info.entries.at(i);
if (directoryMatchesSize(entry->dir, iconsize, scale)) {
return entry;
}
@@ -630,7 +701,7 @@ QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size, int s
int minimalSize = INT_MAX;
QIconLoaderEngineEntry *closestMatch = 0;
for (int i = 0; i < numEntries; ++i) {
- QIconLoaderEngineEntry *entry = m_info.entries.at(i);
+ QIconLoaderEngineEntry *entry = info.entries.at(i);
int distance = directorySizeDistance(entry->dir, iconsize, scale);
if (distance < minimalSize) {
minimalSize = distance;
@@ -654,12 +725,14 @@ QSize QIconLoaderEngine::actualSize(const QSize &size, QIcon::Mode mode,
ensureLoaded();
- QIconLoaderEngineEntry *entry = entryForSize(size);
+ QIconLoaderEngineEntry *entry = entryForSize(m_info, size);
if (entry) {
const QIconDirInfo &dir = entry->dir;
- if (dir.type == QIconDirInfo::Scalable)
+ if (dir.type == QIconDirInfo::Scalable) {
return size;
- else {
+ } else if (dir.type == QIconDirInfo::Fallback) {
+ return QIcon(entry->filename).actualSize(size, mode, state);
+ } else {
int result = qMin<int>(dir.size, qMin(size.width(), size.height()));
return QSize(result, result);
}
@@ -718,7 +791,7 @@ QPixmap QIconLoaderEngine::pixmap(const QSize &size, QIcon::Mode mode,
{
ensureLoaded();
- QIconLoaderEngineEntry *entry = entryForSize(size);
+ QIconLoaderEngineEntry *entry = entryForSize(m_info, size);
if (entry)
return entry->pixmap(size, mode, state);
@@ -745,8 +818,13 @@ void QIconLoaderEngine::virtual_hook(int id, void *data)
// Gets all sizes from the DirectoryInfo entries
for (int i = 0; i < N; ++i) {
- int size = m_info.entries.at(i)->dir.size;
- sizes.append(QSize(size, size));
+ const QIconLoaderEngineEntry *entry = m_info.entries.at(i);
+ if (entry->dir.type == QIconDirInfo::Fallback) {
+ sizes.append(QIcon(entry->filename).availableSizes());
+ } else {
+ int size = entry->dir.size;
+ sizes.append(QSize(size, size));
+ }
}
arg.sizes.swap(sizes); // commit
}
@@ -767,7 +845,7 @@ void QIconLoaderEngine::virtual_hook(int id, void *data)
QIconEngine::ScaledPixmapArgument &arg = *reinterpret_cast<QIconEngine::ScaledPixmapArgument*>(data);
// QIcon::pixmap() multiplies size by the device pixel ratio.
const int integerScale = qCeil(arg.scale);
- QIconLoaderEngineEntry *entry = entryForSize(arg.size / integerScale, integerScale);
+ QIconLoaderEngineEntry *entry = entryForSize(m_info, arg.size / integerScale, integerScale);
arg.pixmap = entry ? entry->pixmap(arg.size, arg.mode, arg.state) : QPixmap();
}
break;