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