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