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