• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdecore
 

tdecore

kicontheme.cpp

00001 /* vi: ts=8 sts=4 sw=4
00002  *
00003  * $Id$
00004  *
00005  * This file is part of the KDE project, module tdecore.
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  * kicontheme.cpp: Lowlevel icon theme handling.
00014  */
00015 
00016 #include <sys/stat.h>
00017 #include <unistd.h>
00018 #include <stdlib.h>
00019 #include <config.h>
00020 
00021 #include <tqstring.h>
00022 #include <tqstringlist.h>
00023 #include <tqvaluelist.h>
00024 #include <tqmap.h>
00025 #include <tqpixmap.h>
00026 #include <tqpixmapcache.h>
00027 #include <tqimage.h>
00028 #include <tqfileinfo.h>
00029 #include <tqdir.h>
00030 
00031 #include <kdebug.h>
00032 #include <kstandarddirs.h>
00033 #include <tdeglobal.h>
00034 #include <tdeconfig.h>
00035 #include <ksimpleconfig.h>
00036 #include <kinstance.h>
00037 
00038 #include "kicontheme.h"
00039 
00040 class TDEIconThemePrivate
00041 {
00042 public:
00043     TQString example, screenshot;
00044     TQString linkOverlay, lockOverlay, zipOverlay, shareOverlay;
00045     bool hidden;
00046     TDESharedConfig::Ptr sharedConfig;
00047 };
00048 
00052 class TDEIconThemeDir
00053 {
00054 public:
00055     TDEIconThemeDir(const TQString& dir, const TDEConfigBase *config);
00056 
00057     bool isValid() const { return mbValid; }
00058     TQString iconPath(const TQString& name) const;
00059     TQStringList iconList() const;
00060     TQString dir() const { return mDir; }
00061 
00062     TDEIcon::Context context() const { return mContext; }
00063     TDEIcon::Type type() const { return mType; }
00064     int size() const { return mSize; }
00065     int minSize() const { return mMinSize; }
00066     int maxSize() const { return mMaxSize; }
00067     int threshold() const { return mThreshold; }
00068 
00069 private:
00070     bool mbValid;
00071     TDEIcon::Type mType;
00072     TDEIcon::Context mContext;
00073     int mSize, mMinSize, mMaxSize;
00074     int mThreshold;
00075 
00076     TQString mDir;
00077 };
00078 
00079 
00080 /*** TDEIconTheme ***/
00081 
00082 TDEIconTheme::TDEIconTheme(const TQString& name, const TQString& appName)
00083 {
00084     d = new TDEIconThemePrivate;
00085 
00086     TQStringList icnlibs;
00087     TQStringList::ConstIterator it, itDir;
00088     TQStringList themeDirs;
00089     TQString cDir;
00090 
00091     // Applications can have local additions to the global "locolor" and
00092     // "hicolor" icon themes. For these, the _global_ theme description
00093     // files are used..
00094 
00095     if (!appName.isEmpty() &&
00096        ( name == "crystalsvg" || name== "hicolor" || name == "locolor" ) )
00097     {
00098     icnlibs = TDEGlobal::dirs()->resourceDirs("data");
00099     for (it=icnlibs.begin(); it!=icnlibs.end(); ++it)
00100     {
00101         cDir = *it + appName + "/icons/" + name;
00102         if (TQFile::exists( cDir ))
00103         themeDirs += cDir + "/";
00104     }
00105     }
00106     // Find the theme description file. These are always global.
00107 
00108     icnlibs = TDEGlobal::dirs()->resourceDirs("icon");
00109     icnlibs += TDEGlobal::dirs()->resourceDirs("xdgdata-icon");
00110     icnlibs += "/usr/share/pixmaps";
00111     // These are not in the icon spec, but e.g. GNOME puts some icons there anyway.
00112     icnlibs += TDEGlobal::dirs()->resourceDirs("xdgdata-pixmap");
00113     for (it=icnlibs.begin(); it!=icnlibs.end(); ++it)
00114     {
00115         cDir = *it + name + "/";
00116         if (TDEStandardDirs::exists(cDir))
00117         {
00118             themeDirs += cDir;
00119         if (mDir.isEmpty()
00120             && (TDEStandardDirs::exists( cDir + "index.desktop") || TDEStandardDirs::exists( cDir + "index.theme")))
00121         mDir = cDir;
00122         }
00123     }
00124 
00125     if (mDir.isEmpty())
00126     {
00127         kdDebug(264) << "Icon theme " << name << " not found.\n";
00128         return;
00129     }
00130 
00131     TQString fileName, mainSection;
00132     if(TQFile::exists(mDir + "index.desktop")) {
00133     fileName = mDir + "index.desktop";
00134     mainSection="KDE Icon Theme";
00135     } else {
00136     fileName = mDir + "index.theme";
00137     mainSection="Icon Theme";
00138     }
00139     // Use TDESharedConfig to avoid parsing the file many times, from each kinstance.
00140     // Need to keep a ref to it to make this useful
00141     d->sharedConfig = TDESharedConfig::openConfig( fileName, true /*readonly*/, false /*useKDEGlobals*/ );
00142     TDEConfig& cfg = *d->sharedConfig;
00143     //was: KSimpleConfig cfg(fileName);
00144 
00145     cfg.setGroup(mainSection);
00146     mName = cfg.readEntry("Name");
00147     mDesc = cfg.readEntry("Comment");
00148     mDepth = cfg.readNumEntry("DisplayDepth", 32);
00149     mInherits = cfg.readListEntry("Inherits");
00150     if ( name != "crystalsvg" )
00151       for ( TQStringList::Iterator it = mInherits.begin(); it != mInherits.end(); ++it )
00152          if ( *it == "default" || *it == "hicolor" ) *it="crystalsvg";
00153 
00154     d->hidden = cfg.readBoolEntry("Hidden", false);
00155     d->example = cfg.readPathEntry("Example");
00156     d->screenshot = cfg.readPathEntry("ScreenShot");
00157     d->linkOverlay = cfg.readEntry("LinkOverlay", "link");
00158     d->lockOverlay = cfg.readEntry("LockOverlay", "lock");
00159     d->zipOverlay = cfg.readEntry("ZipOverlay", "application-vnd.tde.overlay.zip");
00160     d->shareOverlay = cfg.readEntry("ShareOverlay","share");
00161 
00162     TQStringList dirs = cfg.readPathListEntry("Directories");
00163     mDirs.setAutoDelete(true);
00164     for (it=dirs.begin(); it!=dirs.end(); ++it)
00165     {
00166     cfg.setGroup(*it);
00167     for (itDir=themeDirs.begin(); itDir!=themeDirs.end(); ++itDir)
00168     {
00169         if (TDEStandardDirs::exists(*itDir + *it + "/"))
00170         {
00171             TDEIconThemeDir *dir = new TDEIconThemeDir(*itDir + *it, &cfg);
00172             if (!dir->isValid())
00173             {
00174                 kdDebug(264) << "Icon directory " << *itDir << " group " << *it << " not valid.\n";
00175                 delete dir;
00176             }
00177             else
00178                 mDirs.append(dir);
00179             }
00180         }
00181     }
00182 
00183     // Expand available sizes for scalable icons to their full range
00184     int i;
00185     TQMap<int,TQValueList<int> > scIcons;
00186     for (TDEIconThemeDir *dir=mDirs.first(); dir!=0L; dir=mDirs.next())
00187     {
00188         if ((dir->type() == TDEIcon::Scalable) && !scIcons.contains(dir->size()))
00189         {
00190             TQValueList<int> lst;
00191             for (i=dir->minSize(); i<=dir->maxSize(); i++)
00192                 lst += i;
00193             scIcons[dir->size()] = lst;
00194         }
00195     }
00196 
00197     TQStringList groups;
00198     groups += "Desktop";
00199     groups += "Toolbar";
00200     groups += "MainToolbar";
00201     groups += "Small";
00202     groups += "Panel";
00203     const int defDefSizes[] = { 32, 22, 22, 16, 32 };
00204     cfg.setGroup(mainSection);
00205     for (it=groups.begin(), i=0; it!=groups.end(); ++it, i++)
00206     {
00207         mDefSize[i] = cfg.readNumEntry(*it + "Default", defDefSizes[i]);
00208         TQValueList<int> exp, lst = cfg.readIntListEntry(*it + "Sizes");
00209         TQValueList<int>::ConstIterator it2;
00210         for (it2=lst.begin(); it2!=lst.end(); ++it2)
00211         {
00212             if (scIcons.contains(*it2))
00213                 exp += scIcons[*it2];
00214             else
00215                 exp += *it2;
00216         }
00217         mSizes[i] = exp;
00218     }
00219 
00220 }
00221 
00222 TDEIconTheme::~TDEIconTheme()
00223 {
00224     delete d;
00225 }
00226 
00227 bool TDEIconTheme::isValid() const
00228 {
00229     return !mDirs.isEmpty();
00230 }
00231 
00232 bool TDEIconTheme::isHidden() const
00233 {
00234     return d->hidden;
00235 }
00236 
00237 TQString TDEIconTheme::example() const { return d->example; }
00238 TQString TDEIconTheme::screenshot() const { return d->screenshot; }
00239 TQString TDEIconTheme::linkOverlay() const { return d->linkOverlay; }
00240 TQString TDEIconTheme::lockOverlay() const { return d->lockOverlay; }
00241 TQString TDEIconTheme::zipOverlay() const { return d->zipOverlay; }
00242 TQString TDEIconTheme::shareOverlay() const { return d->shareOverlay; }
00243 
00244 int TDEIconTheme::defaultSize(TDEIcon::Group group) const
00245 {
00246     if ((group < 0) || (group >= TDEIcon::LastGroup))
00247     {
00248         kdDebug(264) << "Illegal icon group: " << group << "\n";
00249         return -1;
00250     }
00251     return mDefSize[group];
00252 }
00253 
00254 TQValueList<int> TDEIconTheme::querySizes(TDEIcon::Group group) const
00255 {
00256     TQValueList<int> empty;
00257     if ((group < 0) || (group >= TDEIcon::LastGroup))
00258     {
00259         kdDebug(264) << "Illegal icon group: " << group << "\n";
00260         return empty;
00261     }
00262     return mSizes[group];
00263 }
00264 
00265 TQStringList TDEIconTheme::queryIcons(int size, TDEIcon::Context context) const
00266 {
00267     int delta = 1000, dw;
00268 
00269     TQPtrListIterator<TDEIconThemeDir> dirs(mDirs);
00270     TDEIconThemeDir *dir;
00271 
00272     // Try to find exact match
00273     TQStringList result;
00274     for ( ; dirs.current(); ++dirs)
00275     {
00276         dir = dirs.current();
00277         if ((context != TDEIcon::Any) && (context != dir->context()))
00278             continue;
00279         if ((dir->type() == TDEIcon::Fixed) && (dir->size() == size))
00280         {
00281             result += dir->iconList();
00282             continue;
00283         }
00284         if ((dir->type() == TDEIcon::Scalable) &&
00285             (size >= dir->minSize()) && (size <= dir->maxSize()))
00286         {
00287             result += dir->iconList();
00288             continue;
00289         }
00290     if ((dir->type() == TDEIcon::Threshold) &&
00291             (abs(size-dir->size())<dir->threshold()))
00292             result+=dir->iconList();
00293     }
00294 
00295     return result;
00296 
00297     dirs.toFirst();
00298 
00299     // Find close match
00300     TDEIconThemeDir *best = 0L;
00301     for ( ; dirs.current(); ++dirs)
00302     {
00303         dir = dirs.current();
00304         if ((context != TDEIcon::Any) && (context != dir->context()))
00305             continue;
00306         dw = dir->size() - size;
00307         if ((dw > 6) || (abs(dw) >= abs(delta)))
00308             continue;
00309         delta = dw;
00310         best = dir;
00311     }
00312     if (best == 0L)
00313         return TQStringList();
00314 
00315     return best->iconList();
00316 }
00317 
00318 TQStringList TDEIconTheme::queryIconsByContext(int size, TDEIcon::Context context) const
00319 {
00320     TQPtrListIterator<TDEIconThemeDir> dirs(mDirs);
00321     int dw;
00322     TDEIconThemeDir *dir;
00323 
00324     // We want all the icons for a given context, but we prefer icons
00325     // of size size . Note that this may (will) include duplicate icons
00326     //TQStringList iconlist[34]; // 33 == 48-16+1
00327     TQStringList iconlist[128]; // 33 == 48-16+1
00328     // Usually, only the 0, 6 (22-16), 10 (32-22), 16 (48-32 or 32-16),
00329     // 26 (48-22) and 32 (48-16) will be used, but who knows if someone
00330     // will make icon themes with different icon sizes.
00331 
00332     for ( ; dirs.current(); ++dirs)
00333     {
00334         dir = dirs.current();
00335         if ((context != TDEIcon::Any) && (context != dir->context()))
00336             continue;
00337         dw = abs(dir->size() - size);
00338         iconlist[(dw<127)?dw:127]+=dir->iconList();
00339     }
00340 
00341     TQStringList iconlistResult;
00342     for (int i=0; i<128; i++) iconlistResult+=iconlist[i];
00343 
00344     return iconlistResult;
00345 }
00346 
00347 bool TDEIconTheme::hasContext(TDEIcon::Context context) const
00348 {
00349     TQPtrListIterator<TDEIconThemeDir> dirs(mDirs);
00350     TDEIconThemeDir *dir;
00351 
00352     for ( ; dirs.current(); ++dirs)
00353     {
00354         dir = dirs.current();
00355         if ((context == TDEIcon::Any) || (context == dir->context()))
00356             return true;
00357     }
00358     return false;
00359 }
00360 
00361 TDEIcon TDEIconTheme::iconPath(const TQString& name, int size, TDEIcon::MatchType match) const
00362 {
00363     TDEIcon icon;
00364     TQString path;
00365     int delta = -1000, dw;
00366     TDEIconThemeDir *dir;
00367 
00368     dw = 1000; // shut up, gcc
00369     TQPtrListIterator<TDEIconThemeDir> dirs(mDirs);
00370     for ( ; dirs.current(); ++dirs)
00371     {
00372         dir = dirs.current();
00373 
00374         if (match == TDEIcon::MatchExact)
00375         {
00376             if ((dir->type() == TDEIcon::Fixed) && (dir->size() != size))
00377                 continue;
00378             if ((dir->type() == TDEIcon::Scalable) &&
00379                 ((size < dir->minSize()) || (size > dir->maxSize())))
00380               continue;
00381             if ((dir->type() == TDEIcon::Threshold) &&
00382         (abs(dir->size()-size) > dir->threshold()))
00383                 continue;
00384         } else
00385         {
00386           // dw < 0 means need to scale up to get an icon of the requested size
00387           if (dir->type() == TDEIcon::Fixed)
00388           {
00389             dw = dir->size() - size;
00390           } else if (dir->type() == TDEIcon::Scalable)
00391           {
00392             if (size < dir->minSize())
00393               dw = dir->minSize() - size;
00394             else if (size > dir->maxSize())
00395               dw = dir->maxSize() - size;
00396             else
00397               dw = 0;
00398           } else if (dir->type() == TDEIcon::Threshold)
00399           {
00400             if (size < dir->size() - dir->threshold())
00401               dw = dir->size() - dir->threshold() - size;
00402             else if (size > dir->size() + dir->threshold())
00403               dw = dir->size() + dir->threshold() - size;
00404             else
00405               dw = 0;
00406           }
00407           /* Skip this if we've found a closer one, unless
00408              it's a downscale, and we only had upscales befores.
00409              This is to avoid scaling up unless we have to,
00410              since that looks very ugly */
00411           if (/*(abs(dw) >= abs(delta)) ||*/
00412               (delta > 0 && dw < 0))
00413             continue;
00414         }
00415 
00416         path = dir->iconPath(name);
00417         if (path.isEmpty())
00418             continue;
00419         icon.path = path;
00420         icon.size = dir->size();
00421         icon.type = dir->type();
00422     icon.threshold = dir->threshold();
00423         icon.context = dir->context();
00424 
00425         // if we got in MatchExact that far, we find no better
00426         if (match == TDEIcon::MatchExact)
00427             return icon;
00428     else
00429         {
00430         delta = dw;
00431         if (delta==0) return icon; // We won't find a better match anyway
00432         }
00433     }
00434     return icon;
00435 }
00436 
00437 // static
00438 TQString *TDEIconTheme::_theme = 0L;
00439 
00440 // static
00441 TQStringList *TDEIconTheme::_theme_list = 0L;
00442 
00443 // static
00444 TQString TDEIconTheme::current()
00445 {
00446     // Static pointer because of unloading problems wrt DSO's.
00447     if (_theme != 0L)
00448         return *_theme;
00449 
00450     _theme = new TQString();
00451     TDEConfig *config = TDEGlobal::config();
00452     TDEConfigGroupSaver saver(config, "Icons");
00453     *_theme = config->readEntry("Theme",defaultThemeName());
00454     if ( *_theme == TQString::fromLatin1("hicolor") ) *_theme = defaultThemeName();
00455 /*    if (_theme->isEmpty())
00456     {
00457         if (TQPixmap::defaultDepth() > 8)
00458             *_theme = defaultThemeName();
00459         else
00460             *_theme = TQString::fromLatin1("locolor");
00461     }*/
00462     return *_theme;
00463 }
00464 
00465 // static
00466 TQStringList TDEIconTheme::list()
00467 {
00468     // Static pointer because of unloading problems wrt DSO's.
00469     if (_theme_list != 0L)
00470         return *_theme_list;
00471 
00472     _theme_list = new TQStringList();
00473     TQStringList icnlibs = TDEGlobal::dirs()->resourceDirs("icon");
00474     icnlibs += (TDEGlobal::dirs()->resourceDirs("xdgdata-icon"));
00475     icnlibs += "/usr/share/pixmaps";
00476     // These are not in the icon spec, but e.g. GNOME puts some icons there anyway.
00477     icnlibs += TDEGlobal::dirs()->resourceDirs("xdgdata-pixmap");
00478     TQStringList::ConstIterator it;
00479     for (it=icnlibs.begin(); it!=icnlibs.end(); ++it)
00480     {
00481         TQDir dir(*it);
00482         if (!dir.exists())
00483             continue;
00484         TQStringList lst = dir.entryList(TQDir::Dirs);
00485         TQStringList::ConstIterator it2;
00486         for (it2=lst.begin(); it2!=lst.end(); ++it2)
00487         {
00488             if ((*it2 == ".") || (*it2 == "..") || (*it2).startsWith("default.") )
00489                 continue;
00490             if (!TDEStandardDirs::exists(*it + *it2 + "/index.desktop") && !TDEStandardDirs::exists(*it + *it2 + "/index.theme"))
00491                 continue;
00492         TDEIconTheme oink(*it2);
00493         if (!oink.isValid()) continue;
00494 
00495         if (!_theme_list->contains(*it2))
00496                 _theme_list->append(*it2);
00497         }
00498     }
00499     return *_theme_list;
00500 }
00501 
00502 // static
00503 void TDEIconTheme::reconfigure()
00504 {
00505     delete _theme;
00506     _theme=0L;
00507     delete _theme_list;
00508     _theme_list=0L;
00509 }
00510 
00511 // static
00512 TQString TDEIconTheme::defaultThemeName()
00513 {
00514     return TQString::fromLatin1("crystalsvg");
00515 }
00516 
00517 /*** TDEIconThemeDir ***/
00518 
00519 TDEIconThemeDir::TDEIconThemeDir(const TQString& dir, const TDEConfigBase *config)
00520 {
00521     mbValid = false;
00522     mDir = dir;
00523     mSize = config->readNumEntry("Size");
00524     mMinSize = 1;    // just set the variables to something
00525     mMaxSize = 50;   // meaningful in case someone calls minSize or maxSize
00526     mType = TDEIcon::Fixed;
00527 
00528     if (mSize == 0)
00529         return;
00530 
00531     TQString tmp = config->readEntry("Context");
00532     if (tmp == "Devices")
00533         mContext = TDEIcon::Device;
00534     else if (tmp == "MimeTypes")
00535         mContext = TDEIcon::MimeType;
00536     else if (tmp == "FileSystems")
00537         mContext = TDEIcon::FileSystem;
00538     else if (tmp == "Applications")
00539         mContext = TDEIcon::Application;
00540     else if (tmp == "Actions")
00541         mContext = TDEIcon::Action;
00542     else if (tmp == "Animations")
00543         mContext = TDEIcon::Animation;
00544     else if (tmp == "Categories")
00545         mContext = TDEIcon::Category;
00546     else if (tmp == "Emblems")
00547         mContext = TDEIcon::Emblem;
00548     else if (tmp == "Emotes")
00549         mContext = TDEIcon::Emote;
00550     else if (tmp == "International")
00551         mContext = TDEIcon::International;
00552     else if (tmp == "Places")
00553         mContext = TDEIcon::Place;
00554     else if (tmp == "Status")
00555         mContext = TDEIcon::StatusIcon;
00556     else {
00557         kdDebug(264) << "Invalid Context= line for icon theme: " << mDir << "\n";
00558         return;
00559     }
00560     tmp = config->readEntry("Type");
00561     if (tmp == "Fixed")
00562         mType = TDEIcon::Fixed;
00563     else if (tmp == "Scalable")
00564         mType = TDEIcon::Scalable;
00565     else if (tmp == "Threshold")
00566         mType = TDEIcon::Threshold;
00567     else {
00568         kdDebug(264) << "Invalid Type= line for icon theme: " <<  mDir << "\n";
00569         return;
00570     }
00571     if (mType == TDEIcon::Scalable)
00572     {
00573         mMinSize = config->readNumEntry("MinSize", mSize);
00574         mMaxSize = config->readNumEntry("MaxSize", mSize);
00575     } else if (mType == TDEIcon::Threshold)
00576     mThreshold = config->readNumEntry("Threshold", 2);
00577     mbValid = true;
00578 }
00579 
00580 TQString TDEIconThemeDir::iconPath(const TQString& name) const
00581 {
00582     if (!mbValid)
00583         return TQString::null;
00584     TQString file = mDir + "/" + name;
00585 
00586     if (access(TQFile::encodeName(file), R_OK) == 0)
00587         return file;
00588 
00589     return TQString::null;
00590 }
00591 
00592 TQStringList TDEIconThemeDir::iconList() const
00593 {
00594     TQDir dir(mDir);
00595 #ifdef HAVE_LIBART
00596     TQStringList lst = dir.entryList("*.png;*.svg;*.svgz;*.xpm", TQDir::Files);
00597 #else
00598     TQStringList lst = dir.entryList("*.png;*.xpm", TQDir::Files);
00599 #endif
00600     TQStringList result;
00601     TQStringList::ConstIterator it;
00602     for (it=lst.begin(); it!=lst.end(); ++it)
00603         result += mDir + "/" + *it;
00604     return result;
00605 }

tdecore

Skip menu "tdecore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdecore

Skip menu "tdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.6.3
This website is maintained by Timothy Pearson.