Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qiconloader.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#ifndef QT_NO_ICON
4#include <private/qiconloader_p.h>
5
6#include <private/qguiapplication_p.h>
7#include <private/qicon_p.h>
8
9#include <QtGui/QIconEnginePlugin>
10#include <QtGui/QPixmapCache>
11#include <qpa/qplatformtheme.h>
12#include <QtGui/QIconEngine>
13#include <QtGui/QPalette>
14#include <QtCore/qmath.h>
15#include <QtCore/QList>
16#include <QtCore/QDir>
17#include <QtCore/qloggingcategory.h>
18#if QT_CONFIG(settings)
19#include <QtCore/QSettings>
20#endif
21#include <QtGui/QPainter>
22
23#include <private/qhexstring_p.h>
24
26
27Q_LOGGING_CATEGORY(lcIconLoader, "qt.gui.icon.loader")
28
29using namespace Qt::StringLiterals;
30
31Q_GLOBAL_STATIC(QIconLoader, iconLoaderInstance)
32
33/* Theme to use in last resort, if the theme does not have the icon, neither the parents */
35{
37 const QVariant themeHint = theme->themeHint(QPlatformTheme::SystemIconFallbackThemeName);
38 if (themeHint.isValid())
39 return themeHint.toString();
40 }
41 return QString();
42}
43
45 m_themeKey(1), m_supportsSvg(false), m_initialized(false)
46{
47}
48
49static inline QString systemThemeName()
50{
51 const auto override = qgetenv("QT_QPA_SYSTEM_ICON_THEME");
52 if (!override.isEmpty())
53 return QString::fromLocal8Bit(override);
55 const QVariant themeHint = theme->themeHint(QPlatformTheme::SystemIconThemeName);
56 if (themeHint.isValid())
57 return themeHint.toString();
58 }
59 return QString();
60}
61
63{
65 const QVariant themeHint = theme->themeHint(QPlatformTheme::IconThemeSearchPaths);
66 if (themeHint.isValid())
67 return themeHint.toStringList();
68 }
69 return QStringList();
70}
71
73{
75 const QVariant themeHint = theme->themeHint(QPlatformTheme::IconFallbackSearchPaths);
76 if (themeHint.isValid())
77 return themeHint.toStringList();
78 }
79 return QStringList();
80}
81
83
85{
86 if (!m_initialized) {
88 return; // it's too early: try again later (QTBUG-74252)
89 m_initialized = true;
90 m_systemTheme = systemThemeName();
91
92 if (m_systemTheme.isEmpty())
93 m_systemTheme = systemFallbackThemeName();
94 if (qt_iconEngineFactoryLoader()->keyMap().key("svg"_L1, -1) != -1)
95 m_supportsSvg = true;
96
97 qCDebug(lcIconLoader) << "Initialized icon loader with system theme"
98 << m_systemTheme << "and SVG support" << m_supportsSvg;
99 }
100}
101
113{
114 iconLoaderInstance()->ensureInitialized();
115 return iconLoaderInstance();
116}
117
118// Queries the system theme and invalidates existing
119// icons if the theme has changed.
121{
122 const QString currentSystemTheme = m_systemTheme;
123 m_systemTheme = systemThemeName();
124 if (m_systemTheme.isEmpty())
125 m_systemTheme = systemFallbackThemeName();
126 if (m_systemTheme != currentSystemTheme)
127 qCDebug(lcIconLoader) << "Updated system theme to" << m_systemTheme;
128 // Invalidate even if the system theme name hasn't changed, as the
129 // theme itself may have changed its underlying icon lookup logic.
130 if (!hasUserTheme())
132}
133
135{
136 // Invalidating the key here will result in QThemeIconEngine
137 // recreating the actual engine the next time the icon is used.
138 // We don't need to clear the QIcon cache itself.
139 m_themeKey++;
140}
141
143{
144 return m_userTheme.isEmpty() ? m_systemTheme : m_userTheme;
145}
146
148{
149 if (m_userTheme == themeName)
150 return;
151
152 qCDebug(lcIconLoader) << "Setting user theme name to" << themeName;
153
154 m_userTheme = themeName;
156}
157
159{
160 return m_userFallbackTheme.isEmpty() ? systemFallbackThemeName() : m_userFallbackTheme;
161}
162
164{
165 qCDebug(lcIconLoader) << "Setting fallback theme name to" << themeName;
166 m_userFallbackTheme = themeName;
168}
169
171{
172 qCDebug(lcIconLoader) << "Setting theme search path to" << searchPaths;
173 m_iconDirs = searchPaths;
174 themeList.clear();
176}
177
179{
180 if (m_iconDirs.isEmpty()) {
181 m_iconDirs = systemIconSearchPaths();
182 // Always add resource directory as search path
183 m_iconDirs.append(":/icons"_L1);
184 }
185 return m_iconDirs;
186}
187
189{
190 qCDebug(lcIconLoader) << "Setting fallback search path to" << searchPaths;
191 m_fallbackDirs = searchPaths;
193}
194
196{
197 if (m_fallbackDirs.isEmpty()) {
198 m_fallbackDirs = systemFallbackSearchPaths();
199 }
200 return m_fallbackDirs;
201}
202
211{
212public:
213 explicit QIconCacheGtkReader(const QString &themeDir);
215 bool isValid() const { return m_isValid; }
216private:
217 QFile m_file;
218 const unsigned char *m_data;
219 quint64 m_size;
220 bool m_isValid;
221
222 quint16 read16(uint offset)
223 {
224 if (offset > m_size - 2 || (offset & 0x1)) {
225 m_isValid = false;
226 return 0;
227 }
228 return m_data[offset+1] | m_data[offset] << 8;
229 }
230 quint32 read32(uint offset)
231 {
232 if (offset > m_size - 4 || (offset & 0x3)) {
233 m_isValid = false;
234 return 0;
235 }
236 return m_data[offset+3] | m_data[offset+2] << 8
237 | m_data[offset+1] << 16 | m_data[offset] << 24;
238 }
239};
240
241
243 : m_isValid(false)
244{
245 QFileInfo info(dirName + "/icon-theme.cache"_L1);
246 if (!info.exists() || info.lastModified(QTimeZone::UTC) < QFileInfo(dirName).lastModified(QTimeZone::UTC))
247 return;
249 if (!m_file.open(QFile::ReadOnly))
250 return;
251 m_size = m_file.size();
252 m_data = m_file.map(0, m_size);
253 if (!m_data)
254 return;
255 if (read16(0) != 1) // VERSION_MAJOR
256 return;
257
258 m_isValid = true;
259
260 // Check that all the directories are older than the cache
261 const QDateTime lastModified = info.lastModified(QTimeZone::UTC);
262 quint32 dirListOffset = read32(8);
263 quint32 dirListLen = read32(dirListOffset);
264 for (uint i = 0; i < dirListLen; ++i) {
265 quint32 offset = read32(dirListOffset + 4 + 4 * i);
266 if (!m_isValid || offset >= m_size || lastModified < QFileInfo(dirName + u'/'
267 + QString::fromUtf8(reinterpret_cast<const char*>(m_data + offset))).lastModified(QTimeZone::UTC)) {
268 m_isValid = false;
269 return;
270 }
271 }
272}
273
274static quint32 icon_name_hash(const char *p)
275{
276 quint32 h = static_cast<signed char>(*p);
277 for (p += 1; *p != '\0'; p++)
278 h = (h << 5) - h + *p;
279 return h;
280}
281
288{
290 if (!isValid() || name.isEmpty())
291 return ret;
292
293 QByteArray nameUtf8 = name.toUtf8();
294 quint32 hash = icon_name_hash(nameUtf8);
295
296 quint32 hashOffset = read32(4);
297 quint32 hashBucketCount = read32(hashOffset);
298
299 if (!isValid() || hashBucketCount == 0) {
300 m_isValid = false;
301 return ret;
302 }
303
304 quint32 bucketIndex = hash % hashBucketCount;
305 quint32 bucketOffset = read32(hashOffset + 4 + bucketIndex * 4);
306 while (bucketOffset > 0 && bucketOffset <= m_size - 12) {
307 quint32 nameOff = read32(bucketOffset + 4);
308 if (nameOff < m_size && strcmp(reinterpret_cast<const char*>(m_data + nameOff), nameUtf8) == 0) {
309 quint32 dirListOffset = read32(8);
310 quint32 dirListLen = read32(dirListOffset);
311
312 quint32 listOffset = read32(bucketOffset+8);
313 quint32 listLen = read32(listOffset);
314
315 if (!m_isValid || listOffset + 4 + 8 * listLen > m_size) {
316 m_isValid = false;
317 return ret;
318 }
319
320 ret.reserve(listLen);
321 for (uint j = 0; j < listLen && m_isValid; ++j) {
322 quint32 dirIndex = read16(listOffset + 4 + 8 * j);
323 quint32 o = read32(dirListOffset + 4 + dirIndex*4);
324 if (!m_isValid || dirIndex >= dirListLen || o >= m_size) {
325 m_isValid = false;
326 return ret;
327 }
328 ret.append(reinterpret_cast<const char*>(m_data) + o);
329 }
330 return ret;
331 }
332 bucketOffset = read32(bucketOffset);
333 }
334 return ret;
335}
336
338 : m_valid(false)
339{
340 QFile themeIndex;
341
342 const QStringList iconDirs = QIcon::themeSearchPaths();
343 for ( int i = 0 ; i < iconDirs.size() ; ++i) {
344 QDir iconDir(iconDirs[i]);
345 QString themeDir = iconDir.path() + u'/' + themeName;
346 QFileInfo themeDirInfo(themeDir);
347
348 if (themeDirInfo.isDir()) {
349 m_contentDirs << themeDir;
350 m_gtkCaches << QSharedPointer<QIconCacheGtkReader>::create(themeDir);
351 }
352
353 if (!m_valid) {
354 themeIndex.setFileName(themeDir + "/index.theme"_L1);
355 if (themeIndex.exists())
356 m_valid = true;
357 }
358 }
359#if QT_CONFIG(settings)
360 if (themeIndex.exists()) {
361 const QSettings indexReader(themeIndex.fileName(), QSettings::IniFormat);
362 const QStringList keys = indexReader.allKeys();
363 for (const QString &key : keys) {
364 if (key.endsWith("/Size"_L1)) {
365 // Note the QSettings ini-format does not accept
366 // slashes in key names, hence we have to cheat
367 if (int size = indexReader.value(key).toInt()) {
368 QString directoryKey = key.left(key.size() - 5);
369 QIconDirInfo dirInfo(directoryKey);
370 dirInfo.size = size;
371 QString type = indexReader.value(directoryKey + "/Type"_L1).toString();
372
373 if (type == "Fixed"_L1)
374 dirInfo.type = QIconDirInfo::Fixed;
375 else if (type == "Scalable"_L1)
377 else
379
380 dirInfo.threshold = indexReader.value(directoryKey +
381 "/Threshold"_L1,
382 2).toInt();
383
384 dirInfo.minSize = indexReader.value(directoryKey + "/MinSize"_L1, size).toInt();
385
386 dirInfo.maxSize = indexReader.value(directoryKey + "/MaxSize"_L1, size).toInt();
387
388 dirInfo.scale = indexReader.value(directoryKey + "/Scale"_L1, 1).toInt();
389 m_keyList.append(dirInfo);
390 }
391 }
392 }
393
394 // Parent themes provide fallbacks for missing icons
395 m_parents = indexReader.value("Icon Theme/Inherits"_L1).toStringList();
396 m_parents.removeAll(QString());
397 }
398#endif // settings
399}
400
402{
403 // Respect explicitly declared parents
404 QStringList result = m_parents;
405
406 // Ensure a default fallback for all themes
407 const QString fallback = QIconLoader::instance()->fallbackThemeName();
408 if (!fallback.isEmpty())
409 result.append(fallback);
410
411 // Ensure that all themes fall back to hicolor as the last theme
412 result.removeAll("hicolor"_L1);
413 result.append("hicolor"_L1);
414
415 return result;
416}
417
418QDebug operator<<(QDebug debug, const std::unique_ptr<QIconLoaderEngineEntry> &entry)
419{
420 QDebugStateSaver saver(debug);
421 debug.noquote() << entry->filename;
422 return debug;
423}
424
425QThemeIconInfo QIconLoader::findIconHelper(const QString &themeName,
426 const QString &iconName,
427 QStringList &visited) const
428{
429 qCDebug(lcIconLoader) << "Finding icon" << iconName << "in theme" << themeName;
430
433
434 // Used to protect against potential recursions
435 visited << themeName;
436
437 QIconTheme &theme = themeList[themeName];
438 if (!theme.isValid()) {
440 if (!theme.isValid()) {
441 qCDebug(lcIconLoader) << "Theme" << themeName << "not found";
442 return info;
443 }
444 }
445
446 const QStringList contentDirs = theme.contentDirs();
447
448 QStringView iconNameFallback(iconName);
449
450 // Iterate through all icon's fallbacks in current theme
451 while (info.entries.empty()) {
452 const QString svgIconName = iconNameFallback + ".svg"_L1;
453 const QString pngIconName = iconNameFallback + ".png"_L1;
454
455 // Add all relevant files
456 for (int i = 0; i < contentDirs.size(); ++i) {
458
459 // Try to reduce the amount of subDirs by looking in the GTK+ cache in order to save
460 // a massive amount of file stat (especially if the icon is not there)
461 auto cache = theme.m_gtkCaches.at(i);
462 if (cache->isValid()) {
463 const auto result = cache->lookup(iconNameFallback);
464 if (cache->isValid()) {
465 const QList<QIconDirInfo> subDirsCopy = subDirs;
466 subDirs.clear();
467 subDirs.reserve(result.size());
468 for (const char *s : result) {
470 auto it = std::find_if(subDirsCopy.cbegin(), subDirsCopy.cend(),
471 [&](const QIconDirInfo &info) {
472 return info.path == path; } );
473 if (it != subDirsCopy.cend()) {
474 subDirs.append(*it);
475 }
476 }
477 }
478 }
479
480 QString contentDir = contentDirs.at(i) + u'/';
481 for (int j = 0; j < subDirs.size() ; ++j) {
482 const QIconDirInfo &dirInfo = subDirs.at(j);
483 const QString subDir = contentDir + dirInfo.path + u'/';
484 const QString pngPath = subDir + pngIconName;
485 if (QFile::exists(pngPath)) {
486 auto iconEntry = std::make_unique<PixmapEntry>();
487 iconEntry->dir = dirInfo;
488 iconEntry->filename = pngPath;
489 // Notice we ensure that pixmap entries always come before
490 // scalable to preserve search order afterwards
491 info.entries.insert(info.entries.begin(), std::move(iconEntry));
492 } else if (m_supportsSvg) {
493 const QString svgPath = subDir + svgIconName;
494 if (QFile::exists(svgPath)) {
495 auto iconEntry = std::make_unique<ScalableEntry>();
496 iconEntry->dir = dirInfo;
497 iconEntry->filename = svgPath;
498 info.entries.push_back(std::move(iconEntry));
499 }
500 }
501 }
502 }
503
504 if (!info.entries.empty()) {
505 info.iconName = iconNameFallback.toString();
506 break;
507 }
508
509 // If it's possible - find next fallback for the icon
510 const int indexOfDash = iconNameFallback.lastIndexOf(u'-');
511 if (indexOfDash == -1)
512 break;
513
514 iconNameFallback.truncate(indexOfDash);
515 }
516
517 if (info.entries.empty()) {
518 const QStringList parents = theme.parents();
519 qCDebug(lcIconLoader) << "Did not find matching icons in theme;"
520 << "trying parent themes" << parents
521 << "skipping visited" << visited;
522
523 // Search recursively through inherited themes
524 for (int i = 0 ; i < parents.size() ; ++i) {
525
526 const QString parentTheme = parents.at(i).trimmed();
527
528 if (!visited.contains(parentTheme)) // guard against recursion
529 info = findIconHelper(parentTheme, iconName, visited);
530
531 if (!info.entries.empty()) // success
532 break;
533 }
534 }
535
536 return info;
537}
538
539QThemeIconInfo QIconLoader::lookupFallbackIcon(const QString &iconName) const
540{
541 qCDebug(lcIconLoader) << "Looking up fallback icon" << iconName;
542
544
545 const QString pngIconName = iconName + ".png"_L1;
546 const QString xpmIconName = iconName + ".xpm"_L1;
547 const QString svgIconName = iconName + ".svg"_L1;
548
549 const auto searchPaths = QIcon::fallbackSearchPaths();
550 for (const QString &iconDir: searchPaths) {
551 QDir currentDir(iconDir);
552 std::unique_ptr<QIconLoaderEngineEntry> iconEntry;
553 if (currentDir.exists(pngIconName)) {
554 iconEntry = std::make_unique<PixmapEntry>();
555 iconEntry->dir.type = QIconDirInfo::Fallback;
556 iconEntry->filename = currentDir.filePath(pngIconName);
557 } else if (currentDir.exists(xpmIconName)) {
558 iconEntry = std::make_unique<PixmapEntry>();
559 iconEntry->dir.type = QIconDirInfo::Fallback;
560 iconEntry->filename = currentDir.filePath(xpmIconName);
561 } else if (m_supportsSvg &&
562 currentDir.exists(svgIconName)) {
563 iconEntry = std::make_unique<ScalableEntry>();
564 iconEntry->dir.type = QIconDirInfo::Fallback;
565 iconEntry->filename = currentDir.filePath(svgIconName);
566 }
567 if (iconEntry) {
568 info.entries.push_back(std::move(iconEntry));
569 break;
570 }
571 }
572
573 if (!info.entries.empty())
574 info.iconName = iconName;
575
576 return info;
577}
578
580{
581 qCDebug(lcIconLoader) << "Loading icon" << name;
582
583 QThemeIconInfo iconInfo;
584 QStringList visitedThemes;
585 if (!themeName().isEmpty())
586 iconInfo = findIconHelper(themeName(), name, visitedThemes);
587
588 if (iconInfo.entries.empty() && !fallbackThemeName().isEmpty())
589 iconInfo = findIconHelper(fallbackThemeName(), name, visitedThemes);
590
591 if (iconInfo.entries.empty())
592 iconInfo = lookupFallbackIcon(name);
593
594 qCDebug(lcIconLoader) << "Resulting icon entries" << iconInfo.entries;
595 return iconInfo;
596}
597
598#ifndef QT_NO_DEBUG_STREAM
600{
601 QDebugStateSaver saver(debug);
602 debug.nospace();
603 if (engine) {
604 debug.noquote() << engine->key() << "(";
605 debug << static_cast<const void *>(engine);
606 if (!engine->isNull())
607 debug.quote() << ", " << engine->iconName();
608 else
609 debug << ", null";
610 debug << ")";
611 } else {
612 debug << "QIconEngine(nullptr)";
613 }
614 return debug;
615}
616#endif
617
619{
620 qCDebug(lcIconLoader) << "Resolving icon engine for icon" << iconName;
621
622 auto *platformTheme = QGuiApplicationPrivate::platformTheme();
623 auto *iconEngine = hasUserTheme() || !platformTheme ?
624 new QIconLoaderEngine(iconName) : platformTheme->createIconEngine(iconName);
625
626 qCDebug(lcIconLoader) << "Resulting engine" << iconEngine;
627 return iconEngine;
628}
629
647 , m_iconName(iconName)
648{
649}
650
653 , m_iconName(other.m_iconName)
654{
655}
656
658{
659 // Although we proxy the underlying engine, that's an implementation
660 // detail, so from the point of view of QIcon, and in terms of
661 // serialization, we are the one and only theme icon engine.
662 return u"QThemeIconEngine"_s;
663}
664
666{
667 return new QThemeIconEngine(*this);
668}
669
671 in >> m_iconName;
672 return true;
673}
674
676{
677 out << m_iconName;
678 return true;
679}
680
682{
683 const auto *iconLoader = QIconLoader::instance();
684 auto mostRecentThemeKey = iconLoader->themeKey();
685 if (mostRecentThemeKey != m_themeKey) {
686 qCDebug(lcIconLoader) << "Theme key" << mostRecentThemeKey << "is different"
687 << "than cached key" << m_themeKey << "for icon" << m_iconName;
688 m_proxiedEngine.reset(iconLoader->iconEngine(m_iconName));
689 m_themeKey = mostRecentThemeKey;
690 }
691 return m_proxiedEngine.get();
692}
693
706 : m_iconName(iconName)
707 , m_info(QIconLoader::instance()->loadIcon(m_iconName))
708{
709}
710
712
714{
715 Q_UNREACHABLE();
716 return nullptr; // Cannot be cloned
717}
718
719bool QIconLoaderEngine::hasIcon() const
720{
721 return !(m_info.entries.empty());
722}
723
726{
727 QSize pixmapSize = rect.size() * painter->device()->devicePixelRatio();
728 painter->drawPixmap(rect, pixmap(pixmapSize, mode, state));
729}
730
731/*
732 * This algorithm is defined by the freedesktop spec:
733 * http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
734 */
735static bool directoryMatchesSize(const QIconDirInfo &dir, int iconsize, int iconscale)
736{
737 if (dir.scale != iconscale)
738 return false;
739
740 if (dir.type == QIconDirInfo::Fixed) {
741 return dir.size == iconsize;
742
743 } else if (dir.type == QIconDirInfo::Scalable) {
744 return iconsize <= dir.maxSize &&
745 iconsize >= dir.minSize;
746
747 } else if (dir.type == QIconDirInfo::Threshold) {
748 return iconsize >= dir.size - dir.threshold &&
749 iconsize <= dir.size + dir.threshold;
750 } else if (dir.type == QIconDirInfo::Fallback) {
751 return true;
752 }
753
754 Q_ASSERT(1); // Not a valid value
755 return false;
756}
757
758/*
759 * This algorithm is defined by the freedesktop spec:
760 * http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
761 */
762static int directorySizeDistance(const QIconDirInfo &dir, int iconsize, int iconscale)
763{
764 const int scaledIconSize = iconsize * iconscale;
765 if (dir.type == QIconDirInfo::Fixed) {
766 return qAbs(dir.size * dir.scale - scaledIconSize);
767
768 } else if (dir.type == QIconDirInfo::Scalable) {
769 if (scaledIconSize < dir.minSize * dir.scale)
770 return dir.minSize * dir.scale - scaledIconSize;
771 else if (scaledIconSize > dir.maxSize * dir.scale)
772 return scaledIconSize - dir.maxSize * dir.scale;
773 else
774 return 0;
775
776 } else if (dir.type == QIconDirInfo::Threshold) {
777 if (scaledIconSize < (dir.size - dir.threshold) * dir.scale)
778 return dir.minSize * dir.scale - scaledIconSize;
779 else if (scaledIconSize > (dir.size + dir.threshold) * dir.scale)
780 return scaledIconSize - dir.maxSize * dir.scale;
781 else return 0;
782 } else if (dir.type == QIconDirInfo::Fallback) {
783 return 0;
784 }
785
786 Q_ASSERT(1); // Not a valid value
787 return INT_MAX;
788}
789
791{
792 int iconsize = qMin(size.width(), size.height());
793
794 // Note that m_info.entries are sorted so that png-files
795 // come first
796
797 // Search for exact matches first
798 for (const auto &entry : info.entries) {
799 if (directoryMatchesSize(entry->dir, iconsize, scale)) {
800 return entry.get();
801 }
802 }
803
804 // Find the minimum distance icon
805 int minimalSize = INT_MAX;
807 for (const auto &entry : info.entries) {
808 int distance = directorySizeDistance(entry->dir, iconsize, scale);
809 if (distance < minimalSize) {
810 minimalSize = distance;
811 closestMatch = entry.get();
812 }
813 }
814 return closestMatch;
815}
816
817/*
818 * Returns the actual icon size. For scalable svg's this is equivalent
819 * to the requested size. Otherwise the closest match is returned but
820 * we can never return a bigger size than the requested size.
821 *
822 */
825{
826 Q_UNUSED(mode);
828
830 if (entry) {
831 const QIconDirInfo &dir = entry->dir;
832 if (dir.type == QIconDirInfo::Scalable) {
833 return size;
834 } else if (dir.type == QIconDirInfo::Fallback) {
835 return QIcon(entry->filename).actualSize(size, mode, state);
836 } else {
837 int result = qMin<int>(dir.size, qMin(size.width(), size.height()));
838 return QSize(result, result);
839 }
840 }
841 return QSize(0, 0);
842}
843
845{
847
848 // Ensure that basePixmap is lazily initialized before generating the
849 // key, otherwise the cache key is not unique
850 if (basePixmap.isNull())
852
853 QSize actualSize = basePixmap.size();
854 // If the size of the best match we have (basePixmap) is larger than the
855 // requested size, we downscale it to match.
856 if (!actualSize.isNull() && (actualSize.width() > size.width() || actualSize.height() > size.height()))
857 actualSize.scale(size, Qt::KeepAspectRatio);
858
859 QString key = "$qt_theme_"_L1
863 % HexString<int>(actualSize.width())
864 % HexString<int>(actualSize.height());
865
866 QPixmap cachedPixmap;
867 if (QPixmapCache::find(key, &cachedPixmap)) {
868 return cachedPixmap;
869 } else {
870 if (basePixmap.size() != actualSize)
872 else
873 cachedPixmap = basePixmap;
874 if (QGuiApplication *guiApp = qobject_cast<QGuiApplication *>(qApp))
875 cachedPixmap = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(guiApp))->applyQIconStyleHelper(mode, cachedPixmap);
876 QPixmapCache::insert(key, cachedPixmap);
877 }
878 return cachedPixmap;
879}
880
882{
883 if (svgIcon.isNull())
885
886 // Bypass QIcon API, as that will scale by device pixel ratio of the
887 // highest DPR screen since we're not passing on any QWindow.
888 if (QIconEngine *engine = svgIcon.data_ptr() ? svgIcon.data_ptr()->engine : nullptr)
889 return engine->pixmap(size, mode, state);
890
891 return QPixmap();
892}
893
896{
898 if (entry)
899 return entry->pixmap(size, mode, state);
900
901 return QPixmap();
902}
903
905{
906 return u"QIconLoaderEngine"_s;
907}
908
910{
911 return m_info.iconName;
912}
913
915{
916 return m_info.entries.empty();
917}
918
920{
921 const int integerScale = qCeil(scale);
922 QIconLoaderEngineEntry *entry = entryForSize(m_info, size / integerScale, integerScale);
923 return entry ? entry->pixmap(size, mode, state) : QPixmap();
924}
925
927{
928 Q_UNUSED(mode);
930
931 const qsizetype N = qsizetype(m_info.entries.size());
933 sizes.reserve(N);
934
935 // Gets all sizes from the DirectoryInfo entries
936 for (const auto &entry : m_info.entries) {
937 if (entry->dir.type == QIconDirInfo::Fallback) {
938 sizes.append(QIcon(entry->filename).availableSizes());
939 } else {
940 int size = entry->dir.size;
941 sizes.append(QSize(size, size));
942 }
943 }
944 return sizes;
945}
946
948
949#endif //QT_NO_ICON
NSData * m_data
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore\reentrant
Definition qdatastream.h:30
\inmodule QtCore\reentrant
Definition qdatetime.h:257
\inmodule QtCore
\inmodule QtCore
\inmodule QtCore
Definition qdir.h:19
QString path() const
Returns the path.
Definition qdir.cpp:653
uchar * map(qint64 offset, qint64 size, MemoryMapFlags flags=NoOptions)
Maps size bytes of the file into memory starting at offset.
\inmodule QtCore \reentrant
Definition qfileinfo.h:22
QDateTime lastModified() const
Returns the date and time when the file was last modified.
Definition qfileinfo.h:156
QString absoluteFilePath() const
Returns an absolute path including the file name.
bool isDir() const
Returns true if this object points to a directory or to a symbolic link to a directory.
bool exists() const
Returns true if the file exists; otherwise returns false.
\inmodule QtCore
Definition qfile.h:93
bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition qfile.cpp:881
void setFileName(const QString &name)
Sets the name of the file.
Definition qfile.cpp:302
QString fileName() const override
Returns the name set by setFileName() or to the QFile constructors.
Definition qfile.cpp:277
bool exists() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qfile.cpp:351
qint64 size() const override
\reimp
Definition qfile.cpp:1156
static QPlatformTheme * platformTheme()
\macro qGuiApp
static QPalette palette()
Returns the current application palette.
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
Definition qhash.h:949
QIconCacheGtkReader(const QString &themeDir)
QList< const char * > lookup(QStringView)
The QIconEngine class provides an abstract base class for QIcon renderers.
Definition qiconengine.h:15
An icon engine based on icon entries collected by QIconLoader.
QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override
Returns the actual size of the icon the engine provides for the requested size, mode and state.
static Q_GUI_EXPORT QIconLoaderEngineEntry * entryForSize(const QThemeIconInfo &info, const QSize &size, int scale=1)
bool isNull() override
QString key() const override
\variable QIconEngine::ScaledPixmapArgument::size
QPixmap scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale) override
QIconLoaderEngine(const QString &iconName=QString())
QString iconName() override
QList< QSize > availableSizes(QIcon::Mode mode, QIcon::State state) override
void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override
Uses the given painter to paint the icon with the required mode and state into the rectangle rect.
QIconEngine * clone() const override
Reimplement this method to return a clone of this icon engine.
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override
Returns the icon as a pixmap with the required size, mode, and state.
QThemeIconInfo loadIcon(const QString &iconName) const
void setFallbackThemeName(const QString &themeName)
bool hasUserTheme() const
QStringList fallbackSearchPaths() const
void ensureInitialized()
void setFallbackSearchPaths(const QStringList &searchPaths)
void updateSystemTheme()
QIconDirInfo dirInfo(int dirindex)
void setThemeSearchPath(const QStringList &searchPaths)
static QIconLoader * instance()
QString fallbackThemeName() const
QStringList themeSearchPaths() const
QIconTheme theme()
QIconEngine * iconEngine(const QString &iconName) const
QString themeName() const
void setThemeName(const QString &themeName)
void invalidateKey()
QIconEngine * engine
Definition qicon_p.h:39
QStringList contentDirs()
QStringList parents() const
QList< QIconDirInfo > keyList()
QList< QSharedPointer< QIconCacheGtkReader > > m_gtkCaches
The QIcon class provides scalable icons in different modes and states.
Definition qicon.h:20
static QStringList fallbackSearchPaths()
Definition qicon.cpp:1168
bool isNull() const
Returns true if the icon is empty; otherwise returns false.
Definition qicon.cpp:973
Mode
This enum type describes the mode for which a pixmap is intended to be used.
Definition qicon.h:22
QList< QSize > availableSizes(Mode mode=Normal, State state=Off) const
Definition qicon.cpp:1098
State
This enum describes the state for which a pixmap is intended to be used.
Definition qicon.h:23
DataPtr & data_ptr()
Definition qicon.h:105
static QStringList themeSearchPaths()
Definition qicon.cpp:1149
QSize actualSize(const QSize &size, Mode mode=Normal, State state=Off) const
Returns the actual size of the icon for the requested size, mode, and state.
Definition qicon.cpp:880
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
void reserve(qsizetype size)
Definition qlist.h:746
const_iterator cend() const noexcept
Definition qlist.h:614
void append(parameter_type t)
Definition qlist.h:441
const_iterator cbegin() const noexcept
Definition qlist.h:613
void clear()
Definition qlist.h:417
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:153
qreal devicePixelRatio() const
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
QPaintDevice * device() const
Returns the paint device on which this painter is currently painting, or \nullptr if the painter is n...
void drawPixmap(const QRectF &targetRect, const QPixmap &pixmap, const QRectF &sourceRect)
Draws the rectangular portion source of the given pixmap into the given target in the paint device.
static bool find(const QString &key, QPixmap *pixmap)
Looks for a cached pixmap associated with the given key in the cache.
static bool insert(const QString &key, const QPixmap &pixmap)
Inserts a copy of the pixmap pixmap associated with the key into the cache.
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
QPixmap scaled(int w, int h, Qt::AspectRatioMode aspectMode=Qt::IgnoreAspectRatio, Qt::TransformationMode mode=Qt::FastTransformation) const
Definition qpixmap.h:78
QSize size() const
Returns the size of the pixmap.
Definition qpixmap.cpp:497
bool load(const QString &fileName, const char *format=nullptr, Qt::ImageConversionFlags flags=Qt::AutoColor)
Loads a pixmap from the file with the given fileName.
Definition qpixmap.cpp:708
bool isNull() const
Returns true if this is a null pixmap; otherwise returns false.
Definition qpixmap.cpp:460
qint64 cacheKey() const
Returns a number that identifies this QPixmap.
Definition qpixmap.cpp:888
The QPlatformTheme class allows customizing the UI based on themes.
\inmodule QtCore\reentrant
Definition qrect.h:30
\inmodule QtCore
Definition qsettings.h:30
QVariant value(QAnyStringView key, const QVariant &defaultValue) const
Returns the value for setting key.
QStringList allKeys() const
Returns a list of all keys, including subkeys, that can be read using the QSettings object.
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:132
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:129
void scale(int w, int h, Qt::AspectRatioMode mode) noexcept
Scales the size to a rectangle with the given width and height, according to the specified mode:
Definition qsize.h:144
constexpr bool isNull() const noexcept
Returns true if both the width and height is 0; otherwise returns false.
Definition qsize.h:120
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:76
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5788
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5857
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
QString & append(QChar c)
Definition qstring.cpp:3227
QString left(qsizetype n) const
Returns a substring that contains the n leftmost characters of the string.
Definition qstring.cpp:5161
A named-based icon engine for providing theme icons.
QThemeIconEngine(const QString &iconName=QString())
QString key() const override
\variable QIconEngine::ScaledPixmapArgument::size
bool write(QDataStream &out) const override
Writes the contents of this engine to the QDataStream out.
bool read(QDataStream &in) override
Reads icon engine contents from the QDataStream in.
QIconEngine * clone() const override
Reimplement this method to return a clone of this icon engine.
QIconEngine * proxiedEngine() const override
\inmodule QtCore
Definition qvariant.h:64
bool isValid() const
Returns true if the storage type of this variant is not QMetaType::UnknownType; otherwise returns fal...
Definition qvariant.h:707
int toInt(bool *ok=nullptr) const
Returns the variant as an int if the variant has userType() \l QMetaType::Int, \l QMetaType::Bool,...
QString toString() const
Returns the variant as a QString if the variant has a userType() including, but not limited to:
QStringList toStringList() const
Returns the variant as a QStringList if the variant has userType() \l QMetaType::QStringList,...
QHash< int, QWidget * > hash
[35multi]
QCache< int, Employee > cache
[0]
QSet< QString >::iterator it
rect
[4]
else opt state
[0]
Combined button and popup list for selecting options.
@ SmoothTransformation
@ KeepAspectRatio
@ IgnoreAspectRatio
#define qApp
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
static QStringList systemIconSearchPaths()
QFactoryLoader * qt_iconEngineFactoryLoader()
QDebug operator<<(QDebug debug, const std::unique_ptr< QIconLoaderEngineEntry > &entry)
static QStringList systemFallbackSearchPaths()
static int directorySizeDistance(const QIconDirInfo &dir, int iconsize, int iconscale)
static QString systemThemeName()
static QString systemFallbackThemeName()
static bool directoryMatchesSize(const QIconDirInfo &dir, int iconsize, int iconscale)
static quint32 icon_name_hash(const char *p)
static int closestMatch(QRgb pixel, const QList< QRgb > &clut)
Definition qimage.cpp:2245
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
return ret
int qCeil(T v)
Definition qmath.h:36
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
static QString themeName()
GLenum mode
GLuint64 key
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLsizei GLsizei GLfloat distance
GLenum type
GLenum GLuint GLintptr offset
GLuint name
GLfloat GLfloat GLfloat GLfloat h
GLuint entry
GLuint GLsizei const GLuint const GLintptr const GLsizeiptr * sizes
GLuint in
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
GLenum GLenum GLenum GLenum GLenum scale
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:45
unsigned short quint16
Definition qtypes.h:43
unsigned long long quint64
Definition qtypes.h:56
ptrdiff_t qsizetype
Definition qtypes.h:70
unsigned int uint
Definition qtypes.h:29
double qreal
Definition qtypes.h:92
static const struct @437 keyMap[]
QFileInfo info(fileName)
[8]
QStringList keys
QTextStream out(stdout)
[7]
QSharedPointer< T > other(t)
[5]
QString dir
[11]
widget render & pixmap
QPainter painter(this)
[7]
QJSEngine engine
[0]
QPixmap basePixmap
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override
QThemeIconEntries entries
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override