mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-24 02:42:48 +00:00
1434 lines
42 KiB
C++
1434 lines
42 KiB
C++
/* vi: ts=8 sts=4 sw=4
|
|
*
|
|
* kiconloader.cpp: An icon loader for KDE with theming functionality.
|
|
*
|
|
* This file is part of the KDE project, module kdeui.
|
|
* Copyright (C) 2000 Geert Jansen <jansen@kde.org>
|
|
* Antonio Larrosa <larrosa@kde.org>
|
|
* 2010 Michael Pyne <mpyne@kde.org>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License version 2 as published by the Free Software Foundation.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public License
|
|
* along with this library; see the file COPYING.LIB. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "kiconloader.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <stdlib.h> //for abs
|
|
#include <unistd.h> //for readlink
|
|
#include <dirent.h>
|
|
#include <assert.h>
|
|
|
|
#include <QtCore/QCache>
|
|
#include <QtCore/QFileInfo>
|
|
#include <QtCore/QDir>
|
|
#include <QtGui/QIcon>
|
|
#include <QtGui/QImage>
|
|
#include <QtGui/QPainter>
|
|
#include <QtGui/QPixmap>
|
|
#include <QtGui/QPixmapCache>
|
|
#include <QtGui/QX11Info>
|
|
|
|
// kdecore
|
|
#include <kconfig.h>
|
|
#include <kconfiggroup.h>
|
|
#include <kdebug.h>
|
|
#include <kstandarddirs.h>
|
|
#include <kglobal.h>
|
|
#include <kglobalsettings.h>
|
|
#include <kcomponentdata.h>
|
|
#include <kde_file.h>
|
|
|
|
// kdeui
|
|
#include "kicontheme.h"
|
|
#include "kiconeffect.h"
|
|
|
|
/**
|
|
* Checks for relative paths quickly on UNIX-alikes
|
|
*/
|
|
static bool pathIsRelative(const QString &path)
|
|
{
|
|
return (!path.isEmpty() && path[0] != QChar('/'));
|
|
}
|
|
|
|
/**
|
|
* Holds a QPixmap for this process, along with its associated path on disk.
|
|
*/
|
|
struct PixmapWithPath
|
|
{
|
|
QPixmap pixmap;
|
|
QString path;
|
|
};
|
|
|
|
/*** KIconThemeNode: A node in the icon theme dependancy tree. ***/
|
|
|
|
class KIconThemeNode
|
|
{
|
|
public:
|
|
|
|
KIconThemeNode(KIconTheme *_theme);
|
|
~KIconThemeNode();
|
|
|
|
void queryIcons(QStringList *lst, int size, KIconLoader::Context context) const;
|
|
void queryIconsByContext(QStringList *lst, int size, KIconLoader::Context context) const;
|
|
QString findIcon(const QString& name, int size, KIconLoader::MatchType match) const;
|
|
void printTree(QString& dbgString) const;
|
|
|
|
KIconTheme *theme;
|
|
};
|
|
|
|
KIconThemeNode::KIconThemeNode(KIconTheme *_theme)
|
|
{
|
|
theme = _theme;
|
|
}
|
|
|
|
KIconThemeNode::~KIconThemeNode()
|
|
{
|
|
delete theme;
|
|
}
|
|
|
|
void KIconThemeNode::printTree(QString& dbgString) const
|
|
{
|
|
/* This method doesn't have much sense anymore, so maybe it should
|
|
be removed in the (near?) future */
|
|
dbgString += '(';
|
|
dbgString += theme->name();
|
|
dbgString += ')';
|
|
}
|
|
|
|
void KIconThemeNode::queryIcons(QStringList *result,
|
|
int size, KIconLoader::Context context) const
|
|
{
|
|
// add the icons of this theme to it
|
|
*result += theme->queryIcons(size, context);
|
|
}
|
|
|
|
void KIconThemeNode::queryIconsByContext(QStringList *result,
|
|
int size, KIconLoader::Context context) const
|
|
{
|
|
// add the icons of this theme to it
|
|
*result += theme->queryIconsByContext(size, context);
|
|
}
|
|
|
|
QString KIconThemeNode::findIcon(const QString& name, int size,
|
|
KIconLoader::MatchType match) const
|
|
{
|
|
return theme->iconPath(name, size, match);
|
|
}
|
|
|
|
|
|
/*** KIconGroup: Icon type description. ***/
|
|
|
|
struct KIconGroup
|
|
{
|
|
int size;
|
|
bool alphaBlending;
|
|
};
|
|
|
|
|
|
/*** d pointer for KIconLoader. ***/
|
|
class KIconLoaderPrivate
|
|
{
|
|
public:
|
|
KIconLoaderPrivate(KIconLoader *q)
|
|
: q(q)
|
|
, mpGroups(0)
|
|
{
|
|
}
|
|
|
|
~KIconLoaderPrivate()
|
|
{
|
|
/* antlarr: There's no need to delete d->mpThemeRoot as it's already
|
|
deleted when the elements of d->links are deleted */
|
|
qDeleteAll(links);
|
|
delete[] mpGroups;
|
|
}
|
|
|
|
/**
|
|
* @internal
|
|
*/
|
|
void init(const QString &_appname, KStandardDirs *_dirs);
|
|
|
|
/**
|
|
* @internal
|
|
*/
|
|
bool initIconThemes();
|
|
|
|
/**
|
|
* @internal
|
|
* tries to find an icon with the name. It tries some extension and
|
|
* match strategies
|
|
*/
|
|
QString findMatchingIcon(const QString &name, int size) const;
|
|
|
|
/**
|
|
* @internal
|
|
* tries to find an icon with the name.
|
|
* This is one layer above findMatchingIcon -- it also implements generic fallbacks
|
|
* such as generic icons for mimetypes.
|
|
*/
|
|
QString findMatchingIconWithGenericFallbacks(const QString &name, int size) const;
|
|
|
|
/**
|
|
* @internal
|
|
* Adds themes installed in the application's directory.
|
|
**/
|
|
void addAppThemes(const QString& appname);
|
|
|
|
/**
|
|
* @internal
|
|
* Adds all themes that are part of this node and the themes
|
|
* below (the fallbacks of the theme) into the tree.
|
|
*/
|
|
void addBaseThemes(KIconThemeNode *node, const QString &appname);
|
|
|
|
/**
|
|
* @internal
|
|
* Recursively adds all themes that are specified in the "Inherits"
|
|
* property of the given theme into the tree.
|
|
*/
|
|
void addInheritedThemes(KIconThemeNode *node, const QString &appname);
|
|
|
|
/**
|
|
* @internal
|
|
* Creates a KIconThemeNode out of a theme name, and adds this theme
|
|
* as well as all its inherited themes into the tree. Themes that already
|
|
* exist in the tree will be ignored and not added twice.
|
|
*/
|
|
void addThemeByName(const QString &themename, const QString &appname);
|
|
|
|
/**
|
|
* @internal
|
|
* return the path for the unknown icon in that size
|
|
*/
|
|
QString unknownIconPath(int size) const;
|
|
|
|
/**
|
|
* Checks if name ends in one of the supported icon formats (i.e. .png)
|
|
* and returns the name without the extension if it does.
|
|
*/
|
|
QString removeIconExtension(const QString &name) const;
|
|
|
|
/**
|
|
* @internal
|
|
* Used with KIconLoader::loadIcon to convert the given name, size, group,
|
|
* and icon state information to valid states. All parameters except the
|
|
* name can be modified as well to be valid.
|
|
*/
|
|
void normalizeIconMetadata(KIconLoader::Group &group, int &size, int &state) const;
|
|
|
|
/**
|
|
* @internal
|
|
* Used with KIconLoader::loadIcon to get a base key name from the given
|
|
* icon metadata. Ensure the metadata is normalized first.
|
|
*/
|
|
QString makeCacheKey(const QString &name, KIconLoader::Group group, const QStringList &overlays,
|
|
int size, int state) const;
|
|
|
|
/**
|
|
* @internal
|
|
* Creates the QImage for @p path. If @p size is not zero image will be scaled.
|
|
*/
|
|
QImage createIconImage(const QString &path, int size = 0);
|
|
|
|
/**
|
|
* @internal
|
|
* Adds an QPixmap with its associated path to the shared icon cache.
|
|
*/
|
|
void insertCachedPixmapWithPath(const QString &key, const QPixmap &data, const QString &path);
|
|
|
|
/**
|
|
* @internal
|
|
* Retrieves the path and pixmap of the given key from the shared
|
|
* icon cache.
|
|
*/
|
|
bool findCachedPixmapWithPath(const QString &key, QPixmap &data, QString &path);
|
|
|
|
/**
|
|
* @internal
|
|
* Returns size suitable for overlay image based on the width and height of @p size.
|
|
*/
|
|
int overlaySize(const QSize &size) const;
|
|
|
|
KIconLoader *const q;
|
|
|
|
QStringList mThemesInTree;
|
|
KIconGroup *mpGroups;
|
|
KIconThemeNode *mpThemeRoot;
|
|
KStandardDirs *mpDirs;
|
|
KIconEffect mpEffect;
|
|
QList<KIconThemeNode *> links;
|
|
|
|
// This caches rendered QPixmaps in just this process.
|
|
QCache<QString, PixmapWithPath> mPixmapCache;
|
|
|
|
bool extraDesktopIconsLoaded;
|
|
// lazy loading: initIconThemes() is only needed when the "links" list is needed
|
|
// mIconThemeInited is used inside initIconThemes() to init only once
|
|
bool mIconThemeInited;
|
|
QString appname;
|
|
|
|
void drawOverlays(const KIconLoader *loader, KIconLoader::Group group, int state, QPixmap &pix, const QStringList &overlays);
|
|
};
|
|
|
|
class KIconLoaderGlobalData
|
|
{
|
|
public:
|
|
KIconLoaderGlobalData() {
|
|
const QStringList genericIconsFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", "generic-icons");
|
|
//kDebug() << genericIconsFiles;
|
|
foreach (const QString &file, genericIconsFiles) {
|
|
parseGenericIconsFiles(file);
|
|
}
|
|
}
|
|
|
|
QString genericIconFor(const QString& icon) const {
|
|
return m_genericIcons.value(icon);
|
|
}
|
|
|
|
private:
|
|
void parseGenericIconsFiles(const QString& fileName);
|
|
QHash<QString, QString> m_genericIcons;
|
|
};
|
|
|
|
void KIconLoaderGlobalData::parseGenericIconsFiles(const QString& fileName)
|
|
{
|
|
QFile file(fileName);
|
|
if (file.open(QIODevice::ReadOnly)) {
|
|
while (!file.atEnd()) {
|
|
const QByteArray line = file.readLine().trimmed();
|
|
if (line.isEmpty() || line[0] == '#') {
|
|
continue;
|
|
}
|
|
const int pos = line.indexOf(':');
|
|
if (pos == -1) {
|
|
// syntax error
|
|
continue;
|
|
}
|
|
QByteArray mimeIcon = line.left(pos);
|
|
const int slashindex = mimeIcon.indexOf('/');
|
|
if (slashindex != -1) {
|
|
mimeIcon[slashindex] = '-';
|
|
}
|
|
const QString mimeIconStr = QString::fromLatin1(mimeIcon.constData(), mimeIcon.size());
|
|
|
|
const QByteArray genericIcon = line.mid(pos+1);
|
|
const QString genericIconStr = QString::fromLatin1(genericIcon.constData(), genericIcon.size());
|
|
m_genericIcons.insert(mimeIconStr, genericIconStr);
|
|
//kDebug(264) << mimeIconStr << "->" << genericIconStr;
|
|
}
|
|
}
|
|
}
|
|
|
|
K_GLOBAL_STATIC(KIconLoaderGlobalData, s_globalData)
|
|
|
|
void KIconLoaderPrivate::drawOverlays(const KIconLoader *iconLoader, KIconLoader::Group group, int state, QPixmap &pix, const QStringList &overlays)
|
|
{
|
|
if (overlays.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
const QSize pixSize = pix.size();
|
|
const int iconSize = overlaySize(pixSize);
|
|
|
|
QPainter painter(&pix);
|
|
|
|
int count = 0;
|
|
foreach (const QString &overlay, overlays) {
|
|
// Ensure empty strings fill up a emblem spot
|
|
// Needed when you have several emblems to ensure they're always painted
|
|
// at the same place, even if one is not here
|
|
if (overlay.isEmpty()) {
|
|
++count;
|
|
continue;
|
|
}
|
|
|
|
//TODO: should we pass in the state? it results in a slower
|
|
// path, and perhaps emblems should remain in the default state
|
|
// anyways?
|
|
const QPixmap pixmap = iconLoader->loadIcon(overlay, group, iconSize, state, QStringList(), 0, true);
|
|
|
|
if (pixmap.isNull()) {
|
|
continue;
|
|
}
|
|
|
|
QPoint startPoint;
|
|
switch (count) {
|
|
case 0: {
|
|
// bottom left corner
|
|
startPoint = QPoint(2, pixSize.height() - iconSize - 2);
|
|
break;
|
|
}
|
|
case 1: {
|
|
// bottom right corner
|
|
startPoint = QPoint(pixSize.width() - iconSize - 2, pixSize.height() - iconSize - 2);
|
|
break;
|
|
}
|
|
case 2: {
|
|
// top right corner
|
|
startPoint = QPoint(pixSize.width() - iconSize - 2, 2);
|
|
break;
|
|
}
|
|
case 3: {
|
|
// top left corner
|
|
startPoint = QPoint(2, 2);
|
|
break;
|
|
}
|
|
}
|
|
|
|
painter.drawPixmap(startPoint, pixmap);
|
|
|
|
++count;
|
|
if (count > 3) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
KIconLoader::KIconLoader(const QString &_appname, KStandardDirs *_dirs, QObject* parent)
|
|
: QObject(parent)
|
|
{
|
|
setObjectName(_appname);
|
|
d = new KIconLoaderPrivate(this);
|
|
|
|
connect(
|
|
KGlobalSettings::self(), SIGNAL(iconChanged(int)),
|
|
this, SLOT(newIconLoader())
|
|
);
|
|
d->init(_appname, _dirs);
|
|
}
|
|
|
|
KIconLoader::KIconLoader(const KComponentData &componentData, QObject* parent)
|
|
: QObject(parent)
|
|
{
|
|
setObjectName(componentData.componentName());
|
|
d = new KIconLoaderPrivate(this);
|
|
|
|
connect(
|
|
KGlobalSettings::self(), SIGNAL(iconChanged(int)),
|
|
this, SLOT(newIconLoader())
|
|
);
|
|
d->init(componentData.componentName(), componentData.dirs());
|
|
}
|
|
|
|
void KIconLoader::reconfigure(const QString &_appname, KStandardDirs *_dirs)
|
|
{
|
|
delete d;
|
|
d = new KIconLoaderPrivate(this);
|
|
d->init(_appname, _dirs);
|
|
}
|
|
|
|
void KIconLoaderPrivate::init( const QString &_appname, KStandardDirs *_dirs)
|
|
{
|
|
extraDesktopIconsLoaded=false;
|
|
mIconThemeInited = false;
|
|
mpThemeRoot = 0;
|
|
|
|
if (_dirs) {
|
|
mpDirs = _dirs;
|
|
} else {
|
|
mpDirs = KGlobal::dirs();
|
|
}
|
|
|
|
appname = _appname;
|
|
if (appname.isEmpty()) {
|
|
appname = KGlobal::mainComponent().componentName();
|
|
}
|
|
|
|
// Initialize icon cache
|
|
mPixmapCache.setMaxCost(10240);
|
|
mPixmapCache.clear();
|
|
|
|
// These have to match the order in kiconloader.h
|
|
static const char * const groups[] = { "Desktop", "Toolbar", "MainToolbar", "Small", "Panel", "Dialog", 0L };
|
|
KSharedConfig::Ptr config = KGlobal::config();
|
|
|
|
// loading config and default sizes
|
|
initIconThemes();
|
|
KIconTheme *defaultSizesTheme = links.empty() ? 0 : links.first()->theme;
|
|
mpGroups = new KIconGroup[(int) KIconLoader::LastGroup];
|
|
for (KIconLoader::Group i = KIconLoader::FirstGroup; i < KIconLoader::LastGroup; ++i) {
|
|
if (groups[i] == 0L) {
|
|
break;
|
|
}
|
|
|
|
KConfigGroup cg(config, QLatin1String(groups[i]) + "Icons");
|
|
mpGroups[i].size = cg.readEntry("Size", 0);
|
|
if (QX11Info::appDepth() > 8) {
|
|
mpGroups[i].alphaBlending = cg.readEntry("AlphaBlending", true);
|
|
} else {
|
|
mpGroups[i].alphaBlending = false;
|
|
}
|
|
|
|
if (!mpGroups[i].size && defaultSizesTheme) {
|
|
mpGroups[i].size = defaultSizesTheme->defaultSize(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool KIconLoaderPrivate::initIconThemes()
|
|
{
|
|
if (mIconThemeInited) {
|
|
// If mpThemeRoot isn't 0 then initing has succeeded
|
|
return (mpThemeRoot != 0);
|
|
}
|
|
//kDebug(264);
|
|
mIconThemeInited = true;
|
|
|
|
// Add the default theme and its base themes to the theme tree
|
|
KIconTheme *def = new KIconTheme(KIconTheme::current(), appname);
|
|
if (!def->isValid()) {
|
|
delete def;
|
|
// warn, as this is actually a small penalty hit
|
|
kDebug(264) << "Couldn't find current icon theme, falling back to default.";
|
|
def = new KIconTheme(KIconTheme::defaultThemeName(), appname);
|
|
if (!def->isValid()) {
|
|
kError(264) << "Error: standard icon theme" << KIconTheme::defaultThemeName() << "not found!";
|
|
delete def;
|
|
return false;
|
|
}
|
|
}
|
|
mpThemeRoot = new KIconThemeNode(def);
|
|
mThemesInTree.append(def->internalName());
|
|
links.append(mpThemeRoot);
|
|
addBaseThemes(mpThemeRoot, appname);
|
|
|
|
// Insert application specific themes at the top.
|
|
mpDirs->addResourceType("appicon", "data", appname + "/pics/");
|
|
|
|
// Add legacy icon dirs.
|
|
QStringList dirs;
|
|
dirs += mpDirs->resourceDirs("icon");
|
|
dirs += mpDirs->resourceDirs("pixmap");
|
|
dirs += mpDirs->resourceDirs("pixmaps");
|
|
dirs += mpDirs->resourceDirs("xdgdata-icon");
|
|
// These are not in the icon spec, but e.g. GNOME puts some icons there anyway.
|
|
dirs += mpDirs->resourceDirs("xdgdata-pixmap");
|
|
foreach (const QString &it, dirs) {
|
|
mpDirs->addResourceDir("appicon", it);
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
QString dbgString = "Theme tree: ";
|
|
mpThemeRoot->printTree(dbgString);
|
|
kDebug(264) << dbgString;
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
KIconLoader::~KIconLoader()
|
|
{
|
|
delete d;
|
|
}
|
|
|
|
void KIconLoader::addAppDir(const QString& appname)
|
|
{
|
|
d->initIconThemes();
|
|
|
|
d->mpDirs->addResourceType("appicon", "data", appname + "/pics/");
|
|
d->addAppThemes(appname);
|
|
}
|
|
|
|
void KIconLoaderPrivate::addAppThemes(const QString& appname)
|
|
{
|
|
initIconThemes();
|
|
|
|
KIconTheme *def = new KIconTheme(KIconTheme::current(), appname);
|
|
if (!def->isValid()) {
|
|
delete def;
|
|
def = new KIconTheme(KIconTheme::defaultThemeName(), appname);
|
|
}
|
|
KIconThemeNode* node = new KIconThemeNode(def);
|
|
bool addedToLinks = false;
|
|
|
|
if (!mThemesInTree.contains(node->theme->internalName())) {
|
|
mThemesInTree.append(node->theme->internalName());
|
|
links.append(node);
|
|
addedToLinks = true;
|
|
}
|
|
addBaseThemes(node, appname);
|
|
|
|
if (!addedToLinks) {
|
|
// Nodes in links are being deleted later - this one needs manual care.
|
|
delete node;
|
|
}
|
|
}
|
|
|
|
void KIconLoaderPrivate::addBaseThemes(KIconThemeNode *node, const QString &appname)
|
|
{
|
|
// Quote from the icon theme specification:
|
|
// The lookup is done first in the current theme, and then recursively
|
|
// in each of the current theme's parents, and finally in the
|
|
// default theme called "hicolor" (implementations may add more
|
|
// default themes before "hicolor", but "hicolor" must be last).
|
|
//
|
|
// So we first make sure that all inherited themes are added, then we
|
|
// add the KDE default theme as fallback for all icons that might not be
|
|
// present in an inherited theme, and hicolor goes last.
|
|
|
|
addInheritedThemes(node, appname);
|
|
addThemeByName(KIconTheme::defaultThemeName(), appname);
|
|
addThemeByName("hicolor", appname);
|
|
}
|
|
|
|
void KIconLoaderPrivate::addInheritedThemes(KIconThemeNode *node, const QString &appname)
|
|
{
|
|
foreach (const QString &it, node->theme->inherits()) {
|
|
if (it == QLatin1String("hicolor")) {
|
|
// The icon theme spec says that "hicolor" must be the very last
|
|
// of all inherited themes, so don't add it here but at the very end
|
|
// of addBaseThemes().
|
|
continue;
|
|
}
|
|
addThemeByName(it, appname);
|
|
}
|
|
}
|
|
|
|
void KIconLoaderPrivate::addThemeByName(const QString &themename, const QString &appname)
|
|
{
|
|
if (mThemesInTree.contains(themename + appname)) {
|
|
return;
|
|
}
|
|
KIconTheme *theme = new KIconTheme(themename, appname);
|
|
if (!theme->isValid()) {
|
|
delete theme;
|
|
return;
|
|
}
|
|
KIconThemeNode *n = new KIconThemeNode(theme);
|
|
mThemesInTree.append(themename + appname);
|
|
links.append(n);
|
|
addInheritedThemes(n, appname);
|
|
}
|
|
|
|
void KIconLoader::addExtraDesktopThemes()
|
|
{
|
|
if ( d->extraDesktopIconsLoaded ) return;
|
|
|
|
d->initIconThemes();
|
|
|
|
QStringList list;
|
|
const QStringList icnlibs = KGlobal::dirs()->resourceDirs("icon");
|
|
QStringList::ConstIterator it;
|
|
char buf[1000];
|
|
int r;
|
|
for (it=icnlibs.begin(); it!=icnlibs.end(); ++it)
|
|
{
|
|
QDir dir(*it);
|
|
if (!dir.exists())
|
|
continue;
|
|
const QStringList lst = dir.entryList(QStringList( "default.*" ), QDir::Dirs);
|
|
QStringList::ConstIterator it2;
|
|
for (it2=lst.begin(); it2!=lst.end(); ++it2)
|
|
{
|
|
if (!KStandardDirs::exists(*it + *it2 + "/index.theme"))
|
|
continue;
|
|
r=readlink( QFile::encodeName(*it + *it2) , buf, sizeof(buf)-1);
|
|
if ( r>0 )
|
|
{
|
|
buf[r]=0;
|
|
const QDir dir2( buf );
|
|
QString themeName=dir2.dirName();
|
|
|
|
if (!list.contains(themeName))
|
|
list.append(themeName);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (it = list.constBegin(); it != list.constEnd(); ++it)
|
|
{
|
|
// Don't add the KDE defaults once more, we have them anyways.
|
|
if (*it == QLatin1String("default.kde")
|
|
|| *it == QLatin1String("default.kde4")) {
|
|
continue;
|
|
}
|
|
d->addThemeByName(*it, "");
|
|
}
|
|
|
|
d->extraDesktopIconsLoaded=true;
|
|
|
|
}
|
|
|
|
bool KIconLoader::extraDesktopThemesAdded() const
|
|
{
|
|
return d->extraDesktopIconsLoaded;
|
|
}
|
|
|
|
void KIconLoader::drawOverlays(const QStringList &overlays, QPixmap &pixmap, KIconLoader::Group group, int state) const
|
|
{
|
|
d->drawOverlays(this, group, state, pixmap, overlays);
|
|
}
|
|
|
|
QString KIconLoaderPrivate::removeIconExtension(const QString &name) const
|
|
{
|
|
if (name.endsWith(QLatin1String(".png"))
|
|
|| name.endsWith(QLatin1String(".xpm"))
|
|
|| name.endsWith(QLatin1String(".svg"))) {
|
|
return name.left(name.length() - 4);
|
|
} else if (name.endsWith(QLatin1String(".svgz"))) {
|
|
return name.left(name.length() - 5);
|
|
}
|
|
|
|
return name;
|
|
}
|
|
|
|
void KIconLoaderPrivate::normalizeIconMetadata(KIconLoader::Group &group, int &size, int &state) const
|
|
{
|
|
if ((state < 0) || (state >= KIconLoader::LastState))
|
|
{
|
|
kWarning(264) << "Illegal icon state: " << state;
|
|
state = KIconLoader::DefaultState;
|
|
}
|
|
|
|
if (size < 0) {
|
|
size = 0;
|
|
}
|
|
|
|
// For "User" icons, bail early since the size should be based on the size on disk,
|
|
// which we've already checked.
|
|
if (group == KIconLoader::User) {
|
|
return;
|
|
}
|
|
|
|
if ((group < -1) || (group >= KIconLoader::LastGroup))
|
|
{
|
|
kWarning(264) << "Illegal icon group: " << group;
|
|
group = KIconLoader::Desktop;
|
|
}
|
|
|
|
// If size == 0, use default size for the specified group.
|
|
if (size == 0)
|
|
{
|
|
if (group < 0)
|
|
{
|
|
kWarning(264) << "Neither size nor group specified!";
|
|
group = KIconLoader::Desktop;
|
|
}
|
|
size = mpGroups[group].size;
|
|
}
|
|
}
|
|
|
|
QString KIconLoaderPrivate::makeCacheKey(const QString &name, KIconLoader::Group group,
|
|
const QStringList &overlays, int size, int state) const
|
|
{
|
|
// The icon cache is shared so add some namespacing.
|
|
|
|
return (group == KIconLoader::User
|
|
? QLatin1String("$kicou_")
|
|
: QLatin1String("$kico_"))
|
|
+ name
|
|
+ QLatin1Char('_')
|
|
+ QString::number(size)
|
|
+ QLatin1Char('_')
|
|
+ overlays.join("_")
|
|
+ ( group >= 0 ? mpEffect.fingerprint(group, state) : QLatin1String("noeffect"));
|
|
}
|
|
|
|
QImage KIconLoaderPrivate::createIconImage(const QString &path, int size)
|
|
{
|
|
QImage img(path);
|
|
|
|
if (size != 0 && !img.isNull()) {
|
|
img = img.scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
|
}
|
|
|
|
return img;
|
|
}
|
|
|
|
void KIconLoaderPrivate::insertCachedPixmapWithPath(
|
|
const QString &key,
|
|
const QPixmap &data,
|
|
const QString &path)
|
|
{
|
|
// reject anything bigger than 1024x1024, it is questionable what the limit should be because
|
|
// in some projects the icon loader is abused with pixmaps bigger than that
|
|
if (data.width() > 1024 || data.height() > 1024) {
|
|
kWarning(264) << "trying to insert pixmap bigger than 1024x1024 with path:" << path;
|
|
return;
|
|
}
|
|
|
|
PixmapWithPath *pixmapPath = mPixmapCache.object(key);
|
|
if (pixmapPath
|
|
&& pixmapPath->pixmap == data
|
|
&& pixmapPath->path == path) {
|
|
return;
|
|
}
|
|
|
|
// Even if the pixmap is null, we add it to the caches so that we record
|
|
// the fact that whatever icon led to us getting a null pixmap doesn't
|
|
// exist.
|
|
pixmapPath = new PixmapWithPath;
|
|
pixmapPath->pixmap = data;
|
|
pixmapPath->path = path;
|
|
|
|
mPixmapCache.insert(key, pixmapPath);
|
|
}
|
|
|
|
bool KIconLoaderPrivate::findCachedPixmapWithPath(const QString &key, QPixmap &data, QString &path)
|
|
{
|
|
// If the pixmap is present in our local process cache, use that
|
|
const PixmapWithPath *pixmapPath = mPixmapCache.object(key);
|
|
if (pixmapPath) {
|
|
path = pixmapPath->path;
|
|
data = pixmapPath->pixmap;
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int KIconLoaderPrivate::overlaySize(const QSize &size) const
|
|
{
|
|
const int minSize = qMin(size.width(), size.height());
|
|
if (minSize < 32) {
|
|
return 8;
|
|
} else if (minSize <= 48) {
|
|
return 16;
|
|
} else if (minSize <= 96) {
|
|
return 22;
|
|
} else if (minSize < 256) {
|
|
return 32;
|
|
}
|
|
return 64;
|
|
}
|
|
|
|
QString KIconLoaderPrivate::findMatchingIconWithGenericFallbacks(const QString& name, int size) const
|
|
{
|
|
QString icon = findMatchingIcon(name, size);
|
|
if (!icon.isEmpty()) {
|
|
return icon;
|
|
}
|
|
|
|
const QString genericIcon = s_globalData->genericIconFor(name);
|
|
if (!genericIcon.isEmpty()) {
|
|
icon = findMatchingIcon(genericIcon, size);
|
|
}
|
|
return icon;
|
|
}
|
|
|
|
QString KIconLoaderPrivate::findMatchingIcon(const QString& name, int size) const
|
|
{
|
|
const_cast<KIconLoaderPrivate*>(this)->initIconThemes();
|
|
|
|
QString icon;
|
|
|
|
const char * const ext[4] = { ".png", ".svgz", ".svg", ".xpm" };
|
|
bool genericFallback = name.endsWith(QLatin1String("-x-generic"));
|
|
|
|
// Do two passes through themeNodes.
|
|
//
|
|
// The first pass looks for an exact match in each themeNode one after the other.
|
|
// If one is found and it is an app icon then return that icon.
|
|
//
|
|
// In the next pass (assuming the first pass failed), it looks for exact matches
|
|
// and then generic fallbacks in each themeNode one after the other
|
|
//
|
|
// The reasoning is that application icons should always match exactly, all other
|
|
// icons may fallback. Since we do not know what the context is here when we start
|
|
// looking for it, we can only go by the path found.
|
|
foreach (const KIconThemeNode *themeNode, links) {
|
|
for (int i = 0 ; i < 4 ; i++) {
|
|
icon = themeNode->theme->iconPath(name + ext[i], size, KIconLoader::MatchExact);
|
|
if (!icon.isEmpty()) {
|
|
break;
|
|
}
|
|
|
|
icon = themeNode->theme->iconPath(name + ext[i], size, KIconLoader::MatchBest);
|
|
if (!icon.isEmpty()) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (icon.contains("/apps/")) {
|
|
return icon;
|
|
}
|
|
}
|
|
|
|
foreach (const KIconThemeNode *themeNode, links) {
|
|
QString currentName = name;
|
|
|
|
while (!currentName.isEmpty()) {
|
|
//kDebug(264) << "Looking up" << currentName;
|
|
|
|
for (int i = 0 ; i < 4 ; i++) {
|
|
icon = themeNode->theme->iconPath(currentName + ext[i], size, KIconLoader::MatchExact);
|
|
if (!icon.isEmpty()) {
|
|
return icon;
|
|
}
|
|
|
|
icon = themeNode->theme->iconPath(currentName + ext[i], size, KIconLoader::MatchBest);
|
|
if (!icon.isEmpty()) {
|
|
return icon;
|
|
}
|
|
}
|
|
//kDebug(264) << "Looking up" << currentName;
|
|
|
|
if (genericFallback) {
|
|
// we already tested the base name
|
|
break;
|
|
}
|
|
|
|
int rindex = currentName.lastIndexOf('-');
|
|
if (rindex > 1) { // > 1 so that we don't split x-content or x-epoc
|
|
currentName.truncate(rindex);
|
|
|
|
if (currentName.endsWith(QLatin1String("-x")))
|
|
currentName.chop(2);
|
|
} else {
|
|
// From update-mime-database.c
|
|
static const QSet<QString> mediaTypes = QSet<QString>()
|
|
<< "text" << "application" << "image" << "audio"
|
|
<< "inode" << "video" << "message" << "model" << "multipart"
|
|
<< "x-content" << "x-epoc";
|
|
// Shared-mime-info spec says:
|
|
// "If [generic-icon] is not specified then the mimetype is used to generate the
|
|
// generic icon by using the top-level media type (e.g. "video" in "video/ogg")
|
|
// and appending "-x-generic" (i.e. "video-x-generic" in the previous example)."
|
|
if (mediaTypes.contains(currentName)) {
|
|
currentName += QLatin1String("-x-generic");
|
|
genericFallback = true;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return icon;
|
|
}
|
|
|
|
inline QString KIconLoaderPrivate::unknownIconPath(int size) const
|
|
{
|
|
static const QString str_unknown = QString::fromLatin1("unknown");
|
|
|
|
QString icon = findMatchingIcon(str_unknown, size);
|
|
if (icon.isEmpty()) {
|
|
kDebug(264) << "Warning: could not find \"Unknown\" icon for size = " << size;
|
|
}
|
|
return icon;
|
|
}
|
|
|
|
// Finds the absolute path to an icon.
|
|
|
|
QString KIconLoader::iconPath(const QString& _name, int group_or_size,
|
|
bool canReturnNull) const
|
|
{
|
|
if (!d->initIconThemes()) {
|
|
return QString();
|
|
}
|
|
|
|
if (_name.isEmpty() || !pathIsRelative(_name)) {
|
|
// we have either an absolute path or nothing to work with
|
|
return _name;
|
|
}
|
|
|
|
QString name = d->removeIconExtension(_name);
|
|
|
|
QString path;
|
|
if (group_or_size == KIconLoader::User) {
|
|
path = d->mpDirs->findResource("appicon", name + QLatin1String(".png"));
|
|
if (path.isEmpty()) {
|
|
path = d->mpDirs->findResource("appicon", name + QLatin1String(".svgz"));
|
|
}
|
|
if (path.isEmpty()) {
|
|
path = d->mpDirs->findResource("appicon", name + QLatin1String(".svg"));
|
|
}
|
|
if (path.isEmpty()) {
|
|
path = d->mpDirs->findResource("appicon", name + QLatin1String(".xpm"));
|
|
}
|
|
return path;
|
|
}
|
|
|
|
if (group_or_size >= KIconLoader::LastGroup) {
|
|
kDebug(264) << "Illegal icon group: " << group_or_size;
|
|
return path;
|
|
}
|
|
|
|
int size;
|
|
if (group_or_size >= 0) {
|
|
size = d->mpGroups[group_or_size].size;
|
|
} else {
|
|
size = -group_or_size;
|
|
}
|
|
|
|
if (_name.isEmpty()) {
|
|
if (canReturnNull) {
|
|
return QString();
|
|
}
|
|
return d->unknownIconPath(size);
|
|
}
|
|
|
|
QString icon = d->findMatchingIconWithGenericFallbacks(name, size);
|
|
|
|
if (icon.isEmpty()) {
|
|
// Try "User" group too.
|
|
path = iconPath(name, KIconLoader::User, true);
|
|
if (!path.isEmpty() || canReturnNull) {
|
|
return path;
|
|
}
|
|
|
|
return d->unknownIconPath(size);
|
|
}
|
|
return icon;
|
|
}
|
|
|
|
QPixmap KIconLoader::loadMimeTypeIcon(const QString& _iconName, KIconLoader::Group group, int size,
|
|
int state, const QStringList& overlays, QString *path_store) const
|
|
{
|
|
QString iconName = _iconName;
|
|
const int slashindex = iconName.indexOf(QLatin1Char('/'));
|
|
if (slashindex != -1) {
|
|
iconName[slashindex] = QLatin1Char('-');
|
|
}
|
|
|
|
if (!d->extraDesktopIconsLoaded) {
|
|
const QPixmap pixmap = loadIcon( iconName, group, size, state, overlays, path_store, true );
|
|
if (!pixmap.isNull() ) {
|
|
return pixmap;
|
|
}
|
|
const_cast<KIconLoader *>(this)->addExtraDesktopThemes();
|
|
}
|
|
const QPixmap pixmap = loadIcon(iconName, group, size, state, overlays, path_store, true);
|
|
if (pixmap.isNull()) {
|
|
// Icon not found, fallback to application/octet-stream
|
|
return loadIcon("application-octet-stream", group, size, state, overlays, path_store, false);
|
|
}
|
|
return pixmap;
|
|
}
|
|
|
|
QPixmap KIconLoader::loadIcon(const QString& _name, KIconLoader::Group group, int size,
|
|
int state, const QStringList& overlays,
|
|
QString *path_store, bool canReturnNull) const
|
|
{
|
|
QString name = _name;
|
|
bool favIconOverlay = false;
|
|
|
|
if (size < 0 || _name.isEmpty()) {
|
|
return QPixmap();
|
|
}
|
|
|
|
/*
|
|
* This method works in a kind of pipeline, with the following steps:
|
|
* 1. Sanity checks.
|
|
* 2. Convert _name, group, size, etc. to a key name.
|
|
* 3. Check if the key is already cached.
|
|
* 4. If not, initialize the theme and find/load the icon.
|
|
* 4a Apply overlays
|
|
* 4b Re-add to cache.
|
|
*/
|
|
|
|
// Special case for absolute path icons.
|
|
if (name.startsWith(QLatin1String("favicons/"))) {
|
|
favIconOverlay = true;
|
|
name = KStandardDirs::locateLocal("cache", name+".png");
|
|
}
|
|
|
|
bool absolutePath = !pathIsRelative(name);
|
|
if (!absolutePath) {
|
|
name = d->removeIconExtension(name);
|
|
}
|
|
|
|
// Don't bother looking for an icon with no name.
|
|
if (name.isEmpty()) {
|
|
return QPixmap();
|
|
}
|
|
|
|
// May modify group, size, or state. This function puts them into sane
|
|
// states.
|
|
d->normalizeIconMetadata(group, size, state);
|
|
|
|
// See if the image is already cached.
|
|
QString key = d->makeCacheKey(name, group, overlays, size, state);
|
|
QPixmap pix;
|
|
bool iconWasUnknown = false;
|
|
QString icon;
|
|
|
|
// icon would be empty for "unknown" icons, which should be searched for
|
|
// anew each time.
|
|
if (d->findCachedPixmapWithPath(key, pix, icon) && !icon.isEmpty()) {
|
|
if (path_store) {
|
|
*path_store = icon;
|
|
}
|
|
|
|
return pix;
|
|
}
|
|
|
|
// Image is not cached... go find it and apply effects.
|
|
if (!d->initIconThemes()) {
|
|
return QPixmap();
|
|
}
|
|
|
|
favIconOverlay = favIconOverlay && size > 22;
|
|
|
|
// First we look for non-User icons. If we don't find one we'd search in
|
|
// the User space anyways...
|
|
if (group != KIconLoader::User) {
|
|
if (absolutePath && !favIconOverlay) {
|
|
icon = name;
|
|
} else {
|
|
icon = d->findMatchingIconWithGenericFallbacks(favIconOverlay ? QString("text-html") : name, size);
|
|
}
|
|
}
|
|
|
|
if (icon.isEmpty()) {
|
|
// We do have a "User" icon, or we couldn't find the non-User one.
|
|
icon = (absolutePath ? name : iconPath(name, KIconLoader::User, canReturnNull));
|
|
}
|
|
|
|
// Still can't find it? Use "unknown" if we can't return null.
|
|
// We keep going in the function so we can ensure this result gets cached.
|
|
if (icon.isEmpty() && !canReturnNull) {
|
|
icon = d->unknownIconPath(size);
|
|
iconWasUnknown = true;
|
|
}
|
|
|
|
QImage img = d->createIconImage(icon, size);
|
|
|
|
if (group >= 0) {
|
|
img = d->mpEffect.apply(img, group, state);
|
|
}
|
|
|
|
if (favIconOverlay) {
|
|
QImage favIcon(name, "PNG");
|
|
// if favIcon not there yet, don't try to blend it
|
|
if (!favIcon.isNull()) {
|
|
// ensure it is format supported by QPainter first
|
|
switch (img.format()) {
|
|
case QImage::Format_Mono:
|
|
case QImage::Format_MonoLSB: {
|
|
img = img.convertToFormat(QImage::Format_ARGB32);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// ensure the icon size is suitable for overlay
|
|
const int iconSize = d->overlaySize(img.size());
|
|
favIcon = favIcon.scaled(QSize(iconSize, iconSize), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
|
|
|
QPainter p(&img);
|
|
|
|
// Align the favicon overlay
|
|
QRect r(favIcon.rect());
|
|
r.moveBottomRight(img.rect().bottomRight());
|
|
r.adjust(-1, -1, -1, -1); // Move off edge
|
|
|
|
// Blend favIcon over img.
|
|
p.drawImage(r, favIcon);
|
|
}
|
|
}
|
|
|
|
pix = QPixmap::fromImage(img);
|
|
|
|
// TODO: If we make a loadIcon that returns the image we can convert
|
|
// drawOverlays to use the image instead of pixmaps as well so we don't
|
|
// have to transfer so much to the graphics card.
|
|
d->drawOverlays(this, group, state, pix, overlays);
|
|
|
|
// Don't add the path to our unknown icon to the cache, only cache the
|
|
// actual image.
|
|
if (iconWasUnknown) {
|
|
icon.clear();
|
|
}
|
|
|
|
d->insertCachedPixmapWithPath(key, pix, icon);
|
|
|
|
if (path_store) {
|
|
*path_store = icon;
|
|
}
|
|
|
|
return pix;
|
|
}
|
|
|
|
QStringList KIconLoader::loadAnimated(const QString& name, KIconLoader::Group group, int size) const
|
|
{
|
|
QStringList lst;
|
|
|
|
if (!d->mpGroups) {
|
|
return lst;
|
|
}
|
|
|
|
d->initIconThemes();
|
|
|
|
if (group < -1 || group >= KIconLoader::LastGroup) {
|
|
kDebug(264) << "Illegal icon group: " << group;
|
|
group = KIconLoader::Desktop;
|
|
}
|
|
if (size == 0 && group < 0) {
|
|
kDebug(264) << "Neither size nor group specified!";
|
|
group = KIconLoader::Desktop;
|
|
}
|
|
|
|
QString file = name + "/0001";
|
|
if (group == KIconLoader::User) {
|
|
file = d->mpDirs->findResource("appicon", file + ".png");
|
|
} else {
|
|
if (size == 0) {
|
|
size = d->mpGroups[group].size;
|
|
}
|
|
file = d->findMatchingIcon(file, size);
|
|
}
|
|
if (file.isEmpty()) {
|
|
return lst;
|
|
}
|
|
|
|
QString path = file.left(file.length()-8);
|
|
DIR* dp = opendir( QFile::encodeName(path) );
|
|
if (!dp) {
|
|
return lst;
|
|
}
|
|
|
|
KDE_struct_dirent* ep;
|
|
while( ( ep = KDE_readdir( dp ) ) != 0L )
|
|
{
|
|
QString fn(QFile::decodeName(ep->d_name));
|
|
if(!(fn.left(4)).toUInt())
|
|
continue;
|
|
|
|
lst += path + fn;
|
|
}
|
|
closedir ( dp );
|
|
lst.sort();
|
|
return lst;
|
|
}
|
|
|
|
KIconTheme *KIconLoader::theme() const
|
|
{
|
|
d->initIconThemes();
|
|
if (d->mpThemeRoot) {
|
|
return d->mpThemeRoot->theme;
|
|
}
|
|
return 0L;
|
|
}
|
|
|
|
int KIconLoader::currentSize(KIconLoader::Group group) const
|
|
{
|
|
if (!d->mpGroups) {
|
|
return -1;
|
|
}
|
|
|
|
if (group < 0 || group >= KIconLoader::LastGroup) {
|
|
kDebug(264) << "Illegal icon group: " << group;
|
|
return -1;
|
|
}
|
|
return d->mpGroups[group].size;
|
|
}
|
|
|
|
QStringList KIconLoader::queryIconsByDir( const QString& iconsDir ) const
|
|
{
|
|
const QDir dir(iconsDir);
|
|
const QStringList formats = QStringList() << "*.png" << "*.xpm" << "*.svg" << "*.svgz";
|
|
QStringList result;
|
|
foreach (const QString &it, dir.entryList(formats, QDir::Files)) {
|
|
result.append(iconsDir + '/' + it);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
QStringList KIconLoader::queryIconsByContext(int group_or_size,
|
|
KIconLoader::Context context) const
|
|
{
|
|
d->initIconThemes();
|
|
|
|
QStringList result;
|
|
if (group_or_size >= KIconLoader::LastGroup) {
|
|
kDebug(264) << "Illegal icon group: " << group_or_size;
|
|
return result;
|
|
}
|
|
|
|
int size;
|
|
if (group_or_size >= 0) {
|
|
size = d->mpGroups[group_or_size].size;
|
|
} else {
|
|
size = -group_or_size;
|
|
}
|
|
|
|
foreach (const KIconThemeNode *themeNode, d->links) {
|
|
themeNode->queryIconsByContext(&result, size, context);
|
|
}
|
|
|
|
// Eliminate duplicate entries (same icon in different directories)
|
|
QString name;
|
|
QStringList res2, entries;
|
|
QStringList::ConstIterator it;
|
|
for (it=result.constBegin(); it!=result.constEnd(); ++it)
|
|
{
|
|
int n = (*it).lastIndexOf('/');
|
|
if (n == -1)
|
|
name = *it;
|
|
else
|
|
name = (*it).mid(n+1);
|
|
name = d->removeIconExtension(name);
|
|
if (!entries.contains(name))
|
|
{
|
|
entries += name;
|
|
res2 += *it;
|
|
}
|
|
}
|
|
return res2;
|
|
|
|
}
|
|
|
|
QStringList KIconLoader::queryIcons(int group_or_size, KIconLoader::Context context) const
|
|
{
|
|
d->initIconThemes();
|
|
|
|
QStringList result;
|
|
if (group_or_size >= KIconLoader::LastGroup) {
|
|
kDebug(264) << "Illegal icon group: " << group_or_size;
|
|
return result;
|
|
}
|
|
|
|
int size;
|
|
if (group_or_size >= 0) {
|
|
size = d->mpGroups[group_or_size].size;
|
|
} else {
|
|
size = -group_or_size;
|
|
}
|
|
|
|
foreach (const KIconThemeNode *themeNode, d->links) {
|
|
themeNode->queryIcons(&result, size, context);
|
|
}
|
|
|
|
// Eliminate duplicate entries (same icon in different directories)
|
|
QString name;
|
|
QStringList res2, entries;
|
|
QStringList::ConstIterator it;
|
|
for (it=result.constBegin(); it!=result.constEnd(); ++it)
|
|
{
|
|
int n = (*it).lastIndexOf('/');
|
|
if (n == -1)
|
|
name = *it;
|
|
else
|
|
name = (*it).mid(n+1);
|
|
name = d->removeIconExtension(name);
|
|
if (!entries.contains(name))
|
|
{
|
|
entries += name;
|
|
res2 += *it;
|
|
}
|
|
}
|
|
return res2;
|
|
}
|
|
|
|
// used by KIconDialog to find out which contexts to offer in a combobox
|
|
bool KIconLoader::hasContext(KIconLoader::Context context) const
|
|
{
|
|
d->initIconThemes();
|
|
|
|
foreach (const KIconThemeNode *themeNode, d->links) {
|
|
if (themeNode->theme->hasContext(context)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
KIconEffect * KIconLoader::iconEffect() const
|
|
{
|
|
return &d->mpEffect;
|
|
}
|
|
|
|
bool KIconLoader::alphaBlending(KIconLoader::Group group) const
|
|
{
|
|
if (!d->mpGroups) {
|
|
return false;
|
|
}
|
|
|
|
if (group < 0 || group >= KIconLoader::LastGroup) {
|
|
kDebug(264) << "Illegal icon group: " << group;
|
|
return false;
|
|
}
|
|
return d->mpGroups[group].alphaBlending;
|
|
}
|
|
|
|
// Easy access functions
|
|
|
|
QPixmap DesktopIcon(const QString& name, int force_size, int state, const QStringList &overlays)
|
|
{
|
|
KIconLoader *loader = KIconLoader::global();
|
|
return loader->loadIcon(name, KIconLoader::Desktop, force_size, state, overlays);
|
|
}
|
|
|
|
QPixmap BarIcon(const QString& name, int force_size, int state, const QStringList &overlays)
|
|
{
|
|
KIconLoader *loader = KIconLoader::global();
|
|
return loader->loadIcon(name, KIconLoader::Toolbar, force_size, state, overlays);
|
|
}
|
|
|
|
QPixmap SmallIcon(const QString& name, int force_size, int state, const QStringList &overlays)
|
|
{
|
|
KIconLoader *loader = KIconLoader::global();
|
|
return loader->loadIcon(name, KIconLoader::Small, force_size, state, overlays);
|
|
}
|
|
|
|
QPixmap MainBarIcon(const QString& name, int force_size, int state, const QStringList &overlays)
|
|
{
|
|
KIconLoader *loader = KIconLoader::global();
|
|
return loader->loadIcon(name, KIconLoader::MainToolbar, force_size, state, overlays);
|
|
}
|
|
|
|
QPixmap UserIcon(const QString& name, int state, const QStringList &overlays)
|
|
{
|
|
KIconLoader *loader = KIconLoader::global();
|
|
return loader->loadIcon(name, KIconLoader::User, 0, state, overlays);
|
|
}
|
|
|
|
int IconSize(KIconLoader::Group group)
|
|
{
|
|
KIconLoader *loader = KIconLoader::global();
|
|
return loader->currentSize(group);
|
|
}
|
|
|
|
QPixmap KIconLoader::unknown()
|
|
{
|
|
QPixmap pix;
|
|
if (QPixmapCache::find("unknown", pix)) {
|
|
return pix;
|
|
}
|
|
|
|
QString path = global()->iconPath("unknown", KIconLoader::Small, true);
|
|
if (path.isEmpty()) {
|
|
kDebug(264) << "Warning: Cannot find \"unknown\" icon.";
|
|
pix = QPixmap(32,32);
|
|
} else {
|
|
pix.load(path);
|
|
QPixmapCache::insert("unknown", pix);
|
|
}
|
|
|
|
return pix;
|
|
}
|
|
|
|
/*** the global icon loader ***/
|
|
K_GLOBAL_STATIC_WITH_ARGS(KIconLoader, globalIconLoader, (KGlobal::mainComponent(), 0))
|
|
|
|
KIconLoader *KIconLoader::global()
|
|
{
|
|
return globalIconLoader;
|
|
}
|
|
|
|
void KIconLoader::newIconLoader()
|
|
{
|
|
if ( global() == this) {
|
|
KIconTheme::reconfigure();
|
|
}
|
|
|
|
reconfigure( objectName(), d->mpDirs );
|
|
emit iconLoaderSettingsChanged();
|
|
}
|
|
|
|
#include "moc_kiconloader.cpp"
|
|
|