Coverage Report

Created: 2026-05-31 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/gui/image/qicon.cpp
Line
Count
Source
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"
9
#include "qiconengineplugin.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
33
QT_BEGIN_NAMESPACE
34
35
using namespace Qt::StringLiterals;
36
// Convenience class providing a bool read() function.
37
namespace {
38
class ImageReader
39
{
40
public:
41
    ImageReader(const QString &fileName, QSize size)
42
0
        : m_reader(fileName)
43
0
        , m_atEnd(false)
44
0
    {
45
0
        if (m_reader.supportsOption(QImageIOHandler::ScaledSize))
46
0
            m_reader.setScaledSize(size);
47
0
    }
48
49
0
    QByteArray format() const { return m_reader.format(); }
50
0
    bool supportsReadSize() const { return m_reader.supportsOption(QImageIOHandler::Size); }
51
0
    QSize size() const { return m_reader.size(); }
52
0
    bool jumpToNextImage() { return m_reader.jumpToNextImage(); }
53
0
    void jumpToImage(int index) { m_reader.jumpToImage(index); }
54
55
    bool read(QImage *image)
56
0
    {
57
0
        if (m_atEnd)
58
0
            return false;
59
0
        *image = m_reader.read();
60
0
        if (!image->size().isValid()) {
61
0
            m_atEnd = true;
62
0
            return false;
63
0
        }
64
0
        m_atEnd = !m_reader.jumpToNextImage();
65
0
        return true;
66
0
    }
67
68
private:
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
107
static int nextSerialNumCounter()
108
0
{
109
0
    Q_CONSTINIT static QBasicAtomicInt serial = Q_BASIC_ATOMIC_INITIALIZER(0);
110
0
    return 1 + serial.fetchAndAddRelaxed(1);
111
0
}
112
113
static void qt_cleanup_icon_cache();
114
namespace {
115
    struct IconCache : public QCache<QString, QIcon>
116
    {
117
        IconCache()
118
0
        {
119
            // ### note: won't readd if QApplication is re-created!
120
0
            qAddPostRoutine(qt_cleanup_icon_cache);
121
0
        }
122
    };
123
}
124
125
Q_GLOBAL_STATIC(IconCache, qtIconCache)
126
127
static void qt_cleanup_icon_cache()
128
0
{
129
0
    qtIconCache()->clear();
130
0
}
131
132
QIconPrivate::QIconPrivate(QIconEngine *e)
133
0
    : engine(e), ref(1),
134
0
      serialNum(nextSerialNumCounter()),
135
0
    detach_no(0),
136
0
    is_mask(false)
137
0
{
138
0
}
139
140
void QIconPrivate::clearIconCache()
141
0
{
142
0
    qt_cleanup_icon_cache();
143
0
}
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
*/
156
qreal QIconPrivate::pixmapDevicePixelRatio(qreal displayDevicePixelRatio, const QSize &requestedSize, const QSize &actualSize)
157
0
{
158
0
    QSize targetSize = requestedSize * displayDevicePixelRatio;
159
0
    if ((actualSize.width() == targetSize.width() && actualSize.height() <= targetSize.height()) ||
160
0
        (actualSize.width() <= targetSize.width() && actualSize.height() == targetSize.height())) {
161
        // Correctly scaled for dpr, just having different aspect ratio
162
0
        return displayDevicePixelRatio;
163
0
    }
164
0
    qreal scale = 0.5 * (qreal(actualSize.width()) / qreal(targetSize.width()) +
165
0
                         qreal(actualSize.height()) / qreal(targetSize.height()));
166
0
    qreal dpr = qMax(qreal(1.0), displayDevicePixelRatio * scale);
167
0
    return qRound(dpr * 100) / 100.0;
168
0
}
169
170
QPixmapIconEngine::QPixmapIconEngine()
171
0
{
172
0
}
173
174
QPixmapIconEngine::QPixmapIconEngine(const QPixmapIconEngine &other)
175
0
    : QIconEngine(other), pixmaps(other.pixmaps)
176
0
{
177
0
}
178
179
QPixmapIconEngine::~QPixmapIconEngine()
180
0
{
181
0
}
182
183
void QPixmapIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
184
0
{
185
0
    auto paintDevice = painter->device();
186
0
    qreal dpr = paintDevice ? paintDevice->devicePixelRatio() : qApp->devicePixelRatio();
187
0
    QPixmap px = scaledPixmap(rect.size(), mode, state, dpr);
188
0
    painter->drawPixmap(rect, px);
189
0
}
190
191
0
static 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.)
199
static QPixmapIconEngineEntry *bestSizeScaleMatch(const QSize &size, qreal scale, QPixmapIconEngineEntry *pa, QPixmapIconEngineEntry *pb)
200
0
{
201
0
    const auto scaleA = pa->pixmap.devicePixelRatio();
202
0
    const auto scaleB = pb->pixmap.devicePixelRatio();
203
    // scale: we can only differentiate on scale if the scale differs
204
0
    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
0
        qreal ascore = scaleA - scale;
210
0
        qreal bscore = scaleB - scale;
211
212
        // always prefer positive scores to prevent upscaling
213
0
        if ((ascore < 0) != (bscore < 0))
214
0
            return bscore < 0 ? pa : pb;
215
        // Take the one closest to 0
216
0
        return (qAbs(ascore) < qAbs(bscore)) ? pa : pb;
217
0
    }
218
219
0
    qint64 s = area(size * scale);
220
0
    if (pa->size == QSize() && pa->pixmap.isNull()) {
221
0
        pa->pixmap = QPixmap(pa->fileName);
222
0
        pa->size = pa->pixmap.size();
223
0
    }
224
0
    qint64 a = area(pa->size);
225
0
    if (pb->size == QSize() && pb->pixmap.isNull()) {
226
0
        pb->pixmap = QPixmap(pb->fileName);
227
0
        pb->size = pb->pixmap.size();
228
0
    }
229
0
    qint64 b = area(pb->size);
230
0
    qint64 res = a;
231
0
    if (qMin(a,b) >= s)
232
0
        res = qMin(a,b);
233
0
    else
234
0
        res = qMax(a,b);
235
0
    if (res == a)
236
0
        return pa;
237
0
    return pb;
238
0
}
239
240
QPixmapIconEngineEntry *QPixmapIconEngine::tryMatch(const QSize &size, qreal scale, QIcon::Mode mode, QIcon::State state)
241
0
{
242
0
    QPixmapIconEngineEntry *pe = nullptr;
243
0
    for (auto &entry : pixmaps) {
244
0
        if (entry.mode == mode && entry.state == state) {
245
0
            if (pe)
246
0
                pe = bestSizeScaleMatch(size, scale, &entry, pe);
247
0
            else
248
0
                pe = &entry;
249
0
        }
250
0
    }
251
0
    return pe;
252
0
}
253
254
255
QPixmapIconEngineEntry *QPixmapIconEngine::bestMatch(const QSize &size, qreal scale, QIcon::Mode mode, QIcon::State state)
256
0
{
257
0
    QPixmapIconEngineEntry *pe = tryMatch(size, scale, mode, state);
258
0
    while (!pe){
259
0
        QIcon::State oppositeState = (state == QIcon::On) ? QIcon::Off : QIcon::On;
260
0
        if (mode == QIcon::Disabled || mode == QIcon::Selected) {
261
0
            QIcon::Mode oppositeMode = (mode == QIcon::Disabled) ? QIcon::Selected : QIcon::Disabled;
262
0
            if ((pe = tryMatch(size, scale, QIcon::Normal, state)))
263
0
                break;
264
0
            if ((pe = tryMatch(size, scale, QIcon::Active, state)))
265
0
                break;
266
0
            if ((pe = tryMatch(size, scale, mode, oppositeState)))
267
0
                break;
268
0
            if ((pe = tryMatch(size, scale, QIcon::Normal, oppositeState)))
269
0
                break;
270
0
            if ((pe = tryMatch(size, scale, QIcon::Active, oppositeState)))
271
0
                break;
272
0
            if ((pe = tryMatch(size, scale, oppositeMode, state)))
273
0
                break;
274
0
            if ((pe = tryMatch(size, scale, oppositeMode, oppositeState)))
275
0
                break;
276
0
        } else {
277
0
            QIcon::Mode oppositeMode = (mode == QIcon::Normal) ? QIcon::Active : QIcon::Normal;
278
0
            if ((pe = tryMatch(size, scale, oppositeMode, state)))
279
0
                break;
280
0
            if ((pe = tryMatch(size, scale, mode, oppositeState)))
281
0
                break;
282
0
            if ((pe = tryMatch(size, scale, oppositeMode, oppositeState)))
283
0
                break;
284
0
            if ((pe = tryMatch(size, scale, QIcon::Disabled, state)))
285
0
                break;
286
0
            if ((pe = tryMatch(size, scale, QIcon::Selected, state)))
287
0
                break;
288
0
            if ((pe = tryMatch(size, scale, QIcon::Disabled, oppositeState)))
289
0
                break;
290
0
            if ((pe = tryMatch(size, scale, QIcon::Selected, oppositeState)))
291
0
                break;
292
0
        }
293
294
0
        if (!pe)
295
0
            return pe;
296
0
    }
297
298
0
    if (pe->pixmap.isNull()) {
299
        // delay-load the image
300
0
        QImage image, prevImage;
301
0
        const QSize realSize = size * scale;
302
0
        ImageReader imageReader(pe->fileName, realSize);
303
0
        bool fittingImageFound = false;
304
0
        if (imageReader.supportsReadSize()) {
305
            // find the image with the best size without loading the entire image
306
0
            do {
307
0
                fittingImageFound = imageReader.size() == realSize;
308
0
            } while (!fittingImageFound && imageReader.jumpToNextImage());
309
0
        }
310
0
        if (!fittingImageFound) {
311
0
            imageReader.jumpToImage(0);
312
0
            while (imageReader.read(&image) && image.size() != realSize)
313
0
                prevImage = image;
314
0
            if (image.isNull())
315
0
                image = prevImage;
316
0
        } else {
317
0
            imageReader.read(&image);
318
0
        }
319
0
        if (!image.isNull()) {
320
0
            pe->pixmap.convertFromImage(image);
321
0
            if (!pe->pixmap.isNull()) {
322
0
                pe->size = pe->pixmap.size();
323
0
                pe->pixmap.setDevicePixelRatio(scale);
324
0
            }
325
0
        }
326
0
        if (!pe->size.isValid()) {
327
0
            removePixmapEntry(pe);
328
0
            pe = nullptr;
329
0
        }
330
0
    }
331
332
0
    return pe;
333
0
}
334
335
QPixmap QPixmapIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
336
0
{
337
0
    return scaledPixmap(size, mode, state, 1.0);
338
0
}
339
340
QPixmap QPixmapIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
341
0
{
342
0
    QPixmap pm;
343
0
    QPixmapIconEngineEntry *pe = bestMatch(size, scale, mode, state);
344
0
    if (pe)
345
0
        pm = pe->pixmap;
346
0
    else
347
0
        return pm;
348
349
0
    if (pm.isNull()) {
350
0
        removePixmapEntry(pe);
351
0
        if (pixmaps.isEmpty())
352
0
            return pm;
353
0
        return scaledPixmap(size, mode, state, scale);
354
0
    }
355
356
0
    const auto actualSize = adjustSize(size * scale, pm.size());
357
0
    const auto calculatedDpr = QIconPrivate::pixmapDevicePixelRatio(scale, size, actualSize);
358
0
    QString key = "qt_"_L1
359
0
                  % HexString<quint64>(pm.cacheKey())
360
0
                  % HexString<quint8>(pe->mode)
361
0
                  % HexString<quint64>(QGuiApplication::palette().cacheKey())
362
0
                  % HexString<uint>(actualSize.width())
363
0
                  % HexString<uint>(actualSize.height())
364
0
                  % HexString<quint16>(qRound(calculatedDpr * 1000));
365
366
0
    if (mode == QIcon::Active) {
367
0
        if (QPixmapCache::find(key % HexString<quint8>(mode), &pm))
368
0
            return pm; // horray
369
0
        if (QPixmapCache::find(key % HexString<quint8>(QIcon::Normal), &pm)) {
370
0
            QPixmap active = pm;
371
0
            if (QGuiApplication *guiApp = qobject_cast<QGuiApplication *>(qApp))
372
0
                active = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(guiApp))->applyQIconStyleHelper(QIcon::Active, pm);
373
0
            if (pm.cacheKey() == active.cacheKey())
374
0
                return pm;
375
0
        }
376
0
    }
377
378
0
    if (!QPixmapCache::find(key % HexString<quint8>(mode), &pm)) {
379
0
        if (pm.size() != actualSize)
380
0
            pm = pm.scaled(actualSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
381
0
        if (pe->mode != mode && mode != QIcon::Normal) {
382
0
            QPixmap generated = pm;
383
0
            if (QGuiApplication *guiApp = qobject_cast<QGuiApplication *>(qApp))
384
0
                generated = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(guiApp))->applyQIconStyleHelper(mode, pm);
385
0
            if (!generated.isNull())
386
0
                pm = generated;
387
0
        }
388
0
        pm.setDevicePixelRatio(calculatedDpr);
389
0
        QPixmapCache::insert(key % HexString<quint8>(mode), pm);
390
0
    }
391
0
    return pm;
392
0
}
393
394
QSize QPixmapIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state)
395
0
{
396
0
    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
0
    qreal scale = 1;
402
403
0
    if (QPixmapIconEngineEntry *pe = bestMatch(size, scale, mode, state))
404
0
        actualSize = pe->size;
405
406
0
    return adjustSize(size, actualSize);
407
0
}
408
409
QList<QSize> QPixmapIconEngine::availableSizes(QIcon::Mode mode, QIcon::State state)
410
0
{
411
0
    QList<QSize> sizes;
412
0
    for (QPixmapIconEngineEntry &pe : pixmaps) {
413
0
        if (pe.mode != mode || pe.state != state)
414
0
            continue;
415
0
        if (pe.size.isEmpty() && pe.pixmap.isNull()) {
416
0
            pe.pixmap = QPixmap(pe.fileName);
417
0
            pe.size = pe.pixmap.size();
418
0
        }
419
0
        if (!pe.size.isEmpty() && !sizes.contains(pe.size))
420
0
            sizes.push_back(pe.size);
421
0
    }
422
0
    return sizes;
423
0
}
424
425
void QPixmapIconEngine::addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state)
426
0
{
427
0
    if (!pixmap.isNull()) {
428
0
        QPixmapIconEngineEntry *pe = tryMatch(pixmap.size() / pixmap.devicePixelRatio(),
429
0
                                              pixmap.devicePixelRatio(), mode, state);
430
0
        if (pe && pe->size == pixmap.size() && pe->pixmap.devicePixelRatio() == pixmap.devicePixelRatio()) {
431
0
            pe->pixmap = pixmap;
432
0
            pe->fileName.clear();
433
0
        } else {
434
0
            pixmaps += QPixmapIconEngineEntry(pixmap, mode, state);
435
0
        }
436
0
    }
437
0
}
438
439
// Read out original image depth as set by ICOReader
440
static inline int origIcoDepth(const QImage &image)
441
0
{
442
0
    const QString s = image.text(QStringLiteral("_q_icoOrigDepth"));
443
0
    return s.isEmpty() ? 32 : s.toInt();
444
0
}
445
446
static inline int findBySize(const QList<QImage> &images, const QSize &size)
447
0
{
448
0
    for (qsizetype i = 0; i < images.size(); ++i) {
449
0
        if (images.at(i).size() == size)
450
0
            return i;
451
0
    }
452
0
    return -1;
453
0
}
454
455
void QPixmapIconEngine::addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state)
456
0
{
457
0
    if (fileName.isEmpty())
458
0
        return;
459
0
    const QString abs = fileName.startsWith(u':') ? fileName : QFileInfo(fileName).absoluteFilePath();
460
0
    const bool ignoreSize = !size.isValid();
461
0
    ImageReader imageReader(abs, size);
462
0
    const QByteArray format = imageReader.format();
463
0
    if (format.isEmpty()) // Device failed to open or unsupported format.
464
0
        return;
465
0
    QImage image;
466
0
    if (format != "ico") {
467
0
        if (ignoreSize) { // No size specified: Add all images.
468
0
            if (imageReader.supportsReadSize()) {
469
0
                do {
470
0
                    pixmaps += QPixmapIconEngineEntry(abs, imageReader.size(), mode, state);
471
0
                } while (imageReader.jumpToNextImage());
472
0
            } else {
473
0
                while (imageReader.read(&image))
474
0
                    pixmaps += QPixmapIconEngineEntry(abs, image, mode, state);
475
0
            }
476
0
        } else {
477
0
            pixmaps += QPixmapIconEngineEntry(abs, size, mode, state);
478
0
        }
479
0
        return;
480
0
    }
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
0
    QList<QImage> icoImages;
486
0
    while (imageReader.read(&image)) {
487
0
        if (ignoreSize || image.size() == size) {
488
0
            const int position = findBySize(icoImages, image.size());
489
0
            if (position >= 0) { // Higher quality available? -> replace.
490
0
                if (origIcoDepth(image) > origIcoDepth(icoImages.at(position)))
491
0
                    icoImages[position] = image;
492
0
            } else {
493
0
                icoImages.append(image);
494
0
            }
495
0
        }
496
0
    }
497
0
    for (const QImage &i : std::as_const(icoImages))
498
0
        pixmaps += QPixmapIconEngineEntry(abs, i, mode, state);
499
0
    if (icoImages.isEmpty() && !ignoreSize) // Add placeholder with the filename and empty pixmap for the size.
500
0
        pixmaps += QPixmapIconEngineEntry(abs, size, mode, state);
501
0
}
502
503
bool QPixmapIconEngine::isNull()
504
0
{
505
0
    return pixmaps.isEmpty();
506
0
}
507
508
QString QPixmapIconEngine::key() const
509
0
{
510
0
    return "QPixmapIconEngine"_L1;
511
0
}
512
513
QIconEngine *QPixmapIconEngine::clone() const
514
0
{
515
0
    return new QPixmapIconEngine(*this);
516
0
}
517
518
bool QPixmapIconEngine::read(QDataStream &in)
519
0
{
520
0
    int num_entries;
521
0
    QPixmap pm;
522
0
    QString fileName;
523
0
    QSize sz;
524
0
    uint mode;
525
0
    uint state;
526
527
0
    in >> num_entries;
528
0
    for (int i=0; i < num_entries; ++i) {
529
0
        if (in.atEnd()) {
530
0
            pixmaps.clear();
531
0
            return false;
532
0
        }
533
0
        in >> pm;
534
0
        in >> fileName;
535
0
        in >> sz;
536
0
        in >> mode;
537
0
        in >> state;
538
0
        if (pm.isNull()) {
539
0
            addFile(fileName, sz, QIcon::Mode(mode), QIcon::State(state));
540
0
        } else {
541
0
            QPixmapIconEngineEntry pe(fileName, sz, QIcon::Mode(mode), QIcon::State(state));
542
0
            pe.pixmap = pm;
543
0
            pixmaps += pe;
544
0
        }
545
0
    }
546
0
    return true;
547
0
}
548
549
bool QPixmapIconEngine::write(QDataStream &out) const
550
0
{
551
0
    int num_entries = pixmaps.size();
552
0
    out << num_entries;
553
0
    for (int i=0; i < num_entries; ++i) {
554
0
        if (pixmaps.at(i).pixmap.isNull())
555
0
            out << QPixmap(pixmaps.at(i).fileName);
556
0
        else
557
0
            out << pixmaps.at(i).pixmap;
558
0
        out << pixmaps.at(i).fileName;
559
0
        out << pixmaps.at(i).size;
560
0
        out << (uint) pixmaps.at(i).mode;
561
0
        out << (uint) pixmaps.at(i).state;
562
0
    }
563
0
    return true;
564
0
}
565
566
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, iceLoader,
567
    (QIconEngineFactoryInterface_iid, "/iconengines"_L1, Qt::CaseInsensitive))
568
569
QFactoryLoader *qt_iconEngineFactoryLoader()
570
0
{
571
0
    return iceLoader();
572
0
}
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
*/
758
QIcon::QIcon() noexcept
759
144k
    : d(nullptr)
760
144k
{
761
144k
}
762
763
/*!
764
  Constructs an icon from a \a pixmap.
765
 */
766
QIcon::QIcon(const QPixmap &pixmap)
767
0
    :d(nullptr)
768
0
{
769
0
    addPixmap(pixmap);
770
0
}
771
772
/*!
773
  Constructs a copy of \a other. This is very fast.
774
*/
775
QIcon::QIcon(const QIcon &other)
776
0
    :d(other.d)
777
0
{
778
0
    if (d)
779
0
        d->ref.ref();
780
0
}
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
*/
807
QIcon::QIcon(const QString &fileName)
808
0
    : d(nullptr)
809
0
{
810
0
    addFile(fileName);
811
0
}
812
813
814
/*!
815
    Creates an icon with a specific icon \a engine. The icon takes
816
    ownership of the engine.
817
*/
818
QIcon::QIcon(QIconEngine *engine)
819
0
    :d(new QIconPrivate(engine))
820
0
{
821
0
}
822
823
/*!
824
    Destroys the icon.
825
*/
826
QIcon::~QIcon()
827
144k
{
828
144k
    if (d && !d->ref.deref())
829
0
        delete d;
830
144k
}
831
832
/*!
833
    Assigns the \a other icon to this icon and returns a reference to
834
    this icon.
835
*/
836
QIcon &QIcon::operator=(const QIcon &other)
837
0
{
838
0
    if (other.d)
839
0
        other.d->ref.ref();
840
0
    if (d && !d->ref.deref())
841
0
        delete d;
842
0
    d = other.d;
843
0
    return *this;
844
0
}
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
*/
862
QIcon::operator QVariant() const
863
0
{
864
0
    return QVariant::fromValue(*this);
865
0
}
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
*/
879
qint64 QIcon::cacheKey() const
880
0
{
881
0
    if (!d)
882
0
        return 0;
883
0
    return (((qint64) d->serialNum) << 32) | ((qint64) (d->detach_no));
884
0
}
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
*/
894
QPixmap QIcon::pixmap(const QSize &size, Mode mode, State state) const
895
0
{
896
0
    if (!d)
897
0
        return QPixmap();
898
0
    const qreal dpr = -1; // don't know target dpr
899
0
    return pixmap(size, dpr, mode, state);
900
0
}
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
*/
939
QPixmap QIcon::pixmap(const QSize &size, qreal devicePixelRatio, Mode mode, State state) const
940
0
{
941
0
    if (!d)
942
0
        return QPixmap();
943
944
    // Use the global devicePixelRatio if the caller does not know the target dpr
945
0
    if (devicePixelRatio == -1)
946
0
        devicePixelRatio = qApp->devicePixelRatio();
947
948
0
    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
0
    pixmap.setDevicePixelRatio(d->pixmapDevicePixelRatio(devicePixelRatio, size, pixmap.size()));
953
0
    return pixmap;
954
0
}
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
971
QPixmap QIcon::pixmap(QWindow *window, const QSize &size, Mode mode, State state) const
972
0
{
973
0
    if (!d)
974
0
        return QPixmap();
975
976
0
    qreal devicePixelRatio = window ? window->devicePixelRatio() : qApp->devicePixelRatio();
977
0
    return pixmap(size, devicePixelRatio, mode, state);
978
0
}
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
*/
989
QSize QIcon::actualSize(const QSize &size, Mode mode, State state) const
990
0
{
991
0
    if (!d)
992
0
        return QSize();
993
994
0
    const qreal devicePixelRatio = qApp->devicePixelRatio();
995
996
    // Handle the simple normal-dpi case:
997
0
    if (!(devicePixelRatio > 1.0))
998
0
        return d->engine->actualSize(size, mode, state);
999
1000
0
    const QSize actualSize = d->engine->actualSize(size * devicePixelRatio, mode, state);
1001
0
    return actualSize / d->pixmapDevicePixelRatio(devicePixelRatio, size, actualSize);
1002
0
}
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
1018
QSize QIcon::actualSize(QWindow *window, const QSize &size, Mode mode, State state) const
1019
0
{
1020
0
    if (!d)
1021
0
        return QSize();
1022
1023
0
    qreal devicePixelRatio = window ? window->devicePixelRatio() : qApp->devicePixelRatio();
1024
1025
    // Handle the simple normal-dpi case:
1026
0
    if (!(devicePixelRatio > 1.0))
1027
0
        return d->engine->actualSize(size, mode, state);
1028
1029
0
    QSize actualSize = d->engine->actualSize(size * devicePixelRatio, mode, state);
1030
0
    return actualSize / d->pixmapDevicePixelRatio(devicePixelRatio, size, actualSize);
1031
0
}
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
*/
1040
void QIcon::paint(QPainter *painter, const QRect &rect, Qt::Alignment alignment, Mode mode, State state) const
1041
0
{
1042
0
    if (!d || !painter)
1043
0
        return;
1044
1045
    // Copy of QStyle::alignedRect
1046
0
    const QSize size = d->engine->actualSize(rect.size(), mode, state);
1047
0
    alignment = QGuiApplicationPrivate::visualAlignment(painter->layoutDirection(), alignment);
1048
0
    int x = rect.x();
1049
0
    int y = rect.y();
1050
0
    int w = size.width();
1051
0
    int h = size.height();
1052
0
    if ((alignment & Qt::AlignVCenter) == Qt::AlignVCenter)
1053
0
        y += rect.size().height()/2 - h/2;
1054
0
    else if ((alignment & Qt::AlignBottom) == Qt::AlignBottom)
1055
0
        y += rect.size().height() - h;
1056
0
    if ((alignment & Qt::AlignRight) == Qt::AlignRight)
1057
0
        x += rect.size().width() - w;
1058
0
    else if ((alignment & Qt::AlignHCenter) == Qt::AlignHCenter)
1059
0
        x += rect.size().width()/2 - w/2;
1060
0
    QRect alignedRect(x, y, w, h);
1061
1062
0
    d->engine->paint(painter, alignedRect, mode, state);
1063
0
}
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
*/
1082
bool QIcon::isNull() const
1083
0
{
1084
0
    return !d || d->engine->isNull();
1085
0
}
1086
1087
/*!\internal
1088
 */
1089
bool QIcon::isDetached() const
1090
0
{
1091
0
    return !d || d->ref.loadRelaxed() == 1;
1092
0
}
1093
1094
/*! \internal
1095
 */
1096
void QIcon::detach()
1097
0
{
1098
0
    if (d) {
1099
0
        if (d->engine->isNull()) {
1100
0
            if (!d->ref.deref())
1101
0
                delete d;
1102
0
            d = nullptr;
1103
0
            return;
1104
0
        } else if (d->ref.loadRelaxed() != 1) {
1105
0
            QIconPrivate *x = new QIconPrivate(d->engine->clone());
1106
0
            if (!d->ref.deref())
1107
0
                delete d;
1108
0
            d = x;
1109
0
        }
1110
0
        ++d->detach_no;
1111
0
    }
1112
0
}
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
*/
1123
void QIcon::addPixmap(const QPixmap &pixmap, Mode mode, State state)
1124
0
{
1125
0
    if (pixmap.isNull())
1126
0
        return;
1127
0
    detach();
1128
0
    if (!d)
1129
0
        d = new QIconPrivate(new QPixmapIconEngine);
1130
0
    d->engine->addPixmap(pixmap, mode, state);
1131
0
}
1132
1133
static QIconEngine *iconEngineFromSuffix(const QString &fileName, const QString &suffix)
1134
0
{
1135
0
    if (!suffix.isEmpty()) {
1136
0
        const int index = iceLoader()->indexOf(suffix);
1137
0
        if (index != -1) {
1138
0
            if (QIconEnginePlugin *factory = qobject_cast<QIconEnginePlugin*>(iceLoader()->instance(index))) {
1139
0
                return factory->create(fileName);
1140
0
            }
1141
0
        }
1142
0
    }
1143
0
    return nullptr;
1144
0
}
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
 */
1176
void QIcon::addFile(const QString &fileName, const QSize &size, Mode mode, State state)
1177
0
{
1178
0
    if (fileName.isEmpty())
1179
0
        return;
1180
0
    detach();
1181
0
    bool alreadyAdded = false;
1182
0
    if (!d) {
1183
1184
0
        QFileInfo info(fileName);
1185
0
        QString suffix = info.suffix();
1186
0
#if QT_CONFIG(mimetype)
1187
0
        if (suffix.isEmpty())
1188
0
            suffix = QMimeDatabase().mimeTypeForFile(info).preferredSuffix(); // determination from contents
1189
0
#endif // mimetype
1190
0
        QIconEngine *engine = iconEngineFromSuffix(fileName, suffix);
1191
0
        if (engine)
1192
0
            alreadyAdded = !engine->isNull();
1193
0
        d = new QIconPrivate(engine ? engine : new QPixmapIconEngine);
1194
0
    }
1195
0
    if (!alreadyAdded)
1196
0
        d->engine->addFile(fileName, size, mode, state);
1197
1198
0
    if (d->engine->key() == "svg"_L1)   // not needed and also not supported
1199
0
        return;
1200
1201
    // Check if a "@Nx" file exists and add it.
1202
0
    QVarLengthArray<int, 4> devicePixelRatios;
1203
0
    const auto screens = qApp->screens();
1204
0
    for (const auto *screen : screens) {
1205
0
        const auto dpr = qCeil(screen->devicePixelRatio()); // qt_findAtNxFile only supports integer values
1206
0
        if (dpr >= 1 && !devicePixelRatios.contains(dpr))
1207
0
            devicePixelRatios.push_back(dpr);
1208
0
    }
1209
0
    std::sort(devicePixelRatios.begin(), devicePixelRatios.end(), std::greater<int>());
1210
0
    qreal sourceDevicePixelRatio = std::numeric_limits<qreal>::max();
1211
0
    for (const auto dpr : std::as_const(devicePixelRatios)) {
1212
0
        if (dpr >= sourceDevicePixelRatio)
1213
0
            continue;
1214
0
        const QString atNxFileName = qt_findAtNxFile(fileName, dpr, &sourceDevicePixelRatio);
1215
0
        if (atNxFileName != fileName)
1216
0
            d->engine->addFile(atNxFileName, size, mode, state);
1217
0
    }
1218
0
}
1219
1220
/*!
1221
    Returns a list of available icon sizes for the specified \a mode and
1222
    \a state.
1223
*/
1224
QList<QSize> QIcon::availableSizes(Mode mode, State state) const
1225
0
{
1226
0
    if (!d || !d->engine)
1227
0
        return QList<QSize>();
1228
0
    return d->engine->availableSizes(mode, state);
1229
0
}
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
*/
1239
QString QIcon::name() const
1240
0
{
1241
0
    if (!d || !d->engine)
1242
0
        return QString();
1243
0
    return d->engine->iconName();
1244
0
}
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
*/
1254
void QIcon::setThemeSearchPaths(const QStringList &paths)
1255
0
{
1256
0
    QIconLoader::instance()->setThemeSearchPath(paths);
1257
0
}
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
*/
1267
QStringList QIcon::themeSearchPaths()
1268
0
{
1269
0
    return QIconLoader::instance()->themeSearchPaths();
1270
0
}
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
*/
1287
QStringList QIcon::fallbackSearchPaths()
1288
0
{
1289
0
    return QIconLoader::instance()->fallbackSearchPaths();
1290
0
}
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
*/
1308
void QIcon::setFallbackSearchPaths(const QStringList &paths)
1309
0
{
1310
0
    QIconLoader::instance()->setFallbackSearchPaths(paths);
1311
0
}
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
*/
1329
void QIcon::setThemeName(const QString &name)
1330
0
{
1331
0
    QIconLoader::instance()->setThemeName(name);
1332
0
}
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
*/
1347
QString QIcon::themeName()
1348
0
{
1349
0
    return QIconLoader::instance()->themeName();
1350
0
}
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
*/
1366
QString QIcon::fallbackThemeName()
1367
0
{
1368
0
    return QIconLoader::instance()->fallbackThemeName();
1369
0
}
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
*/
1389
void QIcon::setFallbackThemeName(const QString &name)
1390
0
{
1391
0
    QIconLoader::instance()->setFallbackThemeName(name);
1392
0
}
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
*/
1415
QIcon QIcon::fromTheme(const QString &name)
1416
0
{
1417
1418
0
    if (QIcon *cachedIcon = qtIconCache()->object(name))
1419
0
        return *cachedIcon;
1420
1421
0
    if (QDir::isAbsolutePath(name))
1422
0
        return QIcon(name);
1423
1424
0
    QIcon icon(new QThemeIconEngine(name));
1425
0
    qtIconCache()->insert(name, new QIcon(icon));
1426
0
    return icon;
1427
0
}
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
*/
1453
QIcon QIcon::fromTheme(const QString &name, const QIcon &fallback)
1454
0
{
1455
0
    QIcon icon = fromTheme(name);
1456
1457
0
    if (icon.isNull() || icon.availableSizes().isEmpty())
1458
0
        return fallback;
1459
1460
0
    return icon;
1461
0
}
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
*/
1470
bool QIcon::hasThemeIcon(const QString &name)
1471
0
{
1472
0
    QIcon icon = fromTheme(name);
1473
1474
0
    return icon.name() == name;
1475
0
}
1476
1477
static 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
);
1631
static_assert(QIcon::ThemeIcon::NThemeIcons == QIcon::ThemeIcon(themeIconMapping.count()));
1632
1633
static constexpr QLatin1StringView themeIconName(QIcon::ThemeIcon icon)
1634
0
{
1635
0
    using ThemeIconIndex = std::underlying_type_t<QIcon::ThemeIcon>;
1636
0
    const auto index = static_cast<ThemeIconIndex>(icon);
1637
0
    Q_ASSERT(index < themeIconMapping.count());
1638
0
    return QLatin1StringView(themeIconMapping.viewAt(index));
1639
0
}
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
*/
1834
bool QIcon::hasThemeIcon(QIcon::ThemeIcon icon)
1835
0
{
1836
0
    return hasThemeIcon(themeIconName(icon));
1837
0
}
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
*/
1862
QIcon QIcon::fromTheme(QIcon::ThemeIcon icon)
1863
0
{
1864
0
    return fromTheme(themeIconName(icon));
1865
0
}
1866
1867
QIcon QIcon::fromTheme(QIcon::ThemeIcon icon, const QIcon &fallback)
1868
0
{
1869
0
    return fromTheme(themeIconName(icon), fallback);
1870
0
}
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
*/
1879
void QIcon::setIsMask(bool isMask)
1880
0
{
1881
0
    if (isMask == (d && d->is_mask))
1882
0
        return;
1883
1884
0
    detach();
1885
0
    if (!d)
1886
0
        d = new QIconPrivate(new QPixmapIconEngine);
1887
0
    d->is_mask = isMask;
1888
0
}
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
*/
1899
bool QIcon::isMask() const
1900
0
{
1901
0
    if (!d)
1902
0
        return false;
1903
0
    return d->is_mask;
1904
0
}
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
1920
QDataStream &operator<<(QDataStream &s, const QIcon &icon)
1921
0
{
1922
0
    if (s.version() >= QDataStream::Qt_4_3) {
1923
0
        if (icon.isNull()) {
1924
0
            s << QString();
1925
0
        } else {
1926
0
            s << icon.d->engine->key();
1927
0
            icon.d->engine->write(s);
1928
0
        }
1929
0
    } else if (s.version() == QDataStream::Qt_4_2) {
1930
0
        if (icon.isNull()) {
1931
0
            s << 0;
1932
0
        } else {
1933
0
            QPixmapIconEngine *engine = static_cast<QPixmapIconEngine *>(icon.d->engine);
1934
0
            int num_entries = engine->pixmaps.size();
1935
0
            s << num_entries;
1936
0
            for (int i=0; i < num_entries; ++i) {
1937
0
                s << engine->pixmaps.at(i).pixmap;
1938
0
                s << engine->pixmaps.at(i).fileName;
1939
0
                s << engine->pixmaps.at(i).size;
1940
0
                s << (uint) engine->pixmaps.at(i).mode;
1941
0
                s << (uint) engine->pixmaps.at(i).state;
1942
0
            }
1943
0
        }
1944
0
    } else {
1945
0
        s << QPixmap(icon.pixmap(22,22));
1946
0
    }
1947
0
    return s;
1948
0
}
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
1958
QDataStream &operator>>(QDataStream &s, QIcon &icon)
1959
0
{
1960
0
    if (s.version() >= QDataStream::Qt_4_3) {
1961
0
        icon = QIcon();
1962
0
        QString key;
1963
0
        s >> key;
1964
0
        if (key == "QPixmapIconEngine"_L1) {
1965
0
            icon.d = new QIconPrivate(new QPixmapIconEngine);
1966
0
            icon.d->engine->read(s);
1967
0
        } else if (key == "QIconLoaderEngine"_L1 || key == "QThemeIconEngine"_L1) {
1968
0
            icon.d = new QIconPrivate(new QThemeIconEngine);
1969
0
            icon.d->engine->read(s);
1970
0
        } else {
1971
0
            const int index = iceLoader()->indexOf(key);
1972
0
            if (index != -1) {
1973
0
                if (QIconEnginePlugin *factory = qobject_cast<QIconEnginePlugin*>(iceLoader()->instance(index))) {
1974
0
                    if (QIconEngine *engine= factory->create()) {
1975
0
                        icon.d = new QIconPrivate(engine);
1976
0
                        engine->read(s);
1977
0
                    } // factory
1978
0
                } // instance
1979
0
            } // index
1980
0
        }
1981
0
    } else if (s.version() == QDataStream::Qt_4_2) {
1982
0
        icon = QIcon();
1983
0
        int num_entries;
1984
0
        QPixmap pm;
1985
0
        QString fileName;
1986
0
        QSize sz;
1987
0
        uint mode;
1988
0
        uint state;
1989
1990
0
        s >> num_entries;
1991
0
        for (int i=0; i < num_entries; ++i) {
1992
0
            s >> pm;
1993
0
            s >> fileName;
1994
0
            s >> sz;
1995
0
            s >> mode;
1996
0
            s >> state;
1997
0
            if (pm.isNull())
1998
0
                icon.addFile(fileName, sz, QIcon::Mode(mode), QIcon::State(state));
1999
0
            else
2000
0
                icon.addPixmap(pm, QIcon::Mode(mode), QIcon::State(state));
2001
0
        }
2002
0
    } else {
2003
0
        QPixmap pm;
2004
0
        s >> pm;
2005
0
        icon.addPixmap(pm);
2006
0
    }
2007
0
    return s;
2008
0
}
2009
2010
#endif //QT_NO_DATASTREAM
2011
2012
#ifndef QT_NO_DEBUG_STREAM
2013
QDebug operator<<(QDebug dbg, const QIcon &i)
2014
0
{
2015
0
    QDebugStateSaver saver(dbg);
2016
0
    dbg.resetFormat();
2017
0
    dbg.nospace();
2018
0
    dbg << "QIcon(";
2019
0
    if (i.isNull()) {
2020
0
        dbg << "null";
2021
0
    } else {
2022
0
        if (!i.name().isEmpty())
2023
0
            dbg << i.name() << ',';
2024
0
        dbg << "availableSizes[normal,Off]=" << i.availableSizes()
2025
0
            << ",cacheKey=" << Qt::showbase << Qt::hex << i.cacheKey() << Qt::dec << Qt::noshowbase;
2026
0
    }
2027
0
    dbg << ')';
2028
0
    return dbg;
2029
0
}
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
*/
2054
QString qt_findAtNxFile(const QString &baseFileName, qreal targetDevicePixelRatio,
2055
                        qreal *sourceDevicePixelRatio)
2056
0
{
2057
0
    if (sourceDevicePixelRatio)
2058
0
        *sourceDevicePixelRatio = 1;
2059
0
    if (targetDevicePixelRatio <= 1.0)
2060
0
        return baseFileName;
2061
2062
0
    static bool disableNxImageLoading = !qEnvironmentVariableIsEmpty("QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING");
2063
0
    if (disableNxImageLoading)
2064
0
        return baseFileName;
2065
2066
0
    int dotIndex = baseFileName.lastIndexOf(u'.');
2067
0
    if (dotIndex == -1) { /* no dot */
2068
0
        dotIndex = baseFileName.size(); /* append */
2069
0
    } else if (dotIndex >= 2 && baseFileName[dotIndex - 1] == u'9'
2070
0
        && 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
0
        dotIndex -= 2;
2073
0
    }
2074
2075
0
    QString atNxfileName = baseFileName;
2076
0
    atNxfileName.insert(dotIndex, "@2x"_L1);
2077
    // Check for @Nx, ..., @3x, @2x file versions,
2078
0
    for (int n = qMin(qCeil(targetDevicePixelRatio), 9); n > 1; --n) {
2079
0
        atNxfileName[dotIndex + 1] = QLatin1Char('0' + n);
2080
0
        if (QFile::exists(atNxfileName)) {
2081
0
            if (sourceDevicePixelRatio)
2082
0
                *sourceDevicePixelRatio = n;
2083
0
            return atNxfileName;
2084
0
        }
2085
0
    }
2086
2087
0
    return baseFileName;
2088
0
}
2089
2090
QT_END_NAMESPACE
2091
#endif //QT_NO_ICON