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