kdecore Library API Documentation

kiconloader.cpp

00001 /* vi: ts=8 sts=4 sw=4 00002 * 00003 * $Id: kiconloader.cpp,v 1.220 2004/07/31 10:17:48 binner 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 // ################## KDE4: consider removing the toolbar directory 00224 d->mpDirs->addResourceType("appicon", KStandardDirs::kde_default("data") + 00225 appname + "/toolbar/"); 00226 00227 // Add legacy icon dirs. 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 /* antlarr: There's no need to delete d->mpThemeRoot as it's already 00244 deleted when the elements of d->links are deleted */ 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 // ################## KDE4: consider removing the toolbar directory 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 /* antlarr: Multiple inheritance is a broken concept on icon themes, so 00423 the next code doesn't support it on purpose because in fact, it was 00424 never supported at all. This makes the order in which we look for an 00425 icon as: 00426 00427 png, svgz, svg, xpm exact match 00428 next theme in inheritance tree : png, svgz, svg, xpm exact match 00429 next theme in inheritance tree : png, svgz, svg, xpm exact match 00430 and so on 00431 00432 And if the icon couldn't be found then it tries best match in the same 00433 order. 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 // Finds the absolute path to an icon. 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 // Try "User" group too. 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 // Special case for absolute path icons. 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 // Special case for "User" icons. 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 // We don't know the desired size: use small 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 // Regular case: Check parameters 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 // If size == 0, use default size for the specified group. 00636 if (size == 0) 00637 { 00638 size = d->mpGroups[group].size; 00639 } 00640 favIconOverlay = favIconOverlay && size > 22; 00641 00642 // Generate a unique cache key for the icon. 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 // Is the icon in the cache? 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 // No? load it. 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 // Try "User" icon too. Some apps expect this. 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 // Use the extension as the format. Works for XPM and PNG, but not for SVG 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 // Special stuff for SVG icons 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 // Blend in all overlays 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 // Scale the icon and apply effects if necessary 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 // expensive, but works 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 // In some cases (since size in findMatchingIcon() is more a hint than a 00843 // constraint) image->size can be != size. If so perform rescaling. 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 // Eliminate duplicate entries (same icon in different directories) 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 // Eliminate duplicate entries (same icon in different directories) 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 /*** class for delayed icon loading for QIconSet ***/ 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 { // we need to find out if the icon actually exists 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 // we don't use QIconSet's resizing anyway 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 // QIconSet::Mode to KIcon::State conversion 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 { // active and normal icon are usually the same 01177 if( loader->iconEffect()->fingerprint(group, KIcon::ActiveState ) 01178 == loader->iconEffect()->fingerprint(group, KIcon::DefaultState )) 01179 return 0; // so let QIconSet simply duplicate it 01180 } 01181 // ignore passed size 01182 // ignore passed state (i.e. on/off) 01183 QPixmap pm = loader->loadIcon( iconName, group, size, state ); 01184 return new QPixmap( pm ); 01185 } 01186 01187 // Easy access functions 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 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Sep 29 09:43:10 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003