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