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