00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include <qstring.h>
00017 #include <qstringlist.h>
00018 #include <qptrlist.h>
00019 #include <qintdict.h>
00020 #include <qpixmap.h>
00021 #include <qpixmapcache.h>
00022 #include <qimage.h>
00023 #include <qfileinfo.h>
00024 #include <qdir.h>
00025 #include <qiconset.h>
00026 #include <qmovie.h>
00027 #include <qbitmap.h>
00028
00029 #include <kapplication.h>
00030 #include <kipc.h>
00031 #include <kdebug.h>
00032 #include <kstandarddirs.h>
00033 #include <kglobal.h>
00034 #include <kconfig.h>
00035 #include <ksimpleconfig.h>
00036 #include <kinstance.h>
00037
00038 #include <kicontheme.h>
00039 #include <kiconloader.h>
00040 #include <kiconeffect.h>
00041
00042 #include <sys/types.h>
00043 #include <stdlib.h>
00044 #include <unistd.h>
00045 #include <dirent.h>
00046 #include <config.h>
00047 #include <assert.h>
00048
00049 #ifdef HAVE_LIBART
00050 #include "svgicons/ksvgiconengine.h"
00051 #include "svgicons/ksvgiconpainter.h"
00052 #endif
00053
00054 #include "kiconloader_p.h"
00055
00056
00057
00058 KIconThemeNode::KIconThemeNode(KIconTheme *_theme)
00059 {
00060 theme = _theme;
00061 }
00062
00063 KIconThemeNode::~KIconThemeNode()
00064 {
00065 delete theme;
00066 }
00067
00068 void KIconThemeNode::printTree(QString& dbgString) const
00069 {
00070
00071
00072 dbgString += "(";
00073 dbgString += theme->name();
00074 dbgString += ")";
00075 }
00076
00077 void KIconThemeNode::queryIcons(QStringList *result,
00078 int size, KIcon::Context context) const
00079 {
00080
00081 *result += theme->queryIcons(size, context);
00082 }
00083
00084 void KIconThemeNode::queryIconsByContext(QStringList *result,
00085 int size, KIcon::Context context) const
00086 {
00087
00088 *result += theme->queryIconsByContext(size, context);
00089 }
00090
00091 KIcon KIconThemeNode::findIcon(const QString& name, int size,
00092 KIcon::MatchType match) const
00093 {
00094 return theme->iconPath(name, size, match);
00095 }
00096
00097
00098
00099
00100 struct KIconGroup
00101 {
00102 int size;
00103 bool dblPixels;
00104 bool alphaBlending;
00105 };
00106
00107 #define KICONLOADER_CHECKS
00108 #ifdef KICONLOADER_CHECKS
00109
00110
00111 struct KIconLoaderDebug
00112 {
00113 KIconLoaderDebug( KIconLoader* l, const QString& a )
00114 : loader( l ), appname( a ), valid( true )
00115 {}
00116 KIconLoaderDebug() {};
00117 KIconLoader* loader;
00118 QString appname;
00119 bool valid;
00120 QString delete_bt;
00121 };
00122
00123 static QValueList< KIconLoaderDebug > *kiconloaders;
00124 #endif
00125
00126
00127
00128 KIconLoader::KIconLoader(const QString& _appname, KStandardDirs *_dirs)
00129 {
00130 #ifdef KICONLOADER_CHECKS
00131 if( kiconloaders == NULL )
00132 kiconloaders = new QValueList< KIconLoaderDebug>();
00133
00134
00135 for( QValueList< KIconLoaderDebug >::Iterator it = kiconloaders->begin();
00136 it != kiconloaders->end();
00137 )
00138 {
00139 if( (*it).loader == this )
00140 it = kiconloaders->remove( it );
00141 else
00142 ++it;
00143 }
00144 kiconloaders->append( KIconLoaderDebug( this, _appname ));
00145 #endif
00146 d = new KIconLoaderPrivate;
00147 d->q = this;
00148 d->mpGroups = 0L;
00149 d->imgDict.setAutoDelete(true);
00150 d->links.setAutoDelete(true);
00151
00152 if (kapp) {
00153 kapp->addKipcEventMask(KIPC::IconChanged);
00154 QObject::connect(kapp, SIGNAL(updateIconLoaders()), d, SLOT(reconfigure()));
00155 }
00156
00157 init( _appname, _dirs );
00158 }
00159
00160 void KIconLoader::reconfigure( const QString& _appname, KStandardDirs *_dirs )
00161 {
00162 d->links.clear();
00163 d->imgDict.clear();
00164 d->mThemesInTree.clear();
00165 d->lastImage.reset();
00166 d->lastImageKey = QString::null;
00167 delete [] d->mpGroups;
00168
00169 init( _appname, _dirs );
00170 }
00171
00172 void KIconLoader::init( const QString& _appname, KStandardDirs *_dirs )
00173 {
00174
00175
00176 d->mpThemeRoot = 0L;
00177
00178 d->appname = _appname;
00179 d->extraDesktopIconsLoaded = false;
00180 d->delayedLoading = false;
00181
00182 if (_dirs)
00183 d->mpDirs = _dirs;
00184 else
00185 d->mpDirs = KGlobal::dirs();
00186
00187 QString appname = _appname;
00188 if (appname.isEmpty())
00189 appname = KGlobal::instance()->instanceName();
00190
00191
00192 KIconTheme *def = new KIconTheme(KIconTheme::current(), appname);
00193 if (!def->isValid())
00194 {
00195 delete def;
00196
00197 kdDebug(264) << "Couldn't find current icon theme, falling back to default." << endl;
00198 def = new KIconTheme(KIconTheme::defaultThemeName(), appname);
00199 if (!def->isValid())
00200 {
00201 kdError(264) << "Error: standard icon theme"
00202 << " \"" << KIconTheme::defaultThemeName() << "\" "
00203 << " not found!" << endl;
00204 d->mpGroups=0L;
00205 return;
00206 }
00207 }
00208 d->mpThemeRoot = new KIconThemeNode(def);
00209 d->links.append(d->mpThemeRoot);
00210 d->mThemesInTree += KIconTheme::current();
00211 addBaseThemes(d->mpThemeRoot, appname);
00212
00213
00214 static const char * const groups[] = { "Desktop", "Toolbar", "MainToolbar", "Small", "Panel", 0L };
00215 KConfig *config = KGlobal::config();
00216 KConfigGroupSaver cs(config, "dummy");
00217
00218
00219 d->mpGroups = new KIconGroup[(int) KIcon::LastGroup];
00220 for (KIcon::Group i=KIcon::FirstGroup; i<KIcon::LastGroup; i++)
00221 {
00222 if (groups[i] == 0L)
00223 break;
00224 config->setGroup(QString::fromLatin1(groups[i]) + "Icons");
00225 d->mpGroups[i].size = config->readNumEntry("Size", 0);
00226 d->mpGroups[i].dblPixels = config->readBoolEntry("DoublePixels", false);
00227 if (QPixmap::defaultDepth()>8)
00228 d->mpGroups[i].alphaBlending = config->readBoolEntry("AlphaBlending", true);
00229 else
00230 d->mpGroups[i].alphaBlending = false;
00231
00232 if (!d->mpGroups[i].size)
00233 d->mpGroups[i].size = d->mpThemeRoot->theme->defaultSize(i);
00234 }
00235
00236
00237 d->mpDirs->addResourceType("appicon", KStandardDirs::kde_default("data") +
00238 appname + "/pics/");
00239
00240 d->mpDirs->addResourceType("appicon", KStandardDirs::kde_default("data") +
00241 appname + "/toolbar/");
00242
00243
00244 QStringList dirs;
00245 dirs += d->mpDirs->resourceDirs("icon");
00246 dirs += d->mpDirs->resourceDirs("pixmap");
00247 dirs += d->mpDirs->resourceDirs("xdgdata-icon");
00248 dirs += "/usr/share/pixmaps";
00249
00250 dirs += d->mpDirs->resourceDirs("xdgdata-pixmap");
00251 for (QStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it)
00252 d->mpDirs->addResourceDir("appicon", *it);
00253
00254 #ifndef NDEBUG
00255 QString dbgString = "Theme tree: ";
00256 d->mpThemeRoot->printTree(dbgString);
00257 kdDebug(264) << dbgString << endl;
00258 #endif
00259 }
00260
00261 KIconLoader::~KIconLoader()
00262 {
00263 #ifdef KICONLOADER_CHECKS
00264 for( QValueList< KIconLoaderDebug >::Iterator it = kiconloaders->begin();
00265 it != kiconloaders->end();
00266 ++it )
00267 {
00268 if( (*it).loader == this )
00269 {
00270 (*it).valid = false;
00271 (*it).delete_bt = kdBacktrace();
00272 break;
00273 }
00274 }
00275 #endif
00276
00277
00278 d->mpThemeRoot=0;
00279 delete[] d->mpGroups;
00280 delete d;
00281 }
00282
00283 void KIconLoader::enableDelayedIconSetLoading( bool enable )
00284 {
00285 d->delayedLoading = enable;
00286 }
00287
00288 bool KIconLoader::isDelayedIconSetLoadingEnabled() const
00289 {
00290 return d->delayedLoading;
00291 }
00292
00293 void KIconLoader::addAppDir(const QString& appname)
00294 {
00295 d->mpDirs->addResourceType("appicon", KStandardDirs::kde_default("data") +
00296 appname + "/pics/");
00297
00298 d->mpDirs->addResourceType("appicon", KStandardDirs::kde_default("data") +
00299 appname + "/toolbar/");
00300 addAppThemes(appname);
00301 }
00302
00303 void KIconLoader::addAppThemes(const QString& appname)
00304 {
00305 if ( KIconTheme::current() != KIconTheme::defaultThemeName() )
00306 {
00307 KIconTheme *def = new KIconTheme(KIconTheme::current(), appname);
00308 if (def->isValid())
00309 {
00310 KIconThemeNode* node = new KIconThemeNode(def);
00311 d->links.append(node);
00312 addBaseThemes(node, appname);
00313 }
00314 else
00315 delete def;
00316 }
00317
00318 KIconTheme *def = new KIconTheme(KIconTheme::defaultThemeName(), appname);
00319 KIconThemeNode* node = new KIconThemeNode(def);
00320 d->links.append(node);
00321 addBaseThemes(node, appname);
00322 }
00323
00324 void KIconLoader::addBaseThemes(KIconThemeNode *node, const QString &appname)
00325 {
00326 QStringList lst = node->theme->inherits();
00327 QStringList::ConstIterator it;
00328
00329 for (it=lst.begin(); it!=lst.end(); ++it)
00330 {
00331 if( d->mThemesInTree.contains(*it) && (*it) != "hicolor")
00332 continue;
00333 KIconTheme *theme = new KIconTheme(*it,appname);
00334 if (!theme->isValid()) {
00335 delete theme;
00336 continue;
00337 }
00338 KIconThemeNode *n = new KIconThemeNode(theme);
00339 d->mThemesInTree.append(*it);
00340 d->links.append(n);
00341 addBaseThemes(n, appname);
00342 }
00343 }
00344
00345 void KIconLoader::addExtraDesktopThemes()
00346 {
00347 if ( d->extraDesktopIconsLoaded ) return;
00348
00349 QStringList list;
00350 QStringList icnlibs = KGlobal::dirs()->resourceDirs("icon");
00351 QStringList::ConstIterator it;
00352 char buf[1000];
00353 int r;
00354 for (it=icnlibs.begin(); it!=icnlibs.end(); ++it)
00355 {
00356 QDir dir(*it);
00357 if (!dir.exists())
00358 continue;
00359 QStringList lst = dir.entryList("default.*", QDir::Dirs);
00360 QStringList::ConstIterator it2;
00361 for (it2=lst.begin(); it2!=lst.end(); ++it2)
00362 {
00363 if (!KStandardDirs::exists(*it + *it2 + "/index.desktop")
00364 && !KStandardDirs::exists(*it + *it2 + "/index.theme"))
00365 continue;
00366 r=readlink( QFile::encodeName(*it + *it2) , buf, sizeof(buf)-1);
00367 if ( r>0 )
00368 {
00369 buf[r]=0;
00370 QDir dir2( buf );
00371 QString themeName=dir2.dirName();
00372
00373 if (!list.contains(themeName))
00374 list.append(themeName);
00375 }
00376 }
00377 }
00378
00379 for (it=list.begin(); it!=list.end(); ++it)
00380 {
00381 if ( d->mThemesInTree.contains(*it) )
00382 continue;
00383 if ( *it == QString("default.kde") ) continue;
00384
00385 KIconTheme *def = new KIconTheme( *it, "" );
00386 KIconThemeNode* node = new KIconThemeNode(def);
00387 d->mThemesInTree.append(*it);
00388 d->links.append(node);
00389 addBaseThemes(node, "" );
00390 }
00391
00392 d->extraDesktopIconsLoaded=true;
00393
00394 }
00395
00396 bool KIconLoader::extraDesktopThemesAdded() const
00397 {
00398 return d->extraDesktopIconsLoaded;
00399 }
00400
00401 QString KIconLoader::removeIconExtension(const QString &name) const
00402 {
00403 int extensionLength=0;
00404
00405 QString ext = name.right(4);
00406
00407 static const QString &png_ext = KGlobal::staticQString(".png");
00408 static const QString &xpm_ext = KGlobal::staticQString(".xpm");
00409 if (ext == png_ext || ext == xpm_ext)
00410 extensionLength=4;
00411 #ifdef HAVE_LIBART
00412 else
00413 {
00414 static const QString &svgz_ext = KGlobal::staticQString(".svgz");
00415 static const QString &svg_ext = KGlobal::staticQString(".svg");
00416
00417 if (name.right(5) == svgz_ext)
00418 extensionLength=5;
00419 else if (ext == svg_ext)
00420 extensionLength=4;
00421 }
00422 #endif
00423
00424 if ( extensionLength > 0 )
00425 {
00426 return name.left(name.length() - extensionLength);
00427 }
00428 return name;
00429 }
00430
00431 QString KIconLoader::removeIconExtensionInternal(const QString &name) const
00432 {
00433 QString name_noext = removeIconExtension(name);
00434
00435 #ifndef NDEBUG
00436 if (name != name_noext)
00437 {
00438 kdDebug(264) << "Application " << KGlobal::instance()->instanceName()
00439 << " loads icon " << name << " with extension." << endl;
00440 }
00441 #endif
00442
00443 return name_noext;
00444 }
00445
00446 KIcon KIconLoader::findMatchingIcon(const QString& name, int size) const
00447 {
00448 KIcon icon;
00449
00450 const QString *ext[4];
00451 int count=0;
00452 static const QString &png_ext = KGlobal::staticQString(".png");
00453 ext[count++]=&png_ext;
00454 #ifdef HAVE_LIBART
00455 static const QString &svgz_ext = KGlobal::staticQString(".svgz");
00456 ext[count++]=&svgz_ext;
00457 static const QString &svg_ext = KGlobal::staticQString(".svg");
00458 ext[count++]=&svg_ext;
00459 #endif
00460 static const QString &xpm_ext = KGlobal::staticQString(".xpm");
00461 ext[count++]=&xpm_ext;
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477 for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
00478 themeNode = d->links.next() )
00479 {
00480 for (int i = 0 ; i < count ; i++)
00481 {
00482 icon = themeNode->theme->iconPath(name + *ext[i], size, KIcon::MatchExact);
00483 if (icon.isValid())
00484 return icon;
00485 }
00486
00487 }
00488
00489 for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
00490 themeNode = d->links.next() )
00491 {
00492 for (int i = 0 ; i < count ; i++)
00493 {
00494 icon = themeNode->theme->iconPath(name + *ext[i], size, KIcon::MatchBest);
00495 if (icon.isValid())
00496 return icon;
00497 }
00498
00499 }
00500
00501 return icon;
00502 }
00503
00504 inline QString KIconLoader::unknownIconPath( int size ) const
00505 {
00506 static const QString &str_unknown = KGlobal::staticQString("unknown");
00507
00508 KIcon icon = findMatchingIcon(str_unknown, size);
00509 if (!icon.isValid())
00510 {
00511 kdDebug(264) << "Warning: could not find \"Unknown\" icon for size = "
00512 << size << endl;
00513 return QString::null;
00514 }
00515 return icon.path;
00516 }
00517
00518
00519
00520 QString KIconLoader::iconPath(const QString& _name, int group_or_size,
00521 bool canReturnNull) const
00522 {
00523 if (d->mpThemeRoot == 0L)
00524 return QString::null;
00525
00526 if (!QDir::isRelativePath(_name))
00527 return _name;
00528
00529 QString name = removeIconExtensionInternal( _name );
00530
00531 QString path;
00532 if (group_or_size == KIcon::User)
00533 {
00534 static const QString &png_ext = KGlobal::staticQString(".png");
00535 static const QString &xpm_ext = KGlobal::staticQString(".xpm");
00536 path = d->mpDirs->findResource("appicon", name + png_ext);
00537
00538 #ifdef HAVE_LIBART
00539 static const QString &svgz_ext = KGlobal::staticQString(".svgz");
00540 static const QString &svg_ext = KGlobal::staticQString(".svg");
00541 if (path.isEmpty())
00542 path = d->mpDirs->findResource("appicon", name + svgz_ext);
00543 if (path.isEmpty())
00544 path = d->mpDirs->findResource("appicon", name + svg_ext);
00545 #endif
00546 if (path.isEmpty())
00547 path = d->mpDirs->findResource("appicon", name + xpm_ext);
00548 return path;
00549 }
00550
00551 if (group_or_size >= KIcon::LastGroup)
00552 {
00553 kdDebug(264) << "Illegal icon group: " << group_or_size << endl;
00554 return path;
00555 }
00556
00557 int size;
00558 if (group_or_size >= 0)
00559 size = d->mpGroups[group_or_size].size;
00560 else
00561 size = -group_or_size;
00562
00563 if (_name.isEmpty()) {
00564 if (canReturnNull)
00565 return QString::null;
00566 else
00567 return unknownIconPath(size);
00568 }
00569
00570 KIcon icon = findMatchingIcon(name, size);
00571
00572 if (!icon.isValid())
00573 {
00574
00575 path = iconPath(name, KIcon::User, true);
00576 if (!path.isEmpty() || canReturnNull)
00577 return path;
00578
00579 if (canReturnNull)
00580 return QString::null;
00581 else
00582 return unknownIconPath(size);
00583 }
00584 return icon.path;
00585 }
00586
00587 QPixmap KIconLoader::loadIcon(const QString& _name, KIcon::Group group, int size,
00588 int state, QString *path_store, bool canReturnNull) const
00589 {
00590 QString name = _name;
00591 QPixmap pix;
00592 QString key;
00593 bool absolutePath=false, favIconOverlay=false;
00594
00595 if (d->mpThemeRoot == 0L)
00596 return pix;
00597
00598
00599 if (name.startsWith("favicons/"))
00600 {
00601 favIconOverlay = true;
00602 name = locateLocal("cache", name+".png");
00603 }
00604 if (!QDir::isRelativePath(name)) absolutePath=true;
00605
00606 static const QString &str_unknown = KGlobal::staticQString("unknown");
00607
00608
00609 if (group == KIcon::User)
00610 {
00611 key = "$kicou_";
00612 key += QString::number(size); key += '_';
00613 key += name;
00614 bool inCache = QPixmapCache::find(key, pix);
00615 if (inCache && (path_store == 0L))
00616 return pix;
00617
00618 QString path = (absolutePath) ? name :
00619 iconPath(name, KIcon::User, canReturnNull);
00620 if (path.isEmpty())
00621 {
00622 if (canReturnNull)
00623 return pix;
00624
00625 path = iconPath(str_unknown, KIcon::Small, true);
00626 if (path.isEmpty())
00627 {
00628 kdDebug(264) << "Warning: Cannot find \"unknown\" icon." << endl;
00629 return pix;
00630 }
00631 }
00632
00633 if (path_store != 0L)
00634 *path_store = path;
00635 if (inCache)
00636 return pix;
00637 QImage img(path);
00638 if (size != 0)
00639 img=img.smoothScale(size,size);
00640
00641 pix.convertFromImage(img);
00642 QPixmapCache::insert(key, pix);
00643 return pix;
00644 }
00645
00646
00647
00648 if ((group < -1) || (group >= KIcon::LastGroup))
00649 {
00650 kdDebug(264) << "Illegal icon group: " << group << endl;
00651 group = KIcon::Desktop;
00652 }
00653
00654 int overlay = (state & KIcon::OverlayMask);
00655 state &= ~KIcon::OverlayMask;
00656 if ((state < 0) || (state >= KIcon::LastState))
00657 {
00658 kdDebug(264) << "Illegal icon state: " << state << endl;
00659 state = KIcon::DefaultState;
00660 }
00661
00662 if (size == 0 && group < 0)
00663 {
00664 kdDebug(264) << "Neither size nor group specified!" << endl;
00665 group = KIcon::Desktop;
00666 }
00667
00668 if (!absolutePath)
00669 {
00670 if (!canReturnNull && name.isEmpty())
00671 name = str_unknown;
00672 else
00673 name = removeIconExtensionInternal(name);
00674 }
00675
00676
00677 if (size == 0)
00678 {
00679 size = d->mpGroups[group].size;
00680 }
00681 favIconOverlay = favIconOverlay && size > 22;
00682
00683
00684
00685 key = "$kico_";
00686 key += name; key += '_';
00687 key += QString::number(size); key += '_';
00688
00689 QString overlayStr = QString::number( overlay );
00690
00691 QString noEffectKey = key + '_' + overlayStr;
00692
00693 if (group >= 0)
00694 {
00695 key += d->mpEffect.fingerprint(group, state);
00696 if (d->mpGroups[group].dblPixels)
00697 key += QString::fromLatin1(":dblsize");
00698 } else
00699 key += QString::fromLatin1("noeffect");
00700 key += '_';
00701 key += overlayStr;
00702
00703
00704 bool inCache = QPixmapCache::find(key, pix);
00705 if (inCache && (path_store == 0L))
00706 return pix;
00707
00708 QImage *img = 0;
00709 int iconType;
00710 int iconThreshold;
00711
00712 if ( ( path_store != 0L ) ||
00713 noEffectKey != d->lastImageKey )
00714 {
00715
00716 KIcon icon;
00717 if (absolutePath && !favIconOverlay)
00718 {
00719 icon.context=KIcon::Any;
00720 icon.type=KIcon::Scalable;
00721 icon.path=name;
00722 }
00723 else
00724 {
00725 if (!name.isEmpty())
00726 icon = findMatchingIcon(favIconOverlay ? QString("www") : name, size);
00727
00728 if (!icon.isValid())
00729 {
00730
00731 if (!name.isEmpty())
00732 pix = loadIcon(name, KIcon::User, size, state, path_store, true);
00733 if (!pix.isNull() || canReturnNull) {
00734 QPixmapCache::insert(key, pix);
00735 return pix;
00736 }
00737
00738 icon = findMatchingIcon(str_unknown, size);
00739 if (!icon.isValid())
00740 {
00741 kdDebug(264)
00742 << "Warning: could not find \"Unknown\" icon for size = "
00743 << size << endl;
00744 return pix;
00745 }
00746 }
00747 }
00748
00749 if (path_store != 0L)
00750 *path_store = icon.path;
00751 if (inCache)
00752 return pix;
00753
00754
00755 QString ext = icon.path.right(3).upper();
00756 if(ext != "SVG" && ext != "VGZ")
00757 {
00758 img = new QImage(icon.path, ext.latin1());
00759 if (img->isNull()) {
00760 delete img;
00761 return pix;
00762 }
00763 }
00764 #ifdef HAVE_LIBART
00765 else
00766 {
00767
00768 KSVGIconEngine *svgEngine = new KSVGIconEngine();
00769
00770 if(svgEngine->load(size, size, icon.path))
00771 img = svgEngine->painter()->image();
00772 else
00773 img = new QImage();
00774
00775 delete svgEngine;
00776 }
00777 #endif
00778
00779 iconType = icon.type;
00780 iconThreshold = icon.threshold;
00781
00782 d->lastImage = img->copy();
00783 d->lastImageKey = noEffectKey;
00784 d->lastIconType = iconType;
00785 d->lastIconThreshold = iconThreshold;
00786 }
00787 else
00788 {
00789 img = new QImage( d->lastImage.copy() );
00790 iconType = d->lastIconType;
00791 iconThreshold = d->lastIconThreshold;
00792 }
00793
00794
00795 if (overlay)
00796 {
00797 QImage *ovl;
00798 KIconTheme *theme = d->mpThemeRoot->theme;
00799 if ((overlay & KIcon::LockOverlay) &&
00800 ((ovl = loadOverlay(theme->lockOverlay(), size)) != 0L))
00801 KIconEffect::overlay(*img, *ovl);
00802 if ((overlay & KIcon::LinkOverlay) &&
00803 ((ovl = loadOverlay(theme->linkOverlay(), size)) != 0L))
00804 KIconEffect::overlay(*img, *ovl);
00805 if ((overlay & KIcon::ZipOverlay) &&
00806 ((ovl = loadOverlay(theme->zipOverlay(), size)) != 0L))
00807 KIconEffect::overlay(*img, *ovl);
00808 if ((overlay & KIcon::ShareOverlay) &&
00809 ((ovl = loadOverlay(theme->shareOverlay(), size)) != 0L))
00810 KIconEffect::overlay(*img, *ovl);
00811 if (overlay & KIcon::HiddenOverlay)
00812 {
00813 if (img->depth() != 32)
00814 *img = img->convertDepth(32);
00815 for (int y = 0; y < img->height(); y++)
00816 {
00817 QRgb *line = reinterpret_cast<QRgb *>(img->scanLine(y));
00818 for (int x = 0; x < img->width(); x++)
00819 line[x] = (line[x] & 0x00ffffff) | (QMIN(0x80, qAlpha(line[x])) << 24);
00820 }
00821 }
00822 }
00823
00824
00825 if (iconType == KIcon::Scalable && size != img->width())
00826 {
00827 *img = img->smoothScale(size, size);
00828 }
00829 if (iconType == KIcon::Threshold && size != img->width())
00830 {
00831 if ( abs(size-img->width())>iconThreshold )
00832 *img = img->smoothScale(size, size);
00833 }
00834 if (group >= 0 && d->mpGroups[group].dblPixels)
00835 {
00836 *img = d->mpEffect.doublePixels(*img);
00837 }
00838 if (group >= 0)
00839 {
00840 *img = d->mpEffect.apply(*img, group, state);
00841 }
00842
00843 if (favIconOverlay)
00844 {
00845 QImage favIcon(name, "PNG");
00846 int x = img->width() - favIcon.width() - 1,
00847 y = img->height() - favIcon.height() - 1;
00848 if( favIcon.depth() != 32 )
00849 favIcon = favIcon.convertDepth( 32 );
00850 if( img->depth() != 32 )
00851 *img = img->convertDepth( 32 );
00852 for( int line = 0;
00853 line < favIcon.height();
00854 ++line )
00855 {
00856 QRgb* fpos = reinterpret_cast< QRgb* >( favIcon.scanLine( line ));
00857 QRgb* ipos = reinterpret_cast< QRgb* >( img->scanLine( line + y )) + x;
00858 for( int i = 0;
00859 i < favIcon.width();
00860 ++i, ++fpos, ++ipos )
00861 *ipos = qRgba( ( qRed( *ipos ) * ( 255 - qAlpha( *fpos )) + qRed( *fpos ) * qAlpha( *fpos )) / 255,
00862 ( qGreen( *ipos ) * ( 255 - qAlpha( *fpos )) + qGreen( *fpos ) * qAlpha( *fpos )) / 255,
00863 ( qBlue( *ipos ) * ( 255 - qAlpha( *fpos )) + qBlue( *fpos ) * qAlpha( *fpos )) / 255,
00864 ( qAlpha( *ipos ) * ( 255 - qAlpha( *fpos )) + qAlpha( *fpos ) * qAlpha( *fpos )) / 255 );
00865 }
00866 }
00867
00868 pix.convertFromImage(*img);
00869
00870 delete img;
00871
00872 QPixmapCache::insert(key, pix);
00873 return pix;
00874 }
00875
00876 QImage *KIconLoader::loadOverlay(const QString &name, int size) const
00877 {
00878 QString key = name + '_' + QString::number(size);
00879 QImage *image = d->imgDict.find(key);
00880 if (image != 0L)
00881 return image;
00882
00883 KIcon icon = findMatchingIcon(name, size);
00884 if (!icon.isValid())
00885 {
00886 kdDebug(264) << "Overlay " << name << "not found." << endl;
00887 return 0L;
00888 }
00889 image = new QImage(icon.path);
00890
00891
00892 if ( size != image->width() )
00893 *image = image->smoothScale( size, size );
00894 d->imgDict.insert(key, image);
00895 return image;
00896 }
00897
00898
00899
00900 QMovie KIconLoader::loadMovie(const QString& name, KIcon::Group group, int size) const
00901 {
00902 QString file = moviePath( name, group, size );
00903 if (file.isEmpty())
00904 return QMovie();
00905 int dirLen = file.findRev('/');
00906 QString icon = iconPath(name, size ? -size : group, true);
00907 if (!icon.isEmpty() && file.left(dirLen) != icon.left(dirLen))
00908 return QMovie();
00909 return QMovie(file);
00910 }
00911
00912 QString KIconLoader::moviePath(const QString& name, KIcon::Group group, int size) const
00913 {
00914 if (!d->mpGroups) return QString::null;
00915
00916 if ( (group < -1 || group >= KIcon::LastGroup) && group != KIcon::User )
00917 {
00918 kdDebug(264) << "Illegal icon group: " << group << endl;
00919 group = KIcon::Desktop;
00920 }
00921 if (size == 0 && group < 0)
00922 {
00923 kdDebug(264) << "Neither size nor group specified!" << endl;
00924 group = KIcon::Desktop;
00925 }
00926
00927 QString file = name + ".mng";
00928 if (group == KIcon::User)
00929 {
00930 file = d->mpDirs->findResource("appicon", file);
00931 }
00932 else
00933 {
00934 if (size == 0)
00935 size = d->mpGroups[group].size;
00936
00937 KIcon icon;
00938
00939 for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
00940 themeNode = d->links.next() )
00941 {
00942 icon = themeNode->theme->iconPath(file, size, KIcon::MatchExact);
00943 if (icon.isValid())
00944 break;
00945 }
00946
00947 if ( !icon.isValid() )
00948 {
00949 for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
00950 themeNode = d->links.next() )
00951 {
00952 icon = themeNode->theme->iconPath(file, size, KIcon::MatchBest);
00953 if (icon.isValid())
00954 break;
00955 }
00956 }
00957
00958 file = icon.isValid() ? icon.path : QString::null;
00959 }
00960 return file;
00961 }
00962
00963
00964 QStringList KIconLoader::loadAnimated(const QString& name, KIcon::Group group, int size) const
00965 {
00966 QStringList lst;
00967
00968 if (!d->mpGroups) return lst;
00969
00970 if ((group < -1) || (group >= KIcon::LastGroup))
00971 {
00972 kdDebug(264) << "Illegal icon group: " << group << endl;
00973 group = KIcon::Desktop;
00974 }
00975 if ((size == 0) && (group < 0))
00976 {
00977 kdDebug(264) << "Neither size nor group specified!" << endl;
00978 group = KIcon::Desktop;
00979 }
00980
00981 QString file = name + "/0001";
00982 if (group == KIcon::User)
00983 {
00984 file = d->mpDirs->findResource("appicon", file + ".png");
00985 } else
00986 {
00987 if (size == 0)
00988 size = d->mpGroups[group].size;
00989 KIcon icon = findMatchingIcon(file, size);
00990 file = icon.isValid() ? icon.path : QString::null;
00991
00992 }
00993 if (file.isEmpty())
00994 return lst;
00995
00996 QString path = file.left(file.length()-8);
00997 DIR* dp = opendir( QFile::encodeName(path) );
00998 if(!dp)
00999 return lst;
01000
01001 struct dirent* ep;
01002 while( ( ep = readdir( dp ) ) != 0L )
01003 {
01004 QString fn(QFile::decodeName(ep->d_name));
01005 if(!(fn.left(4)).toUInt())
01006 continue;
01007
01008 lst += path + fn;
01009 }
01010 closedir ( dp );
01011 lst.sort();
01012 return lst;
01013 }
01014
01015 KIconTheme *KIconLoader::theme() const
01016 {
01017 if (d->mpThemeRoot) return d->mpThemeRoot->theme;
01018 return 0L;
01019 }
01020
01021 int KIconLoader::currentSize(KIcon::Group group) const
01022 {
01023 if (!d->mpGroups) return -1;
01024
01025 if (group < 0 || group >= KIcon::LastGroup)
01026 {
01027 kdDebug(264) << "Illegal icon group: " << group << endl;
01028 return -1;
01029 }
01030 return d->mpGroups[group].size;
01031 }
01032
01033 QStringList KIconLoader::queryIconsByDir( const QString& iconsDir ) const
01034 {
01035 QDir dir(iconsDir);
01036 QStringList lst = dir.entryList("*.png;*.xpm", QDir::Files);
01037 QStringList result;
01038 QStringList::ConstIterator it;
01039 for (it=lst.begin(); it!=lst.end(); ++it)
01040 result += iconsDir + "/" + *it;
01041 return result;
01042 }
01043
01044 QStringList KIconLoader::queryIconsByContext(int group_or_size,
01045 KIcon::Context context) const
01046 {
01047 QStringList result;
01048 if (group_or_size >= KIcon::LastGroup)
01049 {
01050 kdDebug(264) << "Illegal icon group: " << group_or_size << endl;
01051 return result;
01052 }
01053 int size;
01054 if (group_or_size >= 0)
01055 size = d->mpGroups[group_or_size].size;
01056 else
01057 size = -group_or_size;
01058
01059 for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
01060 themeNode = d->links.next() )
01061 themeNode->queryIconsByContext(&result, size, context);
01062
01063
01064 QString name;
01065 QStringList res2, entries;
01066 QStringList::ConstIterator it;
01067 for (it=result.begin(); it!=result.end(); ++it)
01068 {
01069 int n = (*it).findRev('/');
01070 if (n == -1)
01071 name = *it;
01072 else
01073 name = (*it).mid(n+1);
01074 name = removeIconExtension(name);
01075 if (!entries.contains(name))
01076 {
01077 entries += name;
01078 res2 += *it;
01079 }
01080 }
01081 return res2;
01082
01083 }
01084
01085 QStringList KIconLoader::queryIcons(int group_or_size, KIcon::Context context) const
01086 {
01087 QStringList result;
01088 if (group_or_size >= KIcon::LastGroup)
01089 {
01090 kdDebug(264) << "Illegal icon group: " << group_or_size << endl;
01091 return result;
01092 }
01093 int size;
01094 if (group_or_size >= 0)
01095 size = d->mpGroups[group_or_size].size;
01096 else
01097 size = -group_or_size;
01098
01099 for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
01100 themeNode = d->links.next() )
01101 themeNode->queryIcons(&result, size, context);
01102
01103
01104 QString name;
01105 QStringList res2, entries;
01106 QStringList::ConstIterator it;
01107 for (it=result.begin(); it!=result.end(); ++it)
01108 {
01109 int n = (*it).findRev('/');
01110 if (n == -1)
01111 name = *it;
01112 else
01113 name = (*it).mid(n+1);
01114 name = removeIconExtension(name);
01115 if (!entries.contains(name))
01116 {
01117 entries += name;
01118 res2 += *it;
01119 }
01120 }
01121 return res2;
01122 }
01123
01124
01125 bool KIconLoader::hasContext(KIcon::Context context) const
01126 {
01127 for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
01128 themeNode = d->links.next() )
01129 if( themeNode->theme->hasContext( context ))
01130 return true;
01131 return false;
01132 }
01133
01134 KIconEffect * KIconLoader::iconEffect() const
01135 {
01136 return &d->mpEffect;
01137 }
01138
01139 bool KIconLoader::alphaBlending(KIcon::Group group) const
01140 {
01141 if (!d->mpGroups) return false;
01142
01143 if (group < 0 || group >= KIcon::LastGroup)
01144 {
01145 kdDebug(264) << "Illegal icon group: " << group << endl;
01146 return false;
01147 }
01148 return d->mpGroups[group].alphaBlending;
01149 }
01150
01151 QIconSet KIconLoader::loadIconSet(const QString& name, KIcon::Group group, int size, bool canReturnNull)
01152 {
01153 return loadIconSet( name, group, size, canReturnNull, true );
01154 }
01155
01156 QIconSet KIconLoader::loadIconSet(const QString& name, KIcon::Group group, int size)
01157 {
01158 return loadIconSet( name, group, size, false );
01159 }
01160
01161
01162
01163 class KIconFactory
01164 : public QIconFactory
01165 {
01166 public:
01167 KIconFactory( const QString& iconName_P, KIcon::Group group_P,
01168 int size_P, KIconLoader* loader_P );
01169 KIconFactory( const QString& iconName_P, KIcon::Group group_P,
01170 int size_P, KIconLoader* loader_P, bool canReturnNull );
01171 virtual QPixmap* createPixmap( const QIconSet&, QIconSet::Size, QIconSet::Mode, QIconSet::State );
01172 private:
01173 QString iconName;
01174 KIcon::Group group;
01175 int size;
01176 KIconLoader* loader;
01177 bool canReturnNull;
01178 };
01179
01180
01181 QIconSet KIconLoader::loadIconSet( const QString& name, KIcon::Group g, int s,
01182 bool canReturnNull, bool immediateExistenceCheck)
01183 {
01184 if ( !d->delayedLoading )
01185 return loadIconSetNonDelayed( name, g, s, canReturnNull );
01186
01187 if (g < -1 || g > 6) {
01188 kdDebug() << "KIconLoader::loadIconSet " << name << " " << (int)g << " " << s << endl;
01189 qDebug("%s", kdBacktrace().latin1());
01190 abort();
01191 }
01192
01193 if(canReturnNull && immediateExistenceCheck)
01194 {
01195 QPixmap pm = loadIcon( name, g, s, KIcon::DefaultState, NULL, true );
01196 if( pm.isNull())
01197 return QIconSet();
01198
01199 QIconSet ret( pm );
01200 ret.installIconFactory( new KIconFactory( name, g, s, this ));
01201 return ret;
01202 }
01203
01204 QIconSet ret;
01205 ret.installIconFactory( new KIconFactory( name, g, s, this, canReturnNull ));
01206 return ret;
01207 }
01208
01209 QIconSet KIconLoader::loadIconSetNonDelayed( const QString& name,
01210 KIcon::Group g,
01211 int s, bool canReturnNull )
01212 {
01213 QIconSet iconset;
01214 QPixmap tmp = loadIcon(name, g, s, KIcon::ActiveState, NULL, canReturnNull);
01215 iconset.setPixmap( tmp, QIconSet::Small, QIconSet::Active );
01216
01217 iconset.setPixmap( tmp, QIconSet::Large, QIconSet::Active );
01218 tmp = loadIcon(name, g, s, KIcon::DisabledState, NULL, canReturnNull);
01219 iconset.setPixmap( tmp, QIconSet::Small, QIconSet::Disabled );
01220 iconset.setPixmap( tmp, QIconSet::Large, QIconSet::Disabled );
01221 tmp = loadIcon(name, g, s, KIcon::DefaultState, NULL, canReturnNull);
01222 iconset.setPixmap( tmp, QIconSet::Small, QIconSet::Normal );
01223 iconset.setPixmap( tmp, QIconSet::Large, QIconSet::Normal );
01224 return iconset;
01225 }
01226
01227 KIconFactory::KIconFactory( const QString& iconName_P, KIcon::Group group_P,
01228 int size_P, KIconLoader* loader_P )
01229 : iconName( iconName_P ), group( group_P ), size( size_P ), loader( loader_P )
01230 {
01231 canReturnNull = false;
01232 setAutoDelete( true );
01233 }
01234
01235 KIconFactory::KIconFactory( const QString& iconName_P, KIcon::Group group_P,
01236 int size_P, KIconLoader* loader_P, bool canReturnNull_P )
01237 : iconName( iconName_P ), group( group_P ), size( size_P ),
01238 loader( loader_P ), canReturnNull( canReturnNull_P)
01239 {
01240 setAutoDelete( true );
01241 }
01242
01243 QPixmap* KIconFactory::createPixmap( const QIconSet&, QIconSet::Size, QIconSet::Mode mode_P, QIconSet::State )
01244 {
01245 #ifdef KICONLOADER_CHECKS
01246 bool found = false;
01247 for( QValueList< KIconLoaderDebug >::Iterator it = kiconloaders->begin();
01248 it != kiconloaders->end();
01249 ++it )
01250 {
01251 if( (*it).loader == loader )
01252 {
01253 found = true;
01254 if( !(*it).valid )
01255 {
01256 #ifdef NDEBUG
01257 loader = KGlobal::iconLoader();
01258 iconName = "no_way_man_you_will_get_broken_icon";
01259 #else
01260 kdWarning() << "Using already destroyed KIconLoader for loading an icon!" << endl;
01261 kdWarning() << "Appname:" << (*it).appname << ", icon:" << iconName << endl;
01262 kdWarning() << "Deleted at:" << endl;
01263 kdWarning() << (*it).delete_bt << endl;
01264 kdWarning() << "Current:" << endl;
01265 kdWarning() << kdBacktrace() << endl;
01266 abort();
01267 return NULL;
01268 #endif
01269 }
01270 break;
01271 }
01272 }
01273 if( !found )
01274 {
01275 #ifdef NDEBUG
01276 loader = KGlobal::iconLoader();
01277 iconName = "no_way_man_you_will_get_broken_icon";
01278 #else
01279 kdWarning() << "Using unknown KIconLoader for loading an icon!" << endl;
01280 kdWarning() << "Icon:" << iconName << endl;
01281 kdWarning() << kdBacktrace() << endl;
01282 abort();
01283 return NULL;
01284 #endif
01285 }
01286 #endif
01287
01288 static const KIcon::States tbl[] = { KIcon::DefaultState, KIcon::DisabledState, KIcon::ActiveState };
01289 int state = KIcon::DefaultState;
01290 if( mode_P <= QIconSet::Active )
01291 state = tbl[ mode_P ];
01292 if( group >= 0 && state == KIcon::ActiveState )
01293 {
01294 if( loader->iconEffect()->fingerprint(group, KIcon::ActiveState )
01295 == loader->iconEffect()->fingerprint(group, KIcon::DefaultState ))
01296 return 0;
01297 }
01298
01299
01300 QPixmap pm = loader->loadIcon( iconName, group, size, state, 0, canReturnNull );
01301 return new QPixmap( pm );
01302 }
01303
01304
01305
01306 QPixmap DesktopIcon(const QString& name, int force_size, int state,
01307 KInstance *instance)
01308 {
01309 KIconLoader *loader = instance->iconLoader();
01310 return loader->loadIcon(name, KIcon::Desktop, force_size, state);
01311 }
01312
01313 QPixmap DesktopIcon(const QString& name, KInstance *instance)
01314 {
01315 return DesktopIcon(name, 0, KIcon::DefaultState, instance);
01316 }
01317
01318 QIconSet DesktopIconSet(const QString& name, int force_size, KInstance *instance)
01319 {
01320 KIconLoader *loader = instance->iconLoader();
01321 return loader->loadIconSet( name, KIcon::Desktop, force_size );
01322 }
01323
01324 QPixmap BarIcon(const QString& name, int force_size, int state,
01325 KInstance *instance)
01326 {
01327 KIconLoader *loader = instance->iconLoader();
01328 return loader->loadIcon(name, KIcon::Toolbar, force_size, state);
01329 }
01330
01331 QPixmap BarIcon(const QString& name, KInstance *instance)
01332 {
01333 return BarIcon(name, 0, KIcon::DefaultState, instance);
01334 }
01335
01336 QIconSet BarIconSet(const QString& name, int force_size, KInstance *instance)
01337 {
01338 KIconLoader *loader = instance->iconLoader();
01339 return loader->loadIconSet( name, KIcon::Toolbar, force_size );
01340 }
01341
01342 QPixmap SmallIcon(const QString& name, int force_size, int state,
01343 KInstance *instance)
01344 {
01345 KIconLoader *loader = instance->iconLoader();
01346 return loader->loadIcon(name, KIcon::Small, force_size, state);
01347 }
01348
01349 QPixmap SmallIcon(const QString& name, KInstance *instance)
01350 {
01351 return SmallIcon(name, 0, KIcon::DefaultState, instance);
01352 }
01353
01354 QIconSet SmallIconSet(const QString& name, int force_size, KInstance *instance)
01355 {
01356 KIconLoader *loader = instance->iconLoader();
01357 return loader->loadIconSet( name, KIcon::Small, force_size );
01358 }
01359
01360 QPixmap MainBarIcon(const QString& name, int force_size, int state,
01361 KInstance *instance)
01362 {
01363 KIconLoader *loader = instance->iconLoader();
01364 return loader->loadIcon(name, KIcon::MainToolbar, force_size, state);
01365 }
01366
01367 QPixmap MainBarIcon(const QString& name, KInstance *instance)
01368 {
01369 return MainBarIcon(name, 0, KIcon::DefaultState, instance);
01370 }
01371
01372 QIconSet MainBarIconSet(const QString& name, int force_size, KInstance *instance)
01373 {
01374 KIconLoader *loader = instance->iconLoader();
01375 return loader->loadIconSet( name, KIcon::MainToolbar, force_size );
01376 }
01377
01378 QPixmap UserIcon(const QString& name, int state, KInstance *instance)
01379 {
01380 KIconLoader *loader = instance->iconLoader();
01381 return loader->loadIcon(name, KIcon::User, 0, state);
01382 }
01383
01384 QPixmap UserIcon(const QString& name, KInstance *instance)
01385 {
01386 return UserIcon(name, KIcon::DefaultState, instance);
01387 }
01388
01389 QIconSet UserIconSet(const QString& name, KInstance *instance)
01390 {
01391 KIconLoader *loader = instance->iconLoader();
01392 return loader->loadIconSet( name, KIcon::User );
01393 }
01394
01395 int IconSize(KIcon::Group group, KInstance *instance)
01396 {
01397 KIconLoader *loader = instance->iconLoader();
01398 return loader->currentSize(group);
01399 }
01400
01401 QPixmap KIconLoader::unknown()
01402 {
01403 QPixmap pix;
01404 if ( QPixmapCache::find("unknown", pix) )
01405 return pix;
01406
01407 QString path = KGlobal::iconLoader()->iconPath("unknown", KIcon::Small, true);
01408 if (path.isEmpty())
01409 {
01410 kdDebug(264) << "Warning: Cannot find \"unknown\" icon." << endl;
01411 pix.resize(32,32);
01412 } else
01413 {
01414 pix.load(path);
01415 QPixmapCache::insert("unknown", pix);
01416 }
01417
01418 return pix;
01419 }
01420
01421 void KIconLoaderPrivate::reconfigure()
01422 {
01423 q->reconfigure(appname, mpDirs);
01424 }
01425
01426 #include "kiconloader_p.moc"