5#include <private/qiconloader_p.h>
7#include <private/qguiapplication_p.h>
8#include <private/qicon_p.h>
10#include <QtGui/QIconEnginePlugin>
11#include <QtGui/QPixmapCache>
12#include <qpa/qplatformtheme.h>
13#include <QtGui/qfontdatabase.h>
14#include <QtGui/QPalette>
15#include <QtCore/qmath.h>
16#include <QtCore/QList>
18#include <QtCore/qloggingcategory.h>
19#if QT_CONFIG(settings)
20#include <QtCore/QSettings>
22#include <QtGui/QPainter>
24#include <private/qhexstring_p.h>
25#include <private/qfactoryloader_p.h>
26#include <private/qfonticonengine_p.h>
32using namespace Qt::StringLiterals;
39 if (
const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
40 const QVariant themeHint = theme->themeHint(QPlatformTheme::SystemIconFallbackThemeName);
41 if (themeHint.isValid())
42 return themeHint.toString();
47QIconLoader::QIconLoader() :
48 m_themeKey(1), m_supportsSvg(
false), m_initialized(
false)
54 if (QString override = qEnvironmentVariable(
"QT_QPA_SYSTEM_ICON_THEME"); !override.isEmpty())
56 if (
const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
57 const QVariant themeHint = theme->themeHint(QPlatformTheme::SystemIconThemeName);
58 if (themeHint.isValid())
59 return themeHint.toString();
66 if (
const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
67 const QVariant themeHint = theme->themeHint(QPlatformTheme::IconThemeSearchPaths);
68 if (themeHint.isValid())
69 return themeHint.toStringList();
76 if (
const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
77 const QVariant themeHint = theme->themeHint(QPlatformTheme::IconFallbackSearchPaths);
78 if (themeHint.isValid())
79 return themeHint.toStringList();
86void QIconLoader::ensureInitialized()
89 if (!QGuiApplicationPrivate::platformTheme())
92 m_systemTheme = systemThemeName();
94 if (m_systemTheme.isEmpty())
95 m_systemTheme = systemFallbackThemeName();
96 if (qt_iconEngineFactoryLoader()->keyMap().key(
"svg"_L1, -1) != -1)
99 qCDebug(lcIconLoader) <<
"Initialized icon loader with system theme"
100 << m_systemTheme <<
"and SVG support" << m_supportsSvg;
105
106
107
108
109
110
111
112
113
114QIconLoader *QIconLoader::instance()
116 iconLoaderInstance()->ensureInitialized();
117 return iconLoaderInstance();
122void QIconLoader::updateSystemTheme()
124 const QString currentSystemTheme = m_systemTheme;
125 m_systemTheme = systemThemeName();
126 if (m_systemTheme.isEmpty())
127 m_systemTheme = systemFallbackThemeName();
128 if (m_systemTheme != currentSystemTheme)
129 qCDebug(lcIconLoader) <<
"Updated system theme to" << m_systemTheme;
136void QIconLoader::invalidateKey()
145 m_factory = std::nullopt;
148QString QIconLoader::themeName()
const
150 return m_userTheme.isEmpty() ? m_systemTheme : m_userTheme;
153void QIconLoader::setThemeName(
const QString &themeName)
155 if (m_userTheme == themeName)
158 qCDebug(lcIconLoader) <<
"Setting user theme name to" << themeName;
160 const bool hadUserTheme = hasUserTheme();
161 m_userTheme = themeName;
165 if (!hasUserTheme() && hadUserTheme)
166 setThemeSearchPath(systemIconSearchPaths());
170QString QIconLoader::fallbackThemeName()
const
172 return m_userFallbackTheme.isEmpty() ? systemFallbackThemeName() : m_userFallbackTheme;
175void QIconLoader::setFallbackThemeName(
const QString &themeName)
177 qCDebug(lcIconLoader) <<
"Setting fallback theme name to" << themeName;
178 m_userFallbackTheme = themeName;
182void QIconLoader::setThemeSearchPath(
const QStringList &searchPaths)
184 qCDebug(lcIconLoader) <<
"Setting theme search path to" << searchPaths;
185 m_iconDirs = searchPaths;
190QStringList QIconLoader::themeSearchPaths()
const
192 if (m_iconDirs.isEmpty()) {
193 m_iconDirs = systemIconSearchPaths();
195 m_iconDirs.append(
":/icons"_L1);
200void QIconLoader::setFallbackSearchPaths(
const QStringList &searchPaths)
202 qCDebug(lcIconLoader) <<
"Setting fallback search path to" << searchPaths;
203 m_fallbackDirs = searchPaths;
207QStringList QIconLoader::fallbackSearchPaths()
const
209 if (m_fallbackDirs.isEmpty()) {
210 m_fallbackDirs = systemFallbackSearchPaths();
212 return m_fallbackDirs;
216
217
218
219
220
221
230 const unsigned char *m_data;
234 quint16 read16(uint offset)
236 if (offset > m_size - 2 || (offset & 0x1)) {
240 return m_data[offset+1] | m_data[offset] << 8;
242 quint32 read32(uint offset)
244 if (offset > m_size - 4 || (offset & 0x3)) {
248 return m_data[offset+3] | m_data[offset+2] << 8
249 | m_data[offset+1] << 16 | m_data[offset] << 24;
257 QFileInfo info(dirName +
"/icon-theme.cache"_L1);
258 if (!info.exists() || info.lastModified(QTimeZone::UTC) < QFileInfo(dirName).lastModified(QTimeZone::UTC))
260 m_file.setFileName(info.absoluteFilePath());
261 if (!m_file.open(QFile::ReadOnly))
263 m_size = m_file.size();
264 m_data = m_file.map(0, m_size);
273 const QDateTime lastModified = info.lastModified(QTimeZone::UTC);
274 quint32 dirListOffset = read32(8);
275 quint32 dirListLen = read32(dirListOffset);
276 for (uint i = 0; i < dirListLen; ++i) {
277 quint32 offset = read32(dirListOffset + 4 + 4 * i);
278 if (!m_isValid || offset >= m_size || lastModified < QFileInfo(dirName + u'/'
279 + QString::fromUtf8(
reinterpret_cast<
const char*>(m_data + offset))).lastModified(QTimeZone::UTC)) {
288 quint32 h =
static_cast<
signed char>(*p);
289 for (p += 1; *p !=
'\0'; p++)
290 h = (h << 5) - h + *p;
295
296
297
298
301 QList<
const char *> ret;
305 QByteArray nameUtf8 = name.toUtf8();
306 quint32 hash = icon_name_hash(nameUtf8);
308 quint32 hashOffset = read32(4);
309 quint32 hashBucketCount = read32(hashOffset);
311 if (!
isValid() || hashBucketCount == 0) {
316 quint32 bucketIndex = hash % hashBucketCount;
317 quint32 bucketOffset = read32(hashOffset + 4 + bucketIndex * 4);
318 while (bucketOffset > 0 && bucketOffset <= m_size - 12) {
319 quint32 nameOff = read32(bucketOffset + 4);
320 if (nameOff < m_size && strcmp(
reinterpret_cast<
const char*>(m_data + nameOff), nameUtf8) == 0) {
321 quint32 dirListOffset = read32(8);
322 quint32 dirListLen = read32(dirListOffset);
324 quint32 listOffset = read32(bucketOffset+8);
325 quint32 listLen = read32(listOffset);
327 if (!m_isValid || listOffset + 4 + 8 * listLen > m_size) {
332 ret.reserve(listLen);
333 for (uint j = 0; j < listLen && m_isValid; ++j) {
334 quint32 dirIndex = read16(listOffset + 4 + 8 * j);
335 quint32 o = read32(dirListOffset + 4 + dirIndex*4);
336 if (!m_isValid || dirIndex >= dirListLen || o >= m_size) {
340 ret.append(
reinterpret_cast<
const char*>(m_data) + o);
344 bucketOffset = read32(bucketOffset);
349QIconTheme::QIconTheme(
const QString &themeName)
354 const QStringList iconDirs = QIcon::themeSearchPaths();
355 for (
int i = 0 ; i < iconDirs.size() ; ++i) {
356 QDir iconDir(iconDirs[i]);
357 QString themeDir = iconDir.path() + u'/' + themeName;
358 QFileInfo themeDirInfo(themeDir);
360 if (themeDirInfo.isDir()) {
361 m_contentDirs << themeDir;
362 m_gtkCaches << QSharedPointer<QIconCacheGtkReader>::create(themeDir);
366 themeIndex.setFileName(themeDir +
"/index.theme"_L1);
367 m_valid = themeIndex.exists();
368 qCDebug(lcIconLoader) <<
"Probing theme file at" << themeIndex.fileName() << m_valid;
371#if QT_CONFIG(settings)
373 const QSettings indexReader(themeIndex.fileName(), QSettings::IniFormat);
374 const QStringList keys = indexReader.allKeys();
375 for (
const QString &key : keys) {
376 if (key.endsWith(
"/Size"_L1)) {
379 if (
int size = indexReader.value(key).toInt()) {
380 QString directoryKey = key.left(key.size() - 5);
381 QIconDirInfo dirInfo(directoryKey);
383 QString type = indexReader.value(directoryKey +
"/Type"_L1).toString();
385 if (type ==
"Fixed"_L1)
386 dirInfo.type = QIconDirInfo::Fixed;
387 else if (type ==
"Scalable"_L1)
388 dirInfo.type = QIconDirInfo::Scalable;
390 dirInfo.type = QIconDirInfo::Threshold;
392 dirInfo.threshold = indexReader.value(directoryKey +
396 dirInfo.minSize = indexReader.value(directoryKey +
"/MinSize"_L1, size).toInt();
398 dirInfo.maxSize = indexReader.value(directoryKey +
"/MaxSize"_L1, size).toInt();
400 dirInfo.scale = indexReader.value(directoryKey +
"/Scale"_L1, 1).toInt();
402 const QString context = indexReader.value(directoryKey +
"/Context"_L1).toString();
403 dirInfo.context = [context]() {
404 if (context ==
"Applications"_L1)
405 return QIconDirInfo::Applications;
406 else if (context ==
"MimeTypes"_L1)
407 return QIconDirInfo::MimeTypes;
409 return QIconDirInfo::UnknownContext;
412 m_keyList.append(dirInfo);
418 m_parents = indexReader.value(
"Icon Theme/Inherits"_L1).toStringList();
419 m_parents.removeAll(QString());
424QStringList QIconTheme::parents()
const
427 QStringList result = m_parents;
430 const QString fallback = QIconLoader::instance()->fallbackThemeName();
431 if (!fallback.isEmpty())
432 result.append(fallback);
435 result.removeAll(
"hicolor"_L1);
436 result.append(
"hicolor"_L1);
441QDebug operator<<(QDebug debug,
const std::unique_ptr<QIconLoaderEngineEntry> &entry)
443 QDebugStateSaver saver(debug);
444 if (entry)
return debug.noquote() << entry->filename;
445 return debug <<
"QIconLoaderEngineEntry(0x0)";
448QThemeIconInfo QIconLoader::findIconHelper(
const QString &themeName,
449 const QString &iconName,
450 QStringList &visited,
453 qCDebug(lcIconLoader) <<
"Finding icon" << iconName <<
"in theme" << themeName
454 <<
"skipping" << visited;
457 Q_ASSERT(!themeName.isEmpty());
460 visited << themeName;
462 QIconTheme &theme = themeList[themeName];
463 if (!theme.isValid()) {
464 theme = QIconTheme(themeName);
465 if (!theme.isValid()) {
466 qCDebug(lcIconLoader) <<
"Theme" << themeName <<
"not found";
471 const QStringList contentDirs = theme.contentDirs();
473 QStringView iconNameFallback(iconName);
474 bool searchingGenericFallback = m_iconName.length() > iconName.length();
477 if (info.entries.empty()) {
478 const QString svgIconName = iconNameFallback +
".svg"_L1;
479 const QString pngIconName = iconNameFallback +
".png"_L1;
482 for (
int i = 0; i < contentDirs.size(); ++i) {
483 QList<QIconDirInfo> subDirs = theme.keyList();
487 auto cache = theme.m_gtkCaches.at(i);
488 if (cache->isValid()) {
489 const auto result = cache->lookup(iconNameFallback);
490 if (cache->isValid()) {
491 const QList<QIconDirInfo> subDirsCopy = subDirs;
493 subDirs.reserve(result.size());
494 for (
const char *s : result) {
495 QString path = QString::fromUtf8(s);
496 auto it = std::find_if(subDirsCopy.cbegin(), subDirsCopy.cend(),
497 [&](
const QIconDirInfo &info) {
498 return info.path == path; } );
499 if (it != subDirsCopy.cend()) {
506 QString contentDir = contentDirs.at(i) + u'/';
507 for (
int j = 0; j < subDirs.size() ; ++j) {
508 const QIconDirInfo &dirInfo = subDirs.at(j);
509 if (searchingGenericFallback &&
510 (dirInfo.context == QIconDirInfo::Applications ||
511 dirInfo.context == QIconDirInfo::MimeTypes))
514 const QString subDir = contentDir + dirInfo.path + u'/';
515 const QString pngPath = subDir + pngIconName;
516 if (QFile::exists(pngPath)) {
517 auto iconEntry = std::make_unique<PixmapEntry>();
518 iconEntry->dir = dirInfo;
519 iconEntry->filename = pngPath;
522 info.entries.insert(info.entries.begin(), std::move(iconEntry));
523 }
else if (m_supportsSvg) {
524 const QString svgPath = subDir + svgIconName;
525 if (QFile::exists(svgPath)) {
526 auto iconEntry = std::make_unique<ScalableEntry>();
527 iconEntry->dir = dirInfo;
528 iconEntry->filename = svgPath;
529 info.entries.push_back(std::move(iconEntry));
535 if (!info.entries.empty()) {
536 info.iconName = iconNameFallback.toString();
540 if (info.entries.empty()) {
541 const QStringList parents = theme.parents();
542 qCDebug(lcIconLoader) <<
"Did not find matching icons in theme;"
543 <<
"trying parent themes" << parents
544 <<
"skipping visited" << visited;
547 for (
int i = 0 ; i < parents.size() ; ++i) {
549 const QString parentTheme = parents.at(i).trimmed();
551 if (!visited.contains(parentTheme))
552 info = findIconHelper(parentTheme, iconName, visited, QIconLoader::NoFallBack);
554 if (!info.entries.empty())
559 if (rule == QIconLoader::FallBack && info.entries.empty()) {
561 const int indexOfDash = iconNameFallback.lastIndexOf(u'-');
562 if (indexOfDash != -1) {
563 qCDebug(lcIconLoader) <<
"Did not find matching icons in all themes;"
564 <<
"trying dash fallback";
565 iconNameFallback.truncate(indexOfDash);
566 QStringList _visited;
567 info = findIconHelper(themeName, iconNameFallback.toString(), _visited, QIconLoader::FallBack);
574QThemeIconInfo QIconLoader::lookupFallbackIcon(
const QString &iconName)
const
576 qCDebug(lcIconLoader) <<
"Looking up fallback icon" << iconName;
580 const QString pngIconName = iconName +
".png"_L1;
581 const QString xpmIconName = iconName +
".xpm"_L1;
582 const QString svgIconName = iconName +
".svg"_L1;
584 const auto searchPaths = QIcon::fallbackSearchPaths();
585 for (
const QString &iconDir: searchPaths) {
586 QDir currentDir(iconDir);
587 std::unique_ptr<QIconLoaderEngineEntry> iconEntry;
588 if (currentDir.exists(pngIconName)) {
589 iconEntry = std::make_unique<PixmapEntry>();
590 iconEntry->dir.type = QIconDirInfo::Fallback;
591 iconEntry->filename = currentDir.filePath(pngIconName);
592 }
else if (currentDir.exists(xpmIconName)) {
593 iconEntry = std::make_unique<PixmapEntry>();
594 iconEntry->dir.type = QIconDirInfo::Fallback;
595 iconEntry->filename = currentDir.filePath(xpmIconName);
596 }
else if (m_supportsSvg &&
597 currentDir.exists(svgIconName)) {
598 iconEntry = std::make_unique<ScalableEntry>();
599 iconEntry->dir.type = QIconDirInfo::Fallback;
600 iconEntry->filename = currentDir.filePath(svgIconName);
603 info.entries.push_back(std::move(iconEntry));
608 if (!info.entries.empty())
609 info.iconName = iconName;
614QThemeIconInfo QIconLoader::loadIcon(
const QString &name)
const
616 qCDebug(lcIconLoader) <<
"Loading icon" << name;
619 QThemeIconInfo iconInfo;
620 QStringList visitedThemes;
621 if (!themeName().isEmpty())
622 iconInfo = findIconHelper(themeName(), name, visitedThemes, QIconLoader::FallBack);
624 if (iconInfo.entries.empty() && !fallbackThemeName().isEmpty())
625 iconInfo = findIconHelper(fallbackThemeName(), name, visitedThemes, QIconLoader::FallBack);
627 if (iconInfo.entries.empty())
628 iconInfo = lookupFallbackIcon(name);
630 qCDebug(lcIconLoader) <<
"Resulting icon entries" << iconInfo.entries;
634#ifndef QT_NO_DEBUG_STREAM
637 QDebugStateSaver saver(debug);
640 debug.noquote() << engine->key() <<
"(";
641 debug <<
static_cast<
const void *>(engine);
642 if (!engine->isNull())
643 debug.quote() <<
", " << engine->iconName();
648 debug <<
"QIconEngine(nullptr)";
654QIconEngine *QIconLoader::iconEngine(
const QString &iconName)
const
656 qCDebug(lcIconLoader) <<
"Resolving icon engine for icon" << iconName;
658 std::unique_ptr<QIconEngine> iconEngine;
661 qCDebug(lcIconLoader) <<
"Finding a plugin for theme" << themeName();
663 const int factoryIndex = qt_iconEngineFactoryLoader()->indexOf(themeName());
664 if (factoryIndex >= 0)
665 m_factory = qobject_cast<QIconEnginePlugin *>(qt_iconEngineFactoryLoader()->instance(factoryIndex));
667 if (m_factory && *m_factory)
668 iconEngine.reset(m_factory.value()->create(iconName));
670 if (hasUserTheme()) {
671 if (!iconEngine || iconEngine->isNull()) {
672 if (QFontDatabase::families().contains(themeName())) {
673 QFont maybeIconFont(themeName());
674 maybeIconFont.setStyleStrategy(QFont::NoFontMerging);
675 qCDebug(lcIconLoader) <<
"Trying font icon engine.";
676 iconEngine.reset(
new QFontIconEngine(iconName, maybeIconFont));
679 if (!iconEngine || iconEngine->isNull()) {
680 qCDebug(lcIconLoader) <<
"Trying loader engine for theme.";
681 iconEngine.reset(
new QIconLoaderEngine(iconName));
685 if (!iconEngine || iconEngine->isNull()) {
686 qCDebug(lcIconLoader) <<
"Icon is not available from theme or fallback theme.";
687 if (
auto *platformTheme = QGuiApplicationPrivate::platformTheme()) {
688 qCDebug(lcIconLoader) <<
"Trying platform engine.";
689 std::unique_ptr<QIconEngine> themeEngine(platformTheme->createIconEngine(iconName));
690 if (themeEngine && !themeEngine->isNull()) {
691 iconEngine = std::move(themeEngine);
692 qCDebug(lcIconLoader) <<
"Icon provided by platform engine.";
698 iconEngine.reset(
new QIconLoaderEngine(iconName));
700 qCDebug(lcIconLoader) <<
"Resulting engine" << iconEngine.get();
701 return iconEngine.release();
705
706
707
708
709
710
711
712
713
714
715
716
717
719QThemeIconEngine::QThemeIconEngine(
const QString& iconName)
721 , m_iconName(iconName)
725QThemeIconEngine::QThemeIconEngine(
const QThemeIconEngine &other)
727 , m_iconName(other.m_iconName)
731QString QThemeIconEngine::key()
const
736 return u"QThemeIconEngine"_s;
739QIconEngine *QThemeIconEngine::clone()
const
741 return new QThemeIconEngine(*
this);
744bool QThemeIconEngine::read(QDataStream &in) {
749bool QThemeIconEngine::write(QDataStream &out)
const
755QIconEngine *QThemeIconEngine::proxiedEngine()
const
757 const auto *iconLoader = QIconLoader::instance();
758 auto mostRecentThemeKey = iconLoader->themeKey();
759 if (mostRecentThemeKey != m_themeKey) {
760 qCDebug(lcIconLoader) <<
"Theme key" << mostRecentThemeKey <<
"is different"
761 <<
"than cached key" << m_themeKey <<
"for icon" << m_iconName;
762 m_proxiedEngine.reset(iconLoader->iconEngine(m_iconName));
763 m_themeKey = mostRecentThemeKey;
765 return m_proxiedEngine.get();
769
770
771
772
773
774
775
776
777
779QIconLoaderEngine::QIconLoaderEngine(
const QString& iconName)
780 : m_iconName(iconName)
781 , m_info(QIconLoader::instance()->loadIcon(m_iconName))
785QIconLoaderEngine::~QIconLoaderEngine() =
default;
787QIconEngine *QIconLoaderEngine::clone()
const
793bool QIconLoaderEngine::hasIcon()
const
795 return !(m_info.entries.empty());
798void QIconLoaderEngine::paint(QPainter *painter,
const QRect &rect,
799 QIcon::Mode mode, QIcon::State state)
801 const auto dpr = painter->device()->devicePixelRatio();
802 painter->drawPixmap(rect, scaledPixmap(rect.size(), mode, state, dpr));
806
807
808
811 if (dir.scale != iconscale)
815 case QIconDirInfo::Fixed:
816 return dir.size == iconsize;
817 case QIconDirInfo::Scalable:
818 return iconsize <= dir.maxSize && iconsize >= dir.minSize;
819 case QIconDirInfo::Threshold:
820 return iconsize >= dir.size - dir.threshold && iconsize <= dir.size + dir.threshold;
821 case QIconDirInfo::Fallback:
830
831
832
835 const auto scaledIconSize = iconsize * iconscale;
838 case QIconDirInfo::Fixed:
839 return dir.size * dir.scale - scaledIconSize;
840 case QIconDirInfo::Scalable: {
841 const auto minScaled = dir.minSize * dir.scale;
842 if (scaledIconSize < minScaled)
843 return minScaled - scaledIconSize;
844 const auto maxScaled = dir.maxSize * dir.scale;
845 if (scaledIconSize > maxScaled)
846 return scaledIconSize - maxScaled;
849 case QIconDirInfo::Threshold:
850 if (scaledIconSize < (dir.size - dir.threshold) * dir.scale)
851 return dir.minSize * dir.scale - scaledIconSize;
852 if (scaledIconSize > (dir.size + dir.threshold) * dir.scale)
853 return scaledIconSize - dir.maxSize * dir.scale;
855 case QIconDirInfo::Fallback:
863QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(
const QThemeIconInfo &info,
const QSize &size,
int scale)
865 if (info.entries.empty())
867 if (info.entries.size() == 1)
868 return info.entries.at(0).get();
870 int iconsize = qMin(size.width(), size.height());
875 int minimalDelta = INT_MIN;
876 QIconLoaderEngineEntry *closestMatch =
nullptr;
877 for (
const auto &entry : info.entries) {
879 if (directoryMatchesSizeAndScale(entry->dir, iconsize, scale))
883 const auto deltaValue = directorySizeDelta(entry->dir, iconsize, scale);
885 if (deltaValue > minimalDelta && minimalDelta <= 0) {
886 minimalDelta = deltaValue;
887 closestMatch = entry.get();
888 }
else if (deltaValue > 0 && deltaValue < qAbs(minimalDelta)) {
889 minimalDelta = deltaValue;
890 closestMatch = entry.get();
891 }
else if (deltaValue == 0) {
894 minimalDelta = deltaValue;
895 closestMatch = entry.get();
898 return closestMatch ? closestMatch : info.entries.at(0).get();
902
903
904
905
906
907QSize QIconLoaderEngine::actualSize(
const QSize &size, QIcon::Mode mode,
913 QIconLoaderEngineEntry *entry = entryForSize(m_info, size);
915 const QIconDirInfo &dir = entry->dir;
916 if (dir.type == QIconDirInfo::Scalable) {
918 }
else if (dir.type == QIconDirInfo::Fallback) {
919 return QIcon(entry->filename).actualSize(size, mode, state);
921 int result = qMin<
int>(dir.size * dir.scale, qMin(size.width(), size.height()));
922 return QSize(result, result);
928QPixmap PixmapEntry::pixmap(
const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
934 if (basePixmap.isNull())
935 basePixmap.load(filename);
939 const auto actualSize = QPixmapIconEngine::adjustSize(size * scale, basePixmap.size());
940 const auto calculatedDpr = QIconPrivate::pixmapDevicePixelRatio(scale, size, actualSize);
941 QString key =
"$qt_theme_"_L1
942 % HexString<quint64>(basePixmap.cacheKey())
943 % HexString<quint8>(mode)
944 % HexString<quint64>(QGuiApplication::palette().cacheKey())
945 % HexString<uint>(actualSize.width())
946 % HexString<uint>(actualSize.height())
947 % HexString<quint16>(qRound(calculatedDpr * 1000));
949 QPixmap cachedPixmap;
950 if (QPixmapCache::find(key, &cachedPixmap)) {
953 if (basePixmap.size() != actualSize)
954 cachedPixmap = basePixmap.scaled(actualSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
956 cachedPixmap = basePixmap;
957 if (QGuiApplication *guiApp = qobject_cast<QGuiApplication *>(qApp))
958 cachedPixmap =
static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(guiApp))->applyQIconStyleHelper(mode, cachedPixmap);
959 cachedPixmap.setDevicePixelRatio(calculatedDpr);
960 QPixmapCache::insert(key, cachedPixmap);
965QPixmap ScalableEntry::pixmap(
const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
967 if (svgIcon.isNull())
968 svgIcon = QIcon(filename);
970 return svgIcon.pixmap(size, scale, mode, state);
973QPixmap QIconLoaderEngine::pixmap(
const QSize &size, QIcon::Mode mode,
976 return scaledPixmap(size, mode, state, 1.0);
979QString QIconLoaderEngine::key()
const
981 return u"QIconLoaderEngine"_s;
984QString QIconLoaderEngine::iconName()
986 return m_info.iconName;
989bool QIconLoaderEngine::isNull()
991 return m_info.entries.empty();
994QPixmap QIconLoaderEngine::scaledPixmap(
const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
996 const int integerScale = qCeil(scale);
997 QIconLoaderEngineEntry *entry = entryForSize(m_info, size, integerScale);
998 return entry ? entry->pixmap(size, mode, state, scale) : QPixmap();
1001QList<QSize> QIconLoaderEngine::availableSizes(QIcon::Mode mode, QIcon::State state)
1006 const qsizetype N = qsizetype(m_info.entries.size());
1011 for (
const auto &entry : m_info.entries) {
1012 if (entry->dir.type == QIconDirInfo::Fallback) {
1013 sizes.append(QIcon(entry->filename).availableSizes());
1015 int size = entry->dir.size;
1016 sizes.append(QSize(size, size));
QIconCacheGtkReader(const QString &themeDir)
QList< const char * > lookup(QStringView)
Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core")
QDebug operator<<(QDebug dbg, const QFileInfo &fi)
static QStringList systemIconSearchPaths()
QFactoryLoader * qt_iconEngineFactoryLoader()
static int directorySizeDelta(const QIconDirInfo &dir, int iconsize, int iconscale)
static bool directoryMatchesSizeAndScale(const QIconDirInfo &dir, int iconsize, int iconscale)
QDebug operator<<(QDebug debug, QIconEngine *engine)
static QStringList systemFallbackSearchPaths()
static QString systemThemeName()
static QString systemFallbackThemeName()
static quint32 icon_name_hash(const char *p)
Q_GLOBAL_STATIC(QReadWriteLock, g_updateMutex)