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