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