00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 #include <qstring.h>
00017 #include <qstringlist.h>
00018 #include <qptrlist.h>
00019 #include <qintdict.h>
00020 #include <qpixmap.h>
00021 #include <qpixmapcache.h>
00022 #include <qimage.h>
00023 #include <qfileinfo.h>
00024 #include <qdir.h>
00025 #include <qiconset.h>
00026 #include <qmovie.h>
00027 #include <qbitmap.h>
00028 
00029 #include <kdebug.h>
00030 #include <kstandarddirs.h>
00031 #include <kglobal.h>
00032 #include <kconfig.h>
00033 #include <ksimpleconfig.h>
00034 #include <kinstance.h>
00035 
00036 #include <kicontheme.h>
00037 #include <kiconloader.h>
00038 #include <kiconeffect.h>
00039 
00040 #include <sys/types.h>
00041 #include <stdlib.h> 
00042 #include <unistd.h>     
00043 #include <dirent.h>
00044 #include <config.h>
00045 #include <assert.h>
00046 
00047 #ifdef HAVE_LIBART
00048 #include "svgicons/ksvgiconengine.h"
00049 #include "svgicons/ksvgiconpainter.h"
00050 #endif
00051 
00052 
00053 
00054 class KIconThemeNode
00055 {
00056 public:
00057 
00058     KIconThemeNode(KIconTheme *_theme);
00059     ~KIconThemeNode();
00060 
00061     void queryIcons(QStringList *lst, int size, KIcon::Context context) const;
00062     void queryIconsByContext(QStringList *lst, int size, KIcon::Context context) const;
00063     KIcon findIcon(const QString& name, int size, KIcon::MatchType match) const;
00064     void printTree(QString& dbgString) const;
00065 
00066     KIconTheme *theme;
00067 };
00068 
00069 KIconThemeNode::KIconThemeNode(KIconTheme *_theme)
00070 {
00071     theme = _theme;
00072 }
00073 
00074 KIconThemeNode::~KIconThemeNode()
00075 {
00076     delete theme;
00077 }
00078 
00079 void KIconThemeNode::printTree(QString& dbgString) const
00080 {
00081     
00082 
00083     dbgString += "(";
00084     dbgString += theme->name();
00085     dbgString += ")";
00086 }
00087 
00088 void KIconThemeNode::queryIcons(QStringList *result,
00089                 int size, KIcon::Context context) const
00090 {
00091     
00092     *result += theme->queryIcons(size, context);
00093 }
00094 
00095 void KIconThemeNode::queryIconsByContext(QStringList *result,
00096                 int size, KIcon::Context context) const
00097 {
00098     
00099     *result += theme->queryIconsByContext(size, context);
00100 }
00101 
00102 KIcon KIconThemeNode::findIcon(const QString& name, int size,
00103                    KIcon::MatchType match) const
00104 {
00105     return theme->iconPath(name, size, match);
00106 }
00107 
00108 
00109 
00110 
00111 struct KIconGroup
00112 {
00113     int size;
00114     bool dblPixels;
00115     bool alphaBlending;
00116 };
00117 
00118 
00119 
00120 
00121 struct KIconLoaderPrivate
00122 {
00123     QStringList mThemeList;
00124     QStringList mThemesInTree;
00125     KIconGroup *mpGroups;
00126     KIconThemeNode *mpThemeRoot;
00127     KStandardDirs *mpDirs;
00128     KIconEffect mpEffect;
00129     QDict<QImage> imgDict;
00130     QImage lastImage; 
00131     QString lastImageKey; 
00132     int lastIconType; 
00133     int lastIconThreshold; 
00134     QPtrList<KIconThemeNode> links;
00135     bool extraDesktopIconsLoaded :1;
00136     bool delayedLoading :1;
00137 };
00138 
00139 
00140 
00141 KIconLoader::KIconLoader(const QString& _appname, KStandardDirs *_dirs)
00142 {
00143     init( _appname, _dirs );
00144 }
00145 
00146 void KIconLoader::reconfigure( const QString& _appname, KStandardDirs *_dirs )
00147 {
00148     delete d;
00149     init( _appname, _dirs );
00150 }
00151 
00152 void KIconLoader::init( const QString& _appname, KStandardDirs *_dirs )
00153 {
00154     d = new KIconLoaderPrivate;
00155     d->imgDict.setAutoDelete( true );
00156     d->links.setAutoDelete(true);
00157     d->extraDesktopIconsLoaded=false;
00158     d->delayedLoading=false;
00159 
00160     if (_dirs)
00161     d->mpDirs = _dirs;
00162     else
00163     d->mpDirs = KGlobal::dirs();
00164 
00165     
00166     
00167     d->mpThemeRoot = 0L;
00168 
00169     
00170     d->mThemeList = KIconTheme::list();
00171     if (!d->mThemeList.contains(KIconTheme::defaultThemeName()))
00172     {
00173         kdError(264) << "Error: standard icon theme"
00174                      << " \"" << KIconTheme::defaultThemeName() << "\" "
00175                      << " not found!" << endl;
00176         d->mpGroups=0L;
00177 
00178         return;
00179     }
00180 
00181     QString appname = _appname;
00182     if (appname.isEmpty())
00183     appname = KGlobal::instance()->instanceName();
00184 
00185     
00186     KIconTheme *def = new KIconTheme(KIconTheme::current(), appname);
00187     if (!def->isValid())
00188     {
00189     delete def;
00190     def = new KIconTheme(KIconTheme::defaultThemeName(), appname);
00191     }
00192     d->mpThemeRoot = new KIconThemeNode(def);
00193     d->links.append(d->mpThemeRoot);
00194     d->mThemesInTree += KIconTheme::current();
00195     addBaseThemes(d->mpThemeRoot, appname);
00196 
00197     
00198     static const char * const groups[] = { "Desktop", "Toolbar", "MainToolbar", "Small", "Panel", 0L };
00199     KConfig *config = KGlobal::config();
00200     KConfigGroupSaver cs(config, "dummy");
00201 
00202     
00203     d->mpGroups = new KIconGroup[(int) KIcon::LastGroup];
00204     for (KIcon::Group i=KIcon::FirstGroup; i<KIcon::LastGroup; i++)
00205     {
00206     if (groups[i] == 0L)
00207         break;
00208     config->setGroup(QString::fromLatin1(groups[i]) + "Icons");
00209     d->mpGroups[i].size = config->readNumEntry("Size", 0);
00210     d->mpGroups[i].dblPixels = config->readBoolEntry("DoublePixels", false);
00211     if (QPixmap::defaultDepth()>8)
00212         d->mpGroups[i].alphaBlending = config->readBoolEntry("AlphaBlending", true);
00213     else
00214         d->mpGroups[i].alphaBlending = false;
00215 
00216     if (!d->mpGroups[i].size)
00217         d->mpGroups[i].size = d->mpThemeRoot->theme->defaultSize(i);
00218     }
00219 
00220     
00221     d->mpDirs->addResourceType("appicon", KStandardDirs::kde_default("data") +
00222         appname + "/pics/");
00223     d->mpDirs->addResourceType("appicon", KStandardDirs::kde_default("data") +
00224         appname + "/toolbar/");
00225 
00226     
00227     QStringList dirs;
00228     dirs += d->mpDirs->resourceDirs("icon");
00229     dirs += d->mpDirs->resourceDirs("pixmap");
00230     for (QStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it)
00231     d->mpDirs->addResourceDir("appicon", *it);
00232 
00233 #ifndef NDEBUG
00234     QString dbgString = "Theme tree: ";
00235     d->mpThemeRoot->printTree(dbgString);
00236     kdDebug(264) << dbgString << endl;
00237 #endif
00238 }
00239 
00240 KIconLoader::~KIconLoader()
00241 {
00242     
00243 
00244     d->mpThemeRoot=0;
00245     delete[] d->mpGroups;
00246     delete d;
00247 }
00248 
00249 void KIconLoader::enableDelayedIconSetLoading( bool enable )
00250 {
00251     d->delayedLoading = enable;
00252 }
00253 
00254 bool KIconLoader::isDelayedIconSetLoadingEnabled() const
00255 {
00256     return d->delayedLoading;
00257 }
00258 
00259 void KIconLoader::addAppDir(const QString& appname)
00260 {
00261     d->mpDirs->addResourceType("appicon", KStandardDirs::kde_default("data") +
00262         appname + "/pics/");
00263     d->mpDirs->addResourceType("appicon", KStandardDirs::kde_default("data") +
00264         appname + "/toolbar/");
00265     addAppThemes(appname);
00266 }
00267 
00268 void KIconLoader::addAppThemes(const QString& appname)
00269 {
00270     if ( KIconTheme::current() != KIconTheme::defaultThemeName() )
00271     {
00272         KIconTheme *def = new KIconTheme(KIconTheme::current(), appname);
00273         if (def->isValid())
00274         {
00275             KIconThemeNode* node = new KIconThemeNode(def);
00276             d->links.append(node);
00277             addBaseThemes(node, appname);
00278         }
00279         else
00280             delete def;
00281     }
00282 
00283     KIconTheme *def = new KIconTheme(KIconTheme::defaultThemeName(), appname);
00284     KIconThemeNode* node = new KIconThemeNode(def);
00285     d->links.append(node);
00286     addBaseThemes(node, appname);
00287 }
00288 
00289 void KIconLoader::addBaseThemes(KIconThemeNode *node, const QString &appname)
00290 {
00291     QStringList lst = node->theme->inherits();
00292     QStringList::ConstIterator it;
00293 
00294     for (it=lst.begin(); it!=lst.end(); ++it)
00295     {
00296     if (!d->mThemeList.contains(*it) ||
00297         ( d->mThemesInTree.contains(*it) && (*it) != "hicolor"))
00298         continue;
00299     KIconTheme *theme = new KIconTheme(*it,appname);
00300     if (!theme->isValid()) {
00301         delete theme;
00302         continue;
00303     }
00304         KIconThemeNode *n = new KIconThemeNode(theme);
00305     d->mThemesInTree.append(*it);
00306     addBaseThemes(n, appname);
00307     d->links.append(n);
00308     }
00309 }
00310 
00311 void KIconLoader::addExtraDesktopThemes()
00312 {
00313     if ( d->extraDesktopIconsLoaded ) return;
00314 
00315     QStringList list;
00316     QStringList icnlibs = KGlobal::dirs()->resourceDirs("icon");
00317     QStringList::ConstIterator it;
00318     char buf[1000];
00319     int r;
00320     for (it=icnlibs.begin(); it!=icnlibs.end(); ++it)
00321     {
00322     QDir dir(*it);
00323     if (!dir.exists())
00324         continue;
00325     QStringList lst = dir.entryList("default.*", QDir::Dirs);
00326     QStringList::ConstIterator it2;
00327     for (it2=lst.begin(); it2!=lst.end(); ++it2)
00328     {
00329         if (!KStandardDirs::exists(*it + *it2 + "/index.desktop")
00330         && !KStandardDirs::exists(*it + *it2 + "/index.theme"))
00331         continue;
00332         r=readlink( QFile::encodeName(*it + *it2) , buf, sizeof(buf)-1);
00333         if ( r>0 )
00334         {
00335           buf[r]=0;
00336           QDir dir2( buf );
00337           QString themeName=dir2.dirName();
00338 
00339           if (!list.contains(themeName))
00340         list.append(themeName);
00341         }
00342     }
00343     }
00344 
00345     for (it=list.begin(); it!=list.end(); ++it)
00346     {
00347     if ( d->mThemesInTree.contains(*it) )
00348         continue;
00349     if ( *it == QString("default.kde") ) continue;
00350 
00351     KIconTheme *def = new KIconTheme( *it, "" );
00352     KIconThemeNode* node = new KIconThemeNode(def);
00353     d->mThemesInTree.append(*it);
00354     d->links.append(node);
00355     addBaseThemes(node, "" );
00356     }
00357 
00358     d->extraDesktopIconsLoaded=true;
00359 
00360 }
00361 
00362 bool KIconLoader::extraDesktopThemesAdded() const
00363 {
00364     return d->extraDesktopIconsLoaded;
00365 }
00366 
00367 QString KIconLoader::removeIconExtension(const QString &name) const
00368 {
00369     int extensionLength=0;
00370 
00371     QString ext = name.right(4);
00372 
00373     static const QString &png_ext = KGlobal::staticQString(".png");
00374     static const QString &xpm_ext = KGlobal::staticQString(".xpm");
00375     if (ext == png_ext || ext == xpm_ext)
00376       extensionLength=4;
00377 #ifdef HAVE_LIBART
00378     else
00379     {
00380     static const QString &svgz_ext = KGlobal::staticQString(".svgz");
00381     static const QString &svg_ext = KGlobal::staticQString(".svg");
00382 
00383     if (name.right(5) == svgz_ext)
00384         extensionLength=5;
00385     else if (ext == svg_ext)
00386         extensionLength=4;
00387     }
00388 #endif
00389 
00390     if ( extensionLength > 0 )
00391     {
00392 #ifndef NDEBUG
00393     kdDebug(264) << "Application " << KGlobal::instance()->instanceName()
00394                      << " loads icon " << name << " with extension." << endl;
00395 #endif
00396 
00397     return name.left(name.length() - extensionLength);
00398     }
00399     return name;
00400 }
00401 
00402 
00403 KIcon KIconLoader::findMatchingIcon(const QString& name, int size) const
00404 {
00405     KIcon icon;
00406 
00407     const QString *ext[4];
00408     int count=0;
00409     static const QString &png_ext = KGlobal::staticQString(".png");
00410     ext[count++]=&png_ext;
00411 #ifdef HAVE_LIBART
00412     static const QString &svgz_ext = KGlobal::staticQString(".svgz");
00413     ext[count++]=&svgz_ext;
00414     static const QString &svg_ext = KGlobal::staticQString(".svg");
00415     ext[count++]=&svg_ext;
00416 #endif
00417     static const QString &xpm_ext = KGlobal::staticQString(".xpm");
00418     ext[count++]=&xpm_ext;
00419 
00420     
00421 
00422 
00423 
00424 
00425 
00426 
00427 
00428 
00429 
00430 
00431 
00432 
00433 
00434     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 
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     
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     
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     
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         
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     
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     
00634     if (size == 0)
00635     {
00636     size = d->mpGroups[group].size;
00637     }
00638     favIconOverlay = favIconOverlay && size > 22;
00639 
00640     
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     
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         
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                 
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     
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         
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     
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     
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         
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     
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     
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 
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     { 
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     
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     
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     { 
01169     if( loader->iconEffect()->fingerprint(group, KIcon::ActiveState )
01170             == loader->iconEffect()->fingerprint(group, KIcon::DefaultState ))
01171             return 0; 
01172     }
01173     
01174     
01175     QPixmap pm = loader->loadIcon( iconName, group, size, state );
01176     return new QPixmap( pm );
01177     }
01178 
01179 
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 }