KIconThemes

kicontheme.cpp
1/*
2
3 kicontheme.cpp: Lowlevel icon theme handling.
4
5 This file is part of the KDE project, module kdecore.
6 SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
7 SPDX-FileCopyrightText: 2000 Antonio Larrosa <larrosa@kde.org>
8
9 SPDX-License-Identifier: LGPL-2.0-only
10*/
11
12#include "kicontheme.h"
13
14#include "debug.h"
15
16#include <KColorSchemeManager>
17#include <KConfigGroup>
18#include <KLocalizedString> // KLocalizedString::localizedFilePath. Need such functionality in, hmm, QLocale? QStandardPaths?
19#include <KSharedConfig>
20
21#include <QAction>
22#include <QCoreApplication>
23#include <QDebug>
24#include <QDir>
25#include <QFileInfo>
26#include <QMap>
27#include <QResource>
28#include <QSet>
29#include <QTimer>
30
31#include <private/qguiapplication_p.h>
32#include <qpa/qplatformtheme.h>
33
34#include <qplatformdefs.h>
35
36#include <array>
37#include <cmath>
38
39#include "config.h"
40
41Q_GLOBAL_STATIC(QString, _themeOverride)
42
43#if !USE_BreezeIcons
44
45// on Android icon theme loading works differently and is managed by code in Kirigami
46// so don't actually touch anything icon-related here
47static void initThemeHelper()
48{
49 // postpone until QGuiApplication applies initial palette
50 QTimer::singleShot(0, [] {
51 // follow the system color, construct the global manager for that
53 });
54}
55
57{
58}
59
60#else
61
62#include <BreezeIcons>
63
64// do init only once and avoid later helpers to mess with it again
65static bool initThemeUsed = false;
66
67// startup function to set theme once the app got constructed
68static void initThemeHelper()
69{
70 // make sure we add application install path to search path, for e.g. bundles on Windows
71 if (initThemeUsed) {
72 // do that similar to QCoreApplicationPrivate::appendApplicationPathToLibraryPaths() with minimal extra API use
74 path.truncate(path.lastIndexOf(QLatin1Char('/')));
75 if (const QString ourPath = path + QStringLiteral("/kiconthemes6"); QFile::exists(ourPath)) {
77 }
78 }
79
80 // Makes sure the icon theme fallback is set to breeze or one of its
81 // variants. Most of our apps use "lots" of icons that most of the times
82 // are only available with breeze, we still honour the user icon theme
83 // but if the icon is not found there, we go to breeze since it's almost
84 // sure it'll be there
86
87 // ensure lib call above did the job
88 Q_ASSERT(!QIcon::fallbackThemeName().isEmpty());
89
90 // only do further stuff if we requested it
91 if (!initThemeUsed) {
92 return;
93 }
94
95 // do nothing if we have the proper platform theme already
96 if (QGuiApplicationPrivate::platformTheme() && QGuiApplicationPrivate::platformTheme()->name() == QLatin1String("kde")) {
97 return;
98 }
99
100 // get config, with fallback to kdeglobals
101 const auto config = KSharedConfig::openConfig();
102
103 // enforce the theme configured by the user, with kdeglobals fallback
104 // if not set, use Breeze
105 const QString themeToUse = KConfigGroup(config, "Icons").readEntry("Theme", QStringLiteral("breeze"));
106
107#if QT_VERSION < QT_VERSION_CHECK(6, 8, 0)
108 // set our theme, Qt internally will still not fully use our engine and lookup
109 QIcon::setThemeName(themeToUse);
110#else
111 // use Qt API to really fully override the engine, if we set KIconEngine the Key in our plugin will
112 // enforce that our engine is used
113 // https://codereview.qt-project.org/c/qt/qtbase/+/563241
114 QIcon::setThemeName(QStringLiteral("KIconEngine"));
115#endif
116
117 // Tell KIconTheme about the theme, in case KIconLoader is used directly
118 *_themeOverride() = themeToUse;
119 qCDebug(KICONTHEMES) << "KIconTheme::initTheme() enforces the icon theme:" << themeToUse;
120
121 // postpone until QGuiApplication applies initial palette
122 QTimer::singleShot(0, [] {
123 // follow the system color, construct the global manager for that
125 });
126}
127
129{
130 // inject paths only once
131 if (!initThemeUsed) {
132 // inject our icon engine in the search path
133 // it will be used as the first found engine for a suffix will be taken
134 // this must be done before the QCoreApplication is constructed
135 const auto paths = QCoreApplication::libraryPaths();
136 for (const auto &path : paths) {
137 if (const QString ourPath = path + QStringLiteral("/kiconthemes6"); QFile::exists(ourPath)) {
139 }
140 }
141 }
142
143 // initThemeHelper will do the remaining work via Q_COREAPP_STARTUP_FUNCTION(initThemeHelper) above
144 initThemeUsed = true;
145}
146
147#endif
148
149Q_COREAPP_STARTUP_FUNCTION(initThemeHelper)
150
151class KIconThemeDir;
152class KIconThemePrivate
153{
154public:
155 QString example, screenshot;
156 bool hidden;
157 KSharedConfig::Ptr sharedConfig;
158
159 struct GroupInfo {
161 const char *name;
162 int defaultSize;
163 QList<int> availableSizes{};
164 };
165 std::array<GroupInfo, KIconLoader::LastGroup> m_iconGroups = {{
166 {KIconLoader::Desktop, "Desktop", 32},
167 {KIconLoader::Toolbar, "Toolbar", 22},
168 {KIconLoader::MainToolbar, "MainToolbar", 22},
169 {KIconLoader::Small, "Small", 16},
170 {KIconLoader::Panel, "Panel", 48},
171 {KIconLoader::Dialog, "Dialog", 32},
172 }};
173
174 int mDepth;
175 QString mDir, mName, mInternalName, mDesc;
176 QStringList mInherits;
177 QStringList mExtensions;
178 QList<KIconThemeDir *> mDirs;
179 QList<KIconThemeDir *> mScaledDirs;
180 bool followsColorScheme : 1;
181
182 /// Searches the given dirs vector for a matching icon
183 QString iconPath(const QList<KIconThemeDir *> &dirs, const QString &name, int size, qreal scale, KIconLoader::MatchType match) const;
184};
185Q_GLOBAL_STATIC(QString, _theme)
186Q_GLOBAL_STATIC(QStringList, _theme_list)
187
188/**
189 * A subdirectory in an icon theme.
190 */
191class KIconThemeDir
192{
193public:
194 KIconThemeDir(const QString &basedir, const QString &themedir, const KConfigGroup &config);
195
196 bool isValid() const
197 {
198 return mbValid;
199 }
200 QString iconPath(const QString &name) const;
201 QStringList iconList() const;
202 QString constructFileName(const QString &file) const
203 {
204 return mBaseDir + mThemeDir + QLatin1Char('/') + file;
205 }
206
207 KIconLoader::Context context() const
208 {
209 return mContext;
210 }
211 KIconLoader::Type type() const
212 {
213 return mType;
214 }
215 int size() const
216 {
217 return mSize;
218 }
219 int scale() const
220 {
221 return mScale;
222 }
223 int minSize() const
224 {
225 return mMinSize;
226 }
227 int maxSize() const
228 {
229 return mMaxSize;
230 }
231 int threshold() const
232 {
233 return mThreshold;
234 }
235
236private:
237 bool mbValid = false;
239 KIconLoader::Context mContext;
240 int mSize = 0;
241 int mScale = 1;
242 int mMinSize = 1;
243 int mMaxSize = 50;
244 int mThreshold = 2;
245
246 const QString mBaseDir;
247 const QString mThemeDir;
248};
249
250QString KIconThemePrivate::iconPath(const QList<KIconThemeDir *> &dirs, const QString &name, int size, qreal scale, KIconLoader::MatchType match) const
251{
252 QString path;
253 QString tempPath; // used to cache icon path if it exists
254
255 int delta = -INT_MAX; // current icon size delta of 'icon'
256 int dw = INT_MAX; // icon size delta of current directory
257
258 // Rather downsample than upsample
259 int integerScale = std::ceil(scale);
260
261 // Search the directory that contains the icon which matches best to the requested
262 // size. If there is no directory which matches exactly to the requested size, the
263 // following criteria get applied:
264 // - Take a directory having icons with a minimum difference to the requested size.
265 // - Prefer directories that allow a downscaling even if the difference to
266 // the requested size is bigger than a directory where an upscaling is required.
267 for (KIconThemeDir *dir : dirs) {
268 if (dir->scale() != integerScale) {
269 continue;
270 }
271
272 if (match == KIconLoader::MatchExact) {
273 if ((dir->type() == KIconLoader::Fixed) && (dir->size() != size)) {
274 continue;
275 }
276 if ((dir->type() == KIconLoader::Scalable) //
277 && ((size < dir->minSize()) || (size > dir->maxSize()))) {
278 continue;
279 }
280 if ((dir->type() == KIconLoader::Threshold) //
281 && (abs(dir->size() - size) > dir->threshold())) {
282 continue;
283 }
284 } else {
285 // dw < 0 means need to scale up to get an icon of the requested size.
286 // Upscaling should only be done if no larger icon is available.
287 if (dir->type() == KIconLoader::Fixed) {
288 dw = dir->size() - size;
289 } else if (dir->type() == KIconLoader::Scalable) {
290 if (size < dir->minSize()) {
291 dw = dir->minSize() - size;
292 } else if (size > dir->maxSize()) {
293 dw = dir->maxSize() - size;
294 } else {
295 dw = 0;
296 }
297 } else if (dir->type() == KIconLoader::Threshold) {
298 if (size < dir->size() - dir->threshold()) {
299 dw = dir->size() - dir->threshold() - size;
300 } else if (size > dir->size() + dir->threshold()) {
301 dw = dir->size() + dir->threshold() - size;
302 } else {
303 dw = 0;
304 }
305 }
306 // Usually if the delta (= 'dw') of the current directory is
307 // not smaller than the delta (= 'delta') of the currently best
308 // matching icon, this candidate can be skipped. But skipping
309 // the candidate may only be done, if this does not imply
310 // in an upscaling of the icon (it is OK to use a directory with
311 // smaller icons that what we've already found, however).
312 if ((abs(dw) >= abs(delta)) && ((dw < 0) || (delta > 0))) {
313 continue;
314 }
315
316 if (match == KIconLoader::MatchBestOrGreaterSize && dw < 0) {
317 continue;
318 }
319 }
320
321 // cache the result of iconPath() call which checks if file exists
322 tempPath = dir->iconPath(name);
323
324 if (tempPath.isEmpty()) {
325 continue;
326 }
327
328 path = tempPath;
329
330 // if we got in MatchExact that far, we find no better
331 if (match == KIconLoader::MatchExact) {
332 return path;
333 }
334 delta = dw;
335 if (delta == 0) {
336 return path; // We won't find a better match anyway
337 }
338 }
339 return path;
340}
341
342KIconTheme::KIconTheme(const QString &name, const QString &appName, const QString &basePathHint)
343 : d(new KIconThemePrivate)
344{
345 d->mInternalName = name;
346
347 QStringList themeDirs;
348
349 // Applications can have local additions to the global "locolor" and
350 // "hicolor" icon themes. For these, the _global_ theme description
351 // files are used..
352
353 /* clang-format off */
354 if (!appName.isEmpty()
355 && (name == defaultThemeName()
356 || name == QLatin1String("hicolor")
357 || name == QLatin1String("locolor"))) { /* clang-format on */
358 const QString suffix = QLatin1Char('/') + appName + QLatin1String("/icons/") + name + QLatin1Char('/');
360 for (auto &cDir : dataDirs) {
361 cDir += suffix;
362 if (QFileInfo::exists(cDir)) {
363 themeDirs += cDir;
364 }
365 }
366
367 if (!basePathHint.isEmpty()) {
368 // Checks for dir existing are done below
369 themeDirs += basePathHint + QLatin1Char('/') + name + QLatin1Char('/');
370 }
371 }
372
373 // Find the theme description file. These are either locally in the :/icons resource path or global.
374 QStringList icnlibs;
375
376 // local embedded icons have preference
377 icnlibs << QStringLiteral(":/icons");
378
379#ifdef Q_OS_ANDROID
380 // Android icon theme installed by Kirigami
381 icnlibs << QStringLiteral("assets:/qml/org/kde/kirigami");
382#endif
383
384 // global icons
386
387 // These are not in the icon spec, but e.g. GNOME puts some icons there anyway.
389
390 QString fileName;
391 QString mainSection;
392 const QString pathSuffix = QLatin1Char('/') + name + QLatin1Char('/');
393 const QLatin1String indexTheme("index.theme");
394 const QLatin1String indexDesktop("theme.desktop");
395 for (auto &iconDir : icnlibs) {
396 iconDir += pathSuffix;
397 const QFileInfo fi(iconDir);
398 if (!fi.exists() || !fi.isDir()) {
399 continue;
400 }
401 themeDirs.append(iconDir);
402
403 if (d->mDir.isEmpty()) {
404 QString possiblePath;
405 if (possiblePath = iconDir + indexTheme; QFileInfo::exists(possiblePath)) {
406 d->mDir = iconDir;
407 fileName = possiblePath;
408 mainSection = QStringLiteral("Icon Theme");
409 } else if (possiblePath = iconDir + indexDesktop; QFileInfo::exists(possiblePath)) {
410 d->mDir = iconDir;
411 fileName = possiblePath;
412 mainSection = QStringLiteral("KDE Icon Theme");
413 }
414 }
415 }
416
417 if (d->mDir.isEmpty()) {
418 qCDebug(KICONTHEMES) << "Icon theme" << name << "not found.";
419 return;
420 }
421
422 // Use KSharedConfig to avoid parsing the file many times, from each component.
423 // Need to keep a ref to it to make this useful
424 d->sharedConfig = KSharedConfig::openConfig(fileName, KConfig::SimpleConfig);
425
426 KConfigGroup cfg(d->sharedConfig, mainSection);
427 d->mName = cfg.readEntry("Name");
428 d->mDesc = cfg.readEntry("Comment");
429 d->mDepth = cfg.readEntry("DisplayDepth", 32);
430 d->mInherits = cfg.readEntry("Inherits", QStringList());
431 if (name != defaultThemeName()) {
432 for (auto &inheritedTheme : d->mInherits) {
433 if (inheritedTheme == QLatin1String("default")) {
434 inheritedTheme = defaultThemeName();
435 }
436 }
437 }
438
439 d->hidden = cfg.readEntry("Hidden", false);
440 d->followsColorScheme = cfg.readEntry("FollowsColorScheme", false);
441 d->example = cfg.readPathEntry("Example", QString());
442 d->screenshot = cfg.readPathEntry("ScreenShot", QString());
443 d->mExtensions =
444 cfg.readEntry("KDE-Extensions", QStringList{QStringLiteral(".png"), QStringLiteral(".svgz"), QStringLiteral(".svg"), QStringLiteral(".xpm")});
445
446 QSet<QString> addedDirs; // Used for avoiding duplicates.
447 const QStringList dirs = cfg.readPathEntry("Directories", QStringList()) + cfg.readPathEntry("ScaledDirectories", QStringList());
448 for (const auto &dirName : dirs) {
449 KConfigGroup cg(d->sharedConfig, dirName);
450 for (const auto &themeDir : std::as_const(themeDirs)) {
451 const QString currentDir(themeDir + dirName + QLatin1Char('/'));
452 if (!addedDirs.contains(currentDir) && QFileInfo::exists(currentDir)) {
453 addedDirs.insert(currentDir);
454 KIconThemeDir *dir = new KIconThemeDir(themeDir, dirName, cg);
455 if (dir->isValid()) {
456 if (dir->scale() > 1) {
457 d->mScaledDirs.append(dir);
458 } else {
459 d->mDirs.append(dir);
460 }
461 } else {
462 delete dir;
463 }
464 }
465 }
466 }
467
468 KConfigGroup cg(d->sharedConfig, mainSection);
469 for (auto &iconGroup : d->m_iconGroups) {
470 iconGroup.defaultSize = cg.readEntry(iconGroup.name + QLatin1String("Default"), iconGroup.defaultSize);
471 iconGroup.availableSizes = cg.readEntry(iconGroup.name + QLatin1String("Sizes"), QList<int>());
472 }
473}
474
475KIconTheme::~KIconTheme()
476{
477 qDeleteAll(d->mDirs);
478 qDeleteAll(d->mScaledDirs);
479}
480
482{
483 return d->mName;
484}
485
487{
488 return d->mInternalName;
489}
490
492{
493 return d->mDesc;
494}
495
497{
498 return d->example;
499}
500
502{
503 return d->screenshot;
504}
505
507{
508 return d->mDir;
509}
510
512{
513 return d->mInherits;
514}
515
517{
518 return !d->mDirs.isEmpty() || !d->mScaledDirs.isEmpty();
519}
520
522{
523 return d->hidden;
524}
525
527{
528 return d->mDepth;
529}
530
532{
533 if (group < 0 || group >= KIconLoader::LastGroup) {
534 qCWarning(KICONTHEMES) << "Invalid icon group:" << group << ", should be one of KIconLoader::Group";
535 return -1;
536 }
537 return d->m_iconGroups[group].defaultSize;
538}
539
541{
542 if (group < 0 || group >= KIconLoader::LastGroup) {
543 qCWarning(KICONTHEMES) << "Invalid icon group:" << group << ", should be one of KIconLoader::Group";
544 return QList<int>();
545 }
546 return d->m_iconGroups[group].availableSizes;
547}
548
549static bool isAnyOrDirContext(const KIconThemeDir *dir, KIconLoader::Context context)
550{
551 return context == KIconLoader::Any || context == dir->context();
552}
553
555{
556 QStringList result;
557 const auto listDirs = d->mDirs + d->mScaledDirs;
558 for (const auto &dir : listDirs) {
559 result.append(dir->iconList());
560 }
561 return result;
562}
563
565{
566 // Try to find exact match
567 QStringList result;
568 const QList<KIconThemeDir *> listDirs = d->mDirs + d->mScaledDirs;
569 for (const KIconThemeDir *dir : listDirs) {
570 if (!isAnyOrDirContext(dir, context)) {
571 continue;
572 }
573
574 const int dirSize = dir->size();
575 if ((dir->type() == KIconLoader::Fixed && dirSize == size) //
576 || (dir->type() == KIconLoader::Scalable && size >= dir->minSize() && size <= dir->maxSize())
577 || (dir->type() == KIconLoader::Threshold && abs(size - dirSize) < dir->threshold())) {
578 result += dir->iconList();
579 }
580 }
581
582 return result;
583}
584
586{
587 int dw;
588
589 // We want all the icons for a given context, but we prefer icons
590 // of size "size" . Note that this may (will) include duplicate icons
591 // QStringList iconlist[34]; // 33 == 48-16+1
592 QStringList iconlist[128]; // 33 == 48-16+1
593 // Usually, only the 0, 6 (22-16), 10 (32-22), 16 (48-32 or 32-16),
594 // 26 (48-22) and 32 (48-16) will be used, but who knows if someone
595 // will make icon themes with different icon sizes.
596 const auto listDirs = d->mDirs + d->mScaledDirs;
597 for (KIconThemeDir *dir : listDirs) {
598 if (!isAnyOrDirContext(dir, context)) {
599 continue;
600 }
601 dw = abs(dir->size() - size);
602 iconlist[(dw < 127) ? dw : 127] += dir->iconList();
603 }
604
605 QStringList iconlistResult;
606 for (int i = 0; i < 128; i++) {
607 iconlistResult += iconlist[i];
608 }
609
610 return iconlistResult;
611}
612
614{
615 const auto listDirs = d->mDirs + d->mScaledDirs;
616 for (KIconThemeDir *dir : listDirs) {
617 if (isAnyOrDirContext(dir, context)) {
618 return true;
619 }
620 }
621 return false;
622}
623
625{
626 return iconPathByName(iconName, size, match, 1 /*scale*/);
627}
628
629QString KIconTheme::iconPathByName(const QString &iconName, int size, KIconLoader::MatchType match, qreal scale) const
630{
631 for (const QString &current : std::as_const(d->mExtensions)) {
632 const QString path = iconPath(iconName + current, size, match, scale);
633 if (!path.isEmpty()) {
634 return path;
635 }
636 }
637 return QString();
638}
639
641{
642 return d->followsColorScheme;
643}
644
646{
647 return iconPath(name, size, match, 1 /*scale*/);
648}
649
650QString KIconTheme::iconPath(const QString &name, int size, KIconLoader::MatchType match, qreal scale) const
651{
652 // first look for a scaled image at exactly the requested size
653 QString path = d->iconPath(d->mScaledDirs, name, size, scale, KIconLoader::MatchExact);
654
655 // then look for an unscaled one but request it at larger size so it doesn't become blurry
656 if (path.isEmpty()) {
657 path = d->iconPath(d->mDirs, name, size * scale, 1, match);
658 }
659 return path;
660}
661
662// static
664{
665 // Static pointers because of unloading problems wrt DSO's.
666 if (_themeOverride && !_themeOverride->isEmpty()) {
667 *_theme() = *_themeOverride();
668 }
669 if (!_theme()->isEmpty()) {
670 return *_theme();
671 }
672
673 QString theme;
674 // Check application specific config for a theme setting.
676 theme = app_cg.readEntry("Theme", QString());
677 if (theme.isEmpty() || theme == QLatin1String("hicolor")) {
678 // No theme, try to use Qt's. A Platform plugin might have set
679 // a good theme there.
680 theme = QIcon::themeName();
681 }
682 if (theme.isEmpty() || theme == QLatin1String("hicolor")) {
683 // Still no theme, try config with kdeglobals.
685 theme = cg.readEntry("Theme", QStringLiteral("breeze"));
686 }
687 if (theme.isEmpty() || theme == QLatin1String("hicolor")) {
688 // Still no good theme, use default.
689 theme = defaultThemeName();
690 }
691 *_theme() = theme;
692 return *_theme();
693}
694
696{
697 *_themeOverride() = themeName;
698 _theme()->clear(); // ::current sets this again based on conditions
699}
700
701// static
703{
704 // Static pointer because of unloading problems wrt DSO's.
705 if (!_theme_list()->isEmpty()) {
706 return *_theme_list();
707 }
708
709 // Find the theme description file. These are either locally in the :/icons resource path or global.
710 QStringList icnlibs;
711
712 // local embedded icons have preference
713 icnlibs << QStringLiteral(":/icons");
714
715 // global icons
717
718 // These are not in the icon spec, but e.g. GNOME puts some icons there anyway.
720
721 for (const QString &iconDir : std::as_const(icnlibs)) {
722 QDir dir(iconDir);
723 const QStringList themeDirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
724 for (const auto &theme : themeDirs) {
725 if (theme.startsWith(QLatin1String("default."))) {
726 continue;
727 }
728
729 const QString prefix = iconDir + QLatin1Char('/') + theme;
730 if (!QFileInfo::exists(prefix + QLatin1String("/index.desktop")) //
731 && !QFileInfo::exists(prefix + QLatin1String("/index.theme"))) {
732 continue;
733 }
734
735 if (!KIconTheme(theme).isValid()) {
736 continue;
737 }
738
739 if (!_theme_list()->contains(theme)) {
740 _theme_list()->append(theme);
741 }
742 }
743 }
744 return *_theme_list();
745}
746
747// static
749{
750 _theme()->clear();
751 _theme_list()->clear();
752}
753
754// static
756{
757 return QStringLiteral("hicolor");
758}
759
760/*** KIconThemeDir ***/
761
762KIconThemeDir::KIconThemeDir(const QString &basedir, const QString &themedir, const KConfigGroup &config)
763 : mSize(config.readEntry("Size", 0))
764 , mScale(config.readEntry("Scale", 1))
765 , mBaseDir(basedir)
766 , mThemeDir(themedir)
767{
768 if (mSize == 0) {
769 return;
770 }
771
772 QString tmp = config.readEntry("Context", QString());
773 if (tmp == QLatin1String("Devices")) {
774 mContext = KIconLoader::Device;
775 } else if (tmp == QLatin1String("MimeTypes")) {
776 mContext = KIconLoader::MimeType;
777 } else if (tmp == QLatin1String("Applications")) {
778 mContext = KIconLoader::Application;
779 } else if (tmp == QLatin1String("Actions")) {
780 mContext = KIconLoader::Action;
781 } else if (tmp == QLatin1String("Animations")) {
782 mContext = KIconLoader::Animation;
783 } else if (tmp == QLatin1String("Categories")) {
784 mContext = KIconLoader::Category;
785 } else if (tmp == QLatin1String("Emblems")) {
786 mContext = KIconLoader::Emblem;
787 } else if (tmp == QLatin1String("Emotes")) {
788 mContext = KIconLoader::Emote;
789 } else if (tmp == QLatin1String("International")) {
791 } else if (tmp == QLatin1String("Places")) {
792 mContext = KIconLoader::Place;
793 } else if (tmp == QLatin1String("Status")) {
794 mContext = KIconLoader::StatusIcon;
795 } else if (tmp == QLatin1String("Stock")) { // invalid, but often present context, skip warning
796 return;
797 } else if (tmp == QLatin1String("FileSystems")) { // invalid, but present context for hicolor, skip warning
798 return;
799 } else if (tmp == QLatin1String("Legacy")) { // invalid, but often present context for Adwaita, skip warning
800 return;
801 } else if (tmp == QLatin1String("UI")) { // invalid, but often present context for Adwaita, skip warning
802 return;
803 } else if (tmp.isEmpty()) {
804 // do nothing. key not required
805 } else {
806 qCDebug(KICONTHEMES) << "Invalid Context=" << tmp << "line for icon theme: " << constructFileName(QString());
807 return;
808 }
809 tmp = config.readEntry("Type", QStringLiteral("Threshold"));
810 if (tmp == QLatin1String("Fixed")) {
811 mType = KIconLoader::Fixed;
812 } else if (tmp == QLatin1String("Scalable")) {
813 mType = KIconLoader::Scalable;
814 } else if (tmp == QLatin1String("Threshold")) {
816 } else {
817 qCDebug(KICONTHEMES) << "Invalid Type=" << tmp << "line for icon theme: " << constructFileName(QString());
818 return;
819 }
820 if (mType == KIconLoader::Scalable) {
821 mMinSize = config.readEntry("MinSize", mSize);
822 mMaxSize = config.readEntry("MaxSize", mSize);
823 } else if (mType == KIconLoader::Threshold) {
824 mThreshold = config.readEntry("Threshold", 2);
825 }
826 mbValid = true;
827}
828
829QString KIconThemeDir::iconPath(const QString &name) const
830{
831 if (!mbValid) {
832 return QString();
833 }
834
835 const QString file = constructFileName(name);
836 if (QFileInfo::exists(file)) {
838 }
839
840 return QString();
841}
842
843QStringList KIconThemeDir::iconList() const
844{
845 const QDir icondir = constructFileName(QString());
846
847 const QStringList formats = QStringList() << QStringLiteral("*.png") << QStringLiteral("*.svg") << QStringLiteral("*.svgz") << QStringLiteral("*.xpm");
848 const QStringList lst = icondir.entryList(formats, QDir::Files);
849
850 QStringList result;
851 result.reserve(lst.size());
852 for (const QString &file : lst) {
853 result += constructFileName(file);
854 }
855 return result;
856}
static KColorSchemeManager * instance()
QString readPathEntry(const char *key, const QString &aDefault) const
QString readEntry(const char *key, const char *aDefault=nullptr) const
Group
The group of the icon.
@ Small
Small icons, e.g. for buttons.
@ Panel
Panel (Plasma Taskbar) icons.
@ LastGroup
Last group.
@ Desktop
Desktop icons.
@ MainToolbar
Main toolbar icons.
@ Toolbar
Toolbar icons.
@ Dialog
Icons for use in dialog titles, page lists, etc.
Context
Defines the context of the icon.
Definition kiconloader.h:80
@ Category
An icon that represents a category.
Definition kiconloader.h:87
@ Emblem
An icon that adds information to an existing icon.
Definition kiconloader.h:88
@ StatusIcon
An icon that represents an event.
Definition kiconloader.h:92
@ Application
An icon that represents an application.
Definition kiconloader.h:83
@ Emote
An icon that expresses an emotion.
Definition kiconloader.h:89
@ Any
Some icon with unknown purpose.
Definition kiconloader.h:81
@ Place
An icon that represents a location (e.g. 'home', 'trash').
Definition kiconloader.h:91
@ MimeType
An icon that represents a mime type (or file type).
Definition kiconloader.h:85
@ Action
An action icon (e.g. 'save', 'print').
Definition kiconloader.h:82
@ International
An icon that represents a country's flag.
Definition kiconloader.h:90
@ Animation
An icon that is animated.
Definition kiconloader.h:86
@ Device
An icon that represents a device.
Definition kiconloader.h:84
Type
The type of the icon.
Definition kiconloader.h:99
@ Fixed
Fixed-size icon.
@ Scalable
Scalable-size icon.
@ Threshold
A threshold icon.
MatchType
The type of a match.
@ MatchExact
Only try to find an exact match.
@ MatchBestOrGreaterSize
Take the best match or the match with a greater size if there is no exact match.
static QStringList list()
List all icon themes installed on the system, global and local.
bool isValid() const
The icon theme exists?
QStringList queryIcons() const
Query all available icons.
QList< int > querySizes(KIconLoader::Group group) const
Query available sizes for a group.
QString iconPathByName(const QString &name, int size, KIconLoader::MatchType match) const
Lookup an icon in the theme.
QString internalName() const
The internal name of the icon theme (same as the name argument passed to the constructor).
QString screenshot() const
Return the name of the screenshot.
static void reconfigure()
Reconfigure the theme.
static void forceThemeForTests(const QString &themeName)
Force a current theme and disable automatic resolution of the current theme in favor of the forced th...
bool isHidden() const
The icon theme should be hidden to the user?
KIconTheme(const QString &name, const QString &appName=QString(), const QString &basePathHint=QString())
Load an icon theme by name.
QStringList queryIconsByContext(int size, KIconLoader::Context context=KIconLoader::Any) const
Query available icons for a context and preferred size.
QString description() const
A description for the icon theme.
static QString current()
Returns the current icon theme.
bool followsColorScheme() const
If true, this theme is made of SVG icons that will be colorized following the system color scheme.
QString dir() const
Returns the toplevel theme directory.
bool hasContext(KIconLoader::Context context) const
Returns true if the theme has any icons for the given context.
QString name() const
The stylized name of the icon theme.
QString iconPath(const QString &name, int size, KIconLoader::MatchType match) const
Lookup an icon in the theme.
static void initTheme()
Enforces the Breeze icon theme (including our KIconEngine for re-coloring).
QStringList inherits() const
The themes this icon theme falls back on.
QString example() const
Return the name of the "example" icon.
int defaultSize(KIconLoader::Group group) const
The default size of this theme for a certain icon group.
static QString defaultThemeName()
Returns the default icon theme.
int depth() const
The minimum display depth required for this theme.
static QString localizedFilePath(const QString &filePath)
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
void initIcons()
QString path(const QString &relativePath)
KIOCORE_EXPORT QString dir(const QString &fileClass)
QString name(StandardAction id)
void addLibraryPath(const QString &path)
QString applicationFilePath()
QStringList libraryPaths()
QStringList entryList(Filters filters, SortFlags sort) const const
bool exists() const const
bool exists() const const
bool exists(const QString &path)
bool isDir() const const
QString fallbackThemeName()
void setThemeName(const QString &name)
QString themeName()
void append(QList< T > &&value)
void reserve(qsizetype size)
qsizetype size() const const
bool contains(const QSet< T > &other) const const
iterator insert(const T &value)
QStringList locateAll(StandardLocation type, const QString &fileName, LocateOptions options)
QStringList standardLocations(StandardLocation type)
void clear()
bool isEmpty() const const
qsizetype lastIndexOf(QChar ch, Qt::CaseSensitivity cs) const const
qsizetype size() const const
void truncate(qsizetype position)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Feb 28 2025 12:01:57 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.