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 if (!m_userTheme.isEmpty())
153 if (m_systemTheme.isEmpty()) {
154 m_systemTheme = systemThemeName();
156 return m_systemTheme;
159void QIconLoader::setThemeName(
const QString &themeName)
161 if (m_userTheme == themeName)
164 qCDebug(lcIconLoader) <<
"Setting user theme name to" << themeName;
166 const bool hadUserTheme = hasUserTheme();
167 m_userTheme = themeName;
171 if (!hasUserTheme() && hadUserTheme)
172 setThemeSearchPath(systemIconSearchPaths());
176QString QIconLoader::fallbackThemeName()
const
178 return m_userFallbackTheme.isEmpty() ? systemFallbackThemeName() : m_userFallbackTheme;
181void QIconLoader::setFallbackThemeName(
const QString &themeName)
183 qCDebug(lcIconLoader) <<
"Setting fallback theme name to" << themeName;
184 m_userFallbackTheme = themeName;
188void QIconLoader::setThemeSearchPath(
const QStringList &searchPaths)
190 qCDebug(lcIconLoader) <<
"Setting theme search path to" << searchPaths;
191 m_iconDirs = searchPaths;
196QStringList QIconLoader::themeSearchPaths()
const
198 if (m_iconDirs.isEmpty()) {
199 m_iconDirs = systemIconSearchPaths();
201 m_iconDirs.append(
":/icons"_L1);
206void QIconLoader::setFallbackSearchPaths(
const QStringList &searchPaths)
208 qCDebug(lcIconLoader) <<
"Setting fallback search path to" << searchPaths;
209 m_fallbackDirs = searchPaths;
213QStringList QIconLoader::fallbackSearchPaths()
const
215 if (m_fallbackDirs.isEmpty()) {
216 m_fallbackDirs = systemFallbackSearchPaths();
218 return m_fallbackDirs;
222
223
224
225
226
227
236 const unsigned char *m_data;
240 quint16 read16(uint offset)
242 if (offset > m_size - 2 || (offset & 0x1)) {
246 return m_data[offset+1] | m_data[offset] << 8;
248 quint32 read32(uint offset)
250 if (offset > m_size - 4 || (offset & 0x3)) {
254 return m_data[offset+3] | m_data[offset+2] << 8
255 | m_data[offset+1] << 16 | m_data[offset] << 24;
263 QFileInfo info(dirName +
"/icon-theme.cache"_L1);
264 if (!info.exists() || info.lastModified(QTimeZone::UTC) < QFileInfo(dirName).lastModified(QTimeZone::UTC))
266 m_file.setFileName(info.absoluteFilePath());
267 if (!m_file.open(QFile::ReadOnly))
269 m_size = m_file.size();
270 m_data = m_file.map(0, m_size);
279 const QDateTime lastModified = info.lastModified(QTimeZone::UTC);
280 quint32 dirListOffset = read32(8);
281 quint32 dirListLen = read32(dirListOffset);
282 for (uint i = 0; i < dirListLen; ++i) {
283 quint32 offset = read32(dirListOffset + 4 + 4 * i);
284 if (!m_isValid || offset >= m_size || lastModified < QFileInfo(dirName + u'/'
285 + QString::fromUtf8(
reinterpret_cast<
const char*>(m_data + offset))).lastModified(QTimeZone::UTC)) {
294 quint32 h =
static_cast<
signed char>(*p);
295 for (p += 1; *p !=
'\0'; p++)
296 h = (h << 5) - h + *p;
301
302
303
304
307 QList<
const char *> ret;
311 QByteArray nameUtf8 = name.toUtf8();
312 quint32 hash = icon_name_hash(nameUtf8);
314 quint32 hashOffset = read32(4);
315 quint32 hashBucketCount = read32(hashOffset);
317 if (!
isValid() || hashBucketCount == 0) {
322 quint32 bucketIndex = hash % hashBucketCount;
323 quint32 bucketOffset = read32(hashOffset + 4 + bucketIndex * 4);
324 while (bucketOffset > 0 && bucketOffset <= m_size - 12) {
325 quint32 nameOff = read32(bucketOffset + 4);
326 if (nameOff < m_size && strcmp(
reinterpret_cast<
const char*>(m_data + nameOff), nameUtf8) == 0) {
327 quint32 dirListOffset = read32(8);
328 quint32 dirListLen = read32(dirListOffset);
330 quint32 listOffset = read32(bucketOffset+8);
331 quint32 listLen = read32(listOffset);
333 if (!m_isValid || listOffset + 4 + 8 * listLen > m_size) {
338 ret.reserve(listLen);
339 for (uint j = 0; j < listLen && m_isValid; ++j) {
340 quint32 dirIndex = read16(listOffset + 4 + 8 * j);
341 quint32 o = read32(dirListOffset + 4 + dirIndex*4);
342 if (!m_isValid || dirIndex >= dirListLen || o >= m_size) {
346 ret.append(
reinterpret_cast<
const char*>(m_data) + o);
350 bucketOffset = read32(bucketOffset);
355QIconTheme::QIconTheme(
const QString &themeName)
360 const QStringList iconDirs = QIcon::themeSearchPaths();
361 for (
const auto &dirName : iconDirs) {
362 QDir iconDir(dirName);
363 QString themeDir = iconDir.path() + u'/' + themeName;
364 QFileInfo themeDirInfo(themeDir);
366 if (themeDirInfo.isDir()) {
367 m_contentDirs << themeDir;
368 m_gtkCaches << QSharedPointer<QIconCacheGtkReader>::create(themeDir);
372 themeIndex.setFileName(themeDir +
"/index.theme"_L1);
373 m_valid = themeIndex.exists();
374 qCDebug(lcIconLoader) <<
"Probing theme file at" << themeIndex.fileName() << m_valid;
377#if QT_CONFIG(settings)
379 const QSettings indexReader(themeIndex.fileName(), QSettings::IniFormat);
380 const QStringList keys = indexReader.allKeys();
381 for (
const QString &key : keys) {
382 if (key.endsWith(
"/Size"_L1)) {
385 if (
int size = indexReader.value(key).toInt()) {
386 QString directoryKey = key.left(key.size() - 5);
387 QIconDirInfo dirInfo(directoryKey);
389 QString type = indexReader.value(directoryKey +
"/Type"_L1).toString();
391 if (type ==
"Fixed"_L1)
392 dirInfo.type = QIconDirInfo::Fixed;
393 else if (type ==
"Scalable"_L1)
394 dirInfo.type = QIconDirInfo::Scalable;
396 dirInfo.type = QIconDirInfo::Threshold;
398 dirInfo.threshold = indexReader.value(directoryKey +
402 dirInfo.minSize = indexReader.value(directoryKey +
"/MinSize"_L1, size).toInt();
404 dirInfo.maxSize = indexReader.value(directoryKey +
"/MaxSize"_L1, size).toInt();
406 dirInfo.scale = indexReader.value(directoryKey +
"/Scale"_L1, 1).toInt();
408 const QString context = indexReader.value(directoryKey +
"/Context"_L1).toString();
409 dirInfo.context = [context]() {
410 if (context ==
"Applications"_L1)
411 return QIconDirInfo::Applications;
412 else if (context ==
"MimeTypes"_L1)
413 return QIconDirInfo::MimeTypes;
415 return QIconDirInfo::UnknownContext;
418 m_keyList.append(dirInfo);
424 m_parents = indexReader.value(
"Icon Theme/Inherits"_L1).toStringList();
425 m_parents.removeAll(QString());
430QStringList QIconTheme::parents()
const
433 QStringList result = m_parents;
436 const QString fallback = QIconLoader::instance()->fallbackThemeName();
437 if (!fallback.isEmpty())
438 result.append(fallback);
441 result.removeAll(
"hicolor"_L1);
442 result.append(
"hicolor"_L1);
447QDebug operator<<(QDebug debug,
const std::unique_ptr<QIconLoaderEngineEntry> &entry)
449 QDebugStateSaver saver(debug);
450 if (entry)
return debug.noquote() << entry->filename;
451 return debug <<
"QIconLoaderEngineEntry(0x0)";
454QThemeIconInfo QIconLoader::findIconHelper(
const QString &themeName,
455 const QString &iconName,
456 QStringList &visited,
459 qCDebug(lcIconLoader) <<
"Finding icon" << iconName <<
"in theme" << themeName
460 <<
"skipping" << visited;
463 Q_ASSERT(!themeName.isEmpty());
466 visited << themeName;
468 QIconTheme &theme = themeList[themeName];
469 if (!theme.isValid()) {
470 theme = QIconTheme(themeName);
471 if (!theme.isValid()) {
472 qCDebug(lcIconLoader) <<
"Theme" << themeName <<
"not found";
477 const QStringList contentDirs = theme.contentDirs();
479 QStringView iconNameFallback(iconName);
480 bool searchingGenericFallback = m_iconName.length() > iconName.length();
483 if (info.entries.empty()) {
484 const QString svgIconName = iconNameFallback +
".svg"_L1;
485 const QString pngIconName = iconNameFallback +
".png"_L1;
488 for (qsizetype i = 0; i < contentDirs.size(); ++i) {
489 QList<QIconDirInfo> subDirs = theme.keyList();
493 auto cache = theme.m_gtkCaches.at(i);
494 if (cache->isValid()) {
495 const auto result = cache->lookup(iconNameFallback);
496 if (cache->isValid()) {
497 const QList<QIconDirInfo> subDirsCopy = subDirs;
499 subDirs.reserve(result.size());
500 for (
const char *s : result) {
501 QString path = QString::fromUtf8(s);
502 auto it = std::find_if(subDirsCopy.cbegin(), subDirsCopy.cend(),
503 [&](
const QIconDirInfo &info) {
504 return info.path == path; } );
505 if (it != subDirsCopy.cend()) {
512 QString contentDir = contentDirs.at(i) + u'/';
513 for (
const auto &dirInfo : std::as_const(subDirs)) {
514 if (searchingGenericFallback &&
515 (dirInfo.context == QIconDirInfo::Applications ||
516 dirInfo.context == QIconDirInfo::MimeTypes))
519 const QString subDir = contentDir + dirInfo.path + u'/';
520 const QString pngPath = subDir + pngIconName;
521 if (QFile::exists(pngPath)) {
522 auto iconEntry = std::make_unique<PixmapEntry>();
523 iconEntry->dir = dirInfo;
524 iconEntry->filename = pngPath;
527 info.entries.insert(info.entries.begin(), std::move(iconEntry));
528 }
else if (m_supportsSvg) {
529 const QString svgPath = subDir + svgIconName;
530 if (QFile::exists(svgPath)) {
531 auto iconEntry = std::make_unique<ScalableEntry>();
532 iconEntry->dir = dirInfo;
533 iconEntry->filename = svgPath;
534 info.entries.push_back(std::move(iconEntry));
540 if (!info.entries.empty()) {
541 info.iconName = iconNameFallback.toString();
545 if (info.entries.empty()) {
546 const QStringList parents = theme.parents();
547 qCDebug(lcIconLoader) <<
"Did not find matching icons in theme;"
548 <<
"trying parent themes" << parents
549 <<
"skipping visited" << visited;
552 for (
const auto &parent : parents) {
554 const QString parentTheme = parent.trimmed();
556 if (!visited.contains(parentTheme))
557 info = findIconHelper(parentTheme, iconName, visited, QIconLoader::NoFallBack);
559 if (!info.entries.empty())
564 if (rule == QIconLoader::FallBack && info.entries.empty()) {
566 const int indexOfDash = iconNameFallback.lastIndexOf(u'-');
567 if (indexOfDash != -1) {
568 qCDebug(lcIconLoader) <<
"Did not find matching icons in all themes;"
569 <<
"trying dash fallback";
570 iconNameFallback.truncate(indexOfDash);
571 QStringList _visited;
572 info = findIconHelper(themeName, iconNameFallback.toString(), _visited, QIconLoader::FallBack);
579QThemeIconInfo QIconLoader::lookupFallbackIcon(
const QString &iconName)
const
581 qCDebug(lcIconLoader) <<
"Looking up fallback icon" << iconName;
585 const QString pngIconName = iconName +
".png"_L1;
586 const QString xpmIconName = iconName +
".xpm"_L1;
587 const QString svgIconName = iconName +
".svg"_L1;
589 const auto searchPaths = QIcon::fallbackSearchPaths();
590 for (
const QString &iconDir: searchPaths) {
591 QDir currentDir(iconDir);
592 std::unique_ptr<QIconLoaderEngineEntry> iconEntry;
593 if (currentDir.exists(pngIconName)) {
594 iconEntry = std::make_unique<PixmapEntry>();
595 iconEntry->dir.type = QIconDirInfo::Fallback;
596 iconEntry->filename = currentDir.filePath(pngIconName);
597 }
else if (currentDir.exists(xpmIconName)) {
598 iconEntry = std::make_unique<PixmapEntry>();
599 iconEntry->dir.type = QIconDirInfo::Fallback;
600 iconEntry->filename = currentDir.filePath(xpmIconName);
601 }
else if (m_supportsSvg &&
602 currentDir.exists(svgIconName)) {
603 iconEntry = std::make_unique<ScalableEntry>();
604 iconEntry->dir.type = QIconDirInfo::Fallback;
605 iconEntry->filename = currentDir.filePath(svgIconName);
608 info.entries.push_back(std::move(iconEntry));
613 if (!info.entries.empty())
614 info.iconName = iconName;
619QThemeIconInfo QIconLoader::loadIcon(
const QString &name)
const
621 qCDebug(lcIconLoader) <<
"Loading icon" << name;
624 QThemeIconInfo iconInfo;
625 QStringList visitedThemes;
626 if (!themeName().isEmpty())
627 iconInfo = findIconHelper(themeName(), name, visitedThemes, QIconLoader::FallBack);
629 if (iconInfo.entries.empty() && !fallbackThemeName().isEmpty())
630 iconInfo = findIconHelper(fallbackThemeName(), name, visitedThemes, QIconLoader::FallBack);
632 if (iconInfo.entries.empty())
633 iconInfo = lookupFallbackIcon(name);
635 qCDebug(lcIconLoader) <<
"Resulting icon entries" << iconInfo.entries;
639#ifndef QT_NO_DEBUG_STREAM
642 QDebugStateSaver saver(debug);
645 debug.noquote() << engine->key() <<
"(";
646 debug <<
static_cast<
const void *>(engine);
647 if (!engine->isNull())
648 debug.quote() <<
", " << engine->iconName();
653 debug <<
"QIconEngine(nullptr)";
659QIconEngine *QIconLoader::iconEngine(
const QString &iconName)
const
661 qCDebug(lcIconLoader) <<
"Resolving icon engine for icon" << iconName;
663 std::unique_ptr<QIconEngine> iconEngine;
666 qCDebug(lcIconLoader) <<
"Finding a plugin for theme" << themeName();
668 const int factoryIndex = qt_iconEngineFactoryLoader()->indexOf(themeName());
669 if (factoryIndex >= 0)
670 m_factory = qobject_cast<QIconEnginePlugin *>(qt_iconEngineFactoryLoader()->instance(factoryIndex));
672 if (m_factory && *m_factory)
673 iconEngine.reset(m_factory.value()->create(iconName));
675 if (hasUserTheme()) {
676 if (!iconEngine || iconEngine->isNull()) {
677 if (QFontDatabase::families().contains(themeName())) {
678 QFont maybeIconFont(themeName());
679 maybeIconFont.setStyleStrategy(QFont::NoFontMerging);
680 qCDebug(lcIconLoader) <<
"Trying font icon engine.";
681 iconEngine.reset(
new QFontIconEngine(iconName, maybeIconFont));
684 if (!iconEngine || iconEngine->isNull()) {
685 qCDebug(lcIconLoader) <<
"Trying loader engine for theme.";
686 iconEngine.reset(
new QIconLoaderEngine(iconName));
690 if (!iconEngine || iconEngine->isNull()) {
691 qCDebug(lcIconLoader) <<
"Icon is not available from theme or fallback theme.";
692 if (
auto *platformTheme = QGuiApplicationPrivate::platformTheme()) {
693 qCDebug(lcIconLoader) <<
"Trying platform engine.";
694 std::unique_ptr<QIconEngine> themeEngine(platformTheme->createIconEngine(iconName));
695 if (themeEngine && !themeEngine->isNull()) {
696 iconEngine = std::move(themeEngine);
697 qCDebug(lcIconLoader) <<
"Icon provided by platform engine.";
703 iconEngine.reset(
new QIconLoaderEngine(iconName));
705 qCDebug(lcIconLoader) <<
"Resulting engine" << iconEngine.get();
706 return iconEngine.release();
710
711
712
713
714
715
716
717
718
719
720
721
722
724QThemeIconEngine::QThemeIconEngine(
const QString& iconName)
726 , m_iconName(iconName)
730QThemeIconEngine::QThemeIconEngine(
const QThemeIconEngine &other)
732 , m_iconName(other.m_iconName)
736QString QThemeIconEngine::key()
const
741 return u"QThemeIconEngine"_s;
744QIconEngine *QThemeIconEngine::clone()
const
746 return new QThemeIconEngine(*
this);
749bool QThemeIconEngine::read(QDataStream &in) {
754bool QThemeIconEngine::write(QDataStream &out)
const
760QIconEngine *QThemeIconEngine::proxiedEngine()
const
762 const auto *iconLoader = QIconLoader::instance();
763 auto mostRecentThemeKey = iconLoader->themeKey();
764 if (mostRecentThemeKey != m_themeKey) {
765 qCDebug(lcIconLoader) <<
"Theme key" << mostRecentThemeKey <<
"is different"
766 <<
"than cached key" << m_themeKey <<
"for icon" << m_iconName;
767 m_proxiedEngine.reset(iconLoader->iconEngine(m_iconName));
768 m_themeKey = mostRecentThemeKey;
770 return m_proxiedEngine.get();
774
775
776
777
778
779
780
781
782
784QIconLoaderEngine::QIconLoaderEngine(
const QString& iconName)
785 : m_iconName(iconName)
786 , m_info(QIconLoader::instance()->loadIcon(m_iconName))
790QIconLoaderEngine::~QIconLoaderEngine() =
default;
792QIconEngine *QIconLoaderEngine::clone()
const
798bool QIconLoaderEngine::hasIcon()
const
800 return !(m_info.entries.empty());
803void QIconLoaderEngine::paint(QPainter *painter,
const QRect &rect,
804 QIcon::Mode mode, QIcon::State state)
806 const auto dpr = painter->device()->devicePixelRatio();
807 painter->drawPixmap(rect, scaledPixmap(rect.size(), mode, state, dpr));
811
812
813
816 if (dir.scale != iconscale)
820 case QIconDirInfo::Fixed:
821 return dir.size == iconsize;
822 case QIconDirInfo::Scalable:
823 return iconsize <= dir.maxSize && iconsize >= dir.minSize;
824 case QIconDirInfo::Threshold:
825 return iconsize >= dir.size - dir.threshold && iconsize <= dir.size + dir.threshold;
826 case QIconDirInfo::Fallback:
835
836
837
840 const auto scaledIconSize = iconsize * iconscale;
843 case QIconDirInfo::Fixed:
844 return dir.size * dir.scale - scaledIconSize;
845 case QIconDirInfo::Scalable: {
846 const auto minScaled = dir.minSize * dir.scale;
847 if (scaledIconSize < minScaled)
848 return minScaled - scaledIconSize;
849 const auto maxScaled = dir.maxSize * dir.scale;
850 if (scaledIconSize > maxScaled)
851 return scaledIconSize - maxScaled;
854 case QIconDirInfo::Threshold:
855 if (scaledIconSize < (dir.size - dir.threshold) * dir.scale)
856 return dir.minSize * dir.scale - scaledIconSize;
857 if (scaledIconSize > (dir.size + dir.threshold) * dir.scale)
858 return scaledIconSize - dir.maxSize * dir.scale;
860 case QIconDirInfo::Fallback:
868QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(
const QThemeIconInfo &info,
const QSize &size,
int scale)
870 if (info.entries.empty())
872 if (info.entries.size() == 1)
873 return info.entries.at(0).get();
875 int iconsize = qMin(size.width(), size.height());
880 int minimalDelta = INT_MIN;
881 QIconLoaderEngineEntry *closestMatch =
nullptr;
882 for (
const auto &entry : info.entries) {
884 if (directoryMatchesSizeAndScale(entry->dir, iconsize, scale))
888 const auto deltaValue = directorySizeDelta(entry->dir, iconsize, scale);
890 if (deltaValue > minimalDelta && minimalDelta <= 0) {
891 minimalDelta = deltaValue;
892 closestMatch = entry.get();
893 }
else if (deltaValue > 0 && deltaValue < qAbs(minimalDelta)) {
894 minimalDelta = deltaValue;
895 closestMatch = entry.get();
896 }
else if (deltaValue == 0) {
899 minimalDelta = deltaValue;
900 closestMatch = entry.get();
903 return closestMatch ? closestMatch : info.entries.at(0).get();
907
908
909
910
911
912QSize QIconLoaderEngine::actualSize(
const QSize &size, QIcon::Mode mode,
918 QIconLoaderEngineEntry *entry = entryForSize(m_info, size);
920 const QIconDirInfo &dir = entry->dir;
921 if (dir.type == QIconDirInfo::Scalable) {
923 }
else if (dir.type == QIconDirInfo::Fallback) {
924 return QIcon(entry->filename).actualSize(size, mode, state);
926 int result = qMin<
int>(dir.size * dir.scale, qMin(size.width(), size.height()));
927 return QSize(result, result);
933QPixmap PixmapEntry::pixmap(
const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
939 if (basePixmap.isNull())
940 basePixmap.load(filename);
944 const auto actualSize = QPixmapIconEngine::adjustSize(size * scale, basePixmap.size());
945 const auto calculatedDpr = QIconPrivate::pixmapDevicePixelRatio(scale, size, actualSize);
946 QString key =
"$qt_theme_"_L1
947 % HexString<quint64>(basePixmap.cacheKey())
948 % HexString<quint8>(mode)
949 % HexString<quint64>(QGuiApplication::palette().cacheKey())
950 % HexString<uint>(actualSize.width())
951 % HexString<uint>(actualSize.height())
952 % HexString<quint16>(qRound(calculatedDpr * 1000));
954 QPixmap cachedPixmap;
955 if (QPixmapCache::find(key, &cachedPixmap)) {
958 if (basePixmap.size() != actualSize)
959 cachedPixmap = basePixmap.scaled(actualSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
961 cachedPixmap = basePixmap;
962 if (QGuiApplication *guiApp = qobject_cast<QGuiApplication *>(qApp))
963 cachedPixmap =
static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(guiApp))->applyQIconStyleHelper(mode, cachedPixmap);
964 cachedPixmap.setDevicePixelRatio(calculatedDpr);
965 QPixmapCache::insert(key, cachedPixmap);
970QPixmap ScalableEntry::pixmap(
const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
972 if (svgIcon.isNull())
973 svgIcon = QIcon(filename);
975 return svgIcon.pixmap(size, scale, mode, state);
978QPixmap QIconLoaderEngine::pixmap(
const QSize &size, QIcon::Mode mode,
981 return scaledPixmap(size, mode, state, 1.0);
984QString QIconLoaderEngine::key()
const
986 return u"QIconLoaderEngine"_s;
989QString QIconLoaderEngine::iconName()
991 return m_info.iconName;
994bool QIconLoaderEngine::isNull()
996 return m_info.entries.empty();
999QPixmap QIconLoaderEngine::scaledPixmap(
const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
1001 const int integerScale = qCeil(scale);
1002 QIconLoaderEngineEntry *entry = entryForSize(m_info, size, integerScale);
1003 return entry ? entry->pixmap(size, mode, state, scale) : QPixmap();
1006QList<QSize> QIconLoaderEngine::availableSizes(QIcon::Mode mode, QIcon::State state)
1011 const qsizetype N = qsizetype(m_info.entries.size());
1016 for (
const auto &entry : m_info.entries) {
1017 if (entry->dir.type == QIconDirInfo::Fallback) {
1018 sizes.append(QIcon(entry->filename).availableSizes());
1020 int size = entry->dir.size;
1021 sizes.append(QSize(size, size));
QIconCacheGtkReader(const QString &themeDir)
QList< const char * > lookup(QStringView)
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)
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)
Q_GLOBAL_STATIC(QReadWriteLock, g_updateMutex)