Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qicon.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// Copyright (C) 2015 Olivier Goffart <ogoffart@woboq.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
6#include "qicon.h"
7#include "qicon_p.h"
8#include "qiconengine.h"
10#include "qimagereader.h"
11#include "private/qfactoryloader_p.h"
12#include "private/qiconloader_p.h"
13#include "qpainter.h"
14#include "qfileinfo.h"
15#if QT_CONFIG(mimetype)
16#include <qmimedatabase.h>
17#include <qmimetype.h>
18#endif
19#include "qpixmapcache.h"
20#include "qvariant.h"
21#include "qcache.h"
22#include "qdebug.h"
23#include "qdir.h"
24#include "qpalette.h"
25#include "qmath.h"
26
27#include "private/qhexstring_p.h"
28#include "private/qguiapplication_p.h"
29#include "private/qoffsetstringarray_p.h"
30#include "qpa/qplatformtheme.h"
31
32#ifndef QT_NO_ICON
34
35using namespace Qt::StringLiterals;
36// Convenience class providing a bool read() function.
37namespace {
38class ImageReader
39{
40public:
41 ImageReader(const QString &fileName, QSize size)
42 : m_reader(fileName)
43 , m_atEnd(false)
44 {
45 if (m_reader.supportsOption(QImageIOHandler::ScaledSize)) {
46 // The scaled size is exact, so fit it to the aspect ratio of the image.
47 const QSize imageSize = m_reader.size();
48 m_reader.setScaledSize(!imageSize.isEmpty() && !size.isEmpty()
49 ? imageSize.scaled(size, Qt::KeepAspectRatio)
50 : size);
51 }
52 }
53
54 QByteArray format() const { return m_reader.format(); }
55 bool supportsReadSize() const { return m_reader.supportsOption(QImageIOHandler::Size); }
56 QSize size() const { return m_reader.size(); }
57 bool jumpToNextImage() { return m_reader.jumpToNextImage(); }
58 void jumpToImage(int index) { m_reader.jumpToImage(index); }
59
60 bool read(QImage *image)
61 {
62 if (m_atEnd)
63 return false;
64 *image = m_reader.read();
65 if (!image->size().isValid()) {
66 m_atEnd = true;
67 return false;
68 }
69 m_atEnd = !m_reader.jumpToNextImage();
70 return true;
71 }
72
73private:
74 QImageReader m_reader;
75 bool m_atEnd;
76};
77} // namespace
78
79/*!
80 \enum QIcon::Mode
81
82 This enum type describes the mode for which a pixmap is intended
83 to be used. The currently defined modes are:
84
85 \value Normal
86 Display the pixmap when the user is
87 not interacting with the icon, but the
88 functionality represented by the icon is available.
89 \value Disabled
90 Display the pixmap when the
91 functionality represented by the icon is not available.
92 \value Active
93 Display the pixmap when the
94 functionality represented by the icon is available and
95 the user is interacting with the icon, for example, moving the
96 mouse over it or clicking it.
97 \value Selected
98 Display the pixmap when the item represented by the icon is
99 selected.
100*/
101
102/*!
103 \enum QIcon::State
104
105 This enum describes the state for which a pixmap is intended to be
106 used. The \e state can be:
107
108 \value On Display the pixmap when the widget is in an "on" state
109 \value Off Display the pixmap when the widget is in an "off" state
110*/
111
113{
114 Q_CONSTINIT static QBasicAtomicInt serial = Q_BASIC_ATOMIC_INITIALIZER(0);
115 return 1 + serial.fetchAndAddRelaxed(1);
116}
117
118static void qt_cleanup_icon_cache();
119namespace {
120 struct IconCache : public QCache<QString, QIcon>
121 {
122 IconCache()
123 {
124 // ### note: won't readd if QApplication is re-created!
125 qAddPostRoutine(qt_cleanup_icon_cache);
126 }
127 };
128}
129
130Q_GLOBAL_STATIC(IconCache, qtIconCache)
131
133{
134 qtIconCache()->clear();
135}
136
138 : engine(e), ref(1),
140 detach_no(0),
141 is_mask(false)
142{
143}
144
149
150/*! \internal
151 Computes the displayDevicePixelRatio for a pixmap.
152
153 If displayDevicePixelRatio is 1.0 the returned value is 1.0, always.
154
155 For a displayDevicePixelRatio of 2.0 the returned value will be between
156 1.0 and 2.0, depending on requestedSize and actualsize:
157 * If actualsize < requestedSize : 1.0 (not enough pixels for a normal-dpi pixmap)
158 * If actualsize == requestedSize * 2.0 : 2.0 (enough pixels for a high-dpi pixmap)
159 * else : a scaled value between 1.0 and 2.0. (pixel count is between normal-dpi and high-dpi)
160*/
161qreal QIconPrivate::pixmapDevicePixelRatio(qreal displayDevicePixelRatio, const QSize &requestedSize, const QSize &actualSize)
162{
163 QSize targetSize = requestedSize * displayDevicePixelRatio;
164 if ((actualSize.width() == targetSize.width() && actualSize.height() <= targetSize.height()) ||
165 (actualSize.width() <= targetSize.width() && actualSize.height() == targetSize.height())) {
166 // Correctly scaled for dpr, just having different aspect ratio
167 return displayDevicePixelRatio;
168 }
169 qreal scale = 0.5 * (qreal(actualSize.width()) / qreal(targetSize.width()) +
170 qreal(actualSize.height()) / qreal(targetSize.height()));
171 qreal dpr = qMax(qreal(1.0), displayDevicePixelRatio * scale);
172 return qRound(dpr * 100) / 100.0;
173}
174
175QPixmapIconEngine::QPixmapIconEngine()
176{
177}
178
179QPixmapIconEngine::QPixmapIconEngine(const QPixmapIconEngine &other)
180 : QIconEngine(other), pixmaps(other.pixmaps)
181{
182}
183
184QPixmapIconEngine::~QPixmapIconEngine()
185{
186}
187
188void QPixmapIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
189{
190 auto paintDevice = painter->device();
191 qreal dpr = paintDevice ? paintDevice->devicePixelRatio() : qApp->devicePixelRatio();
192 QPixmap px = scaledPixmap(rect.size(), mode, state, dpr);
193 painter->drawPixmap(rect, px);
194}
195
196static inline qint64 area(const QSize &s) { return qint64(s.width()) * s.height(); }
197
198// Returns the smallest of the two that is still larger than or equal to size.
199// Pixmaps at the correct scale are preferred, pixmaps at lower scale are
200// used as fallbacks. We assume that the pixmap set is complete, in the sense
201// that no 2x pixmap is going to be a better match than a 3x pixmap for the the
202// target scale of 3 (It's OK if 3x pixmaps are missing - we'll fall back to
203// the 2x pixmaps then.)
205{
206 const auto scaleA = pa->pixmap.devicePixelRatio();
207 const auto scaleB = pb->pixmap.devicePixelRatio();
208 // scale: we can only differentiate on scale if the scale differs
209 if (scaleA != scaleB) {
210
211 // Score the pixmaps: 0 is an exact scale match, positive
212 // scores have more detail than requested, negative scores
213 // have less detail than requested.
214 qreal ascore = scaleA - scale;
215 qreal bscore = scaleB - scale;
216
217 // always prefer positive scores to prevent upscaling
218 if ((ascore < 0) != (bscore < 0))
219 return bscore < 0 ? pa : pb;
220 // Take the one closest to 0
221 return (qAbs(ascore) < qAbs(bscore)) ? pa : pb;
222 }
223
224 qint64 s = area(size * scale);
225 if (pa->size == QSize() && pa->pixmap.isNull()) {
226 pa->pixmap = QPixmap(pa->fileName);
227 pa->size = pa->pixmap.size();
228 }
229 qint64 a = area(pa->size);
230 if (pb->size == QSize() && pb->pixmap.isNull()) {
231 pb->pixmap = QPixmap(pb->fileName);
232 pb->size = pb->pixmap.size();
233 }
234 qint64 b = area(pb->size);
235 qint64 res = a;
236 if (qMin(a,b) >= s)
237 res = qMin(a,b);
238 else
239 res = qMax(a,b);
240 if (res == a)
241 return pa;
242 return pb;
243}
244
245QPixmapIconEngineEntry *QPixmapIconEngine::tryMatch(const QSize &size, qreal scale, QIcon::Mode mode, QIcon::State state)
246{
247 QPixmapIconEngineEntry *pe = nullptr;
248 for (auto &entry : pixmaps) {
249 if (entry.mode == mode && entry.state == state) {
250 if (pe)
251 pe = bestSizeScaleMatch(size, scale, &entry, pe);
252 else
253 pe = &entry;
254 }
255 }
256 return pe;
257}
258
259
260QPixmapIconEngineEntry *QPixmapIconEngine::bestMatch(const QSize &size, qreal scale, QIcon::Mode mode, QIcon::State state)
261{
262 QPixmapIconEngineEntry *pe = tryMatch(size, scale, mode, state);
263 while (!pe){
264 QIcon::State oppositeState = (state == QIcon::On) ? QIcon::Off : QIcon::On;
265 if (mode == QIcon::Disabled || mode == QIcon::Selected) {
266 QIcon::Mode oppositeMode = (mode == QIcon::Disabled) ? QIcon::Selected : QIcon::Disabled;
267 if ((pe = tryMatch(size, scale, QIcon::Normal, state)))
268 break;
269 if ((pe = tryMatch(size, scale, QIcon::Active, state)))
270 break;
271 if ((pe = tryMatch(size, scale, mode, oppositeState)))
272 break;
273 if ((pe = tryMatch(size, scale, QIcon::Normal, oppositeState)))
274 break;
275 if ((pe = tryMatch(size, scale, QIcon::Active, oppositeState)))
276 break;
277 if ((pe = tryMatch(size, scale, oppositeMode, state)))
278 break;
279 if ((pe = tryMatch(size, scale, oppositeMode, oppositeState)))
280 break;
281 } else {
282 QIcon::Mode oppositeMode = (mode == QIcon::Normal) ? QIcon::Active : QIcon::Normal;
283 if ((pe = tryMatch(size, scale, oppositeMode, state)))
284 break;
285 if ((pe = tryMatch(size, scale, mode, oppositeState)))
286 break;
287 if ((pe = tryMatch(size, scale, oppositeMode, oppositeState)))
288 break;
289 if ((pe = tryMatch(size, scale, QIcon::Disabled, state)))
290 break;
291 if ((pe = tryMatch(size, scale, QIcon::Selected, state)))
292 break;
293 if ((pe = tryMatch(size, scale, QIcon::Disabled, oppositeState)))
294 break;
295 if ((pe = tryMatch(size, scale, QIcon::Selected, oppositeState)))
296 break;
297 }
298
299 if (!pe)
300 return pe;
301 }
302
303 if (pe->pixmap.isNull()) {
304 // delay-load the image
305 QImage image, prevImage;
306 const QSize realSize = size * scale;
307 ImageReader imageReader(pe->fileName, realSize);
308 bool fittingImageFound = false;
309 if (imageReader.supportsReadSize()) {
310 // find the image with the best size without loading the entire image
311 do {
312 fittingImageFound = imageReader.size() == realSize;
313 } while (!fittingImageFound && imageReader.jumpToNextImage());
314 }
315 if (!fittingImageFound) {
316 imageReader.jumpToImage(0);
317 while (imageReader.read(&image) && image.size() != realSize)
318 prevImage = image;
319 if (image.isNull())
320 image = prevImage;
321 } else {
322 imageReader.read(&image);
323 }
324 if (!image.isNull()) {
325 if (pe->pixmap.convertFromImage(image))
326 pe->size = pe->pixmap.size();
327 }
328 if (!pe->size.isValid()) {
329 removePixmapEntry(pe);
330 pe = nullptr;
331 }
332 }
333
334 return pe;
335}
336
337QPixmap QPixmapIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
338{
339 return scaledPixmap(size, mode, state, 1.0);
340}
341
342QPixmap QPixmapIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
343{
344 QPixmapIconEngineEntry *pe = bestMatch(size, scale, mode, state);
345 if (!pe)
346 return {};
347
348 if (pe->pixmap.isNull()) {
349 removePixmapEntry(pe);
350 if (pixmaps.empty())
351 return {};
352 return scaledPixmap(size, mode, state, scale);
353 }
354
355 const auto actualSize = adjustSize(size * scale, pe->pixmap.size());
356 const auto calculatedDpr = QIconPrivate::pixmapDevicePixelRatio(scale, size, actualSize);
357 const QString key = u"qt_"
358 % HexString<quint64>(pe->pixmap.cacheKey())
359 % HexString<quint8>(pe->mode) // might differ from actual mode when generated below
360 % HexString<quint64>(QGuiApplication::palette().cacheKey())
361 % HexString<uint>(actualSize.width())
362 % HexString<uint>(actualSize.height())
363 % HexString<quint16>(qRound(calculatedDpr * 1000))
364 % HexString<quint8>(mode);
365 QPixmap pm;
366 if (QPixmapCache::find(key, &pm))
367 return pm; // horray
368
369 pm = pe->pixmap;
370 if (pm.size() != actualSize)
371 pm = pm.scaled(actualSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
372 // let the style generate an appropriate pixmap for the given mode
373 if (pe->mode != mode && mode != QIcon::Normal) {
374 if (const QGuiApplication *guiApp = qobject_cast<const QGuiApplication *>(qApp)) {
375 const auto guiAppPrivate =
376 static_cast<const QGuiApplicationPrivate *>(QObjectPrivate::get(guiApp));
377 const QPixmap generated = guiAppPrivate->applyQIconStyleHelper(mode, pm);
378 if (!generated.isNull())
379 pm = generated;
380 }
381 }
382 pm.setDevicePixelRatio(calculatedDpr);
383 QPixmapCache::insert(key, pm);
384 return pm;
385}
386
387QSize QPixmapIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state)
388{
389 QSize actualSize;
390
391 // The returned actual size is the size in device independent pixels,
392 // so we limit the search to scale 1 and assume that e.g. @2x versions
393 // does not proviode extra actual sizes not also provided by the 1x versions.
394 qreal scale = 1;
395
396 if (QPixmapIconEngineEntry *pe = bestMatch(size, scale, mode, state))
397 actualSize = pe->size;
398
399 return adjustSize(size, actualSize);
400}
401
402QList<QSize> QPixmapIconEngine::availableSizes(QIcon::Mode mode, QIcon::State state)
403{
404 QList<QSize> sizes;
405 for (QPixmapIconEngineEntry &pe : pixmaps) {
406 if (pe.mode != mode || pe.state != state)
407 continue;
408 if (pe.size.isEmpty() && pe.pixmap.isNull()) {
409 pe.pixmap = QPixmap(pe.fileName);
410 pe.size = pe.pixmap.size();
411 }
412 if (!pe.size.isEmpty() && !sizes.contains(pe.size))
413 sizes.push_back(pe.size);
414 }
415 return sizes;
416}
417
418void QPixmapIconEngine::addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state)
419{
420 if (!pixmap.isNull()) {
421 QPixmapIconEngineEntry *pe = tryMatch(pixmap.size() / pixmap.devicePixelRatio(),
422 pixmap.devicePixelRatio(), mode, state);
423 if (pe && pe->size == pixmap.size() && pe->pixmap.devicePixelRatio() == pixmap.devicePixelRatio()) {
424 pe->pixmap = pixmap;
425 pe->fileName.clear();
426 } else {
427 pixmaps.emplace_back(pixmap, mode, state);
428 }
429 }
430}
431
432// Read out original image depth as set by ICOReader
433static inline int origIcoDepth(const QImage &image)
434{
435 const QString s = image.text(QStringLiteral("_q_icoOrigDepth"));
436 return s.isEmpty() ? 32 : s.toInt();
437}
438
439static inline int findBySize(const QList<QImage> &images, const QSize &size)
440{
441 for (qsizetype i = 0; i < images.size(); ++i) {
442 if (images.at(i).size() == size)
443 return i;
444 }
445 return -1;
446}
447
448void QPixmapIconEngine::addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state)
449{
450 if (fileName.isEmpty())
451 return;
452 const QString abs = fileName.startsWith(u':') ? fileName : QFileInfo(fileName).absoluteFilePath();
453 const bool ignoreSize = !size.isValid();
454 ImageReader imageReader(abs, size);
455 const QByteArray format = imageReader.format();
456 if (format.isEmpty()) // Device failed to open or unsupported format.
457 return;
458 QImage image;
459 if (format != "ico") {
460 if (ignoreSize) { // No size specified: Add all images.
461 if (imageReader.supportsReadSize()) {
462 do {
463 pixmaps.emplace_back(abs, imageReader.size(), mode, state);
464 } while (imageReader.jumpToNextImage());
465 } else {
466 while (imageReader.read(&image))
467 pixmaps.emplace_back(abs, image, mode, state);
468 }
469 } else {
470 pixmaps.emplace_back(abs, size, mode, state);
471 }
472 return;
473 }
474 // Special case for reading Windows ".ico" files. Historically (QTBUG-39287),
475 // these files may contain low-resolution images. As this information is lost,
476 // ICOReader sets the original format as an image text key value. Read all matching
477 // images into a list trying to find the highest quality per size.
478 QList<QImage> icoImages;
479 while (imageReader.read(&image)) {
480 if (ignoreSize || image.size() == size) {
481 const int position = findBySize(icoImages, image.size());
482 if (position >= 0) { // Higher quality available? -> replace.
483 if (origIcoDepth(image) > origIcoDepth(icoImages.at(position)))
484 icoImages[position] = image;
485 } else {
486 icoImages.append(image);
487 }
488 }
489 }
490 for (const QImage &i : std::as_const(icoImages))
491 pixmaps.emplace_back(abs, i, mode, state);
492 if (icoImages.empty() && !ignoreSize) // Add placeholder with the filename and empty pixmap for the size.
493 pixmaps.emplace_back(abs, size, mode, state);
494}
495
496bool QPixmapIconEngine::isNull()
497{
498 return pixmaps.empty();
499}
500
501QString QPixmapIconEngine::key() const
502{
503 return "QPixmapIconEngine"_L1;
504}
505
506QIconEngine *QPixmapIconEngine::clone() const
507{
508 return new QPixmapIconEngine(*this);
509}
510
511bool QPixmapIconEngine::read(QDataStream &in)
512{
513 int num_entries;
514 QPixmap pm;
515 QString fileName;
516 QSize sz;
517 uint mode;
518 uint state;
519
520 in >> num_entries;
521 for (int i=0; i < num_entries; ++i) {
522 if (in.atEnd()) {
523 pixmaps.clear();
524 return false;
525 }
526 in >> pm;
527 in >> fileName;
528 in >> sz;
529 in >> mode;
530 in >> state;
531 if (pm.isNull()) {
532 addFile(fileName, sz, QIcon::Mode(mode), QIcon::State(state));
533 } else {
534 QPixmapIconEngineEntry pe(fileName, sz, QIcon::Mode(mode), QIcon::State(state));
535 pe.pixmap = pm;
536 pixmaps.push_back(std::move(pe));
537 }
538 }
539 return true;
540}
541
542bool QPixmapIconEngine::write(QDataStream &out) const
543{
544 int num_entries = pixmaps.size();
545 out << num_entries;
546 for (int i=0; i < num_entries; ++i) {
547 if (pixmaps.at(i).pixmap.isNull())
548 out << QPixmap(pixmaps.at(i).fileName);
549 else
550 out << pixmaps.at(i).pixmap;
551 out << pixmaps.at(i).fileName;
552 out << pixmaps.at(i).size;
553 out << (uint) pixmaps.at(i).mode;
554 out << (uint) pixmaps.at(i).state;
555 }
556 return true;
557}
558
559Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, iceLoader,
560 (QIconEngineFactoryInterface_iid, "/iconengines"_L1, Qt::CaseInsensitive))
561
562QFactoryLoader *qt_iconEngineFactoryLoader()
563{
564 return iceLoader();
565}
566
567
568/*!
569 \class QIcon
570
571 \brief The QIcon class provides scalable icons in different modes
572 and states.
573
574 \ingroup painting
575 \ingroup shared
576 \inmodule QtGui
577
578 A QIcon can generate smaller, larger, active, and disabled pixmaps
579 from the set of pixmaps it is given. Such pixmaps are used by Qt
580 UI components to show an icon representing a particular action.
581
582 \section1 Creating an icon from image files
583
584 The simplest way to construct a QIcon is to create one from one or
585 several image files or resources. For example:
586
587 \snippet code/src_gui_image_qicon.cpp 0
588
589 QIcon can store several images for different states, and Qt will
590 select the image that is the closest match for the action's current
591 state.
592
593 \snippet code/src_gui_image_qicon.cpp addFile
594
595 Qt will generate the required icon styles and sizes when needed,
596 e.g. the pixmap for the QIcon::Disabled state might be generated by
597 graying out one of the provided pixmaps.
598
599 To clear the icon, simply set a null icon in its place:
600
601 \snippet code/src_gui_image_qicon.cpp 1
602
603 Use the QImageReader::supportedImageFormats() and
604 QImageWriter::supportedImageFormats() functions to retrieve a
605 complete list of the supported file formats.
606
607 \note If using an SVG image file, make sure to add it before any non-SVG files,
608 so that the correct \l{Icon Engines}{icon engine} gets selected.
609
610 \section1 Creating an icon from a theme or icon library
611
612 The most convenient way to construct an icon is by using the
613 \l{QIcon::}{fromTheme()} factory function. Qt implements access to
614 the native icon library on platforms that support the
615 \l {Freedesktop Icon Theme Specification}.
616
617 Applications can use the same theming specification to provide
618 their own icon library. See below for an example theme description
619 and the corresponding directory structure for the image files.
620
621 Since Qt 6.7, Qt also provides access to the native icon library on macOS,
622 iOS, and Windows 10 and 11. On Android, Qt can access icons from the Material
623 design system as long as the
624 \l{https://github.com/google/material-design-icons/tree/master/font}
625 {MaterialIcons-Regular} font is available on the system, or bundled
626 as a resource at \c{:/qt-project.org/icons/MaterialIcons-Regular.ttf}
627 with the application.
628
629 \snippet code/src_gui_image_qicon.cpp fromTheme
630
631 Since Qt 6.9, Qt can generate icons from named glyphs in an available icon
632 font. Set the \l{QIcon::themeName()}{theme name} to the family name of the
633 font, and use \l{QIcon::}{fromTheme()} with the name of the glyph.
634
635 \snippet code/src_gui_image_qicon.cpp iconFont
636
637 The icon font can be installed on the system, or bundled as an
638 \l{QFontDatabase::addApplicationFont()}{application font}.
639
640 \section1 Icon Engines
641
642 Internally, QIcon instantiates an \l {QIconEngine} {icon engine}
643 backend to handle and render the icon images. The type of icon
644 engine is determined by the first file or pixmap or theme added to a
645 QIcon object. Additional files or pixmaps will then be handled by
646 the same engine.
647
648 Icon engines differ in the way they handle and render icons. The
649 default pixmap-based engine only deals with fixed images, while the
650 QtSvg module provides an icon engine that can re-render the provided
651 vector graphics files at the requested size for better quality. The
652 theme icon engines will typically only provide images from native
653 platform icon library, and ignore any added files or pixmaps.
654
655 In addition, it is possible to provide custom icon engines. This
656 allows applications to customize every aspect of generated
657 icons. With QIconEnginePlugin it is possible to register different
658 icon engines for different file suffixes, making it possible for
659 third parties to provide additional icon engines to those included
660 with Qt.
661
662 \section1 Using QIcon in the User Interface
663
664 If you write your own widgets that have an option to set a small
665 pixmap, consider allowing a QIcon to be set for that pixmap. The
666 Qt class QToolButton is an example of such a widget.
667
668 Provide a method to set a QIcon, and paint the QIcon with
669 \l{QIcon::}{paint}, choosing the appropriate parameters based
670 on the current state of your widget. For example:
671
672 \snippet code/src_gui_image_qicon.cpp 2
673
674 When you retrieve a pixmap using pixmap(QSize, Mode, State), and no
675 pixmap for this given size, mode and state has been added with
676 addFile() or addPixmap(), then QIcon will generate one on the
677 fly. This pixmap generation happens in a QIconEngine. The default
678 engine scales pixmaps down if required, but never up, and it uses
679 the current style to calculate a disabled appearance.
680
681 You might also make use of the \c Active mode, perhaps making your
682 widget \c Active when the mouse is over the widget (see \l
683 QWidget::enterEvent()), while the mouse is pressed pending the
684 release that will activate the function, or when it is the currently
685 selected item. If the widget can be toggled, the "On" mode might be
686 used to draw a different icon.
687
688 QIcons generated from the native icon library, or from an icon font, use the
689 same glyph for both the \c On and \c Off states of the icon. Applications can
690 change the icon depending on the state of the respective UI control or action.
691 In a Qt Quick application, this can be done with a binding.
692
693 \snippet code/src_gui_image_qicon.qml iconFont
694
695 \image icon.png QIcon
696
697 \note QIcon needs a QGuiApplication instance before the icon is created.
698
699 \section1 High DPI Icons
700
701 Icons that are provided by the native icon library, or generated from the
702 glyph in an icon font, are usually based on vector graphics, and will
703 automatically be rendered in the appropriate resolution.
704
705 When providing your own image files via \l addFile(), then QIcon will
706 use Qt's \l {High Resolution Versions of Images}{"@nx" high DPI syntax}.
707 This is useful if you have your own custom directory structure and do not
708 use follow \l {Freedesktop Icon Theme Specification}.
709
710 When providing an application theme, then you need to follow the Icon Theme
711 Specification to specify which files to use for different resolutions.
712 To make QIcon use the high DPI version of an image, add an additional entry
713 to the appropriate \c index.theme file:
714
715 \badcode
716 [Icon Theme]
717 Name=Test
718 Comment=Test Theme
719
720 Directories=32x32/actions,32x32@2/actions
721
722 [32x32/actions]
723 Size=32
724 Context=Actions
725 Type=Fixed
726
727 # High DPI version of the entry above.
728 [32x32@2/actions]
729 Size=32
730 Scale=2
731 Type=Fixed
732 \endcode
733
734 Your icon theme directory would then look something like this:
735
736 \badcode
737 ├── 32x32
738 │ └── actions
739 │ └── appointment-new.png
740 ├── 32x32@2
741 │ └── actions
742 │ └── appointment-new.png
743 └── index.theme
744 \endcode
745*/
746
747
748/*!
749 Constructs a null icon.
750*/
751QIcon::QIcon() noexcept
752 : d(nullptr)
753{
754}
755
756/*!
757 Constructs an icon from a \a pixmap.
758 */
759QIcon::QIcon(const QPixmap &pixmap)
760 :d(nullptr)
761{
762 addPixmap(pixmap);
763}
764
765/*!
766 Constructs a copy of \a other. This is very fast.
767*/
768QIcon::QIcon(const QIcon &other)
769 :d(other.d)
770{
771 if (d)
772 d->ref.ref();
773}
774
775/*!
776 \fn QIcon::QIcon(QIcon &&other)
777
778 Move-constructs a QIcon instance, making it point to the same object
779 that \a other was pointing to.
780*/
781
782/*!
783 Constructs an icon from the file with the given \a fileName. The
784 file will be loaded on demand.
785
786 If \a fileName contains a relative path (e.g. the filename only)
787 the relevant file must be found relative to the runtime working
788 directory.
789
790 The file name can refer to an actual file on disk or to
791 one of the application's embedded resources. See the
792 \l{resources.html}{Resource System} overview for details on how to
793 embed images and other resource files in the application's
794 executable.
795
796 Use the QImageReader::supportedImageFormats() and
797 QImageWriter::supportedImageFormats() functions to retrieve a
798 complete list of the supported file formats.
799*/
800QIcon::QIcon(const QString &fileName)
801 : d(nullptr)
802{
803 addFile(fileName);
804}
805
806
807/*!
808 Creates an icon with a specific icon \a engine. The icon takes
809 ownership of the engine.
810*/
811QIcon::QIcon(QIconEngine *engine)
812 :d(new QIconPrivate(engine))
813{
814}
815
816/*!
817 Destroys the icon.
818*/
819QIcon::~QIcon()
820{
821 if (d && !d->ref.deref())
822 delete d;
823}
824
825/*!
826 Assigns the \a other icon to this icon and returns a reference to
827 this icon.
828*/
829QIcon &QIcon::operator=(const QIcon &other)
830{
831 if (other.d)
832 other.d->ref.ref();
833 if (d && !d->ref.deref())
834 delete d;
835 d = other.d;
836 return *this;
837}
838
839/*!
840 \fn QIcon &QIcon::operator=(QIcon &&other)
841
842 Move-assigns \a other to this QIcon instance.
843
844 \since 5.2
845*/
846
847/*!
848 \fn void QIcon::swap(QIcon &other)
849 \memberswap{icon}
850*/
851
852/*!
853 Returns the icon as a QVariant.
854*/
855QIcon::operator QVariant() const
856{
857 return QVariant::fromValue(*this);
858}
859
860/*!
861 Returns a number that identifies the contents of this QIcon
862 object. Distinct QIcon objects can have the same key if
863 they refer to the same contents.
864
865 The cacheKey() will change when the icon is altered via
866 addPixmap() or addFile().
867
868 Cache keys are mostly useful in conjunction with caching.
869
870 \sa QPixmap::cacheKey()
871*/
872qint64 QIcon::cacheKey() const
873{
874 if (!d)
875 return 0;
876 return (((qint64) d->serialNum) << 32) | ((qint64) (d->detach_no));
877}
878
879/*!
880 Returns a pixmap with the requested \a size, \a mode, and \a
881 state, generating one if necessary. The pixmap might be smaller than
882 requested, but never larger, unless the device-pixel ratio of the returned
883 pixmap is larger than 1.
884
885 \sa actualSize(), paint()
886*/
887QPixmap QIcon::pixmap(const QSize &size, Mode mode, State state) const
888{
889 if (!d)
890 return QPixmap();
891 const qreal dpr = -1; // don't know target dpr
892 return pixmap(size, dpr, mode, state);
893}
894
895/*!
896 \fn QPixmap QIcon::pixmap(int w, int h, Mode mode = Normal, State state = Off) const
897
898 \overload
899
900 Returns a pixmap of size QSize(\a w, \a h). The pixmap might be smaller than
901 requested, but never larger, unless the device-pixel ratio of the returned
902 pixmap is larger than 1.
903*/
904
905/*!
906 \fn QPixmap QIcon::pixmap(int extent, Mode mode = Normal, State state = Off) const
907
908 \overload
909
910 Returns a pixmap of size QSize(\a extent, \a extent). The pixmap might be smaller
911 than requested, but never larger, unless the device-pixel ratio of the returned
912 pixmap is larger than 1.
913*/
914
915/*!
916 \overload
917 \since 6.0
918
919 Returns a pixmap with the requested \a size, \a devicePixelRatio, \a mode, and \a
920 state, generating one with the given \a mode and \a state if necessary. The pixmap
921 might be smaller than requested, but never larger, unless the device-pixel ratio
922 of the returned pixmap is larger than 1.
923
924 \note The requested devicePixelRatio might not match the returned one. This delays the
925 scaling of the QPixmap until it is drawn later on.
926 \note Prior to Qt 6.8 this function wronlgy passed the device dependent pixmap size to
927 QIconEngine::scaledPixmap(), since Qt 6.8 it's the device independent size (not scaled
928 with the \a devicePixelRatio).
929
930 \sa actualSize(), paint()
931*/
932QPixmap QIcon::pixmap(const QSize &size, qreal devicePixelRatio, Mode mode, State state) const
933{
934 if (!d)
935 return QPixmap();
936
937 // Use the global devicePixelRatio if the caller does not know the target dpr
938 if (devicePixelRatio == -1)
939 devicePixelRatio = qApp->devicePixelRatio();
940
941 QPixmap pixmap = d->engine->scaledPixmap(size, mode, state, devicePixelRatio);
942 // even though scaledPixmap() should return a pixmap with an appropriate size, we
943 // can not rely on it. Therefore we simply set the dpr to a correct size to make
944 // sure the pixmap is not larger than requested.
945 pixmap.setDevicePixelRatio(d->pixmapDevicePixelRatio(devicePixelRatio, size, pixmap.size()));
946 return pixmap;
947}
948
949#if QT_DEPRECATED_SINCE(6, 0)
950/*!
951 \since 5.1
952 \deprecated [6.0] Use pixmap(size, devicePixelRatio) instead.
953
954 Returns a pixmap with the requested \a window \a size, \a mode, and \a
955 state, generating one if necessary.
956
957 The pixmap can be smaller than the requested size. If \a window is on
958 a high-dpi display the pixmap can be larger. In that case it will have
959 a devicePixelRatio larger than 1.
960
961 \sa actualSize(), paint()
962*/
963
964QPixmap QIcon::pixmap(QWindow *window, const QSize &size, Mode mode, State state) const
965{
966 if (!d)
967 return QPixmap();
968
969 qreal devicePixelRatio = window ? window->devicePixelRatio() : qApp->devicePixelRatio();
970 return pixmap(size, devicePixelRatio, mode, state);
971}
972#endif
973
974
975/*! Returns the actual size of the icon for the requested \a size, \a
976 mode, and \a state. The result might be smaller than requested, but
977 never larger. The returned size is in device-independent pixels (This
978 is relevant for high-dpi pixmaps.)
979
980 \sa pixmap(), paint()
981*/
982QSize QIcon::actualSize(const QSize &size, Mode mode, State state) const
983{
984 if (!d)
985 return QSize();
986
987 const qreal devicePixelRatio = qApp->devicePixelRatio();
988
989 // Handle the simple normal-dpi case:
990 if (!(devicePixelRatio > 1.0))
991 return d->engine->actualSize(size, mode, state);
992
993 const QSize actualSize = d->engine->actualSize(size * devicePixelRatio, mode, state);
994 return actualSize / d->pixmapDevicePixelRatio(devicePixelRatio, size, actualSize);
995}
996
997#if QT_DEPRECATED_SINCE(6, 0)
998/*!
999 \since 5.1
1000 \deprecated [6.0] Use actualSize(size) instead.
1001
1002 Returns the actual size of the icon for the requested \a window \a size, \a
1003 mode, and \a state.
1004
1005 The pixmap can be smaller than the requested size. The returned size
1006 is in device-independent pixels (This is relevant for high-dpi pixmaps.)
1007
1008 \sa actualSize(), pixmap(), paint()
1009*/
1010
1011QSize QIcon::actualSize(QWindow *window, const QSize &size, Mode mode, State state) const
1012{
1013 if (!d)
1014 return QSize();
1015
1016 qreal devicePixelRatio = window ? window->devicePixelRatio() : qApp->devicePixelRatio();
1017
1018 // Handle the simple normal-dpi case:
1019 if (!(devicePixelRatio > 1.0))
1020 return d->engine->actualSize(size, mode, state);
1021
1022 QSize actualSize = d->engine->actualSize(size * devicePixelRatio, mode, state);
1023 return actualSize / d->pixmapDevicePixelRatio(devicePixelRatio, size, actualSize);
1024}
1025#endif
1026
1027/*!
1028 Uses the \a painter to paint the icon with specified \a alignment,
1029 required \a mode, and \a state into the rectangle \a rect.
1030
1031 \sa actualSize(), pixmap()
1032*/
1033void QIcon::paint(QPainter *painter, const QRect &rect, Qt::Alignment alignment, Mode mode, State state) const
1034{
1035 if (!d || !painter)
1036 return;
1037
1038 // Copy of QStyle::alignedRect
1039 const QSize size = d->engine->actualSize(rect.size(), mode, state);
1040 alignment = QGuiApplicationPrivate::visualAlignment(painter->layoutDirection(), alignment);
1041 int x = rect.x();
1042 int y = rect.y();
1043 int w = size.width();
1044 int h = size.height();
1045 if ((alignment & Qt::AlignVCenter) == Qt::AlignVCenter)
1046 y += rect.size().height()/2 - h/2;
1047 else if ((alignment & Qt::AlignBottom) == Qt::AlignBottom)
1048 y += rect.size().height() - h;
1049 if ((alignment & Qt::AlignRight) == Qt::AlignRight)
1050 x += rect.size().width() - w;
1051 else if ((alignment & Qt::AlignHCenter) == Qt::AlignHCenter)
1052 x += rect.size().width()/2 - w/2;
1053 QRect alignedRect(x, y, w, h);
1054
1055 d->engine->paint(painter, alignedRect, mode, state);
1056}
1057
1058/*!
1059 \fn void QIcon::paint(QPainter *painter, int x, int y, int w, int h, Qt::Alignment alignment,
1060 Mode mode, State state) const
1061
1062 \overload
1063
1064 Paints the icon into the rectangle QRect(\a x, \a y, \a w, \a h).
1065*/
1066
1067/*!
1068 Returns \c true if the icon is empty; otherwise returns \c false.
1069
1070 An icon is empty if it has neither a pixmap nor a filename.
1071
1072 Note: Even a non-null icon might not be able to create valid
1073 pixmaps, eg. if the file does not exist or cannot be read.
1074*/
1075bool QIcon::isNull() const
1076{
1077 return !d || d->engine->isNull();
1078}
1079
1080/*!\internal
1081 */
1082bool QIcon::isDetached() const
1083{
1084 return !d || d->ref.loadRelaxed() == 1;
1085}
1086
1087/*! \internal
1088 */
1089void QIcon::detach()
1090{
1091 if (d) {
1092 if (d->engine->isNull()) {
1093 if (!d->ref.deref())
1094 delete d;
1095 d = nullptr;
1096 return;
1097 } else if (d->ref.loadRelaxed() != 1) {
1098 QIconPrivate *x = new QIconPrivate(d->engine->clone());
1099 if (!d->ref.deref())
1100 delete d;
1101 d = x;
1102 }
1103 ++d->detach_no;
1104 }
1105}
1106
1107/*!
1108 Adds \a pixmap to the icon, as a specialization for \a mode and
1109 \a state.
1110
1111 Custom icon engines are free to ignore additionally added
1112 pixmaps.
1113
1114 \sa addFile()
1115*/
1116void QIcon::addPixmap(const QPixmap &pixmap, Mode mode, State state)
1117{
1118 if (pixmap.isNull())
1119 return;
1120 detach();
1121 if (!d)
1122 d = new QIconPrivate(new QPixmapIconEngine);
1123 d->engine->addPixmap(pixmap, mode, state);
1124}
1125
1126static QIconEngine *iconEngineFromSuffix(const QString &fileName, const QString &suffix)
1127{
1128 if (!suffix.isEmpty()) {
1129 const int index = iceLoader()->indexOf(suffix);
1130 if (index != -1) {
1131 if (QIconEnginePlugin *factory = qobject_cast<QIconEnginePlugin*>(iceLoader()->instance(index))) {
1132 return factory->create(fileName);
1133 }
1134 }
1135 }
1136 return nullptr;
1137}
1138
1139/*! Adds an image from the file with the given \a fileName to the
1140 icon, as a specialization for \a size, \a mode and \a state. The
1141 file will be loaded on demand. Note: custom icon engines are free
1142 to ignore additionally added pixmaps.
1143
1144 If \a fileName contains a relative path (e.g. the filename only)
1145 the relevant file must be found relative to the runtime working
1146 directory.
1147
1148 The file name can refer to an actual file on disk or to
1149 one of the application's embedded resources. See the
1150 \l{resources.html}{Resource System} overview for details on how to
1151 embed images and other resource files in the application's
1152 executable.
1153
1154 Use the QImageReader::supportedImageFormats() and
1155 QImageWriter::supportedImageFormats() functions to retrieve a
1156 complete list of the supported file formats.
1157
1158 If a high resolution version of the image exists (identified by
1159 the suffix \c @2x on the base name), it is automatically loaded
1160 and added with the \e{device pixel ratio} set to a value of 2.
1161 This can be disabled by setting the environment variable
1162 \c QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING (see QImageReader).
1163
1164 \note When you add a non-empty filename to a QIcon, the icon becomes
1165 non-null, even if the file doesn't exist or points to a corrupt file.
1166
1167 \sa addPixmap(), QPixmap::devicePixelRatio()
1168 */
1169void QIcon::addFile(const QString &fileName, const QSize &size, Mode mode, State state)
1170{
1171 if (fileName.isEmpty())
1172 return;
1173 detach();
1174 bool alreadyAdded = false;
1175 if (!d) {
1176
1177 QFileInfo info(fileName);
1178 QString suffix = info.suffix();
1179#if QT_CONFIG(mimetype)
1180 if (suffix.isEmpty())
1181 suffix = QMimeDatabase().mimeTypeForFile(info).preferredSuffix(); // determination from contents
1182#endif // mimetype
1183 QIconEngine *engine = iconEngineFromSuffix(fileName, suffix);
1184 if (engine)
1185 alreadyAdded = !engine->isNull();
1186 d = new QIconPrivate(engine ? engine : new QPixmapIconEngine);
1187 }
1188 if (!alreadyAdded)
1189 d->engine->addFile(fileName, size, mode, state);
1190
1191 if (d->engine->key() == "svg"_L1) // not needed and also not supported
1192 return;
1193
1194 // Check if a "@Nx" file exists and add it.
1195 QVarLengthArray<int, 4> devicePixelRatios;
1196 const auto screens = qApp->screens();
1197 for (const auto *screen : screens) {
1198 const auto dpr = qCeil(screen->devicePixelRatio()); // qt_findAtNxFile only supports integer values
1199 if (dpr >= 1 && !devicePixelRatios.contains(dpr))
1200 devicePixelRatios.push_back(dpr);
1201 }
1202 std::sort(devicePixelRatios.begin(), devicePixelRatios.end(), std::greater<int>());
1203 qreal sourceDevicePixelRatio = std::numeric_limits<qreal>::max();
1204 for (const auto dpr : std::as_const(devicePixelRatios)) {
1205 if (dpr >= sourceDevicePixelRatio)
1206 continue;
1207 const QString atNxFileName = qt_findAtNxFile(fileName, dpr, &sourceDevicePixelRatio);
1208 if (atNxFileName != fileName)
1209 d->engine->addFile(atNxFileName, size, mode, state);
1210 }
1211}
1212
1213/*!
1214 Returns a list of available icon sizes for the specified \a mode and
1215 \a state.
1216*/
1217QList<QSize> QIcon::availableSizes(Mode mode, State state) const
1218{
1219 if (!d || !d->engine)
1220 return QList<QSize>();
1221 return d->engine->availableSizes(mode, state);
1222}
1223
1224/*!
1225 Returns the name used to create the icon, if available.
1226
1227 Depending on the way the icon was created, it may have an associated
1228 name. This is the case for icons created with fromTheme().
1229
1230 \sa fromTheme(), QIconEngine::iconName()
1231*/
1232QString QIcon::name() const
1233{
1234 if (!d || !d->engine)
1235 return QString();
1236 return d->engine->iconName();
1237}
1238
1239/*!
1240 Sets the search paths for icon themes to \a paths.
1241
1242 The content of \a paths should follow the theme format
1243 documented by setThemeName().
1244
1245 \sa themeSearchPaths(), fromTheme(), setThemeName()
1246*/
1247void QIcon::setThemeSearchPaths(const QStringList &paths)
1248{
1249 QIconLoader::instance()->setThemeSearchPath(paths);
1250}
1251
1252/*!
1253 Returns the search paths for icon themes.
1254
1255 The default search paths will be defined by the platform.
1256 All platforms will also have the resource directory \c{:\icons} as a fallback.
1257
1258 \sa setThemeSearchPaths(), fromTheme(), setThemeName()
1259*/
1260QStringList QIcon::themeSearchPaths()
1261{
1262 return QIconLoader::instance()->themeSearchPaths();
1263}
1264
1265/*!
1266 \since 5.11
1267
1268 Returns the fallback search paths for icons.
1269
1270 The fallback search paths are consulted for standalone
1271 icon files if the \l{themeName()}{current icon theme}
1272 or \l{fallbackThemeName()}{fallback icon theme} do
1273 not provide results for an icon lookup.
1274
1275 If not set, the fallback search paths will be defined
1276 by the platform.
1277
1278 \sa setFallbackSearchPaths(), themeSearchPaths()
1279*/
1280QStringList QIcon::fallbackSearchPaths()
1281{
1282 return QIconLoader::instance()->fallbackSearchPaths();
1283}
1284
1285/*!
1286 \since 5.11
1287
1288 Sets the fallback search paths for icons to \a paths.
1289
1290 The fallback search paths are consulted for standalone
1291 icon files if the \l{themeName()}{current icon theme}
1292 or \l{fallbackThemeName()}{fallback icon theme} do
1293 not provide results for an icon lookup.
1294
1295 For example:
1296
1297 \snippet code/src_gui_image_qicon.cpp 5
1298
1299 \sa fallbackSearchPaths(), setThemeSearchPaths()
1300*/
1301void QIcon::setFallbackSearchPaths(const QStringList &paths)
1302{
1303 QIconLoader::instance()->setFallbackSearchPaths(paths);
1304}
1305
1306/*!
1307 Sets the current icon theme to \a name.
1308
1309 If the theme matches the name of an installed font that provides named
1310 glyphs, then QIcon::fromTheme calls that match one of the glyphs will
1311 produce an icon for that glyph.
1312
1313 Otherwise, the theme will be looked up in themeSearchPaths(). At the moment
1314 the only supported icon theme format is the \l{Freedesktop Icon Theme
1315 Specification}. The \a name should correspond to a directory name in the
1316 themeSearchPath() containing an \c index.theme file describing its
1317 contents.
1318
1319 \sa themeSearchPaths(), themeName(),
1320 {Freedesktop Icon Theme Specification}
1321*/
1322void QIcon::setThemeName(const QString &name)
1323{
1324 QIconLoader::instance()->setThemeName(name);
1325}
1326
1327/*!
1328 Returns the name of the current icon theme.
1329
1330 If not set, the current icon theme will be defined by the
1331 platform.
1332
1333 \note Platform icon themes are only implemented on
1334 \l{Freedesktop} based systems at the moment, and the
1335 icon theme depends on your desktop settings.
1336
1337 \sa setThemeName(), themeSearchPaths(), fromTheme(),
1338 hasThemeIcon()
1339*/
1340QString QIcon::themeName()
1341{
1342 return QIconLoader::instance()->themeName();
1343}
1344
1345/*!
1346 \since 5.12
1347
1348 Returns the name of the fallback icon theme.
1349
1350 If not set, the fallback icon theme will be defined by the
1351 platform.
1352
1353 \note Platform fallback icon themes are only implemented on
1354 \l{Freedesktop} based systems at the moment, and the
1355 icon theme depends on your desktop settings.
1356
1357 \sa setFallbackThemeName(), themeName()
1358*/
1359QString QIcon::fallbackThemeName()
1360{
1361 return QIconLoader::instance()->fallbackThemeName();
1362}
1363
1364/*!
1365 \since 5.12
1366
1367 Sets the fallback icon theme to \a name.
1368
1369 The fallback icon theme is consulted for icons not provided by
1370 the \l{themeName()}{current icon theme}, or if the \l{themeName()}
1371 {current icon theme} does not exist.
1372
1373 The \a name should correspond to theme in the same format
1374 as documented by setThemeName(), and will be looked up
1375 in themeSearchPaths().
1376
1377 \note Fallback icon themes should be set before creating
1378 QGuiApplication, to ensure correct initialization.
1379
1380 \sa fallbackThemeName(), themeSearchPaths(), themeName()
1381*/
1382void QIcon::setFallbackThemeName(const QString &name)
1383{
1384 QIconLoader::instance()->setFallbackThemeName(name);
1385}
1386
1387/*!
1388 Returns the QIcon corresponding to \a name in the
1389 \l{themeName()}{current icon theme}.
1390
1391 If the current theme does not provide an icon for \a name,
1392 the \l{fallbackThemeName()}{fallback icon theme} is consulted,
1393 before falling back to looking up standalone icon files in the
1394 \l{QIcon::fallbackSearchPaths()}{fallback icon search path}.
1395 Finally, the platform's native icon library is consulted.
1396
1397 To fetch an icon from the current icon theme:
1398
1399 \snippet code/src_gui_image_qicon.cpp fromTheme
1400
1401 If an \l{themeName()}{icon theme} has not been explicitly
1402 set via setThemeName() a platform defined icon theme will
1403 be used.
1404
1405 \sa themeName(), fallbackThemeName(), setThemeName(), themeSearchPaths(), fallbackSearchPaths(),
1406 {Freedesktop Icon Naming Specification}
1407*/
1408QIcon QIcon::fromTheme(const QString &name)
1409{
1410 if (name.isEmpty())
1411 return {};
1412
1413 if (QIcon *cachedIcon = qtIconCache()->object(name))
1414 return *cachedIcon;
1415
1416 if (QDir::isAbsolutePath(name))
1417 return QIcon(name);
1418
1419 QIcon icon(new QThemeIconEngine(name));
1420 qtIconCache()->insert(name, new QIcon(icon));
1421 return icon;
1422}
1423
1424/*!
1425 \overload
1426
1427 Returns the QIcon corresponding to \a name in the
1428 \l{themeName()}{current icon theme}.
1429
1430 If the current theme does not provide an icon for \a name,
1431 the \l{fallbackThemeName()}{fallback icon theme} is consulted,
1432 before falling back to looking up standalone icon files in the
1433 \l{QIcon::fallbackSearchPaths()}{fallback icon search path}.
1434 Finally, the platform's native icon library is consulted.
1435
1436 If no icon is found \a fallback is returned.
1437
1438 This is useful to provide a guaranteed fallback, regardless of
1439 whether the current set of icon themes and fallbacks paths
1440 support the requested icon.
1441
1442 For example:
1443
1444 \snippet code/src_gui_image_qicon.cpp 4
1445
1446 \sa fallbackThemeName(), fallbackSearchPaths()
1447*/
1448QIcon QIcon::fromTheme(const QString &name, const QIcon &fallback)
1449{
1450 QIcon icon = fromTheme(name);
1451
1452 if (icon.isNull() || icon.availableSizes().isEmpty())
1453 return fallback;
1454
1455 return icon;
1456}
1457
1458/*!
1459 Returns \c true if there is an icon available for \a name in the
1460 current icon theme or any of the fallbacks, as described by
1461 fromTheme(), otherwise returns \c false.
1462
1463 \sa themeSearchPaths(), fromTheme(), setThemeName()
1464*/
1465bool QIcon::hasThemeIcon(const QString &name)
1466{
1467 QIcon icon = fromTheme(name);
1468
1469 return icon.name() == name;
1470}
1471
1472static constexpr auto themeIconMapping = qOffsetStringArray(
1473 "address-book-new",
1474 "application-exit",
1475 "appointment-new",
1476 "call-start",
1477 "call-stop",
1478 "contact-new",
1479 "document-new",
1480 "document-open",
1481 "document-open-recent",
1482 "document-page-setup",
1483 "document-print",
1484 "document-print-preview",
1485 "document-properties",
1486 "document-revert",
1487 "document-save",
1488 "document-save-as",
1489 "document-send",
1490 "edit-clear",
1491 "edit-copy",
1492 "edit-cut",
1493 "edit-delete",
1494 "edit-find",
1495 "edit-paste",
1496 "edit-redo",
1497 "edit-select-all",
1498 "edit-undo",
1499 "folder-new",
1500 "format-indent-less",
1501 "format-indent-more",
1502 "format-justify-center",
1503 "format-justify-fill",
1504 "format-justify-left",
1505 "format-justify-right",
1506 "format-text-direction-ltr",
1507 "format-text-direction-rtl",
1508 "format-text-bold",
1509 "format-text-italic",
1510 "format-text-underline",
1511 "format-text-strikethrough",
1512 "go-down",
1513 "go-home",
1514 "go-next",
1515 "go-previous",
1516 "go-up",
1517 "help-about",
1518 "help-faq",
1519 "insert-image",
1520 "insert-link",
1521 "insert-text",
1522 "list-add",
1523 "list-remove",
1524 "mail-forward",
1525 "mail-mark-important",
1526 "mail-mark-read",
1527 "mail-mark-unread",
1528 "mail-message-new",
1529 "mail-reply-all",
1530 "mail-reply-sender",
1531 "mail-send",
1532 "media-eject",
1533 "media-playback-pause",
1534 "media-playback-start",
1535 "media-playback-stop",
1536 "media-record",
1537 "media-seek-backward",
1538 "media-seek-forward",
1539 "media-skip-backward",
1540 "media-skip-forward",
1541 "object-rotate-left",
1542 "object-rotate-right",
1543 "process-stop",
1544 "system-lock-screen",
1545 "system-log-out",
1546 "system-search",
1547 "system-reboot",
1548 "system-shutdown",
1549 "tools-check-spelling",
1550 "view-fullscreen",
1551 "view-refresh",
1552 "view-restore",
1553 "window-close",
1554 "window-new",
1555 "zoom-fit-best",
1556 "zoom-in",
1557 "zoom-out",
1558
1559 "audio-card",
1560 "audio-input-microphone",
1561 "battery",
1562 "camera-photo",
1563 "camera-video",
1564 "camera-web",
1565 "computer",
1566 "drive-harddisk",
1567 "drive-optical",
1568 "input-gaming",
1569 "input-keyboard",
1570 "input-mouse",
1571 "input-tablet",
1572 "media-flash",
1573 "media-optical",
1574 "media-tape",
1575 "multimedia-player",
1576 "network-wired",
1577 "network-wireless",
1578 "phone",
1579 "printer",
1580 "scanner",
1581 "video-display",
1582
1583 "appointment-missed",
1584 "appointment-soon",
1585 "audio-volume-high",
1586 "audio-volume-low",
1587 "audio-volume-medium",
1588 "audio-volume-muted",
1589 "battery-caution",
1590 "battery-low",
1591 "dialog-error",
1592 "dialog-information",
1593 "dialog-password",
1594 "dialog-question",
1595 "dialog-warning",
1596 "folder-drag-accept",
1597 "folder-open",
1598 "folder-visiting",
1599 "image-loading",
1600 "image-missing",
1601 "mail-attachment",
1602 "mail-unread",
1603 "mail-read",
1604 "mail-replied",
1605 "media-playlist-repeat",
1606 "media-playlist-shuffle",
1607 "network-offline",
1608 "printer-printing",
1609 "security-high",
1610 "security-low",
1611 "software-update-available",
1612 "software-update-urgent",
1613 "sync-error",
1614 "sync-synchronizing",
1615 "user-available",
1616 "user-offline",
1617 "weather-clear",
1618 "weather-clear-night",
1619 "weather-few-clouds",
1620 "weather-few-clouds-night",
1621 "weather-fog",
1622 "weather-showers",
1623 "weather-snow",
1624 "weather-storm"
1625);
1626static_assert(QIcon::ThemeIcon::NThemeIcons == QIcon::ThemeIcon(themeIconMapping.count()));
1627
1628static constexpr QLatin1StringView themeIconName(QIcon::ThemeIcon icon)
1629{
1630 using ThemeIconIndex = std::underlying_type_t<QIcon::ThemeIcon>;
1631 const auto index = static_cast<ThemeIconIndex>(icon);
1632 Q_ASSERT(index < themeIconMapping.count());
1633 return QLatin1StringView(themeIconMapping.viewAt(index));
1634}
1635
1636/*!
1637 \enum QIcon::ThemeIcon
1638 \since 6.7
1639
1640 This enum provides access to icons that are provided by most
1641 icon theme implementations.
1642
1643 \value AddressBookNew The icon for the action to create a new address book.
1644 \value ApplicationExit The icon for exiting an application.
1645 \value AppointmentNew The icon for the action to create a new appointment.
1646 \value CallStart The icon for initiating or accepting a call.
1647 \value CallStop The icon for stopping a current call.
1648 \value ContactNew The icon for the action to create a new contact.
1649 \value DocumentNew The icon for the action to create a new document.
1650 \value DocumentOpen The icon for the action to open a document.
1651 \value DocumentOpenRecent The icon for the action to open a document that was recently opened.
1652 \value DocumentPageSetup The icon for the \e{page setup} action.
1653 \value DocumentPrint The icon for the \e{print} action.
1654 \value DocumentPrintPreview The icon for the \e{print preview} action.
1655 \value DocumentProperties The icon for the action to view the properties of a document.
1656 \value DocumentRevert The icon for the action of reverting to a previous version of a document.
1657 \value DocumentSave The icon for the \e{save} action.
1658 \value DocumentSaveAs The icon for the \e{save as} action.
1659 \value DocumentSend The icon for the \e{send} action.
1660 \value EditClear The icon for the \e{clear} action.
1661 \value EditCopy The icon for the \e{copy} action.
1662 \value EditCut The icon for the \e{cut} action.
1663 \value EditDelete The icon for the \e{delete} action.
1664 \value EditFind The icon for the \e{find} action.
1665 \value EditPaste The icon for the \e{paste} action.
1666 \value EditRedo The icon for the \e{redo} action.
1667 \value EditSelectAll The icon for the \e{select all} action.
1668 \value EditUndo The icon for the \e{undo} action.
1669 \value FolderNew The icon for creating a new folder.
1670 \value FormatIndentLess The icon for the \e{decrease indent formatting} action.
1671 \value FormatIndentMore The icon for the \e{increase indent formatting} action.
1672 \value FormatJustifyCenter The icon for the \e{center justification formatting} action.
1673 \value FormatJustifyFill The icon for the \e{fill justification formatting} action.
1674 \value FormatJustifyLeft The icon for the \e{left justification formatting} action.
1675 \value FormatJustifyRight The icon for the \e{right justification} action.
1676 \value FormatTextDirectionLtr The icon for the \e{left-to-right text formatting} action.
1677 \value FormatTextDirectionRtl The icon for the \e{right-to-left formatting} action.
1678 \value FormatTextBold The icon for the \e{bold text formatting} action.
1679 \value FormatTextItalic The icon for the \e{italic text formatting} action.
1680 \value FormatTextUnderline The icon for the \e{underlined text formatting} action.
1681 \value FormatTextStrikethrough The icon for the \e{strikethrough text formatting} action.
1682 \value GoDown The icon for the \e{go down in a list} action.
1683 \value GoHome The icon for the \e{go to home location} action.
1684 \value GoNext The icon for the \e{go to the next item in a list} action.
1685 \value GoPrevious The icon for the \e{go to the previous item in a list} action.
1686 \value GoUp The icon for the \e{go up in a list} action.
1687 \value HelpAbout The icon for the \e{About} item in the Help menu.
1688 \value HelpFaq The icon for the \e{FAQ} item in the Help menu.
1689 \value InsertImage The icon for the \e{insert image} action of an application.
1690 \value InsertLink The icon for the \e{insert link} action of an application.
1691 \value InsertText The icon for the \e{insert text} action of an application.
1692 \value ListAdd The icon for the \e{add to list} action.
1693 \value ListRemove The icon for the \e{remove from list} action.
1694 \value MailForward The icon for the \e{forward} action.
1695 \value MailMarkImportant The icon for the \e{mark as important} action.
1696 \value MailMarkRead The icon for the \e{mark as read} action.
1697 \value MailMarkUnread The icon for the \e{mark as unread} action.
1698 \value MailMessageNew The icon for the \e{compose new mail} action.
1699 \value MailReplyAll The icon for the \e{reply to all} action.
1700 \value MailReplySender The icon for the \e{reply to sender} action.
1701 \value MailSend The icon for the \e{send} action.
1702 \value MediaEject The icon for the \e{eject} action of a media player or file manager.
1703 \value MediaPlaybackPause The icon for the \e{pause} action of a media player.
1704 \value MediaPlaybackStart The icon for the \e{start playback} action of a media player.
1705 \value MediaPlaybackStop The icon for the \e{stop} action of a media player.
1706 \value MediaRecord The icon for the \e{record} action of a media application.
1707 \value MediaSeekBackward The icon for the \e{seek backward} action of a media player.
1708 \value MediaSeekForward The icon for the \e{seek forward} action of a media player.
1709 \value MediaSkipBackward The icon for the \e{skip backward} action of a media player.
1710 \value MediaSkipForward The icon for the \e{skip forward} action of a media player.
1711 \value ObjectRotateLeft The icon for the \e{rotate left} action performed on an object.
1712 \value ObjectRotateRight The icon for the \e{rotate right} action performed on an object.
1713 \value ProcessStop The icon for the \e{stop action in applications with} actions that
1714 may take a while to process, such as web page loading in a browser.
1715 \value SystemLockScreen The icon for the \e{lock screen} action.
1716 \value SystemLogOut The icon for the \e{log out} action.
1717 \value SystemSearch The icon for the \e{search} action.
1718 \value SystemReboot The icon for the \e{reboot} action.
1719 \value SystemShutdown The icon for the \e{shutdown} action.
1720 \value ToolsCheckSpelling The icon for the \e{check spelling} action.
1721 \value ViewFullscreen The icon for the \e{fullscreen} action.
1722 \value ViewRefresh The icon for the \e{refresh} action.
1723 \value ViewRestore The icon for leaving the fullscreen view.
1724 \value WindowClose The icon for the \e{close window} action.
1725 \value WindowNew The icon for the \e{new window} action.
1726 \value ZoomFitBest The icon for the \e{best fit} action.
1727 \value ZoomIn The icon for the \e{zoom in} action.
1728 \value ZoomOut The icon for the \e{zoom out} action.
1729
1730 \value AudioCard The icon for the audio rendering device.
1731 \value AudioInputMicrophone The icon for the microphone audio input device.
1732 \value Battery The icon for the system battery device.
1733 \value CameraPhoto The icon for a digital still camera devices.
1734 \value CameraVideo The icon for a video camera device.
1735 \value CameraWeb The icon for a web camera device.
1736 \value Computer The icon for the computing device as a whole.
1737 \value DriveHarddisk The icon for hard disk drives.
1738 \value DriveOptical The icon for optical media drives such as CD and DVD.
1739 \value InputGaming The icon for the gaming input device.
1740 \value InputKeyboard The icon for the keyboard input device.
1741 \value InputMouse The icon for the mousing input device.
1742 \value InputTablet The icon for graphics tablet input devices.
1743 \value MediaFlash The icon for flash media, such as a memory stick.
1744 \value MediaOptical The icon for physical optical media such as CD and DVD.
1745 \value MediaTape The icon for generic physical tape media.
1746 \value MultimediaPlayer The icon for generic multimedia playing devices.
1747 \value NetworkWired The icon for wired network connections.
1748 \value NetworkWireless The icon for wireless network connections.
1749 \value Phone The icon for phone devices.
1750 \value Printer The icon for a printer device.
1751 \value Scanner The icon for a scanner device.
1752 \value VideoDisplay The icon for the monitor that video gets displayed on.
1753
1754 \value AppointmentMissed The icon for when an appointment was missed.
1755 \value AppointmentSoon The icon for when an appointment will occur soon.
1756 \value AudioVolumeHigh The icon used to indicate high audio volume.
1757 \value AudioVolumeLow The icon used to indicate low audio volume.
1758 \value AudioVolumeMedium The icon used to indicate medium audio volume.
1759 \value AudioVolumeMuted The icon used to indicate the muted state for audio playback.
1760 \value BatteryCaution The icon used when the battery is below 40%.
1761 \value BatteryLow The icon used when the battery is below 20%.
1762 \value DialogError The icon used when a dialog is opened to explain an error
1763 condition to the user.
1764 \value DialogInformation The icon used when a dialog is opened to give information to the
1765 user that may be pertinent to the requested action.
1766 \value DialogPassword The icon used when a dialog requesting the authentication
1767 credentials for a user is opened.
1768 \value DialogQuestion The icon used when a dialog is opened to ask a simple question
1769 to the user.
1770 \value DialogWarning The icon used when a dialog is opened to warn the user of
1771 impending issues with the requested action.
1772 \value FolderDragAccept The icon used for a folder while an acceptable object is being
1773 dragged onto it.
1774 \value FolderOpen The icon used for folders, while their contents are being displayed
1775 within the same window.
1776 \value FolderVisiting The icon used for folders, while their contents are being displayed
1777 in another window.
1778 \value ImageLoading The icon used while another image is being loaded.
1779 \value ImageMissing The icon used when another image could not be loaded.
1780 \value MailAttachment The icon for a message that contains attachments.
1781 \value MailUnread The icon for an unread message.
1782 \value MailRead The icon for a read message.
1783 \value MailReplied The icon for a message that has been replied to.
1784 \value MediaPlaylistRepeat The icon for the repeat mode of a media player.
1785 \value MediaPlaylistShuffle The icon for the shuffle mode of a media player.
1786 \value NetworkOffline The icon used to indicate that the device is not connected to the
1787 network.
1788 \value PrinterPrinting The icon used while a print job is successfully being spooled to a
1789 printing device.
1790 \value SecurityHigh The icon used to indicate that the security level of an item is
1791 known to be high.
1792 \value SecurityLow The icon used to indicate that the security level of an item is
1793 known to be low.
1794 \value SoftwareUpdateAvailable The icon used to indicate that an update is available.
1795 \value SoftwareUpdateUrgent The icon used to indicate that an urgent update is available.
1796 \value SyncError The icon used when an error occurs while attempting to synchronize
1797 data across devices.
1798 \value SyncSynchronizing The icon used while data is successfully synchronizing across
1799 devices.
1800 \value UserAvailable The icon used to indicate that a user is available.
1801 \value UserOffline The icon used to indicate that a user is not available.
1802 \value WeatherClear The icon used to indicate that the sky is clear.
1803 \value WeatherClearNight The icon used to indicate that the sky is clear
1804 during the night.
1805 \value WeatherFewClouds The icon used to indicate that the sky is partly cloudy.
1806 \value WeatherFewCloudsNight The icon used to indicate that the sky is partly cloudy
1807 during the night.
1808 \value WeatherFog The icon used to indicate that the weather is foggy.
1809 \value WeatherShowers The icon used to indicate that rain showers are occurring.
1810 \value WeatherSnow The icon used to indicate that snow is falling.
1811 \value WeatherStorm The icon used to indicate that the weather is stormy.
1812
1813 \omitvalue NThemeIcons
1814
1815 \sa {Creating an icon from a theme or icon library},
1816 fromTheme()
1817*/
1818
1819/*!
1820 \since 6.7
1821 \overload
1822
1823 Returns \c true if there is an icon available for \a icon in the
1824 current icon theme or any of the fallbacks, as described by
1825 fromTheme(), otherwise returns \c false.
1826
1827 \sa fromTheme()
1828*/
1829bool QIcon::hasThemeIcon(QIcon::ThemeIcon icon)
1830{
1831 return hasThemeIcon(themeIconName(icon));
1832}
1833
1834/*!
1835 \fn QIcon QIcon::fromTheme(QIcon::ThemeIcon icon)
1836 \fn QIcon QIcon::fromTheme(QIcon::ThemeIcon icon, const QIcon &fallback)
1837 \since 6.7
1838 \overload
1839
1840 Returns the QIcon corresponding to \a icon in the
1841 \l{themeName()}{current icon theme}.
1842
1843 If the current theme does not provide an icon for \a icon,
1844 the \l{fallbackThemeName()}{fallback icon theme} is consulted,
1845 before falling back to looking up standalone icon files in the
1846 \l{QIcon::fallbackSearchPaths()}{fallback icon search path}.
1847 Finally, the platform's native icon library is consulted.
1848
1849 If no icon is found and a \a fallback is provided, \a fallback is
1850 returned. This is useful to provide a guaranteed fallback, regardless
1851 of whether the current set of icon themes and fallbacks paths
1852 support the requested icon.
1853
1854 If no icon is found and no \a fallback is provided, a default
1855 constructed, empty QIcon is returned.
1856*/
1857QIcon QIcon::fromTheme(QIcon::ThemeIcon icon)
1858{
1859 return fromTheme(themeIconName(icon));
1860}
1861
1862QIcon QIcon::fromTheme(QIcon::ThemeIcon icon, const QIcon &fallback)
1863{
1864 return fromTheme(themeIconName(icon), fallback);
1865}
1866
1867/*!
1868 \since 5.6
1869
1870 Indicate that this icon is a mask image(boolean \a isMask), and hence can
1871 potentially be modified based on where it's displayed.
1872 \sa isMask()
1873*/
1874void QIcon::setIsMask(bool isMask)
1875{
1876 if (isMask == (d && d->is_mask))
1877 return;
1878
1879 detach();
1880 if (!d)
1881 d = new QIconPrivate(new QPixmapIconEngine);
1882 d->is_mask = isMask;
1883}
1884
1885/*!
1886 \since 5.6
1887
1888 Returns \c true if this icon has been marked as a mask image.
1889 Certain platforms render mask icons differently (for example,
1890 menu icons on \macos).
1891
1892 \sa setIsMask()
1893*/
1894bool QIcon::isMask() const
1895{
1896 if (!d)
1897 return false;
1898 return d->is_mask;
1899}
1900
1901/*****************************************************************************
1902 QIcon stream functions
1903 *****************************************************************************/
1904#if !defined(QT_NO_DATASTREAM)
1905/*!
1906 \fn QDataStream &operator<<(QDataStream &stream, const QIcon &icon)
1907 \relates QIcon
1908
1909 Writes the given \a icon to the given \a stream as a PNG
1910 image. If the icon contains more than one image, all images will
1911 be written to the stream. Note that writing the stream to a file
1912 will not produce a valid image file.
1913*/
1914
1915QDataStream &operator<<(QDataStream &s, const QIcon &icon)
1916{
1917 if (s.version() >= QDataStream::Qt_4_3) {
1918 if (icon.isNull()) {
1919 s << QString();
1920 } else {
1921 s << icon.d->engine->key();
1922 icon.d->engine->write(s);
1923 }
1924 } else if (s.version() == QDataStream::Qt_4_2) {
1925 if (icon.isNull()) {
1926 s << 0;
1927 } else {
1928 QPixmapIconEngine *engine = static_cast<QPixmapIconEngine *>(icon.d->engine);
1929 int num_entries = engine->pixmaps.size();
1930 s << num_entries;
1931 for (int i=0; i < num_entries; ++i) {
1932 s << engine->pixmaps.at(i).pixmap;
1933 s << engine->pixmaps.at(i).fileName;
1934 s << engine->pixmaps.at(i).size;
1935 s << (uint) engine->pixmaps.at(i).mode;
1936 s << (uint) engine->pixmaps.at(i).state;
1937 }
1938 }
1939 } else {
1940 s << QPixmap(icon.pixmap(22,22));
1941 }
1942 return s;
1943}
1944
1945/*!
1946 \fn QDataStream &operator>>(QDataStream &stream, QIcon &icon)
1947 \relates QIcon
1948
1949 Reads an image, or a set of images, from the given \a stream into
1950 the given \a icon.
1951*/
1952
1953QDataStream &operator>>(QDataStream &s, QIcon &icon)
1954{
1955 if (s.version() >= QDataStream::Qt_4_3) {
1956 icon = QIcon();
1957 QString key;
1958 s >> key;
1959 if (key == "QPixmapIconEngine"_L1) {
1960 icon.d = new QIconPrivate(new QPixmapIconEngine);
1961 icon.d->engine->read(s);
1962 } else if (key == "QIconLoaderEngine"_L1 || key == "QThemeIconEngine"_L1) {
1963 icon.d = new QIconPrivate(new QThemeIconEngine);
1964 icon.d->engine->read(s);
1965 } else {
1966 const int index = iceLoader()->indexOf(key);
1967 if (index != -1) {
1968 if (QIconEnginePlugin *factory = qobject_cast<QIconEnginePlugin*>(iceLoader()->instance(index))) {
1969 if (QIconEngine *engine= factory->create()) {
1970 icon.d = new QIconPrivate(engine);
1971 engine->read(s);
1972 } // factory
1973 } // instance
1974 } // index
1975 }
1976 } else if (s.version() == QDataStream::Qt_4_2) {
1977 icon = QIcon();
1978 int num_entries;
1979 QPixmap pm;
1981 QSize sz;
1982 uint mode;
1983 uint state;
1984
1985 s >> num_entries;
1986 for (int i=0; i < num_entries; ++i) {
1987 s >> pm;
1988 s >> fileName;
1989 s >> sz;
1990 s >> mode;
1991 s >> state;
1992 if (pm.isNull())
1993 icon.addFile(fileName, sz, QIcon::Mode(mode), QIcon::State(state));
1994 else
1995 icon.addPixmap(pm, QIcon::Mode(mode), QIcon::State(state));
1996 }
1997 } else {
1998 QPixmap pm;
1999 s >> pm;
2000 icon.addPixmap(pm);
2001 }
2002 return s;
2003}
2004
2005#endif //QT_NO_DATASTREAM
2006
2007#ifndef QT_NO_DEBUG_STREAM
2008QDebug operator<<(QDebug dbg, const QIcon &i)
2009{
2010 QDebugStateSaver saver(dbg);
2011 dbg.resetFormat();
2012 dbg.nospace();
2013 dbg << "QIcon(";
2014 if (i.isNull()) {
2015 dbg << "null";
2016 } else {
2017 if (!i.name().isEmpty())
2018 dbg << i.name() << ',';
2019 dbg << "availableSizes[normal,Off]=" << i.availableSizes()
2020 << ",cacheKey=" << Qt::showbase << Qt::hex << i.cacheKey() << Qt::dec << Qt::noshowbase;
2021 }
2022 dbg << ')';
2023 return dbg;
2024}
2025#endif
2026
2027/*!
2028 \fn DataPtr &QIcon::data_ptr()
2029 \internal
2030*/
2031
2032/*!
2033 \typedef QIcon::DataPtr
2034 \internal
2035*/
2036
2037/*!
2038 \internal
2039 \since 5.6
2040 Attempts to find a suitable @Nx file for the given \a targetDevicePixelRatio
2041 Returns the \a baseFileName if no such file was found.
2042
2043 Given base foo.png and a target dpr of 2.5, this function will look for
2044 foo@3x.png, then foo@2x, then fall back to foo.png if not found.
2045
2046 \a sourceDevicePixelRatio will be set to the value of N if the argument is
2047 not \nullptr
2048*/
2049QString qt_findAtNxFile(const QString &baseFileName, qreal targetDevicePixelRatio,
2050 qreal *sourceDevicePixelRatio)
2051{
2052 if (sourceDevicePixelRatio)
2053 *sourceDevicePixelRatio = 1;
2054 if (targetDevicePixelRatio <= 1.0)
2055 return baseFileName;
2056
2057 static bool disableNxImageLoading = !qEnvironmentVariableIsEmpty("QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING");
2058 if (disableNxImageLoading)
2059 return baseFileName;
2060
2061 int dotIndex = baseFileName.lastIndexOf(u'.');
2062 if (dotIndex == -1) { /* no dot */
2063 dotIndex = baseFileName.size(); /* append */
2064 } else if (dotIndex >= 2 && baseFileName[dotIndex - 1] == u'9'
2065 && baseFileName[dotIndex - 2] == u'.') {
2066 // If the file has a .9.* (9-patch image) extension, we must ensure that the @nx goes before it.
2067 dotIndex -= 2;
2068 }
2069
2070 QString atNxfileName = baseFileName;
2071 atNxfileName.insert(dotIndex, "@2x"_L1);
2072 // Check for @Nx, ..., @3x, @2x file versions,
2073 for (int n = qMin(qCeil(targetDevicePixelRatio), 9); n > 1; --n) {
2074 atNxfileName[dotIndex + 1] = QLatin1Char('0' + n);
2075 if (QFile::exists(atNxfileName)) {
2076 if (sourceDevicePixelRatio)
2077 *sourceDevicePixelRatio = n;
2078 return atNxfileName;
2079 }
2080 }
2081
2082 return baseFileName;
2083}
2084
2085QT_END_NAMESPACE
2086#endif //QT_NO_ICON
QIconEngine * engine
Definition qicon_p.h:45
int serialNum
Definition qicon_p.h:48
bool is_mask
Definition qicon_p.h:50
QIconPrivate(QIconEngine *e)
Definition qicon.cpp:137
int detach_no
Definition qicon_p.h:49
static void clearIconCache()
Definition qicon.cpp:145
QString fileName() const
If the currently assigned device is a QFile, or if setFileName() has been called, this function retur...
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:177
Combined button and popup list for selecting options.
QDataStream & operator>>(QDataStream &s, QKeyCombination &combination)
QDebug operator<<(QDebug dbg, const QFileInfo &fi)
static void qt_cleanup_icon_cache()
Definition qicon.cpp:132
static constexpr auto themeIconMapping
Definition qicon.cpp:1472
static int origIcoDepth(const QImage &image)
Definition qicon.cpp:433
static qint64 area(const QSize &s)
Definition qicon.cpp:196
static int nextSerialNumCounter()
Definition qicon.cpp:112
static QIconEngine * iconEngineFromSuffix(const QString &fileName, const QString &suffix)
Definition qicon.cpp:1126
QString qt_findAtNxFile(const QString &baseFileName, qreal targetDevicePixelRatio, qreal *sourceDevicePixelRatio)
Definition qicon.cpp:2049
static int findBySize(const QList< QImage > &images, const QSize &size)
Definition qicon.cpp:439
static QPixmapIconEngineEntry * bestSizeScaleMatch(const QSize &size, qreal scale, QPixmapIconEngineEntry *pa, QPixmapIconEngineEntry *pb)
Definition qicon.cpp:204
static constexpr QLatin1StringView themeIconName(QIcon::ThemeIcon icon)
Definition qicon.cpp:1628
#define QIconEngineFactoryInterface_iid
Q_GLOBAL_STATIC_WITH_ARGS(PermissionStatusHash, g_permissionStatusHash,({ { qMetaTypeId< QCameraPermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QMicrophonePermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QBluetoothPermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QContactsPermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QCalendarPermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QLocationPermission >(), Qt::PermissionStatus::Undetermined } }))