17 #include <tqstringlist.h>
18 #include <tqptrlist.h>
19 #include <tqintdict.h>
21 #include <tqpixmapcache.h>
23 #include <tqfileinfo.h>
25 #include <tqiconset.h>
29 #include <tdeapplication.h>
32 #include <kstandarddirs.h>
33 #include <tdeglobal.h>
34 #include <tdeconfig.h>
35 #include <ksimpleconfig.h>
36 #include <kinstance.h>
38 #include <kicontheme.h>
39 #include <kiconloader.h>
40 #include <kiconeffect.h>
42 #include <sys/types.h>
50 #include "svgicons/ksvgiconengine.h"
51 #include "svgicons/ksvgiconpainter.h"
54 #include <kimageeffect.h>
56 #include "kiconloader_p.h"
65 TDEIconThemeNode::~TDEIconThemeNode()
70 void TDEIconThemeNode::printTree(TQString& dbgString)
const
75 dbgString += theme->
name();
79 void TDEIconThemeNode::queryIcons(TQStringList *result,
83 *result += theme->queryIcons(size, context);
86 void TDEIconThemeNode::queryIconsByContext(TQStringList *result,
90 *result += theme->queryIconsByContext(size, context);
93 TDEIcon TDEIconThemeNode::findIcon(
const TQString& name,
int size,
96 return theme->iconPath(name, size, match);
114 #ifdef TDEICONLOADER_DEBUG
117 struct TDEIconLoaderDebug
120 : loader( l ), appname( a ), valid( true )
122 TDEIconLoaderDebug() {};
129 static TQValueList< TDEIconLoaderDebug > *kiconloaders;
136 #ifdef TDEICONLOADER_DEBUG
137 if( kiconloaders == NULL )
138 kiconloaders =
new TQValueList< TDEIconLoaderDebug>();
141 for( TQValueList< TDEIconLoaderDebug >::Iterator it = kiconloaders->begin();
142 it != kiconloaders->end();
145 if( (*it).loader ==
this )
146 it = kiconloaders->remove( it );
150 kiconloaders->append( TDEIconLoaderDebug(
this, _appname ));
152 d =
new TDEIconLoaderPrivate;
155 d->imgDict.setAutoDelete(
true);
156 d->links.setAutoDelete(
true);
159 kapp->addKipcEventMask(KIPC::IconChanged);
160 TQObject::connect(kapp, TQT_SIGNAL(updateIconLoaders()), d, TQT_SLOT(
reconfigure()));
163 init( _appname, _dirs );
170 d->mThemesInTree.clear();
171 d->lastImage.reset();
172 d->lastImageKey = TQString::null;
173 delete [] d->mpGroups;
175 init( _appname, _dirs );
178 void TDEIconLoader::init(
const TQString& _appname,
TDEStandardDirs *_dirs )
184 d->appname = _appname;
185 d->extraDesktopIconsLoaded =
false;
186 d->delayedLoading =
false;
193 TQString appname = _appname;
194 if (appname.isEmpty())
203 kdDebug(264) <<
"Couldn't find current icon theme, falling back to default." <<
endl;
207 kdError(264) <<
"Error: standard icon theme"
209 <<
" not found!" <<
endl;
214 d->mpThemeRoot =
new TDEIconThemeNode(def);
215 d->links.append(d->mpThemeRoot);
217 addBaseThemes(d->mpThemeRoot, appname);
220 static const char *
const groups[] = {
"Desktop",
"Toolbar",
"MainToolbar",
"Small",
"Panel", 0L };
230 config->
setGroup(TQString::fromLatin1(groups[i]) +
"Icons");
232 d->mpGroups[i].dblPixels = config->
readBoolEntry(
"DoublePixels",
false);
233 if (TQPixmap::defaultDepth()>8)
234 d->mpGroups[i].alphaBlending = config->
readBoolEntry(
"AlphaBlending",
true);
236 d->mpGroups[i].alphaBlending =
false;
238 if (!d->mpGroups[i].size)
239 d->mpGroups[i].size = d->mpThemeRoot->theme->defaultSize(i);
247 appname +
"/toolbar/");
251 dirs += d->mpDirs->resourceDirs(
"icon");
252 dirs += d->mpDirs->resourceDirs(
"pixmap");
253 dirs += d->mpDirs->resourceDirs(
"xdgdata-icon");
254 dirs +=
"/usr/share/pixmaps";
256 dirs += d->mpDirs->resourceDirs(
"xdgdata-pixmap");
257 for (TQStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it)
258 d->mpDirs->addResourceDir(
"appicon", *it);
261 TQString dbgString =
"Theme tree: ";
262 d->mpThemeRoot->printTree(dbgString);
263 kdDebug(264) << dbgString <<
endl;
269 #ifdef TDEICONLOADER_DEBUG
270 for( TQValueList< TDEIconLoaderDebug >::Iterator it = kiconloaders->begin();
271 it != kiconloaders->end();
274 if( (*it).loader ==
this )
277 (*it).delete_bt = kdBacktrace();
285 delete[] d->mpGroups;
291 d->delayedLoading = enable;
296 return d->delayedLoading;
305 appname +
"/toolbar/");
306 addAppThemes(appname);
309 void TDEIconLoader::addAppThemes(
const TQString& appname)
316 TDEIconThemeNode* node =
new TDEIconThemeNode(def);
317 d->links.append(node);
318 addBaseThemes(node, appname);
325 TDEIconThemeNode* node =
new TDEIconThemeNode(def);
326 d->links.append(node);
327 addBaseThemes(node, appname);
330 void TDEIconLoader::addBaseThemes(TDEIconThemeNode *node,
const TQString &appname)
332 TQStringList lst = node->theme->inherits();
333 TQStringList::ConstIterator it;
335 for (it=lst.begin(); it!=lst.end(); ++it)
337 if( d->mThemesInTree.contains(*it) && (*it) !=
"hicolor")
344 TDEIconThemeNode *n =
new TDEIconThemeNode(theme);
345 d->mThemesInTree.append(*it);
347 addBaseThemes(n, appname);
353 if ( d->extraDesktopIconsLoaded )
return;
357 TQStringList::ConstIterator it;
360 for (it=icnlibs.begin(); it!=icnlibs.end(); ++it)
365 TQStringList lst = dir.entryList(
"default.*", TQDir::Dirs);
366 TQStringList::ConstIterator it2;
367 for (it2=lst.begin(); it2!=lst.end(); ++it2)
372 r=readlink( TQFile::encodeName(*it + *it2) , buf,
sizeof(buf)-1);
377 TQString themeName=dir2.dirName();
379 if (!list.contains(themeName))
380 list.append(themeName);
385 for (it=list.begin(); it!=list.end(); ++it)
387 if ( d->mThemesInTree.contains(*it) )
389 if ( *it == TQString(
"default.tde") )
continue;
392 TDEIconThemeNode* node =
new TDEIconThemeNode(def);
393 d->mThemesInTree.append(*it);
394 d->links.append(node);
395 addBaseThemes(node,
"" );
398 d->extraDesktopIconsLoaded=
true;
404 return d->extraDesktopIconsLoaded;
407 TQString TDEIconLoader::removeIconExtension(
const TQString &name)
const
409 int extensionLength=0;
411 TQString ext = name.right(4);
415 if (ext == png_ext || ext == xpm_ext)
423 if (name.right(5) == svgz_ext)
425 else if (ext == svg_ext)
430 if ( extensionLength > 0 )
432 return name.left(name.length() - extensionLength);
437 TQString TDEIconLoader::removeIconExtensionInternal(
const TQString &name)
const
439 TQString name_noext = removeIconExtension(name);
442 if (name != name_noext)
445 <<
" loads icon " << name <<
" with extension." <<
endl;
452 TDEIcon TDEIconLoader::findMatchingIcon(
const TQString& name,
int size)
const
456 const TQString *ext[4];
459 ext[count++]=&png_ext;
462 ext[count++]=&svgz_ext;
464 ext[count++]=&svg_ext;
467 ext[count++]=&xpm_ext;
481 for ( TDEIconThemeNode *themeNode = d->links.first() ; themeNode ;
482 themeNode = d->links.next() )
484 for (
int i = 0 ; i < count ; i++)
487 if (icon.
isValid())
goto icon_found ;
490 for (
int i = 0 ; i < count ; i++)
493 if (icon.
isValid())
goto icon_found;
500 inline TQString TDEIconLoader::unknownIconPath(
int size )
const
504 TDEIcon icon = findMatchingIcon(str_unknown, size);
507 kdDebug(264) <<
"Warning: could not find \"Unknown\" icon for size = "
509 return TQString::null;
517 bool canReturnNull)
const
519 if (d->mpThemeRoot == 0L)
520 return TQString::null;
522 if (!TQDir::isRelativePath(_name))
525 TQString name = removeIconExtensionInternal( _name );
532 path = d->mpDirs->findResource(
"appicon", name + png_ext);
538 path = d->mpDirs->findResource(
"appicon", name + svgz_ext);
540 path = d->mpDirs->findResource(
"appicon", name + svg_ext);
543 path = d->mpDirs->findResource(
"appicon", name + xpm_ext);
547 if (group_or_size >= TDEIcon::LastGroup)
549 kdDebug(264) <<
"Illegal icon group: " << group_or_size <<
endl;
554 if (group_or_size >= 0)
555 size = d->mpGroups[group_or_size].size;
557 size = -group_or_size;
559 if (_name.isEmpty()) {
561 return TQString::null;
563 return unknownIconPath(size);
566 TDEIcon icon = findMatchingIcon(name, size);
572 if (!path.isEmpty() || canReturnNull)
576 return TQString::null;
578 return unknownIconPath(size);
584 int state, TQString *path_store,
bool canReturnNull)
const
586 TQString name = _name;
589 bool absolutePath=
false, favIconOverlay=
false;
591 if (d->mpThemeRoot == 0L)
595 if (name.startsWith(
"favicons/"))
597 favIconOverlay =
true;
598 name = locateLocal(
"cache", name+
".png");
600 if (!TQDir::isRelativePath(name)) absolutePath=
true;
608 key += TQString::number(size); key +=
'_';
610 bool inCache = TQPixmapCache::find(key, pix);
611 if (inCache && (path_store == 0L))
614 TQString path = (absolutePath) ? name :
624 kdDebug(264) <<
"Warning: Cannot find \"unknown\" icon." <<
endl;
629 if (path_store != 0L)
635 img=img.smoothScale(size,size);
637 pix.convertFromImage(img);
638 TQPixmapCache::insert(key, pix);
644 if ((group < -1) || (group >= TDEIcon::LastGroup))
646 kdDebug(264) <<
"Illegal icon group: " << group <<
endl;
650 int overlay = (state & TDEIcon::OverlayMask);
651 state &= ~
TDEIcon::OverlayMask;
654 kdDebug(264) <<
"Illegal icon state: " << state <<
endl;
658 if (size == 0 && group < 0)
660 kdDebug(264) <<
"Neither size nor group specified!" <<
endl;
666 if (!canReturnNull && name.isEmpty())
669 name = removeIconExtensionInternal(name);
675 size = d->mpGroups[group].size;
677 favIconOverlay = favIconOverlay && size > 22;
682 key += name; key +=
'_';
683 key += TQString::number(size); key +=
'_';
685 TQString overlayStr = TQString::number( overlay );
687 TQString noEffectKey = key +
'_' + overlayStr;
691 key += d->mpEffect.fingerprint(group, state);
692 if (d->mpGroups[group].dblPixels)
693 key += TQString::fromLatin1(
":dblsize");
695 key += TQString::fromLatin1(
"noeffect");
700 bool inCache = TQPixmapCache::find(key, pix);
701 if (inCache && (path_store == 0L))
708 if ( ( path_store != 0L ) ||
709 noEffectKey != d->lastImageKey )
713 if (absolutePath && !favIconOverlay)
722 icon = findMatchingIcon(favIconOverlay ? TQString(
"www") : name, size);
729 if (!pix.isNull() || canReturnNull) {
730 TQPixmapCache::insert(key, pix);
734 icon = findMatchingIcon(str_unknown, size);
738 <<
"Warning: could not find \"Unknown\" icon for size = "
745 if (path_store != 0L)
746 *path_store = icon.
path;
751 TQString ext = icon.
path.right(3).upper();
752 if(ext !=
"SVG" && ext !=
"VGZ")
754 img =
new TQImage(icon.
path, ext.latin1());
764 KSVGIconEngine *svgEngine =
new KSVGIconEngine();
766 if(svgEngine->load(size, size, icon.
path))
767 img = svgEngine->painter()->image();
777 iconType = icon.
type;
780 d->lastImage = img->copy();
781 d->lastImageKey = noEffectKey;
782 d->lastIconType = iconType;
783 d->lastIconThreshold = iconThreshold;
787 img =
new TQImage( d->lastImage.copy() );
788 iconType = d->lastIconType;
789 iconThreshold = d->lastIconThreshold;
798 ((ovl = loadOverlay(theme->
lockOverlay(), size)) != 0L))
801 ((ovl = loadOverlay(theme->
linkOverlay(), size)) != 0L))
804 ((ovl = loadOverlay(theme->
zipOverlay(), size)) != 0L))
807 ((ovl = loadOverlay(theme->
shareOverlay(), size)) != 0L))
811 if (img->depth() != 32)
812 *img = img->convertDepth(32);
813 for (
int y = 0; y < img->height(); y++)
815 QRgb *line =
reinterpret_cast<QRgb *
>(img->scanLine(y));
816 for (
int x = 0; x < img->width(); x++)
817 line[x] = (line[x] & 0x00ffffff) | (TQMIN(0x80, tqAlpha(line[x])) << 24);
825 *img = img->smoothScale(size, size);
829 if ( abs(size-img->width())>iconThreshold )
830 *img = img->smoothScale(size, size);
832 if (group >= 0 && d->mpGroups[group].dblPixels)
834 *img = d->mpEffect.doublePixels(*img);
838 *img = d->mpEffect.apply(*img, group, state);
843 TQImage favIcon(name,
"PNG");
844 int x = img->width() - favIcon.width() - 1,
845 y = img->height() - favIcon.height() - 1;
846 if( favIcon.depth() != 32 )
847 favIcon = favIcon.convertDepth( 32 );
848 if( img->depth() != 32 )
849 *img = img->convertDepth( 32 );
851 line < favIcon.height();
854 QRgb* fpos =
reinterpret_cast< QRgb*
>( favIcon.scanLine( line ));
855 QRgb* ipos =
reinterpret_cast< QRgb*
>( img->scanLine( line + y )) + x;
858 ++i, ++fpos, ++ipos )
859 *ipos = tqRgba( ( tqRed( *ipos ) * ( 255 - tqAlpha( *fpos )) + tqRed( *fpos ) * tqAlpha( *fpos )) / 255,
860 ( tqGreen( *ipos ) * ( 255 - tqAlpha( *fpos )) + tqGreen( *fpos ) * tqAlpha( *fpos )) / 255,
861 ( tqBlue( *ipos ) * ( 255 - tqAlpha( *fpos )) + tqBlue( *fpos ) * tqAlpha( *fpos )) / 255,
862 ( tqAlpha( *ipos ) * ( 255 - tqAlpha( *fpos )) + tqAlpha( *fpos ) * tqAlpha( *fpos )) / 255 );
866 if (TQPaintDevice::x11AppDepth() == 32) pix.convertFromImage(KImageEffect::convertToPremultipliedAlpha( *img ));
867 else pix.convertFromImage(*img);
871 TQPixmapCache::insert(key, pix);
875 TQImage *TDEIconLoader::loadOverlay(
const TQString &name,
int size)
const
877 TQString key = name +
'_' + TQString::number(size);
878 TQImage *image = d->imgDict.find(key);
882 TDEIcon icon = findMatchingIcon(name, size);
885 kdDebug(264) <<
"Overlay " << name <<
"not found." <<
endl;
888 image =
new TQImage(icon.
path);
891 if ( size != image->width() )
892 *image = image->smoothScale( size, size );
893 d->imgDict.insert(key, image);
901 TQString file =
moviePath( name, group, size );
904 int dirLen = file.findRev(
'/');
905 TQString icon =
iconPath(name, size ? -size : group,
true);
906 if (!icon.isEmpty() && file.left(dirLen) != icon.left(dirLen))
908 return TQMovie(file);
913 if (!d->mpGroups)
return TQString::null;
915 if ( (group < -1 || group >= TDEIcon::LastGroup) && group !=
TDEIcon::User )
917 kdDebug(264) <<
"Illegal icon group: " << group <<
endl;
920 if (size == 0 && group < 0)
922 kdDebug(264) <<
"Neither size nor group specified!" <<
endl;
926 TQString file = name +
".mng";
929 file = d->mpDirs->findResource(
"appicon", file);
934 size = d->mpGroups[group].size;
938 for ( TDEIconThemeNode *themeNode = d->links.first() ; themeNode ;
939 themeNode = d->links.next() )
942 if (icon.
isValid())
goto icon_found ;
945 if (icon.
isValid())
goto icon_found ;
949 file = icon.
isValid() ? icon.
path : TQString::null;
959 if (!d->mpGroups)
return lst;
961 if ((group < -1) || (group >= TDEIcon::LastGroup))
963 kdDebug(264) <<
"Illegal icon group: " << group <<
endl;
966 if ((size == 0) && (group < 0))
968 kdDebug(264) <<
"Neither size nor group specified!" <<
endl;
972 TQString file = name +
"/0001";
975 file = d->mpDirs->findResource(
"appicon", file +
".png");
979 size = d->mpGroups[group].size;
980 TDEIcon icon = findMatchingIcon(file, size);
981 file = icon.
isValid() ? icon.
path : TQString::null;
987 TQString path = file.left(file.length()-8);
988 DIR* dp = opendir( TQFile::encodeName(path) );
993 while( ( ep = readdir( dp ) ) != 0L )
995 TQString fn(TQFile::decodeName(ep->d_name));
996 if(!(fn.left(4)).toUInt())
1008 if (d->mpThemeRoot)
return d->mpThemeRoot->theme;
1014 if (!d->mpGroups)
return -1;
1016 if (group < 0 || group >= TDEIcon::LastGroup)
1018 kdDebug(264) <<
"Illegal icon group: " << group <<
endl;
1021 return d->mpGroups[group].size;
1026 TQDir dir(iconsDir);
1027 TQStringList lst = dir.entryList(
"*.png;*.xpm", TQDir::Files);
1028 TQStringList result;
1029 TQStringList::ConstIterator it;
1030 for (it=lst.begin(); it!=lst.end(); ++it)
1031 result += iconsDir +
"/" + *it;
1038 TQStringList result;
1039 if (group_or_size >= TDEIcon::LastGroup)
1041 kdDebug(264) <<
"Illegal icon group: " << group_or_size <<
endl;
1045 if (group_or_size >= 0)
1046 size = d->mpGroups[group_or_size].size;
1048 size = -group_or_size;
1050 for ( TDEIconThemeNode *themeNode = d->links.first() ; themeNode ;
1051 themeNode = d->links.next() )
1052 themeNode->queryIconsByContext(&result, size, context);
1056 TQStringList res2, entries;
1057 TQStringList::ConstIterator it;
1058 for (it=result.begin(); it!=result.end(); ++it)
1060 int n = (*it).findRev(
'/');
1064 name = (*it).mid(n+1);
1065 name = removeIconExtension(name);
1066 if (!entries.contains(name))
1078 TQStringList result;
1079 if (group_or_size >= TDEIcon::LastGroup)
1081 kdDebug(264) <<
"Illegal icon group: " << group_or_size <<
endl;
1085 if (group_or_size >= 0)
1086 size = d->mpGroups[group_or_size].size;
1088 size = -group_or_size;
1090 for ( TDEIconThemeNode *themeNode = d->links.first() ; themeNode ;
1091 themeNode = d->links.next() )
1092 themeNode->queryIcons(&result, size, context);
1096 TQStringList res2, entries;
1097 TQStringList::ConstIterator it;
1098 for (it=result.begin(); it!=result.end(); ++it)
1100 int n = (*it).findRev(
'/');
1104 name = (*it).mid(n+1);
1105 name = removeIconExtension(name);
1106 if (!entries.contains(name))
1118 for ( TDEIconThemeNode *themeNode = d->links.first() ; themeNode ;
1119 themeNode = d->links.next() )
1120 if( themeNode->theme->hasContext( context ))
1127 return &d->mpEffect;
1132 if (!d->mpGroups)
return false;
1134 if (group < 0 || group >= TDEIcon::LastGroup)
1136 kdDebug(264) <<
"Illegal icon group: " << group <<
endl;
1139 return d->mpGroups[group].alphaBlending;
1144 return loadIconSet( name, group, size, canReturnNull,
true );
1154 class TDEIconFactory
1155 :
public TQIconFactory
1158 TDEIconFactory(
const TQString& iconName_P,
TDEIcon::Group group_P,
1160 TDEIconFactory(
const TQString& iconName_P,
TDEIcon::Group group_P,
1162 virtual TQPixmap* createPixmap(
const TQIconSet&, TQIconSet::Size, TQIconSet::Mode, TQIconSet::State );
1173 bool canReturnNull,
bool immediateExistenceCheck)
1175 if ( !d->delayedLoading )
1176 return loadIconSetNonDelayed( name, g, s, canReturnNull );
1178 if (g < -1 || g > 6) {
1179 kdDebug() <<
"TDEIconLoader::loadIconSet " << name <<
" " << (int)g <<
" " << s <<
endl;
1180 tqDebug(
"%s", kdBacktrace().latin1());
1184 if(canReturnNull && immediateExistenceCheck)
1190 TQIconSet ret( pm );
1191 ret.installIconFactory(
new TDEIconFactory( name, g, s,
this ));
1196 ret.installIconFactory(
new TDEIconFactory( name, g, s,
this, canReturnNull ));
1200 TQIconSet TDEIconLoader::loadIconSetNonDelayed(
const TQString& name,
1202 int s,
bool canReturnNull )
1206 iconset.setPixmap( tmp, TQIconSet::Small, TQIconSet::Active );
1208 iconset.setPixmap( tmp, TQIconSet::Large, TQIconSet::Active );
1210 iconset.setPixmap( tmp, TQIconSet::Small, TQIconSet::Disabled );
1211 iconset.setPixmap( tmp, TQIconSet::Large, TQIconSet::Disabled );
1213 iconset.setPixmap( tmp, TQIconSet::Small, TQIconSet::Normal );
1214 iconset.setPixmap( tmp, TQIconSet::Large, TQIconSet::Normal );
1218 TDEIconFactory::TDEIconFactory(
const TQString& iconName_P,
TDEIcon::Group group_P,
1220 : iconName( iconName_P ), group( group_P ), size( size_P ), loader( loader_P )
1222 canReturnNull =
false;
1223 setAutoDelete(
true );
1226 TDEIconFactory::TDEIconFactory(
const TQString& iconName_P,
TDEIcon::Group group_P,
1228 : iconName( iconName_P ), group( group_P ), size( size_P ),
1229 loader( loader_P ), canReturnNull( canReturnNull_P)
1231 setAutoDelete(
true );
1234 TQPixmap* TDEIconFactory::createPixmap(
const TQIconSet&, TQIconSet::Size, TQIconSet::Mode mode_P, TQIconSet::State )
1236 #ifdef TDEICONLOADER_DEBUG
1238 for( TQValueList< TDEIconLoaderDebug >::Iterator it = kiconloaders->begin();
1239 it != kiconloaders->end();
1242 if( (*it).loader == loader )
1249 iconName =
"no_way_man_you_will_get_broken_icon";
1251 kdWarning() <<
"Using already destroyed TDEIconLoader for loading an icon!" <<
endl;
1252 kdWarning() <<
"Appname:" << (*it).appname <<
", icon:" << iconName <<
endl;
1268 iconName =
"no_way_man_you_will_get_broken_icon";
1270 kdWarning() <<
"Using unknown TDEIconLoader for loading an icon!" <<
endl;
1281 if( mode_P <= TQIconSet::Active )
1282 state = tbl[ mode_P ];
1291 TQPixmap pm = loader->loadIcon( iconName, group, size, state, 0, canReturnNull );
1292 return new TQPixmap( pm );
1315 TQPixmap
BarIcon(
const TQString& name,
int force_size,
int state,
1333 TQPixmap
SmallIcon(
const TQString& name,
int force_size,
int state,
1395 if ( TQPixmapCache::find(
"unknown", pix) )
1401 kdDebug(264) <<
"Warning: Cannot find \"unknown\" icon." <<
endl;
1406 TQPixmapCache::insert(
"unknown", pix);
1412 void TDEIconLoaderPrivate::reconfigure()
1414 q->reconfigure(appname, mpDirs);
1417 #include "kiconloader_p.moc"