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 (
const auto &dirName : iconDirs) {
356 QDir iconDir(dirName);
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 (qsizetype 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 (
const auto &dirInfo : std::as_const(subDirs)) {
508 if (searchingGenericFallback &&
509 (dirInfo.context == QIconDirInfo::Applications ||
510 dirInfo.context == QIconDirInfo::MimeTypes))
513 const QString subDir = contentDir + dirInfo.path + u'/';
514 const QString pngPath = subDir + pngIconName;
515 if (QFile::exists(pngPath)) {
516 auto iconEntry = std::make_unique<PixmapEntry>();
517 iconEntry->dir = dirInfo;
518 iconEntry->filename = pngPath;
521 info.entries.insert(info.entries.begin(), std::move(iconEntry));
522 }
else if (m_supportsSvg) {
523 const QString svgPath = subDir + svgIconName;
524 if (QFile::exists(svgPath)) {
525 auto iconEntry = std::make_unique<ScalableEntry>();
526 iconEntry->dir = dirInfo;
527 iconEntry->filename = svgPath;
528 info.entries.push_back(std::move(iconEntry));
534 if (!info.entries.empty()) {
535 info.iconName = iconNameFallback.toString();
539 if (info.entries.empty()) {
540 const QStringList parents = theme.parents();
541 qCDebug(lcIconLoader) <<
"Did not find matching icons in theme;"
542 <<
"trying parent themes" << parents
543 <<
"skipping visited" << visited;
546 for (
const auto &parent : parents) {
548 const QString parentTheme = parent.trimmed();
550 if (!visited.contains(parentTheme))
551 info = findIconHelper(parentTheme, iconName, visited, QIconLoader::NoFallBack);
553 if (!info.entries.empty())
558 if (rule == QIconLoader::FallBack && info.entries.empty()) {
560 const int indexOfDash = iconNameFallback.lastIndexOf(u'-');
561 if (indexOfDash != -1) {
562 qCDebug(lcIconLoader) <<
"Did not find matching icons in all themes;"
563 <<
"trying dash fallback";
564 iconNameFallback.truncate(indexOfDash);
565 QStringList _visited;
566 info = findIconHelper(themeName, iconNameFallback.toString(), _visited, QIconLoader::FallBack);
573QThemeIconInfo QIconLoader::lookupFallbackIcon(
const QString &iconName)
const
575 qCDebug(lcIconLoader) <<
"Looking up fallback icon" << iconName;
579 const QString pngIconName = iconName +
".png"_L1;
580 const QString xpmIconName = iconName +
".xpm"_L1;
581 const QString svgIconName = iconName +
".svg"_L1;
583 const auto searchPaths = QIcon::fallbackSearchPaths();
584 for (
const QString &iconDir: searchPaths) {
585 QDir currentDir(iconDir);
586 std::unique_ptr<QIconLoaderEngineEntry> iconEntry;
587 if (currentDir.exists(pngIconName)) {
588 iconEntry = std::make_unique<PixmapEntry>();
589 iconEntry->dir.type = QIconDirInfo::Fallback;
590 iconEntry->filename = currentDir.filePath(pngIconName);
591 }
else if (currentDir.exists(xpmIconName)) {
592 iconEntry = std::make_unique<PixmapEntry>();
593 iconEntry->dir.type = QIconDirInfo::Fallback;
594 iconEntry->filename = currentDir.filePath(xpmIconName);
595 }
else if (m_supportsSvg &&
596 currentDir.exists(svgIconName)) {
597 iconEntry = std::make_unique<ScalableEntry>();
598 iconEntry->dir.type = QIconDirInfo::Fallback;
599 iconEntry->filename = currentDir.filePath(svgIconName);
602 info.entries.push_back(std::move(iconEntry));
607 if (!info.entries.empty())
608 info.iconName = iconName;
613QThemeIconInfo QIconLoader::loadIcon(
const QString &name)
const
615 qCDebug(lcIconLoader) <<
"Loading icon" << name;
618 QThemeIconInfo iconInfo;
619 QStringList visitedThemes;
620 if (!themeName().isEmpty())
621 iconInfo = findIconHelper(themeName(), name, visitedThemes, QIconLoader::FallBack);
623 if (iconInfo.entries.empty() && !fallbackThemeName().isEmpty())
624 iconInfo = findIconHelper(fallbackThemeName(), name, visitedThemes, QIconLoader::FallBack);
626 if (iconInfo.entries.empty())
627 iconInfo = lookupFallbackIcon(name);
629 qCDebug(lcIconLoader) <<
"Resulting icon entries" << iconInfo.entries;
633#ifndef QT_NO_DEBUG_STREAM
636 QDebugStateSaver saver(debug);
639 debug.noquote() << engine->key() <<
"(";
640 debug <<
static_cast<
const void *>(engine);
641 if (!engine->isNull())
642 debug.quote() <<
", " << engine->iconName();
647 debug <<
"QIconEngine(nullptr)";
653QIconEngine *QIconLoader::iconEngine(
const QString &iconName)
const
655 qCDebug(lcIconLoader) <<
"Resolving icon engine for icon" << iconName;
657 std::unique_ptr<QIconEngine> iconEngine;
660 qCDebug(lcIconLoader) <<
"Finding a plugin for theme" << themeName();
662 const int factoryIndex = qt_iconEngineFactoryLoader()->indexOf(themeName());
663 if (factoryIndex >= 0)
664 m_factory = qobject_cast<QIconEnginePlugin *>(qt_iconEngineFactoryLoader()->instance(factoryIndex));
666 if (m_factory && *m_factory)
667 iconEngine.reset(m_factory.value()->create(iconName));
669 if (hasUserTheme()) {
670 if (!iconEngine || iconEngine->isNull()) {
671 if (QFontDatabase::families().contains(themeName())) {
672 QFont maybeIconFont(themeName());
673 maybeIconFont.setStyleStrategy(QFont::NoFontMerging);
674 qCDebug(lcIconLoader) <<
"Trying font icon engine.";
675 iconEngine.reset(
new QFontIconEngine(iconName, maybeIconFont));
678 if (!iconEngine || iconEngine->isNull()) {
679 qCDebug(lcIconLoader) <<
"Trying loader engine for theme.";
680 iconEngine.reset(
new QIconLoaderEngine(iconName));
684 if (!iconEngine || iconEngine->isNull()) {
685 qCDebug(lcIconLoader) <<
"Icon is not available from theme or fallback theme.";
686 if (
auto *platformTheme = QGuiApplicationPrivate::platformTheme()) {
687 qCDebug(lcIconLoader) <<
"Trying platform engine.";
688 std::unique_ptr<QIconEngine> themeEngine(platformTheme->createIconEngine(iconName));
689 if (themeEngine && !themeEngine->isNull()) {
690 iconEngine = std::move(themeEngine);
691 qCDebug(lcIconLoader) <<
"Icon provided by platform engine.";
697 iconEngine.reset(
new QIconLoaderEngine(iconName));
699 qCDebug(lcIconLoader) <<
"Resulting engine" << iconEngine.get();
700 return iconEngine.release();
704
705
706
707
708
709
710
711
712
713
714
715
716
718QThemeIconEngine::QThemeIconEngine(
const QString& iconName)
720 , m_iconName(iconName)
724QThemeIconEngine::QThemeIconEngine(
const QThemeIconEngine &other)
726 , m_iconName(other.m_iconName)
730QString QThemeIconEngine::key()
const
735 return u"QThemeIconEngine"_s;
738QIconEngine *QThemeIconEngine::clone()
const
740 return new QThemeIconEngine(*
this);
743bool QThemeIconEngine::read(QDataStream &in) {
748bool QThemeIconEngine::write(QDataStream &out)
const
754QIconEngine *QThemeIconEngine::proxiedEngine()
const
756 const auto *iconLoader = QIconLoader::instance();
757 auto mostRecentThemeKey = iconLoader->themeKey();
758 if (mostRecentThemeKey != m_themeKey) {
759 qCDebug(lcIconLoader) <<
"Theme key" << mostRecentThemeKey <<
"is different"
760 <<
"than cached key" << m_themeKey <<
"for icon" << m_iconName;
761 m_proxiedEngine.reset(iconLoader->iconEngine(m_iconName));
762 m_themeKey = mostRecentThemeKey;
764 return m_proxiedEngine.get();
768
769
770
771
772
773
774
775
776
778QIconLoaderEngine::QIconLoaderEngine(
const QString& iconName)
779 : m_iconName(iconName)
780 , m_info(QIconLoader::instance()->loadIcon(m_iconName))
784QIconLoaderEngine::~QIconLoaderEngine() =
default;
786QIconEngine *QIconLoaderEngine::clone()
const
792bool QIconLoaderEngine::hasIcon()
const
794 return !(m_info.entries.empty());
797void QIconLoaderEngine::paint(QPainter *painter,
const QRect &rect,
798 QIcon::Mode mode, QIcon::State state)
800 const auto dpr = painter->device()->devicePixelRatio();
801 painter->drawPixmap(rect, scaledPixmap(rect.size(), mode, state, dpr));
805
806
807
810 if (dir.scale != iconscale)
814 case QIconDirInfo::Fixed:
815 return dir.size == iconsize;
816 case QIconDirInfo::Scalable:
817 return iconsize <= dir.maxSize && iconsize >= dir.minSize;
818 case QIconDirInfo::Threshold:
819 return iconsize >= dir.size - dir.threshold && iconsize <= dir.size + dir.threshold;
820 case QIconDirInfo::Fallback:
829
830
831
834 const auto scaledIconSize = iconsize * iconscale;
837 case QIconDirInfo::Fixed:
838 return dir.size * dir.scale - scaledIconSize;
839 case QIconDirInfo::Scalable: {
840 const auto minScaled = dir.minSize * dir.scale;
841 if (scaledIconSize < minScaled)
842 return minScaled - scaledIconSize;
843 const auto maxScaled = dir.maxSize * dir.scale;
844 if (scaledIconSize > maxScaled)
845 return scaledIconSize - maxScaled;
848 case QIconDirInfo::Threshold:
849 if (scaledIconSize < (dir.size - dir.threshold) * dir.scale)
850 return dir.minSize * dir.scale - scaledIconSize;
851 if (scaledIconSize > (dir.size + dir.threshold) * dir.scale)
852 return scaledIconSize - dir.maxSize * dir.scale;
854 case QIconDirInfo::Fallback:
862QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(
const QThemeIconInfo &info,
const QSize &size,
int scale)
864 if (info.entries.empty())
866 if (info.entries.size() == 1)
867 return info.entries.at(0).get();
869 int iconsize = qMin(size.width(), size.height());
874 int minimalDelta = INT_MIN;
875 QIconLoaderEngineEntry *closestMatch =
nullptr;
876 for (
const auto &entry : info.entries) {
878 if (directoryMatchesSizeAndScale(entry->dir, iconsize, scale))
882 const auto deltaValue = directorySizeDelta(entry->dir, iconsize, scale);
884 if (deltaValue > minimalDelta && minimalDelta <= 0) {
885 minimalDelta = deltaValue;
886 closestMatch = entry.get();
887 }
else if (deltaValue > 0 && deltaValue < qAbs(minimalDelta)) {
888 minimalDelta = deltaValue;
889 closestMatch = entry.get();
890 }
else if (deltaValue == 0) {
893 minimalDelta = deltaValue;
894 closestMatch = entry.get();
897 return closestMatch ? closestMatch : info.entries.at(0).get();
901
902
903
904
905
906QSize QIconLoaderEngine::actualSize(
const QSize &size, QIcon::Mode mode,
912 QIconLoaderEngineEntry *entry = entryForSize(m_info, size);
914 const QIconDirInfo &dir = entry->dir;
915 if (dir.type == QIconDirInfo::Scalable) {
917 }
else if (dir.type == QIconDirInfo::Fallback) {
918 return QIcon(entry->filename).actualSize(size, mode, state);
920 int result = qMin<
int>(dir.size * dir.scale, qMin(size.width(), size.height()));
921 return QSize(result, result);
927QPixmap PixmapEntry::pixmap(
const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
933 if (basePixmap.isNull())
934 basePixmap.load(filename);
938 const auto actualSize = QPixmapIconEngine::adjustSize(size * scale, basePixmap.size());
939 const auto calculatedDpr = QIconPrivate::pixmapDevicePixelRatio(scale, size, actualSize);
940 QString key =
"$qt_theme_"_L1
941 % HexString<quint64>(basePixmap.cacheKey())
942 % HexString<quint8>(mode)
943 % HexString<quint64>(QGuiApplication::palette().cacheKey())
944 % HexString<uint>(actualSize.width())
945 % HexString<uint>(actualSize.height())
946 % HexString<quint16>(qRound(calculatedDpr * 1000));
948 QPixmap cachedPixmap;
949 if (QPixmapCache::find(key, &cachedPixmap)) {
952 if (basePixmap.size() != actualSize)
953 cachedPixmap = basePixmap.scaled(actualSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
955 cachedPixmap = basePixmap;
956 if (QGuiApplication *guiApp = qobject_cast<QGuiApplication *>(qApp))
957 cachedPixmap =
static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(guiApp))->applyQIconStyleHelper(mode, cachedPixmap);
958 cachedPixmap.setDevicePixelRatio(calculatedDpr);
959 QPixmapCache::insert(key, cachedPixmap);
964QPixmap ScalableEntry::pixmap(
const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
966 if (svgIcon.isNull())
967 svgIcon = QIcon(filename);
969 return svgIcon.pixmap(size, scale, mode, state);
972QPixmap QIconLoaderEngine::pixmap(
const QSize &size, QIcon::Mode mode,
975 return scaledPixmap(size, mode, state, 1.0);
978QString QIconLoaderEngine::key()
const
980 return u"QIconLoaderEngine"_s;
983QString QIconLoaderEngine::iconName()
985 return m_info.iconName;
988bool QIconLoaderEngine::isNull()
990 return m_info.entries.empty();
993QPixmap QIconLoaderEngine::scaledPixmap(
const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
995 const int integerScale = qCeil(scale);
996 QIconLoaderEngineEntry *entry = entryForSize(m_info, size, integerScale);
997 return entry ? entry->pixmap(size, mode, state, scale) : QPixmap();
1000QList<QSize> QIconLoaderEngine::availableSizes(QIcon::Mode mode, QIcon::State state)
1005 const qsizetype N = qsizetype(m_info.entries.size());
1010 for (
const auto &entry : m_info.entries) {
1011 if (entry->dir.type == QIconDirInfo::Fallback) {
1012 sizes.append(QIcon(entry->filename).availableSizes());
1014 int size = entry->dir.size;
1015 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)