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 <kapplication.h>
32 #include <kstandarddirs.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"
60 KIconThemeNode::KIconThemeNode(
KIconTheme *_theme)
65 KIconThemeNode::~KIconThemeNode()
70 void KIconThemeNode::printTree(TQString& dbgString)
const
75 dbgString += theme->
name();
79 void KIconThemeNode::queryIcons(TQStringList *result,
83 *result += theme->queryIcons(size, context);
86 void KIconThemeNode::queryIconsByContext(TQStringList *result,
90 *result += theme->queryIconsByContext(size, context);
93 KIcon KIconThemeNode::findIcon(
const TQString& name,
int size,
96 return theme->iconPath(name, size, match);
109 #define KICONLOADER_CHECKS
110 #ifdef KICONLOADER_CHECKS
113 struct KIconLoaderDebug
115 KIconLoaderDebug(
KIconLoader* l,
const TQString& a )
116 : loader( l ), appname( a ), valid( true )
118 KIconLoaderDebug() {};
125 static TQValueList< KIconLoaderDebug > *kiconloaders;
132 #ifdef KICONLOADER_CHECKS
133 if( kiconloaders == NULL )
134 kiconloaders =
new TQValueList< KIconLoaderDebug>();
137 for( TQValueList< KIconLoaderDebug >::Iterator it = kiconloaders->begin();
138 it != kiconloaders->end();
141 if( (*it).loader ==
this )
142 it = kiconloaders->remove( it );
146 kiconloaders->append( KIconLoaderDebug(
this, _appname ));
148 d =
new KIconLoaderPrivate;
151 d->imgDict.setAutoDelete(
true);
152 d->links.setAutoDelete(
true);
155 kapp->addKipcEventMask(KIPC::IconChanged);
156 TQObject::connect(kapp, TQT_SIGNAL(updateIconLoaders()), d, TQT_SLOT(
reconfigure()));
159 init( _appname, _dirs );
166 d->mThemesInTree.clear();
167 d->lastImage.reset();
168 d->lastImageKey = TQString::null;
169 delete [] d->mpGroups;
171 init( _appname, _dirs );
174 void KIconLoader::init(
const TQString& _appname,
KStandardDirs *_dirs )
180 d->appname = _appname;
181 d->extraDesktopIconsLoaded =
false;
182 d->delayedLoading =
false;
189 TQString appname = _appname;
190 if (appname.isEmpty())
199 kdDebug(264) <<
"Couldn't find current icon theme, falling back to default." <<
endl;
203 kdError(264) <<
"Error: standard icon theme"
205 <<
" not found!" <<
endl;
210 d->mpThemeRoot =
new KIconThemeNode(def);
211 d->links.append(d->mpThemeRoot);
213 addBaseThemes(d->mpThemeRoot, appname);
216 static const char *
const groups[] = {
"Desktop",
"Toolbar",
"MainToolbar",
"Small",
"Panel", 0L };
226 config->
setGroup(TQString::fromLatin1(groups[i]) +
"Icons");
228 d->mpGroups[i].dblPixels = config->
readBoolEntry(
"DoublePixels",
false);
229 if (TQPixmap::defaultDepth()>8)
230 d->mpGroups[i].alphaBlending = config->
readBoolEntry(
"AlphaBlending",
true);
232 d->mpGroups[i].alphaBlending =
false;
234 if (!d->mpGroups[i].size)
235 d->mpGroups[i].size = d->mpThemeRoot->theme->defaultSize(i);
243 appname +
"/toolbar/");
247 dirs += d->mpDirs->resourceDirs(
"icon");
248 dirs += d->mpDirs->resourceDirs(
"pixmap");
249 dirs += d->mpDirs->resourceDirs(
"xdgdata-icon");
250 dirs +=
"/usr/share/pixmaps";
252 dirs += d->mpDirs->resourceDirs(
"xdgdata-pixmap");
253 for (TQStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it)
254 d->mpDirs->addResourceDir(
"appicon", *it);
257 TQString dbgString =
"Theme tree: ";
258 d->mpThemeRoot->printTree(dbgString);
259 kdDebug(264) << dbgString <<
endl;
265 #ifdef KICONLOADER_CHECKS
266 for( TQValueList< KIconLoaderDebug >::Iterator it = kiconloaders->begin();
267 it != kiconloaders->end();
270 if( (*it).loader ==
this )
273 (*it).delete_bt = kdBacktrace();
281 delete[] d->mpGroups;
287 d->delayedLoading = enable;
292 return d->delayedLoading;
301 appname +
"/toolbar/");
302 addAppThemes(appname);
305 void KIconLoader::addAppThemes(
const TQString& appname)
312 KIconThemeNode* node =
new KIconThemeNode(def);
313 d->links.append(node);
314 addBaseThemes(node, appname);
321 KIconThemeNode* node =
new KIconThemeNode(def);
322 d->links.append(node);
323 addBaseThemes(node, appname);
326 void KIconLoader::addBaseThemes(KIconThemeNode *node,
const TQString &appname)
328 TQStringList lst = node->theme->inherits();
329 TQStringList::ConstIterator it;
331 for (it=lst.begin(); it!=lst.end(); ++it)
333 if( d->mThemesInTree.contains(*it) && (*it) !=
"hicolor")
340 KIconThemeNode *n =
new KIconThemeNode(theme);
341 d->mThemesInTree.append(*it);
343 addBaseThemes(n, appname);
349 if ( d->extraDesktopIconsLoaded )
return;
353 TQStringList::ConstIterator it;
356 for (it=icnlibs.begin(); it!=icnlibs.end(); ++it)
361 TQStringList lst = dir.entryList(
"default.*", TQDir::Dirs);
362 TQStringList::ConstIterator it2;
363 for (it2=lst.begin(); it2!=lst.end(); ++it2)
368 r=readlink( TQFile::encodeName(*it + *it2) , buf,
sizeof(buf)-1);
373 TQString themeName=dir2.dirName();
375 if (!list.contains(themeName))
376 list.append(themeName);
381 for (it=list.begin(); it!=list.end(); ++it)
383 if ( d->mThemesInTree.contains(*it) )
385 if ( *it == TQString(
"default.kde") )
continue;
388 KIconThemeNode* node =
new KIconThemeNode(def);
389 d->mThemesInTree.append(*it);
390 d->links.append(node);
391 addBaseThemes(node,
"" );
394 d->extraDesktopIconsLoaded=
true;
400 return d->extraDesktopIconsLoaded;
403 TQString KIconLoader::removeIconExtension(
const TQString &name)
const
405 int extensionLength=0;
407 TQString ext = name.right(4);
411 if (ext == png_ext || ext == xpm_ext)
419 if (name.right(5) == svgz_ext)
421 else if (ext == svg_ext)
426 if ( extensionLength > 0 )
428 return name.left(name.length() - extensionLength);
433 TQString KIconLoader::removeIconExtensionInternal(
const TQString &name)
const
435 TQString name_noext = removeIconExtension(name);
438 if (name != name_noext)
441 <<
" loads icon " << name <<
" with extension." <<
endl;
448 KIcon KIconLoader::findMatchingIcon(
const TQString& name,
int size)
const
452 const TQString *ext[4];
455 ext[count++]=&png_ext;
458 ext[count++]=&svgz_ext;
460 ext[count++]=&svg_ext;
463 ext[count++]=&xpm_ext;
477 for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
478 themeNode = d->links.next() )
480 for (
int i = 0 ; i < count ; i++)
483 if (icon.
isValid())
goto icon_found ;
486 for (
int i = 0 ; i < count ; i++)
489 if (icon.
isValid())
goto icon_found;
496 inline TQString KIconLoader::unknownIconPath(
int size )
const
500 KIcon icon = findMatchingIcon(str_unknown, size);
503 kdDebug(264) <<
"Warning: could not find \"Unknown\" icon for size = "
505 return TQString::null;
513 bool canReturnNull)
const
515 if (d->mpThemeRoot == 0L)
516 return TQString::null;
518 if (!TQDir::isRelativePath(_name))
521 TQString name = removeIconExtensionInternal( _name );
528 path = d->mpDirs->findResource(
"appicon", name + png_ext);
534 path = d->mpDirs->findResource(
"appicon", name + svgz_ext);
536 path = d->mpDirs->findResource(
"appicon", name + svg_ext);
539 path = d->mpDirs->findResource(
"appicon", name + xpm_ext);
543 if (group_or_size >= KIcon::LastGroup)
545 kdDebug(264) <<
"Illegal icon group: " << group_or_size <<
endl;
550 if (group_or_size >= 0)
551 size = d->mpGroups[group_or_size].size;
553 size = -group_or_size;
555 if (_name.isEmpty()) {
557 return TQString::null;
559 return unknownIconPath(size);
562 KIcon icon = findMatchingIcon(name, size);
568 if (!path.isEmpty() || canReturnNull)
572 return TQString::null;
574 return unknownIconPath(size);
580 int state, TQString *path_store,
bool canReturnNull)
const
582 TQString name = _name;
585 bool absolutePath=
false, favIconOverlay=
false;
587 if (d->mpThemeRoot == 0L)
591 if (name.startsWith(
"favicons/"))
593 favIconOverlay =
true;
594 name = locateLocal(
"cache", name+
".png");
596 if (!TQDir::isRelativePath(name)) absolutePath=
true;
604 key += TQString::number(size); key +=
'_';
606 bool inCache = TQPixmapCache::find(key, pix);
607 if (inCache && (path_store == 0L))
610 TQString path = (absolutePath) ? name :
620 kdDebug(264) <<
"Warning: Cannot find \"unknown\" icon." <<
endl;
625 if (path_store != 0L)
631 img=img.smoothScale(size,size);
633 pix.convertFromImage(img);
634 TQPixmapCache::insert(key, pix);
640 if ((group < -1) || (group >= KIcon::LastGroup))
642 kdDebug(264) <<
"Illegal icon group: " << group <<
endl;
646 int overlay = (state & KIcon::OverlayMask);
647 state &= ~
KIcon::OverlayMask;
650 kdDebug(264) <<
"Illegal icon state: " << state <<
endl;
654 if (size == 0 && group < 0)
656 kdDebug(264) <<
"Neither size nor group specified!" <<
endl;
662 if (!canReturnNull && name.isEmpty())
665 name = removeIconExtensionInternal(name);
671 size = d->mpGroups[group].size;
673 favIconOverlay = favIconOverlay && size > 22;
678 key += name; key +=
'_';
679 key += TQString::number(size); key +=
'_';
681 TQString overlayStr = TQString::number( overlay );
683 TQString noEffectKey = key +
'_' + overlayStr;
687 key += d->mpEffect.fingerprint(group, state);
688 if (d->mpGroups[group].dblPixels)
689 key += TQString::fromLatin1(
":dblsize");
691 key += TQString::fromLatin1(
"noeffect");
696 bool inCache = TQPixmapCache::find(key, pix);
697 if (inCache && (path_store == 0L))
704 if ( ( path_store != 0L ) ||
705 noEffectKey != d->lastImageKey )
709 if (absolutePath && !favIconOverlay)
718 icon = findMatchingIcon(favIconOverlay ? TQString(
"www") : name, size);
725 if (!pix.isNull() || canReturnNull) {
726 TQPixmapCache::insert(key, pix);
730 icon = findMatchingIcon(str_unknown, size);
734 <<
"Warning: could not find \"Unknown\" icon for size = "
741 if (path_store != 0L)
742 *path_store = icon.
path;
747 TQString ext = icon.
path.right(3).upper();
748 if(ext !=
"SVG" && ext !=
"VGZ")
750 img =
new TQImage(icon.
path, ext.latin1());
760 KSVGIconEngine *svgEngine =
new KSVGIconEngine();
762 if(svgEngine->load(size, size, icon.
path))
763 img = svgEngine->painter()->image();
773 iconType = icon.
type;
776 d->lastImage = img->copy();
777 d->lastImageKey = noEffectKey;
778 d->lastIconType = iconType;
779 d->lastIconThreshold = iconThreshold;
783 img =
new TQImage( d->lastImage.copy() );
784 iconType = d->lastIconType;
785 iconThreshold = d->lastIconThreshold;
794 ((ovl = loadOverlay(theme->
lockOverlay(), size)) != 0L))
797 ((ovl = loadOverlay(theme->
linkOverlay(), size)) != 0L))
800 ((ovl = loadOverlay(theme->
zipOverlay(), size)) != 0L))
803 ((ovl = loadOverlay(theme->
shareOverlay(), size)) != 0L))
807 if (img->depth() != 32)
808 *img = img->convertDepth(32);
809 for (
int y = 0; y < img->height(); y++)
811 QRgb *line =
reinterpret_cast<QRgb *
>(img->scanLine(y));
812 for (
int x = 0; x < img->width(); x++)
813 line[x] = (line[x] & 0x00ffffff) | (QMIN(0x80, tqAlpha(line[x])) << 24);
821 *img = img->smoothScale(size, size);
825 if ( abs(size-img->width())>iconThreshold )
826 *img = img->smoothScale(size, size);
828 if (group >= 0 && d->mpGroups[group].dblPixels)
830 *img = d->mpEffect.doublePixels(*img);
834 *img = d->mpEffect.apply(*img, group, state);
839 TQImage favIcon(name,
"PNG");
840 int x = img->width() - favIcon.width() - 1,
841 y = img->height() - favIcon.height() - 1;
842 if( favIcon.depth() != 32 )
843 favIcon = favIcon.convertDepth( 32 );
844 if( img->depth() != 32 )
845 *img = img->convertDepth( 32 );
847 line < favIcon.height();
850 QRgb* fpos =
reinterpret_cast< QRgb*
>( favIcon.scanLine( line ));
851 QRgb* ipos =
reinterpret_cast< QRgb*
>( img->scanLine( line + y )) + x;
854 ++i, ++fpos, ++ipos )
855 *ipos = tqRgba( ( tqRed( *ipos ) * ( 255 - tqAlpha( *fpos )) + tqRed( *fpos ) * tqAlpha( *fpos )) / 255,
856 ( tqGreen( *ipos ) * ( 255 - tqAlpha( *fpos )) + tqGreen( *fpos ) * tqAlpha( *fpos )) / 255,
857 ( tqBlue( *ipos ) * ( 255 - tqAlpha( *fpos )) + tqBlue( *fpos ) * tqAlpha( *fpos )) / 255,
858 ( tqAlpha( *ipos ) * ( 255 - tqAlpha( *fpos )) + tqAlpha( *fpos ) * tqAlpha( *fpos )) / 255 );
862 if (TQPaintDevice::x11AppDepth() == 32) pix.convertFromImage(KImageEffect::convertToPremultipliedAlpha( *img ));
863 else pix.convertFromImage(*img);
867 TQPixmapCache::insert(key, pix);
871 TQImage *KIconLoader::loadOverlay(
const TQString &name,
int size)
const
873 TQString key = name +
'_' + TQString::number(size);
874 TQImage *image = d->imgDict.find(key);
878 KIcon icon = findMatchingIcon(name, size);
881 kdDebug(264) <<
"Overlay " << name <<
"not found." <<
endl;
884 image =
new TQImage(icon.
path);
887 if ( size != image->width() )
888 *image = image->smoothScale( size, size );
889 d->imgDict.insert(key, image);
897 TQString file =
moviePath( name, group, size );
900 int dirLen = file.findRev(
'/');
901 TQString icon =
iconPath(name, size ? -size : group,
true);
902 if (!icon.isEmpty() && file.left(dirLen) != icon.left(dirLen))
904 return TQMovie(file);
909 if (!d->mpGroups)
return TQString::null;
911 if ( (group < -1 || group >= KIcon::LastGroup) && group !=
KIcon::User )
913 kdDebug(264) <<
"Illegal icon group: " << group <<
endl;
916 if (size == 0 && group < 0)
918 kdDebug(264) <<
"Neither size nor group specified!" <<
endl;
922 TQString file = name +
".mng";
925 file = d->mpDirs->findResource(
"appicon", file);
930 size = d->mpGroups[group].size;
934 for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
935 themeNode = d->links.next() )
938 if (icon.
isValid())
goto icon_found ;
941 if (icon.
isValid())
goto icon_found ;
945 file = icon.
isValid() ? icon.
path : TQString::null;
955 if (!d->mpGroups)
return lst;
957 if ((group < -1) || (group >= KIcon::LastGroup))
959 kdDebug(264) <<
"Illegal icon group: " << group <<
endl;
962 if ((size == 0) && (group < 0))
964 kdDebug(264) <<
"Neither size nor group specified!" <<
endl;
968 TQString file = name +
"/0001";
971 file = d->mpDirs->findResource(
"appicon", file +
".png");
975 size = d->mpGroups[group].size;
976 KIcon icon = findMatchingIcon(file, size);
977 file = icon.
isValid() ? icon.
path : TQString::null;
983 TQString path = file.left(file.length()-8);
984 DIR* dp = opendir( TQFile::encodeName(path) );
989 while( ( ep = readdir( dp ) ) != 0L )
991 TQString fn(TQFile::decodeName(ep->d_name));
992 if(!(fn.left(4)).toUInt())
1004 if (d->mpThemeRoot)
return d->mpThemeRoot->theme;
1010 if (!d->mpGroups)
return -1;
1012 if (group < 0 || group >= KIcon::LastGroup)
1014 kdDebug(264) <<
"Illegal icon group: " << group <<
endl;
1017 return d->mpGroups[group].size;
1022 TQDir dir(iconsDir);
1023 TQStringList lst = dir.entryList(
"*.png;*.xpm", TQDir::Files);
1024 TQStringList result;
1025 TQStringList::ConstIterator it;
1026 for (it=lst.begin(); it!=lst.end(); ++it)
1027 result += iconsDir +
"/" + *it;
1034 TQStringList result;
1035 if (group_or_size >= KIcon::LastGroup)
1037 kdDebug(264) <<
"Illegal icon group: " << group_or_size <<
endl;
1041 if (group_or_size >= 0)
1042 size = d->mpGroups[group_or_size].size;
1044 size = -group_or_size;
1046 for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
1047 themeNode = d->links.next() )
1048 themeNode->queryIconsByContext(&result, size, context);
1052 TQStringList res2, entries;
1053 TQStringList::ConstIterator it;
1054 for (it=result.begin(); it!=result.end(); ++it)
1056 int n = (*it).findRev(
'/');
1060 name = (*it).mid(n+1);
1061 name = removeIconExtension(name);
1062 if (!entries.contains(name))
1074 TQStringList result;
1075 if (group_or_size >= KIcon::LastGroup)
1077 kdDebug(264) <<
"Illegal icon group: " << group_or_size <<
endl;
1081 if (group_or_size >= 0)
1082 size = d->mpGroups[group_or_size].size;
1084 size = -group_or_size;
1086 for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
1087 themeNode = d->links.next() )
1088 themeNode->queryIcons(&result, size, context);
1092 TQStringList res2, entries;
1093 TQStringList::ConstIterator it;
1094 for (it=result.begin(); it!=result.end(); ++it)
1096 int n = (*it).findRev(
'/');
1100 name = (*it).mid(n+1);
1101 name = removeIconExtension(name);
1102 if (!entries.contains(name))
1114 for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
1115 themeNode = d->links.next() )
1116 if( themeNode->theme->hasContext( context ))
1123 return &d->mpEffect;
1128 if (!d->mpGroups)
return false;
1130 if (group < 0 || group >= KIcon::LastGroup)
1132 kdDebug(264) <<
"Illegal icon group: " << group <<
endl;
1135 return d->mpGroups[group].alphaBlending;
1140 return loadIconSet( name, group, size, canReturnNull,
true );
1151 :
public TQIconFactory
1154 KIconFactory(
const TQString& iconName_P,
KIcon::Group group_P,
1156 KIconFactory(
const TQString& iconName_P,
KIcon::Group group_P,
1157 int size_P,
KIconLoader* loader_P,
bool canReturnNull );
1158 virtual TQPixmap* createPixmap(
const TQIconSet&, TQIconSet::Size, TQIconSet::Mode, TQIconSet::State );
1169 bool canReturnNull,
bool immediateExistenceCheck)
1171 if ( !d->delayedLoading )
1172 return loadIconSetNonDelayed( name, g, s, canReturnNull );
1174 if (g < -1 || g > 6) {
1175 kdDebug() <<
"KIconLoader::loadIconSet " << name <<
" " << (int)g <<
" " << s <<
endl;
1176 qDebug(
"%s", kdBacktrace().latin1());
1180 if(canReturnNull && immediateExistenceCheck)
1186 TQIconSet ret( pm );
1187 ret.installIconFactory(
new KIconFactory( name, g, s,
this ));
1192 ret.installIconFactory(
new KIconFactory( name, g, s,
this, canReturnNull ));
1196 TQIconSet KIconLoader::loadIconSetNonDelayed(
const TQString& name,
1198 int s,
bool canReturnNull )
1202 iconset.setPixmap( tmp, TQIconSet::Small, TQIconSet::Active );
1204 iconset.setPixmap( tmp, TQIconSet::Large, TQIconSet::Active );
1206 iconset.setPixmap( tmp, TQIconSet::Small, TQIconSet::Disabled );
1207 iconset.setPixmap( tmp, TQIconSet::Large, TQIconSet::Disabled );
1209 iconset.setPixmap( tmp, TQIconSet::Small, TQIconSet::Normal );
1210 iconset.setPixmap( tmp, TQIconSet::Large, TQIconSet::Normal );
1214 KIconFactory::KIconFactory(
const TQString& iconName_P,
KIcon::Group group_P,
1216 : iconName( iconName_P ), group( group_P ), size( size_P ), loader( loader_P )
1218 canReturnNull =
false;
1219 setAutoDelete(
true );
1222 KIconFactory::KIconFactory(
const TQString& iconName_P,
KIcon::Group group_P,
1223 int size_P,
KIconLoader* loader_P,
bool canReturnNull_P )
1224 : iconName( iconName_P ), group( group_P ), size( size_P ),
1225 loader( loader_P ), canReturnNull( canReturnNull_P)
1227 setAutoDelete(
true );
1230 TQPixmap* KIconFactory::createPixmap(
const TQIconSet&, TQIconSet::Size, TQIconSet::Mode mode_P, TQIconSet::State )
1232 #ifdef KICONLOADER_CHECKS
1234 for( TQValueList< KIconLoaderDebug >::Iterator it = kiconloaders->begin();
1235 it != kiconloaders->end();
1238 if( (*it).loader == loader )
1245 iconName =
"no_way_man_you_will_get_broken_icon";
1247 kdWarning() <<
"Using already destroyed KIconLoader for loading an icon!" <<
endl;
1248 kdWarning() <<
"Appname:" << (*it).appname <<
", icon:" << iconName <<
endl;
1264 iconName =
"no_way_man_you_will_get_broken_icon";
1266 kdWarning() <<
"Using unknown KIconLoader for loading an icon!" <<
endl;
1277 if( mode_P <= TQIconSet::Active )
1278 state = tbl[ mode_P ];
1287 TQPixmap pm = loader->loadIcon( iconName, group, size, state, 0, canReturnNull );
1288 return new TQPixmap( pm );
1311 TQPixmap
BarIcon(
const TQString& name,
int force_size,
int state,
1329 TQPixmap
SmallIcon(
const TQString& name,
int force_size,
int state,
1391 if ( TQPixmapCache::find(
"unknown", pix) )
1397 kdDebug(264) <<
"Warning: Cannot find \"unknown\" icon." <<
endl;
1402 TQPixmapCache::insert(
"unknown", pix);
1408 void KIconLoaderPrivate::reconfigure()
1410 q->reconfigure(appname, mpDirs);
1413 #include "kiconloader_p.moc"