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