kdecore Library API Documentation

kiconloader.cpp

00001 /* vi: ts=8 sts=4 sw=4 00002 * 00003 * $Id: kiconloader.cpp,v 1.217 2003/11/20 21:41:54 antlarr Exp $ 00004 * 00005 * This file is part of the KDE project, module kdecore. 00006 * Copyright (C) 2000 Geert Jansen <jansen@kde.org> 00007 * Antonio Larrosa <larrosa@kde.org> 00008 * 00009 * This is free software; it comes under the GNU Library General 00010 * Public License, version 2. See the file "COPYING.LIB" for the 00011 * exact licensing terms. 00012 * 00013 * kiconloader.cpp: An icon loader for KDE with theming functionality. 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> //for abs 00042 #include <unistd.h> //for readlink 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 /*** KIconThemeNode: A node in the icon theme dependancy tree. ***/ 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 /* This method doesn't have much sense anymore, so maybe it should 00082 be removed in the (near?) future */ 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 // add the icons of this theme to it 00092 *result += theme->queryIcons(size, context); 00093 } 00094 00095 void KIconThemeNode::queryIconsByContext(QStringList *result, 00096 int size, KIcon::Context context) const 00097 { 00098 // add the icons of this theme to it 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 /*** KIconGroup: Icon type description. ***/ 00110 00111 struct KIconGroup 00112 { 00113 int size; 00114 bool dblPixels; 00115 bool alphaBlending; 00116 }; 00117 00118 00119 /*** d pointer for KIconLoader. ***/ 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; // last loaded image without effect applied 00131 QString lastImageKey; // key for icon without effect 00132 int lastIconType; // see KIcon::type 00133 int lastIconThreshold; // see KIcon::threshold 00134 QPtrList<KIconThemeNode> links; 00135 bool extraDesktopIconsLoaded :1; 00136 bool delayedLoading :1; 00137 }; 00138 00139 /*** KIconLoader: the icon loader ***/ 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 // If this is unequal to 0, the iconloader is initialized 00166 // successfully. 00167 d->mpThemeRoot = 0L; 00168 00169 // Check installed themes. 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 // Add the default theme and its base themes to the theme tree 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 // These have to match the order in kicontheme.h 00198 static const char * const groups[] = { "Desktop", "Toolbar", "MainToolbar", "Small", "Panel", 0L }; 00199 KConfig *config = KGlobal::config(); 00200 KConfigGroupSaver cs(config, "dummy"); 00201 00202 // loading config and default sizes 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 // Insert application specific themes at the top. 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 // Add legacy icon dirs. 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 /* antlarr: There's no need to delete d->mpThemeRoot as it's already 00243 deleted when the elements of d->links are deleted */ 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 /* antlarr: Multiple inheritance is a broken concept on icon themes, so 00421 the next code doesn't support it on purpose because in fact, it was 00422 never supported at all. This makes the order in which we look for an 00423 icon as: 00424 00425 png, svgz, svg, xpm exact match 00426 next theme in inheritance tree : png, svgz, svg, xpm exact match 00427 next theme in inheritance tree : png, svgz, svg, xpm exact match 00428 and so on 00429 00430 And if the icon couldn't be found then it tries best match in the same 00431 order. 00432 00433 */ 00434 for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ; 00435 themeNode = d->links.next() ) 00436 { 00437 for (int i = 0 ; i < count ; i++) 00438 { 00439 icon = themeNode->theme->iconPath(name + *ext[i], size, KIcon::MatchExact); 00440 if (icon.isValid()) 00441 return icon; 00442 } 00443 00444 } 00445 00446 for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ; 00447 themeNode = d->links.next() ) 00448 { 00449 for (int i = 0 ; i < count ; i++) 00450 { 00451 icon = themeNode->theme->iconPath(name + *ext[i], size, KIcon::MatchBest); 00452 if (icon.isValid()) 00453 return icon; 00454 } 00455 00456 } 00457 00458 return icon; 00459 } 00460 00461 inline QString KIconLoader::unknownIconPath( int size ) const 00462 { 00463 static const QString &str_unknown = KGlobal::staticQString("unknown"); 00464 00465 KIcon icon = findMatchingIcon(str_unknown, size); 00466 if (!icon.isValid()) 00467 { 00468 kdDebug(264) << "Warning: could not find \"Unknown\" icon for size = " 00469 << size << endl; 00470 return QString::null; 00471 } 00472 return icon.path; 00473 } 00474 00475 // Finds the absolute path to an icon. 00476 00477 QString KIconLoader::iconPath(const QString& _name, int group_or_size, 00478 bool canReturnNull) const 00479 { 00480 if (d->mpThemeRoot == 0L) 00481 return QString::null; 00482 00483 if (_name.at(0) == '/') 00484 return _name; 00485 00486 QString name = removeIconExtension( _name ); 00487 00488 QString path; 00489 if (group_or_size == KIcon::User) 00490 { 00491 static const QString &png_ext = KGlobal::staticQString(".png"); 00492 static const QString &xpm_ext = KGlobal::staticQString(".xpm"); 00493 path = d->mpDirs->findResource("appicon", name + png_ext); 00494 00495 #ifdef HAVE_LIBART 00496 static const QString &svgz_ext = KGlobal::staticQString(".svgz"); 00497 static const QString &svg_ext = KGlobal::staticQString(".svg"); 00498 if (path.isEmpty()) 00499 path = d->mpDirs->findResource("appicon", name + svgz_ext); 00500 if (path.isEmpty()) 00501 path = d->mpDirs->findResource("appicon", name + svg_ext); 00502 #endif 00503 if (path.isEmpty()) 00504 path = d->mpDirs->findResource("appicon", name + xpm_ext); 00505 return path; 00506 } 00507 00508 if (group_or_size >= KIcon::LastGroup) 00509 { 00510 kdDebug(264) << "Illegal icon group: " << group_or_size << endl; 00511 return path; 00512 } 00513 00514 int size; 00515 if (group_or_size >= 0) 00516 size = d->mpGroups[group_or_size].size; 00517 else 00518 size = -group_or_size; 00519 00520 if (_name.isEmpty()) { 00521 if (canReturnNull) 00522 return QString::null; 00523 else 00524 return unknownIconPath(size); 00525 } 00526 00527 KIcon icon = findMatchingIcon(name, size); 00528 00529 if (!icon.isValid()) 00530 { 00531 // Try "User" group too. 00532 path = iconPath(name, KIcon::User, true); 00533 if (!path.isEmpty() || canReturnNull) 00534 return path; 00535 00536 if (canReturnNull) 00537 return QString::null; 00538 else 00539 return unknownIconPath(size); 00540 } 00541 return icon.path; 00542 } 00543 00544 QPixmap KIconLoader::loadIcon(const QString& _name, KIcon::Group group, int size, 00545 int state, QString *path_store, bool canReturnNull) const 00546 { 00547 QString name = _name; 00548 QPixmap pix; 00549 QString key; 00550 bool absolutePath=false, favIconOverlay=false; 00551 00552 if (d->mpThemeRoot == 0L) 00553 return pix; 00554 00555 // Special case for absolute path icons. 00556 if (name.startsWith("favicons/")) 00557 { 00558 favIconOverlay = true; 00559 name = locateLocal("cache", name+".png"); 00560 } 00561 if (name.at(0) == '/') absolutePath=true; 00562 00563 static const QString &str_unknown = KGlobal::staticQString("unknown"); 00564 00565 // Special case for "User" icons. 00566 if (group == KIcon::User) 00567 { 00568 key = "$kicou_"; 00569 key += QString::number(size); key += '_'; 00570 key += name; 00571 bool inCache = QPixmapCache::find(key, pix); 00572 if (inCache && (path_store == 0L)) 00573 return pix; 00574 00575 QString path = (absolutePath) ? name : 00576 iconPath(name, KIcon::User, canReturnNull); 00577 if (path.isEmpty()) 00578 { 00579 if (canReturnNull) 00580 return pix; 00581 // We don't know the desired size: use small 00582 path = iconPath(str_unknown, KIcon::Small, true); 00583 if (path.isEmpty()) 00584 { 00585 kdDebug(264) << "Warning: Cannot find \"unknown\" icon." << endl; 00586 return pix; 00587 } 00588 } 00589 00590 if (path_store != 0L) 00591 *path_store = path; 00592 if (inCache) 00593 return pix; 00594 QImage img(path); 00595 if (size != 0) 00596 img=img.smoothScale(size,size); 00597 00598 pix.convertFromImage(img); 00599 QPixmapCache::insert(key, pix); 00600 return pix; 00601 } 00602 00603 // Regular case: Check parameters 00604 00605 if ((group < -1) || (group >= KIcon::LastGroup)) 00606 { 00607 kdDebug(264) << "Illegal icon group: " << group << endl; 00608 group = KIcon::Desktop; 00609 } 00610 00611 int overlay = (state & KIcon::OverlayMask); 00612 state &= ~KIcon::OverlayMask; 00613 if ((state < 0) || (state >= KIcon::LastState)) 00614 { 00615 kdDebug(264) << "Illegal icon state: " << state << endl; 00616 state = KIcon::DefaultState; 00617 } 00618 00619 if (size == 0 && group < 0) 00620 { 00621 kdDebug(264) << "Neither size nor group specified!" << endl; 00622 group = KIcon::Desktop; 00623 } 00624 00625 if (!absolutePath) 00626 { 00627 if (!canReturnNull && name.isEmpty()) 00628 name = str_unknown; 00629 else 00630 name = removeIconExtension(name); 00631 } 00632 00633 // If size == 0, use default size for the specified group. 00634 if (size == 0) 00635 { 00636 size = d->mpGroups[group].size; 00637 } 00638 favIconOverlay = favIconOverlay && size > 22; 00639 00640 // Generate a unique cache key for the icon. 00641 00642 key = "$kico_"; 00643 key += name; key += '_'; 00644 key += QString::number(size); key += '_'; 00645 00646 QString overlayStr = QString::number( overlay ); 00647 00648 QString noEffectKey = key + '_' + overlayStr; 00649 00650 if (group >= 0) 00651 { 00652 key += d->mpEffect.fingerprint(group, state); 00653 if (d->mpGroups[group].dblPixels) 00654 key += QString::fromLatin1(":dblsize"); 00655 } else 00656 key += QString::fromLatin1("noeffect"); 00657 key += '_'; 00658 key += overlayStr; 00659 00660 // Is the icon in the cache? 00661 bool inCache = QPixmapCache::find(key, pix); 00662 if (inCache && (path_store == 0L)) 00663 return pix; 00664 00665 QImage *img = 0; 00666 int iconType; 00667 int iconThreshold; 00668 00669 if ( ( path_store != 0L ) || 00670 noEffectKey != d->lastImageKey ) 00671 { 00672 // No? load it. 00673 KIcon icon; 00674 if (absolutePath && !favIconOverlay) 00675 { 00676 icon.context=KIcon::Any; 00677 icon.type=KIcon::Scalable; 00678 icon.path=name; 00679 } 00680 else 00681 { 00682 if (!name.isEmpty()) 00683 icon = findMatchingIcon(favIconOverlay ? QString("www") : name, size); 00684 00685 if (!icon.isValid()) 00686 { 00687 // Try "User" icon too. Some apps expect this. 00688 if (!name.isEmpty()) 00689 pix = loadIcon(name, KIcon::User, size, state, path_store, true); 00690 if (!pix.isNull() || canReturnNull) 00691 return pix; 00692 00693 icon = findMatchingIcon(str_unknown, size); 00694 if (!icon.isValid()) 00695 { 00696 kdDebug(264) 00697 << "Warning: could not find \"Unknown\" icon for size = " 00698 << size << endl; 00699 return pix; 00700 } 00701 } 00702 } 00703 00704 if (path_store != 0L) 00705 *path_store = icon.path; 00706 if (inCache) 00707 return pix; 00708 00709 // Use the extension as the format. Works for XPM and PNG, but not for SVG 00710 QString ext = icon.path.right(3).upper(); 00711 if(ext != "SVG" && ext != "VGZ") 00712 { 00713 img = new QImage(icon.path, ext.latin1()); 00714 if (img->isNull()) { 00715 delete img; 00716 return pix; 00717 } 00718 } 00719 #ifdef HAVE_LIBART 00720 else 00721 { 00722 // Special stuff for SVG icons 00723 KSVGIconEngine *svgEngine = new KSVGIconEngine(); 00724 00725 if(svgEngine->load(size, size, icon.path)) 00726 img = svgEngine->painter()->image(); 00727 else 00728 img = new QImage(); 00729 00730 delete svgEngine; 00731 } 00732 #endif 00733 00734 iconType = icon.type; 00735 iconThreshold = icon.threshold; 00736 00737 d->lastImage = img->copy(); 00738 d->lastImageKey = noEffectKey; 00739 d->lastIconType = iconType; 00740 d->lastIconThreshold = iconThreshold; 00741 } 00742 else 00743 { 00744 img = new QImage( d->lastImage.copy() ); 00745 iconType = d->lastIconType; 00746 iconThreshold = d->lastIconThreshold; 00747 } 00748 00749 // Blend in all overlays 00750 if (overlay) 00751 { 00752 QImage *ovl; 00753 KIconTheme *theme = d->mpThemeRoot->theme; 00754 if ((overlay & KIcon::LockOverlay) && 00755 ((ovl = loadOverlay(theme->lockOverlay(), size)) != 0L)) 00756 KIconEffect::overlay(*img, *ovl); 00757 if ((overlay & KIcon::LinkOverlay) && 00758 ((ovl = loadOverlay(theme->linkOverlay(), size)) != 0L)) 00759 KIconEffect::overlay(*img, *ovl); 00760 if ((overlay & KIcon::ZipOverlay) && 00761 ((ovl = loadOverlay(theme->zipOverlay(), size)) != 0L)) 00762 KIconEffect::overlay(*img, *ovl); 00763 if ((overlay & KIcon::ShareOverlay) && 00764 ((ovl = loadOverlay(theme->shareOverlay(), size)) != 0L)) 00765 KIconEffect::overlay(*img, *ovl); 00766 if (overlay & KIcon::HiddenOverlay) 00767 for (int y = 0; y < img->height(); y++) 00768 { 00769 Q_UINT32 *line = reinterpret_cast<Q_UINT32 *>(img->scanLine(y)); 00770 for (int x = 0; x < img->width(); x++) 00771 line[x] = (line[x] & 0x00ffffff) | (QMIN(0x80, qAlpha(line[x])) << 24); 00772 } 00773 } 00774 00775 // Scale the icon and apply effects if necessary 00776 if (iconType == KIcon::Scalable && size != img->width()) 00777 { 00778 *img = img->smoothScale(size, size); 00779 } 00780 if (iconType == KIcon::Threshold && size != img->width()) 00781 { 00782 if ( abs(size-img->width())>iconThreshold ) 00783 *img = img->smoothScale(size, size); 00784 } 00785 if (group >= 0 && d->mpGroups[group].dblPixels) 00786 { 00787 *img = d->mpEffect.doublePixels(*img); 00788 } 00789 if (group >= 0) 00790 { 00791 *img = d->mpEffect.apply(*img, group, state); 00792 } 00793 00794 pix.convertFromImage(*img); 00795 00796 delete img; 00797 00798 if (favIconOverlay) 00799 { 00800 QPixmap favIcon(name, "PNG"); 00801 int x = pix.width() - favIcon.width() - 1, 00802 y = pix.height() - favIcon.height() - 1; 00803 if (pix.mask()) 00804 { 00805 QBitmap mask = *pix.mask(); 00806 QBitmap fmask; 00807 if (favIcon.mask()) 00808 fmask = *favIcon.mask(); 00809 else { 00810 // expensive, but works 00811 fmask = favIcon.createHeuristicMask(); 00812 } 00813 00814 bitBlt(&mask, x, y, &fmask, 00815 0, 0, favIcon.width(), favIcon.height(), 00816 favIcon.mask() ? Qt::OrROP : Qt::SetROP); 00817 pix.setMask(mask); 00818 } 00819 bitBlt(&pix, x, y, &favIcon); 00820 } 00821 00822 QPixmapCache::insert(key, pix); 00823 return pix; 00824 } 00825 00826 QImage *KIconLoader::loadOverlay(const QString &name, int size) const 00827 { 00828 QString key = name + '_' + QString::number(size); 00829 QImage *image = d->imgDict.find(key); 00830 if (image != 0L) 00831 return image; 00832 00833 KIcon icon = findMatchingIcon(name, size); 00834 if (!icon.isValid()) 00835 { 00836 kdDebug(264) << "Overlay " << name << "not found." << endl; 00837 return 0L; 00838 } 00839 image = new QImage(icon.path); 00840 d->imgDict.insert(key, image); 00841 return image; 00842 } 00843 00844 00845 00846 QMovie KIconLoader::loadMovie(const QString& name, KIcon::Group group, int size) const 00847 { 00848 QString file = moviePath( name, group, size ); 00849 if (file.isEmpty()) 00850 return QMovie(); 00851 int dirLen = file.findRev('/'); 00852 QString icon = iconPath(name, size ? -size : group, true); 00853 if (!icon.isEmpty() && file.left(dirLen) != icon.left(dirLen)) 00854 return QMovie(); 00855 return QMovie(file); 00856 } 00857 00858 QString KIconLoader::moviePath(const QString& name, KIcon::Group group, int size) const 00859 { 00860 if (!d->mpGroups) return QString::null; 00861 00862 if ( (group < -1 || group >= KIcon::LastGroup) && group != KIcon::User ) 00863 { 00864 kdDebug(264) << "Illegal icon group: " << group << endl; 00865 group = KIcon::Desktop; 00866 } 00867 if (size == 0 && group < 0) 00868 { 00869 kdDebug(264) << "Neither size nor group specified!" << endl; 00870 group = KIcon::Desktop; 00871 } 00872 00873 QString file = name + ".mng"; 00874 if (group == KIcon::User) 00875 { 00876 file = d->mpDirs->findResource("appicon", file); 00877 } 00878 else 00879 { 00880 if (size == 0) 00881 size = d->mpGroups[group].size; 00882 00883 KIcon icon; 00884 00885 for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ; 00886 themeNode = d->links.next() ) 00887 { 00888 icon = themeNode->theme->iconPath(file, size, KIcon::MatchExact); 00889 if (icon.isValid()) 00890 break; 00891 } 00892 00893 if ( !icon.isValid() ) 00894 { 00895 for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ; 00896 themeNode = d->links.next() ) 00897 { 00898 icon = themeNode->theme->iconPath(file, size, KIcon::MatchBest); 00899 if (icon.isValid()) 00900 break; 00901 } 00902 } 00903 00904 file = icon.isValid() ? icon.path : QString::null; 00905 } 00906 return file; 00907 } 00908 00909 00910 QStringList KIconLoader::loadAnimated(const QString& name, KIcon::Group group, int size) const 00911 { 00912 QStringList lst; 00913 00914 if (!d->mpGroups) return lst; 00915 00916 if ((group < -1) || (group >= KIcon::LastGroup)) 00917 { 00918 kdDebug(264) << "Illegal icon group: " << group << endl; 00919 group = KIcon::Desktop; 00920 } 00921 if ((size == 0) && (group < 0)) 00922 { 00923 kdDebug(264) << "Neither size nor group specified!" << endl; 00924 group = KIcon::Desktop; 00925 } 00926 00927 QString file = name + "/0001"; 00928 if (group == KIcon::User) 00929 { 00930 file = d->mpDirs->findResource("appicon", file + ".png"); 00931 } else 00932 { 00933 if (size == 0) 00934 size = d->mpGroups[group].size; 00935 KIcon icon = findMatchingIcon(file, size); 00936 file = icon.isValid() ? icon.path : QString::null; 00937 00938 } 00939 if (file.isEmpty()) 00940 return lst; 00941 00942 QString path = file.left(file.length()-8); 00943 DIR* dp = opendir( QFile::encodeName(path) ); 00944 if(!dp) 00945 return lst; 00946 00947 struct dirent* ep; 00948 while( ( ep = readdir( dp ) ) != 0L ) 00949 { 00950 QString fn(QFile::decodeName(ep->d_name)); 00951 if(!(fn.left(4)).toUInt()) 00952 continue; 00953 00954 lst += path + fn; 00955 } 00956 closedir ( dp ); 00957 lst.sort(); 00958 return lst; 00959 } 00960 00961 KIconTheme *KIconLoader::theme() const 00962 { 00963 if (d->mpThemeRoot) return d->mpThemeRoot->theme; 00964 return 0L; 00965 } 00966 00967 int KIconLoader::currentSize(KIcon::Group group) const 00968 { 00969 if (!d->mpGroups) return -1; 00970 00971 if (group < 0 || group >= KIcon::LastGroup) 00972 { 00973 kdDebug(264) << "Illegal icon group: " << group << endl; 00974 return -1; 00975 } 00976 return d->mpGroups[group].size; 00977 } 00978 00979 QStringList KIconLoader::queryIconsByDir( const QString& iconsDir ) const 00980 { 00981 QDir dir(iconsDir); 00982 QStringList lst = dir.entryList("*.png;*.xpm", QDir::Files); 00983 QStringList result; 00984 QStringList::ConstIterator it; 00985 for (it=lst.begin(); it!=lst.end(); ++it) 00986 result += iconsDir + "/" + *it; 00987 return result; 00988 } 00989 00990 QStringList KIconLoader::queryIconsByContext(int group_or_size, 00991 KIcon::Context context) const 00992 { 00993 QStringList result; 00994 if (group_or_size >= KIcon::LastGroup) 00995 { 00996 kdDebug(264) << "Illegal icon group: " << group_or_size << endl; 00997 return result; 00998 } 00999 int size; 01000 if (group_or_size >= 0) 01001 size = d->mpGroups[group_or_size].size; 01002 else 01003 size = -group_or_size; 01004 01005 for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ; 01006 themeNode = d->links.next() ) 01007 themeNode->queryIconsByContext(&result, size, context); 01008 01009 // Eliminate duplicate entries (same icon in different directories) 01010 QString name; 01011 QStringList res2, entries; 01012 QStringList::ConstIterator it; 01013 for (it=result.begin(); it!=result.end(); ++it) 01014 { 01015 int n = (*it).findRev('/'); 01016 if (n == -1) 01017 name = *it; 01018 else 01019 name = (*it).mid(n+1); 01020 if (!entries.contains(name)) 01021 { 01022 entries += name; 01023 res2 += *it; 01024 } 01025 } 01026 return res2; 01027 01028 } 01029 01030 QStringList KIconLoader::queryIcons(int group_or_size, KIcon::Context context) const 01031 { 01032 QStringList result; 01033 if (group_or_size >= KIcon::LastGroup) 01034 { 01035 kdDebug(264) << "Illegal icon group: " << group_or_size << endl; 01036 return result; 01037 } 01038 int size; 01039 if (group_or_size >= 0) 01040 size = d->mpGroups[group_or_size].size; 01041 else 01042 size = -group_or_size; 01043 01044 for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ; 01045 themeNode = d->links.next() ) 01046 themeNode->queryIcons(&result, size, context); 01047 01048 // Eliminate duplicate entries (same icon in different directories) 01049 QString name; 01050 QStringList res2, entries; 01051 QStringList::ConstIterator it; 01052 for (it=result.begin(); it!=result.end(); ++it) 01053 { 01054 int n = (*it).findRev('/'); 01055 if (n == -1) 01056 name = *it; 01057 else 01058 name = (*it).mid(n+1); 01059 if (!entries.contains(name)) 01060 { 01061 entries += name; 01062 res2 += *it; 01063 } 01064 } 01065 return res2; 01066 } 01067 01068 KIconEffect * KIconLoader::iconEffect() const 01069 { 01070 return &d->mpEffect; 01071 } 01072 01073 bool KIconLoader::alphaBlending(KIcon::Group group) const 01074 { 01075 if (!d->mpGroups) return -1; 01076 01077 if (group < 0 || group >= KIcon::LastGroup) 01078 { 01079 kdDebug(264) << "Illegal icon group: " << group << endl; 01080 return -1; 01081 } 01082 return d->mpGroups[group].alphaBlending; 01083 } 01084 01085 QIconSet KIconLoader::loadIconSet(const QString& name, KIcon::Group group, int size) 01086 { 01087 return loadIconSet( name, group, size, false ); 01088 } 01089 01090 /*** class for delayed icon loading for QIconSet ***/ 01091 01092 class KIconFactory 01093 : public QIconFactory 01094 { 01095 public: 01096 KIconFactory( const QString& iconName_P, KIcon::Group group_P, 01097 int size_P, KIconLoader* loader_P ); 01098 virtual QPixmap* createPixmap( const QIconSet&, QIconSet::Size, QIconSet::Mode, QIconSet::State ); 01099 private: 01100 QString iconName; 01101 KIcon::Group group; 01102 int size; 01103 KIconLoader* loader; 01104 }; 01105 01106 01107 QIconSet KIconLoader::loadIconSet( const QString& name, KIcon::Group g, int s, 01108 bool canReturnNull) 01109 { 01110 if ( !d->delayedLoading ) 01111 return loadIconSetNonDelayed( name, g, s, canReturnNull ); 01112 01113 if (g < -1 || g > 6) { 01114 kdDebug() << "KIconLoader::loadIconSet " << name << " " << (int)g << " " << s << endl; 01115 qDebug("%s", kdBacktrace().latin1()); 01116 abort(); 01117 } 01118 01119 if(canReturnNull) 01120 { // we need to find out if the icon actually exists 01121 QPixmap pm = loadIcon( name, g, s, KIcon::DefaultState, NULL, true ); 01122 if( pm.isNull()) 01123 return QIconSet(); 01124 01125 QIconSet ret( pm ); 01126 ret.installIconFactory( new KIconFactory( name, g, s, this )); 01127 return ret; 01128 } 01129 01130 QIconSet ret; 01131 ret.installIconFactory( new KIconFactory( name, g, s, this )); 01132 return ret; 01133 } 01134 01135 QIconSet KIconLoader::loadIconSetNonDelayed( const QString& name, 01136 KIcon::Group g, 01137 int s, bool canReturnNull ) 01138 { 01139 QIconSet iconset; 01140 QPixmap tmp = loadIcon(name, g, s, KIcon::ActiveState, NULL, canReturnNull); 01141 iconset.setPixmap( tmp, QIconSet::Small, QIconSet::Active ); 01142 // we don't use QIconSet's resizing anyway 01143 iconset.setPixmap( tmp, QIconSet::Large, QIconSet::Active ); 01144 tmp = loadIcon(name, g, s, KIcon::DisabledState, NULL, canReturnNull); 01145 iconset.setPixmap( tmp, QIconSet::Small, QIconSet::Disabled ); 01146 iconset.setPixmap( tmp, QIconSet::Large, QIconSet::Disabled ); 01147 tmp = loadIcon(name, g, s, KIcon::DefaultState, NULL, canReturnNull); 01148 iconset.setPixmap( tmp, QIconSet::Small, QIconSet::Normal ); 01149 iconset.setPixmap( tmp, QIconSet::Large, QIconSet::Normal ); 01150 return iconset; 01151 } 01152 01153 KIconFactory::KIconFactory( const QString& iconName_P, KIcon::Group group_P, 01154 int size_P, KIconLoader* loader_P ) 01155 : iconName( iconName_P ), group( group_P ), size( size_P ), loader( loader_P ) 01156 { 01157 setAutoDelete( true ); 01158 } 01159 01160 QPixmap* KIconFactory::createPixmap( const QIconSet&, QIconSet::Size, QIconSet::Mode mode_P, QIconSet::State ) 01161 { 01162 // QIconSet::Mode to KIcon::State conversion 01163 static const KIcon::States tbl[] = { KIcon::DefaultState, KIcon::DisabledState, KIcon::ActiveState }; 01164 int state = KIcon::DefaultState; 01165 if( mode_P <= QIconSet::Active ) 01166 state = tbl[ mode_P ]; 01167 if( group >= 0 && state == KIcon::ActiveState ) 01168 { // active and normal icon are usually the same 01169 if( loader->iconEffect()->fingerprint(group, KIcon::ActiveState ) 01170 == loader->iconEffect()->fingerprint(group, KIcon::DefaultState )) 01171 return 0; // so let QIconSet simply duplicate it 01172 } 01173 // ignore passed size 01174 // ignore passed state (i.e. on/off) 01175 QPixmap pm = loader->loadIcon( iconName, group, size, state ); 01176 return new QPixmap( pm ); 01177 } 01178 01179 // Easy access functions 01180 01181 QPixmap DesktopIcon(const QString& name, int force_size, int state, 01182 KInstance *instance) 01183 { 01184 KIconLoader *loader = instance->iconLoader(); 01185 return loader->loadIcon(name, KIcon::Desktop, force_size, state); 01186 } 01187 01188 QPixmap DesktopIcon(const QString& name, KInstance *instance) 01189 { 01190 return DesktopIcon(name, 0, KIcon::DefaultState, instance); 01191 } 01192 01193 QIconSet DesktopIconSet(const QString& name, int force_size, KInstance *instance) 01194 { 01195 KIconLoader *loader = instance->iconLoader(); 01196 return loader->loadIconSet( name, KIcon::Desktop, force_size ); 01197 } 01198 01199 QPixmap BarIcon(const QString& name, int force_size, int state, 01200 KInstance *instance) 01201 { 01202 KIconLoader *loader = instance->iconLoader(); 01203 return loader->loadIcon(name, KIcon::Toolbar, force_size, state); 01204 } 01205 01206 QPixmap BarIcon(const QString& name, KInstance *instance) 01207 { 01208 return BarIcon(name, 0, KIcon::DefaultState, instance); 01209 } 01210 01211 QIconSet BarIconSet(const QString& name, int force_size, KInstance *instance) 01212 { 01213 KIconLoader *loader = instance->iconLoader(); 01214 return loader->loadIconSet( name, KIcon::Toolbar, force_size ); 01215 } 01216 01217 QPixmap SmallIcon(const QString& name, int force_size, int state, 01218 KInstance *instance) 01219 { 01220 KIconLoader *loader = instance->iconLoader(); 01221 return loader->loadIcon(name, KIcon::Small, force_size, state); 01222 } 01223 01224 QPixmap SmallIcon(const QString& name, KInstance *instance) 01225 { 01226 return SmallIcon(name, 0, KIcon::DefaultState, instance); 01227 } 01228 01229 QIconSet SmallIconSet(const QString& name, int force_size, KInstance *instance) 01230 { 01231 KIconLoader *loader = instance->iconLoader(); 01232 return loader->loadIconSet( name, KIcon::Small, force_size ); 01233 } 01234 01235 QPixmap MainBarIcon(const QString& name, int force_size, int state, 01236 KInstance *instance) 01237 { 01238 KIconLoader *loader = instance->iconLoader(); 01239 return loader->loadIcon(name, KIcon::MainToolbar, force_size, state); 01240 } 01241 01242 QPixmap MainBarIcon(const QString& name, KInstance *instance) 01243 { 01244 return MainBarIcon(name, 0, KIcon::DefaultState, instance); 01245 } 01246 01247 QIconSet MainBarIconSet(const QString& name, int force_size, KInstance *instance) 01248 { 01249 KIconLoader *loader = instance->iconLoader(); 01250 return loader->loadIconSet( name, KIcon::MainToolbar, force_size ); 01251 } 01252 01253 QPixmap UserIcon(const QString& name, int state, KInstance *instance) 01254 { 01255 KIconLoader *loader = instance->iconLoader(); 01256 return loader->loadIcon(name, KIcon::User, 0, state); 01257 } 01258 01259 QPixmap UserIcon(const QString& name, KInstance *instance) 01260 { 01261 return UserIcon(name, KIcon::DefaultState, instance); 01262 } 01263 01264 QIconSet UserIconSet(const QString& name, KInstance *instance) 01265 { 01266 KIconLoader *loader = instance->iconLoader(); 01267 return loader->loadIconSet( name, KIcon::User ); 01268 } 01269 01270 int IconSize(KIcon::Group group, KInstance *instance) 01271 { 01272 KIconLoader *loader = instance->iconLoader(); 01273 return loader->currentSize(group); 01274 } 01275 01276 QPixmap KIconLoader::unknown() 01277 { 01278 QPixmap pix; 01279 if ( QPixmapCache::find("unknown", pix) ) 01280 return pix; 01281 01282 QString path = KGlobal::iconLoader()->iconPath("unknown", KIcon::Small, true); 01283 if (path.isEmpty()) 01284 { 01285 kdDebug(264) << "Warning: Cannot find \"unknown\" icon." << endl; 01286 pix.resize(32,32); 01287 } else 01288 { 01289 pix.load(path); 01290 QPixmapCache::insert("unknown", pix); 01291 } 01292 01293 return pix; 01294 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 20 09:48:26 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003