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 const QString &themeName = systemThemeName();
155 m_systemTheme = !themeName.isEmpty() ? themeName : fallbackThemeName();
157 return m_systemTheme;
160void QIconLoader::setThemeName(
const QString &themeName)
162 if (m_userTheme == themeName)
165 qCDebug(lcIconLoader) <<
"Setting user theme name to" << themeName;
167 const bool hadUserTheme = hasUserTheme();
168 m_userTheme = themeName;
172 if (!hasUserTheme() && hadUserTheme)
173 setThemeSearchPath(systemIconSearchPaths());
177QString QIconLoader::fallbackThemeName()
const
179 return m_userFallbackTheme.isEmpty() ? systemFallbackThemeName() : m_userFallbackTheme;
182void QIconLoader::setFallbackThemeName(
const QString &themeName)
184 qCDebug(lcIconLoader) <<
"Setting fallback theme name to" << themeName;
185 m_userFallbackTheme = themeName;
189void QIconLoader::setThemeSearchPath(
const QStringList &searchPaths)
191 qCDebug(lcIconLoader) <<
"Setting theme search path to" << searchPaths;
192 m_iconDirs = searchPaths;
197QStringList QIconLoader::themeSearchPaths()
const
199 if (m_iconDirs.isEmpty()) {
200 m_iconDirs = systemIconSearchPaths();
202 m_iconDirs.append(
":/icons"_L1);
207void QIconLoader::setFallbackSearchPaths(
const QStringList &searchPaths)
209 qCDebug(lcIconLoader) <<
"Setting fallback search path to" << searchPaths;
210 m_fallbackDirs = searchPaths;
214QStringList QIconLoader::fallbackSearchPaths()
const
216 if (m_fallbackDirs.isEmpty()) {
217 m_fallbackDirs = systemFallbackSearchPaths();
219 return m_fallbackDirs;
223
224
225
226
227
228
237 const unsigned char *m_data;
241 quint16 read16(uint offset)
243 if (offset > m_size - 2 || (offset & 0x1)) {
247 return m_data[offset+1] | m_data[offset] << 8;
249 quint32 read32(uint offset)
251 if (offset > m_size - 4 || (offset & 0x3)) {
255 return m_data[offset+3] | m_data[offset+2] << 8
256 | m_data[offset+1] << 16 | m_data[offset] << 24;
264 QFileInfo info(dirName +
"/icon-theme.cache"_L1);
265 if (!info.exists() || info.lastModified(QTimeZone::UTC) < QFileInfo(dirName).lastModified(QTimeZone::UTC))
267 m_file.setFileName(info.absoluteFilePath());
268 if (!m_file.open(QFile::ReadOnly))
270 m_size = m_file.size();
271 m_data = m_file.map(0, m_size);
280 const QDateTime lastModified = info.lastModified(QTimeZone::UTC);
281 quint32 dirListOffset = read32(8);
282 quint32 dirListLen = read32(dirListOffset);
283 for (uint i = 0; i < dirListLen; ++i) {
284 quint32 offset = read32(dirListOffset + 4 + 4 * i);
285 if (!m_isValid || offset >= m_size || lastModified < QFileInfo(dirName + u'/'
286 + QString::fromUtf8(
reinterpret_cast<
const char*>(m_data + offset))).lastModified(QTimeZone::UTC)) {
295 quint32 h =
static_cast<
signed char>(*p);
296 for (p += 1; *p !=
'\0'; p++)
297 h = (h << 5) - h + *p;
302
303
304
305
308 QList<
const char *> ret;
312 QByteArray nameUtf8 = name.toUtf8();
313 quint32 hash = icon_name_hash(nameUtf8);
315 quint32 hashOffset = read32(4);
316 quint32 hashBucketCount = read32(hashOffset);
318 if (!
isValid() || hashBucketCount == 0) {
323 quint32 bucketIndex = hash % hashBucketCount;
324 quint32 bucketOffset = read32(hashOffset + 4 + bucketIndex * 4);
325 while (bucketOffset > 0 && bucketOffset <= m_size - 12) {
326 quint32 nameOff = read32(bucketOffset + 4);
327 if (nameOff < m_size && strcmp(
reinterpret_cast<
const char*>(m_data + nameOff), nameUtf8) == 0) {
328 quint32 dirListOffset = read32(8);
329 quint32 dirListLen = read32(dirListOffset);
331 quint32 listOffset = read32(bucketOffset+8);
332 quint32 listLen = read32(listOffset);
334 if (!m_isValid || listOffset + 4 + 8 * listLen > m_size) {
339 ret.reserve(listLen);
340 for (uint j = 0; j < listLen && m_isValid; ++j) {
341 quint32 dirIndex = read16(listOffset + 4 + 8 * j);
342 quint32 o = read32(dirListOffset + 4 + dirIndex*4);
343 if (!m_isValid || dirIndex >= dirListLen || o >= m_size) {
347 ret.append(
reinterpret_cast<
const char*>(m_data) + o);
351 bucketOffset = read32(bucketOffset);
356QIconTheme::QIconTheme(
const QString &themeName)
361 const QStringList iconDirs = QIcon::themeSearchPaths();
362 for (
const auto &dirName : iconDirs) {
363 QDir iconDir(dirName);
364 QString themeDir = iconDir.path() + u'/' + themeName;
365 QFileInfo themeDirInfo(themeDir);
367 if (themeDirInfo.isDir()) {
368 m_contentDirs << themeDir;
369 m_gtkCaches << QSharedPointer<QIconCacheGtkReader>::create(themeDir);
373 themeIndex.setFileName(themeDir +
"/index.theme"_L1);
374 m_valid = themeIndex.exists();
375 qCDebug(lcIconLoader) <<
"Probing theme file at" << themeIndex.fileName() << m_valid;
378#if QT_CONFIG(settings)
380 const QSettings indexReader(themeIndex.fileName(), QSettings::IniFormat);
381 const QStringList keys = indexReader.allKeys();
382 for (
const QString &key : keys) {
383 if (key.endsWith(
"/Size"_L1)) {
386 if (
int size = indexReader.value(key).toInt()) {
387 QString directoryKey = key.left(key.size() - 5);
388 QIconDirInfo dirInfo(directoryKey);
390 QString type = indexReader.value(directoryKey +
"/Type"_L1).toString();
392 if (type ==
"Fixed"_L1)
393 dirInfo.type = QIconDirInfo::Fixed;
394 else if (type ==
"Scalable"_L1)
395 dirInfo.type = QIconDirInfo::Scalable;
397 dirInfo.type = QIconDirInfo::Threshold;
399 dirInfo.threshold = indexReader.value(directoryKey +
403 dirInfo.minSize = indexReader.value(directoryKey +
"/MinSize"_L1, size).toInt();
405 dirInfo.maxSize = indexReader.value(directoryKey +
"/MaxSize"_L1, size).toInt();
407 dirInfo.scale = indexReader.value(directoryKey +
"/Scale"_L1, 1).toInt();
409 const QString context = indexReader.value(directoryKey +
"/Context"_L1).toString();
410 dirInfo.context = [context]() {
411 if (context ==
"Applications"_L1)
412 return QIconDirInfo::Applications;
413 else if (context ==
"MimeTypes"_L1)
414 return QIconDirInfo::MimeTypes;
416 return QIconDirInfo::UnknownContext;
419 m_keyList.append(dirInfo);
425 m_parents = indexReader.value(
"Icon Theme/Inherits"_L1).toStringList();
426 m_parents.removeAll(QString());
431QStringList QIconTheme::parents()
const
434 QStringList result = m_parents;
437 const QString fallback = QIconLoader::instance()->fallbackThemeName();
438 if (!fallback.isEmpty())
439 result.append(fallback);
442 result.removeAll(
"hicolor"_L1);
443 result.append(
"hicolor"_L1);
448QDebug operator<<(QDebug debug,
const std::unique_ptr<QIconLoaderEngineEntry> &entry)
450 QDebugStateSaver saver(debug);
451 if (entry)
return debug.noquote() << entry->filename;
452 return debug <<
"QIconLoaderEngineEntry(0x0)";
455QThemeIconInfo QIconLoader::findIconHelper(
const QString &themeName,
456 const QString &iconName,
457 QStringList &visited,
460 qCDebug(lcIconLoader) <<
"Finding icon" << iconName <<
"in theme" << themeName
461 <<
"skipping" << visited;
464 Q_ASSERT(!themeName.isEmpty());
467 visited << themeName;
469 QIconTheme &theme = themeList[themeName];
470 if (!theme.isValid()) {
471 theme = QIconTheme(themeName);
472 if (!theme.isValid()) {
473 qCDebug(lcIconLoader) <<
"Theme" << themeName <<
"not found";
478 const QStringList contentDirs = theme.contentDirs();
480 QStringView iconNameFallback(iconName);
481 bool searchingGenericFallback = m_iconName.length() > iconName.length();
484 if (info.entries.empty()) {
485 const QString svgIconName = iconNameFallback +
".svg"_L1;
486 const QString pngIconName = iconNameFallback +
".png"_L1;
489 for (qsizetype i = 0; i < contentDirs.size(); ++i) {
490 QList<QIconDirInfo> subDirs = theme.keyList();
494 auto cache = theme.m_gtkCaches.at(i);
495 if (cache->isValid()) {
496 const auto result = cache->lookup(iconNameFallback);
497 if (cache->isValid()) {
498 const QList<QIconDirInfo> subDirsCopy = subDirs;
500 subDirs.reserve(result.size());
501 for (
const char *s : result) {
502 QString path = QString::fromUtf8(s);
503 auto it = std::find_if(subDirsCopy.cbegin(), subDirsCopy.cend(),
504 [&](
const QIconDirInfo &info) {
505 return info.path == path; } );
506 if (it != subDirsCopy.cend()) {
513 QString contentDir = contentDirs.at(i) + u'/';
514 for (
const auto &dirInfo : std::as_const(subDirs)) {
515 if (searchingGenericFallback &&
516 (dirInfo.context == QIconDirInfo::Applications ||
517 dirInfo.context == QIconDirInfo::MimeTypes))
520 const QString subDir = contentDir + dirInfo.path + u'/';
521 const QString pngPath = subDir + pngIconName;
522 if (QFile::exists(pngPath)) {
523 auto iconEntry = std::make_unique<PixmapEntry>();
524 iconEntry->dir = dirInfo;
525 iconEntry->filename = pngPath;
528 info.entries.insert(info.entries.begin(), std::move(iconEntry));
529 }
else if (m_supportsSvg) {
530 const QString svgPath = subDir + svgIconName;
531 if (QFile::exists(svgPath)) {
532 auto iconEntry = std::make_unique<ScalableEntry>();
533 iconEntry->dir = dirInfo;
534 iconEntry->filename = svgPath;
535 info.entries.push_back(std::move(iconEntry));
541 if (!info.entries.empty()) {
542 info.iconName = iconNameFallback.toString();
546 if (info.entries.empty()) {
547 const QStringList parents = theme.parents();
548 qCDebug(lcIconLoader) <<
"Did not find matching icons in theme;"
549 <<
"trying parent themes" << parents
550 <<
"skipping visited" << visited;
553 for (
const auto &parent : parents) {
555 const QString parentTheme = parent.trimmed();
557 if (!visited.contains(parentTheme))
558 info = findIconHelper(parentTheme, iconName, visited, QIconLoader::NoFallBack);
560 if (!info.entries.empty())
565 if (rule == QIconLoader::FallBack && info.entries.empty()) {
567 const int indexOfDash = iconNameFallback.lastIndexOf(u'-');
568 if (indexOfDash != -1) {
569 qCDebug(lcIconLoader) <<
"Did not find matching icons in all themes;"
570 <<
"trying dash fallback";
571 iconNameFallback.truncate(indexOfDash);
572 QStringList _visited;
573 info = findIconHelper(themeName, iconNameFallback.toString(), _visited, QIconLoader::FallBack);
580QThemeIconInfo QIconLoader::lookupFallbackIcon(
const QString &iconName)
const
582 qCDebug(lcIconLoader) <<
"Looking up fallback icon" << iconName;
586 const QString pngIconName = iconName +
".png"_L1;
587 const QString xpmIconName = iconName +
".xpm"_L1;
588 const QString svgIconName = iconName +
".svg"_L1;
590 const auto searchPaths = QIcon::fallbackSearchPaths();
591 for (
const QString &iconDir: searchPaths) {
592 QDir currentDir(iconDir);
593 std::unique_ptr<QIconLoaderEngineEntry> iconEntry;
594 if (currentDir.exists(pngIconName)) {
595 iconEntry = std::make_unique<PixmapEntry>();
596 iconEntry->dir.type = QIconDirInfo::Fallback;
597 iconEntry->filename = currentDir.filePath(pngIconName);
598 }
else if (currentDir.exists(xpmIconName)) {
599 iconEntry = std::make_unique<PixmapEntry>();
600 iconEntry->dir.type = QIconDirInfo::Fallback;
601 iconEntry->filename = currentDir.filePath(xpmIconName);
602 }
else if (m_supportsSvg &&
603 currentDir.exists(svgIconName)) {
604 iconEntry = std::make_unique<ScalableEntry>();
605 iconEntry->dir.type = QIconDirInfo::Fallback;
606 iconEntry->filename = currentDir.filePath(svgIconName);
609 info.entries.push_back(std::move(iconEntry));
614 if (!info.entries.empty())
615 info.iconName = iconName;
620QThemeIconInfo QIconLoader::loadIcon(
const QString &name)
const
622 qCDebug(lcIconLoader) <<
"Loading icon" << name;
625 QThemeIconInfo iconInfo;
626 QStringList visitedThemes;
627 if (!themeName().isEmpty())
628 iconInfo = findIconHelper(themeName(), name, visitedThemes, QIconLoader::FallBack);
630 if (iconInfo.entries.empty() && !fallbackThemeName().isEmpty())
631 iconInfo = findIconHelper(fallbackThemeName(), name, visitedThemes, QIconLoader::FallBack);
633 if (iconInfo.entries.empty())
634 iconInfo = lookupFallbackIcon(name);
636 qCDebug(lcIconLoader) <<
"Resulting icon entries" << iconInfo.entries;
640#ifndef QT_NO_DEBUG_STREAM
643 QDebugStateSaver saver(debug);
646 debug.noquote() << engine->key() <<
"(";
647 debug <<
static_cast<
const void *>(engine);
648 if (!engine->isNull())
649 debug.quote() <<
", " << engine->iconName();
654 debug <<
"QIconEngine(nullptr)";
660QIconEngine *QIconLoader::iconEngine(
const QString &iconName)
const
662 qCDebug(lcIconLoader) <<
"Resolving icon engine for icon" << iconName;
664 std::unique_ptr<QIconEngine> iconEngine;
667 qCDebug(lcIconLoader) <<
"Finding a plugin for theme" << themeName();
669 const int factoryIndex = qt_iconEngineFactoryLoader()->indexOf(themeName());
670 if (factoryIndex >= 0)
671 m_factory = qobject_cast<QIconEnginePlugin *>(qt_iconEngineFactoryLoader()->instance(factoryIndex));
673 if (m_factory && *m_factory)
674 iconEngine.reset(m_factory.value()->create(iconName));
676 if (hasUserTheme()) {
677 if (!iconEngine || iconEngine->isNull()) {
678 if (QFontDatabase::families().contains(themeName())) {
679 QFont maybeIconFont(themeName());
680 maybeIconFont.setStyleStrategy(QFont::NoFontMerging);
681 qCDebug(lcIconLoader) <<
"Trying font icon engine.";
682 iconEngine.reset(
new QFontIconEngine(iconName, maybeIconFont));
685 if (!iconEngine || iconEngine->isNull()) {
686 qCDebug(lcIconLoader) <<
"Trying loader engine for theme.";
687 iconEngine.reset(
new QIconLoaderEngine(iconName));
691 if (!iconEngine || iconEngine->isNull()) {
692 qCDebug(lcIconLoader) <<
"Icon is not available from theme or fallback theme.";
693 if (
auto *platformTheme = QGuiApplicationPrivate::platformTheme()) {
694 qCDebug(lcIconLoader) <<
"Trying platform engine.";
695 std::unique_ptr<QIconEngine> themeEngine(platformTheme->createIconEngine(iconName));
696 if (themeEngine && !themeEngine->isNull()) {
697 iconEngine = std::move(themeEngine);
698 qCDebug(lcIconLoader) <<
"Icon provided by platform engine.";
704 iconEngine.reset(
new QIconLoaderEngine(iconName));
706 qCDebug(lcIconLoader) <<
"Resulting engine" << iconEngine.get();
707 return iconEngine.release();
711
712
713
714
715
716
717
718
719
720
721
722
723
725QThemeIconEngine::QThemeIconEngine(
const QString& iconName)
727 , m_iconName(iconName)
731QThemeIconEngine::QThemeIconEngine(
const QThemeIconEngine &other)
733 , m_iconName(other.m_iconName)
737QString QThemeIconEngine::key()
const
742 return u"QThemeIconEngine"_s;
745QIconEngine *QThemeIconEngine::clone()
const
747 return new QThemeIconEngine(*
this);
750bool QThemeIconEngine::read(QDataStream &in) {
755bool QThemeIconEngine::write(QDataStream &out)
const
761QIconEngine *QThemeIconEngine::proxiedEngine()
const
763 const auto *iconLoader = QIconLoader::instance();
764 auto mostRecentThemeKey = iconLoader->themeKey();
765 if (mostRecentThemeKey != m_themeKey) {
766 qCDebug(lcIconLoader) <<
"Theme key" << mostRecentThemeKey <<
"is different"
767 <<
"than cached key" << m_themeKey <<
"for icon" << m_iconName;
768 m_proxiedEngine.reset(iconLoader->iconEngine(m_iconName));
769 m_themeKey = mostRecentThemeKey;
771 return m_proxiedEngine.get();
775
776
777
778
779
780
781
782
783
785QIconLoaderEngine::QIconLoaderEngine(
const QString& iconName)
786 : m_iconName(iconName)
787 , m_info(QIconLoader::instance()->loadIcon(m_iconName))
791QIconLoaderEngine::~QIconLoaderEngine() =
default;
793QIconEngine *QIconLoaderEngine::clone()
const
799bool QIconLoaderEngine::hasIcon()
const
801 return !(m_info.entries.empty());
804void QIconLoaderEngine::paint(QPainter *painter,
const QRect &rect,
805 QIcon::Mode mode, QIcon::State state)
807 const auto dpr = painter->device()->devicePixelRatio();
808 painter->drawPixmap(rect, scaledPixmap(rect.size(), mode, state, dpr));
812
813
814
817 if (dir.scale != iconscale)
821 case QIconDirInfo::Fixed:
822 return dir.size == iconsize;
823 case QIconDirInfo::Scalable:
824 return iconsize <= dir.maxSize && iconsize >= dir.minSize;
825 case QIconDirInfo::Threshold:
826 return iconsize >= dir.size - dir.threshold && iconsize <= dir.size + dir.threshold;
827 case QIconDirInfo::Fallback:
836
837
838
841 const auto scaledIconSize = iconsize * iconscale;
844 case QIconDirInfo::Fixed:
845 return dir.size * dir.scale - scaledIconSize;
846 case QIconDirInfo::Scalable: {
847 const auto minScaled = dir.minSize * dir.scale;
848 if (scaledIconSize < minScaled)
849 return minScaled - scaledIconSize;
850 const auto maxScaled = dir.maxSize * dir.scale;
851 if (scaledIconSize > maxScaled)
852 return scaledIconSize - maxScaled;
855 case QIconDirInfo::Threshold:
856 if (scaledIconSize < (dir.size - dir.threshold) * dir.scale)
857 return dir.minSize * dir.scale - scaledIconSize;
858 if (scaledIconSize > (dir.size + dir.threshold) * dir.scale)
859 return scaledIconSize - dir.maxSize * dir.scale;
861 case QIconDirInfo::Fallback:
869QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(
const QThemeIconInfo &info,
const QSize &size,
int scale)
871 if (info.entries.empty())
873 if (info.entries.size() == 1)
874 return info.entries.at(0).get();
876 int iconsize = qMin(size.width(), size.height());
881 int minimalDelta = INT_MIN;
882 QIconLoaderEngineEntry *closestMatch =
nullptr;
883 for (
const auto &entry : info.entries) {
885 if (directoryMatchesSizeAndScale(entry->dir, iconsize, scale))
889 const auto deltaValue = directorySizeDelta(entry->dir, iconsize, scale);
891 if (deltaValue > minimalDelta && minimalDelta <= 0) {
892 minimalDelta = deltaValue;
893 closestMatch = entry.get();
894 }
else if (deltaValue > 0 && deltaValue < qAbs(minimalDelta)) {
895 minimalDelta = deltaValue;
896 closestMatch = entry.get();
897 }
else if (deltaValue == 0) {
900 minimalDelta = deltaValue;
901 closestMatch = entry.get();
904 return closestMatch ? closestMatch : info.entries.at(0).get();
908
909
910
911
912
913QSize QIconLoaderEngine::actualSize(
const QSize &size, QIcon::Mode mode,
919 QIconLoaderEngineEntry *entry = entryForSize(m_info, size);
921 const QIconDirInfo &dir = entry->dir;
922 if (dir.type == QIconDirInfo::Scalable) {
924 }
else if (dir.type == QIconDirInfo::Fallback) {
925 return QIcon(entry->filename).actualSize(size, mode, state);
927 int result = qMin<
int>(dir.size * dir.scale, qMin(size.width(), size.height()));
928 return QSize(result, result);
934QPixmap PixmapEntry::pixmap(
const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
940 if (basePixmap.isNull())
941 basePixmap.load(filename);
945 const auto actualSize = QPixmapIconEngine::adjustSize(size * scale, basePixmap.size());
946 const auto calculatedDpr = QIconPrivate::pixmapDevicePixelRatio(scale, size, actualSize);
947 QString key =
"$qt_theme_"_L1
948 % HexString<quint64>(basePixmap.cacheKey())
949 % HexString<quint8>(mode)
950 % HexString<quint64>(QGuiApplication::palette().cacheKey())
951 % HexString<uint>(actualSize.width())
952 % HexString<uint>(actualSize.height())
953 % HexString<quint16>(qRound(calculatedDpr * 1000));
955 QPixmap cachedPixmap;
956 if (QPixmapCache::find(key, &cachedPixmap)) {
959 if (basePixmap.size() != actualSize)
960 cachedPixmap = basePixmap.scaled(actualSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
962 cachedPixmap = basePixmap;
963 if (QGuiApplication *guiApp = qobject_cast<QGuiApplication *>(qApp))
964 cachedPixmap =
static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(guiApp))->applyQIconStyleHelper(mode, cachedPixmap);
965 cachedPixmap.setDevicePixelRatio(calculatedDpr);
966 QPixmapCache::insert(key, cachedPixmap);
971QPixmap ScalableEntry::pixmap(
const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
973 if (svgIcon.isNull())
974 svgIcon = QIcon(filename);
976 return svgIcon.pixmap(size, scale, mode, state);
979QPixmap QIconLoaderEngine::pixmap(
const QSize &size, QIcon::Mode mode,
982 return scaledPixmap(size, mode, state, 1.0);
985QString QIconLoaderEngine::key()
const
987 return u"QIconLoaderEngine"_s;
990QString QIconLoaderEngine::iconName()
992 return m_info.iconName;
995bool QIconLoaderEngine::isNull()
997 return m_info.entries.empty();
1000QPixmap QIconLoaderEngine::scaledPixmap(
const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
1002 const int integerScale = qCeil(scale);
1003 QIconLoaderEngineEntry *entry = entryForSize(m_info, size, integerScale);
1004 return entry ? entry->pixmap(size, mode, state, scale) : QPixmap();
1007QList<QSize> QIconLoaderEngine::availableSizes(QIcon::Mode mode, QIcon::State state)
1012 const qsizetype N = qsizetype(m_info.entries.size());
1017 for (
const auto &entry : m_info.entries) {
1018 if (entry->dir.type == QIconDirInfo::Fallback) {
1019 sizes.append(QIcon(entry->filename).availableSizes());
1021 int size = entry->dir.size;
1022 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)