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;
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{
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 // Try to find exact match
557 QStringList result;
558 const QList<KIconThemeDir *> listDirs = d->mDirs + d->mScaledDirs;
559 for (const KIconThemeDir *dir : listDirs) {
560 if (!isAnyOrDirContext(dir, context)) {
561 continue;
562 }
563
564 const int dirSize = dir->size();
565 if ((dir->type() == KIconLoader::Fixed && dirSize == size) //
566 || (dir->type() == KIconLoader::Scalable && size >= dir->minSize() && size <= dir->maxSize())
567 || (dir->type() == KIconLoader::Threshold && abs(size - dirSize) < dir->threshold())) {
568 result += dir->iconList();
569 }
570 }
571
572 return result;
573}
574
576{
577 int dw;
578
579 // We want all the icons for a given context, but we prefer icons
580 // of size "size" . Note that this may (will) include duplicate icons
581 // QStringList iconlist[34]; // 33 == 48-16+1
582 QStringList iconlist[128]; // 33 == 48-16+1
583 // Usually, only the 0, 6 (22-16), 10 (32-22), 16 (48-32 or 32-16),
584 // 26 (48-22) and 32 (48-16) will be used, but who knows if someone
585 // will make icon themes with different icon sizes.
586 const auto listDirs = d->mDirs + d->mScaledDirs;
587 for (KIconThemeDir *dir : listDirs) {
588 if (!isAnyOrDirContext(dir, context)) {
589 continue;
590 }
591 dw = abs(dir->size() - size);
592 iconlist[(dw < 127) ? dw : 127] += dir->iconList();
593 }
594
595 QStringList iconlistResult;
596 for (int i = 0; i < 128; i++) {
597 iconlistResult += iconlist[i];
598 }
599
600 return iconlistResult;
601}
602
604{
605 const auto listDirs = d->mDirs + d->mScaledDirs;
606 for (KIconThemeDir *dir : listDirs) {
607 if (isAnyOrDirContext(dir, context)) {
608 return true;
609 }
610 }
611 return false;
612}
613
615{
616 return iconPathByName(iconName, size, match, 1 /*scale*/);
617}
618
619QString KIconTheme::iconPathByName(const QString &iconName, int size, KIconLoader::MatchType match, qreal scale) const
620{
621 for (const QString &current : std::as_const(d->mExtensions)) {
622 const QString path = iconPath(iconName + current, size, match, scale);
623 if (!path.isEmpty()) {
624 return path;
625 }
626 }
627 return QString();
628}
629
631{
632 return d->followsColorScheme;
633}
634
636{
637 return iconPath(name, size, match, 1 /*scale*/);
638}
639
640QString KIconTheme::iconPath(const QString &name, int size, KIconLoader::MatchType match, qreal scale) const
641{
642 // first look for a scaled image at exactly the requested size
643 QString path = d->iconPath(d->mScaledDirs, name, size, scale, KIconLoader::MatchExact);
644
645 // then look for an unscaled one but request it at larger size so it doesn't become blurry
646 if (path.isEmpty()) {
647 path = d->iconPath(d->mDirs, name, size * scale, 1, match);
648 }
649 return path;
650}
651
652// static
654{
655 // Static pointers because of unloading problems wrt DSO's.
656 if (_themeOverride && !_themeOverride->isEmpty()) {
657 *_theme() = *_themeOverride();
658 }
659 if (!_theme()->isEmpty()) {
660 return *_theme();
661 }
662
663 QString theme;
664 // Check application specific config for a theme setting.
666 theme = app_cg.readEntry("Theme", QString());
667 if (theme.isEmpty() || theme == QLatin1String("hicolor")) {
668 // No theme, try to use Qt's. A Platform plugin might have set
669 // a good theme there.
670 theme = QIcon::themeName();
671 }
672 if (theme.isEmpty() || theme == QLatin1String("hicolor")) {
673 // Still no theme, try config with kdeglobals.
675 theme = cg.readEntry("Theme", QStringLiteral("breeze"));
676 }
677 if (theme.isEmpty() || theme == QLatin1String("hicolor")) {
678 // Still no good theme, use default.
679 theme = defaultThemeName();
680 }
681 *_theme() = theme;
682 return *_theme();
683}
684
686{
687 *_themeOverride() = themeName;
688 _theme()->clear(); // ::current sets this again based on conditions
689}
690
691// static
693{
694 // Static pointer because of unloading problems wrt DSO's.
695 if (!_theme_list()->isEmpty()) {
696 return *_theme_list();
697 }
698
699 // Find the theme description file. These are either locally in the :/icons resource path or global.
700 QStringList icnlibs;
701
702 // local embedded icons have preference
703 icnlibs << QStringLiteral(":/icons");
704
705 // global icons
707
708 // These are not in the icon spec, but e.g. GNOME puts some icons there anyway.
710
711 for (const QString &iconDir : std::as_const(icnlibs)) {
712 QDir dir(iconDir);
713 const QStringList themeDirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
714 for (const auto &theme : themeDirs) {
715 if (theme.startsWith(QLatin1String("default."))) {
716 continue;
717 }
718
719 const QString prefix = iconDir + QLatin1Char('/') + theme;
720 if (!QFileInfo::exists(prefix + QLatin1String("/index.desktop")) //
721 && !QFileInfo::exists(prefix + QLatin1String("/index.theme"))) {
722 continue;
723 }
724
725 if (!KIconTheme(theme).isValid()) {
726 continue;
727 }
728
729 if (!_theme_list()->contains(theme)) {
730 _theme_list()->append(theme);
731 }
732 }
733 }
734 return *_theme_list();
735}
736
737// static
739{
740 _theme()->clear();
741 _theme_list()->clear();
742}
743
744// static
746{
747 return QStringLiteral("hicolor");
748}
749
750/*** KIconThemeDir ***/
751
752KIconThemeDir::KIconThemeDir(const QString &basedir, const QString &themedir, const KConfigGroup &config)
753 : mSize(config.readEntry("Size", 0))
754 , mScale(config.readEntry("Scale", 1))
755 , mBaseDir(basedir)
756 , mThemeDir(themedir)
757{
758 if (mSize == 0) {
759 return;
760 }
761
762 QString tmp = config.readEntry("Context", QString());
763 if (tmp == QLatin1String("Devices")) {
764 mContext = KIconLoader::Device;
765 } else if (tmp == QLatin1String("MimeTypes")) {
766 mContext = KIconLoader::MimeType;
767 } else if (tmp == QLatin1String("Applications")) {
768 mContext = KIconLoader::Application;
769 } else if (tmp == QLatin1String("Actions")) {
770 mContext = KIconLoader::Action;
771 } else if (tmp == QLatin1String("Animations")) {
772 mContext = KIconLoader::Animation;
773 } else if (tmp == QLatin1String("Categories")) {
774 mContext = KIconLoader::Category;
775 } else if (tmp == QLatin1String("Emblems")) {
776 mContext = KIconLoader::Emblem;
777 } else if (tmp == QLatin1String("Emotes")) {
778 mContext = KIconLoader::Emote;
779 } else if (tmp == QLatin1String("International")) {
781 } else if (tmp == QLatin1String("Places")) {
782 mContext = KIconLoader::Place;
783 } else if (tmp == QLatin1String("Status")) {
784 mContext = KIconLoader::StatusIcon;
785 } else if (tmp == QLatin1String("Stock")) { // invalid, but often present context, skip warning
786 return;
787 } else if (tmp == QLatin1String("FileSystems")) { // invalid, but present context for hicolor, skip warning
788 return;
789 } else if (tmp == QLatin1String("Legacy")) { // invalid, but often present context for Adwaita, skip warning
790 return;
791 } else if (tmp == QLatin1String("UI")) { // invalid, but often present context for Adwaita, skip warning
792 return;
793 } else if (tmp.isEmpty()) {
794 // do nothing. key not required
795 } else {
796 qCDebug(KICONTHEMES) << "Invalid Context=" << tmp << "line for icon theme: " << constructFileName(QString());
797 return;
798 }
799 tmp = config.readEntry("Type", QStringLiteral("Threshold"));
800 if (tmp == QLatin1String("Fixed")) {
801 mType = KIconLoader::Fixed;
802 } else if (tmp == QLatin1String("Scalable")) {
803 mType = KIconLoader::Scalable;
804 } else if (tmp == QLatin1String("Threshold")) {
806 } else {
807 qCDebug(KICONTHEMES) << "Invalid Type=" << tmp << "line for icon theme: " << constructFileName(QString());
808 return;
809 }
810 if (mType == KIconLoader::Scalable) {
811 mMinSize = config.readEntry("MinSize", mSize);
812 mMaxSize = config.readEntry("MaxSize", mSize);
813 } else if (mType == KIconLoader::Threshold) {
814 mThreshold = config.readEntry("Threshold", 2);
815 }
816 mbValid = true;
817}
818
819QString KIconThemeDir::iconPath(const QString &name) const
820{
821 if (!mbValid) {
822 return QString();
823 }
824
825 const QString file = constructFileName(name);
826 if (QFileInfo::exists(file)) {
828 }
829
830 return QString();
831}
832
833QStringList KIconThemeDir::iconList() const
834{
835 const QDir icondir = constructFileName(QString());
836
837 const QStringList formats = QStringList() << QStringLiteral("*.png") << QStringLiteral("*.svg") << QStringLiteral("*.svgz") << QStringLiteral("*.xpm");
838 const QStringList lst = icondir.entryList(formats, QDir::Files);
839
840 QStringList result;
841 result.reserve(lst.size());
842 for (const QString &file : lst) {
843 result += constructFileName(file);
844 }
845 return result;
846}
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?
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.
QStringList queryIcons(int size, KIconLoader::Context context=KIconLoader::Any) const
Query available icons for a size and context.
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-2024 The KDE developers.
Generated on Sat Dec 21 2024 16:57:01 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.