22#include <QApplication>
25#include <QMutableListIterator>
27#include <QStringBuilder>
31#include "private/effectwatcher_p.h"
34#include <kcolorscheme.h>
35#include <kcomponentdata.h>
36#include <kconfiggroup.h>
40#include <kglobalsettings.h>
41#include <kmanagerselection.h>
42#include <kimagecache.h>
43#include <ksharedconfig.h>
44#include <kstandarddirs.h>
45#include <kwindowsystem.h>
48#include "animations/animationscriptengine_p.h"
49#include "libplasma-theme-global.h"
50#include "private/packages_p.h"
57#define DEFAULT_WALLPAPER_THEME "default"
58#define DEFAULT_WALLPAPER_SUFFIX ".png"
72Q_DECLARE_FLAGS(CacheTypes, CacheType)
73Q_DECLARE_OPERATORS_FOR_FLAGS(CacheTypes)
78 ThemePrivate(Theme *theme)
80 colorScheme(QPalette::Active, KColorScheme::Window, KSharedConfigPtr(0)),
81 buttonColorScheme(QPalette::Active, KColorScheme::Button, KSharedConfigPtr(0)),
82 viewColorScheme(QPalette::Active, KColorScheme::View, KSharedConfigPtr(0)),
90 compositingActive(KWindowSystem::self()->compositingActive()),
95 useNativeWidgetStyle(
false)
97 generalFont = QApplication::font();
99 cacheTheme = config.cacheTheme();
101 saveTimer =
new QTimer(q);
102 saveTimer->setSingleShot(
true);
103 saveTimer->setInterval(600);
104 QObject::connect(saveTimer, SIGNAL(timeout()), q, SLOT(scheduledCacheUpdate()));
106 updateNotificationTimer =
new QTimer(q);
107 updateNotificationTimer->setSingleShot(
true);
108 updateNotificationTimer->setInterval(500);
109 QObject::connect(updateNotificationTimer, SIGNAL(timeout()), q, SLOT(notifyOfChanged()));
111 if (QPixmap::defaultDepth() > 8) {
112 QObject::connect(KWindowSystem::self(), SIGNAL(compositingChanged(
bool)), q, SLOT(compositingChanged(
bool)));
115 if (!s_blurEffectWatcher) {
116 s_blurEffectWatcher =
new EffectWatcher(
"_KDE_NET_WM_BLUR_BEHIND_REGION");
119 QObject::connect(s_blurEffectWatcher, SIGNAL(effectChanged(
bool)), q, SLOT(blurBehindChanged(
bool)));
129 KConfigGroup &config()
131 if (!cfg.isValid()) {
132 QString groupName =
"Theme";
135 QString app = KGlobal::mainComponent().componentName();
137 if (!app.isEmpty()) {
138 kDebug() <<
"using theme for app" << app;
139 groupName.append(
"-").append(app);
143 cfg = KConfigGroup(KSharedConfig::openConfig(themeRcFile), groupName);
149 QString findInTheme(
const QString &image,
const QString &theme,
bool cache =
true);
150 void compositingChanged(
bool active);
151 void discardCache(CacheTypes caches);
152 void scheduledCacheUpdate();
153 void scheduleThemeChangeNotification(CacheTypes caches);
154 void notifyOfChanged();
155 void colorsChanged();
156 void blurBehindChanged(
bool blur);
158 void settingsFileChanged(
const QString &);
159 void setThemeName(
const QString &themeName,
bool writeSettings);
160 void onAppExitCleanup();
161 void processWallpaperSettings(KConfigBase *metadata);
162 void processAnimationSettings(
const QString &theme, KConfigBase *metadata);
164 const QString processStyleSheet(
const QString &css);
166 static const char *defaultTheme;
167 static const char *systemColorsTheme;
168 static const char *themeRcFile;
171 static EffectWatcher *s_blurEffectWatcher;
176 QList<QString> fallbackThemes;
177 KSharedConfigPtr colors;
178 KColorScheme colorScheme;
179 KColorScheme buttonColorScheme;
180 KColorScheme viewColorScheme;
183 QString defaultWallpaperTheme;
184 QString defaultWallpaperSuffix;
185 int defaultWallpaperWidth;
186 int defaultWallpaperHeight;
187 KImageCache *pixmapCache;
188 KSharedConfigPtr svgElementsCache;
189 QHash<QString, QSet<QString> > invalidElements;
190 QHash<QString, QPixmap> pixmapsToCache;
191 QHash<QString, QString> keysToCache;
192 QHash<QString, QString> idsToCache;
193 QHash<QString, QString> animationMapping;
194 QHash<styles, QString> cachedStyleSheets;
195 QHash<QString, QString> discoveries;
197 QTimer *updateNotificationTimer;
199 CacheTypes cachesToDiscard;
200 QString themeVersion;
201 QString themeMetadataPath;
204 bool compositingActive : 1;
208 bool hasWallpapers : 1;
210 bool useNativeWidgetStyle :1;
213PackageStructure::Ptr ThemePrivate::packageStructure(0);
214const char *ThemePrivate::defaultTheme =
"default";
216const char *ThemePrivate::themeRcFile =
"plasmarc";
219const char *ThemePrivate::systemColorsTheme =
"internal-system-colors";
221EffectWatcher *ThemePrivate::s_blurEffectWatcher = 0;
224bool ThemePrivate::useCache()
226 bool cachesTooOld =
false;
228 if (cacheTheme && !pixmapCache) {
229 const bool isRegularTheme = themeName != systemColorsTheme;
230 QString cacheFile =
"plasma_theme_" + themeName;
233 themeVersion.clear();
235 if (!themeMetadataPath.isEmpty()) {
236 KDirWatch::self()->removeFile(themeMetadataPath);
238 themeMetadataPath = KStandardDirs::locate(
"data",
"desktoptheme/" + themeName +
"/metadata.desktop");
240 if (isRegularTheme) {
241 const QString cacheFileBase = cacheFile +
"*.kcache";
246 QString currentCacheFileName;
247 if (!themeMetadataPath.isEmpty()) {
249 const KPluginInfo pluginInfo(themeMetadataPath);
250 themeVersion = pluginInfo.version();
251 if (!themeVersion.isEmpty()) {
252 cacheFile +=
"_v" + themeVersion;
253 currentCacheFileName = cacheFile +
".kcache";
257 KDirWatch::self()->addFile(themeMetadataPath);
258 QObject::connect(KDirWatch::self(), SIGNAL(created(QString)),
259 q, SLOT(settingsFileChanged(QString)),
260 Qt::UniqueConnection);
261 QObject::connect(KDirWatch::self(), SIGNAL(dirty(QString)),
262 q, SLOT(settingsFileChanged(QString)),
263 Qt::UniqueConnection);
267 foreach (
const QString &file, KGlobal::dirs()->findAllResources(
"cache", cacheFileBase)) {
268 if (currentCacheFileName.isEmpty() ||
269 !file.endsWith(currentCacheFileName)) {
277 if (isRegularTheme && !themeMetadataPath.isEmpty()) {
286 const QString cacheFilePath = KStandardDirs::locateLocal(
"cache", cacheFile);
287 if (!cacheFilePath.isEmpty()) {
288 const QFileInfo cacheFileInfo(cacheFilePath);
289 const QFileInfo metadataFileInfo(themeMetadataPath);
290 cachesTooOld = cacheFileInfo.lastModified().toTime_t() > metadataFileInfo.lastModified().toTime_t();
295 pixmapCache =
new KImageCache(cacheFile, config.themeCacheKb() * 1024);
298 discardCache(PixmapCache | SvgElementsCache);
302 if (cacheTheme && !svgElementsCache) {
303 const QString svgElementsFileNameBase =
"plasma-svgelements-" + themeName;
304 QString svgElementsFileName = svgElementsFileNameBase;
305 if (!themeVersion.isEmpty()) {
306 svgElementsFileName +=
"_v" + themeVersion;
310 foreach (
const QString &file, KGlobal::dirs()->findAllResources(
"cache", svgElementsFileNameBase +
"*")) {
311 if (cachesTooOld || !file.endsWith(svgElementsFileName)) {
316 const QString svgElementsFile = KStandardDirs::locateLocal(
"cache", svgElementsFileName);
317 svgElementsCache = KSharedConfig::openConfig(svgElementsFile);
323void ThemePrivate::onAppExitCleanup()
325 pixmapsToCache.clear();
331QString ThemePrivate::findInTheme(
const QString &image,
const QString &theme,
bool cache)
333 if (cache && discoveries.contains(image)) {
334 return discoveries[image];
340 search = QLatin1Literal(
"desktoptheme/") % theme % QLatin1Literal(
"/locolor/") % image;
341 search = KStandardDirs::locate(
"data", search);
342 }
else if (!compositingActive) {
343 search = QLatin1Literal(
"desktoptheme/") % theme % QLatin1Literal(
"/opaque/") % image;
344 search = KStandardDirs::locate(
"data", search);
345 }
else if (WindowEffects::isEffectAvailable(WindowEffects::BlurBehind)) {
346 search = QLatin1Literal(
"desktoptheme/") % theme % QLatin1Literal(
"/translucent/") % image;
347 search = KStandardDirs::locate(
"data", search);
351 if (search.isEmpty()) {
352 search = QLatin1Literal(
"desktoptheme/") % theme % QLatin1Char(
'/') % image;
353 search = KStandardDirs::locate(
"data", search);
356 if (cache && !search.isEmpty()) {
357 discoveries.insert(image, search);
363void ThemePrivate::compositingChanged(
bool active)
366 if (compositingActive != active) {
367 compositingActive = active;
369 scheduleThemeChangeNotification(PixmapCache | SvgElementsCache);
374void ThemePrivate::discardCache(CacheTypes caches)
376 if (caches & PixmapCache) {
377 pixmapsToCache.clear();
380 pixmapCache->clear();
388 cachedStyleSheets.clear();
390 if (caches & SvgElementsCache) {
392 invalidElements.clear();
393 svgElementsCache = 0;
397void ThemePrivate::scheduledCacheUpdate()
400 QHashIterator<QString, QPixmap> it(pixmapsToCache);
401 while (it.hasNext()) {
403 pixmapCache->insertPixmap(idsToCache[it.key()], it.value());
407 pixmapsToCache.clear();
412void ThemePrivate::colorsChanged()
414 colorScheme = KColorScheme(QPalette::Active, KColorScheme::Window, colors);
415 buttonColorScheme = KColorScheme(QPalette::Active, KColorScheme::Button, colors);
416 viewColorScheme = KColorScheme(QPalette::Active, KColorScheme::View, colors);
417 scheduleThemeChangeNotification(PixmapCache);
420void ThemePrivate::blurBehindChanged(
bool blur)
422 if (blurActive != blur) {
424 scheduleThemeChangeNotification(PixmapCache | SvgElementsCache);
428void ThemePrivate::scheduleThemeChangeNotification(CacheTypes caches)
430 cachesToDiscard |= caches;
431 updateNotificationTimer->start();
434void ThemePrivate::notifyOfChanged()
437 discardCache(cachesToDiscard);
439 emit q->themeChanged();
442const QString ThemePrivate::processStyleSheet(
const QString &css)
446 stylesheet = cachedStyleSheets.value(DEFAULTSTYLE);
447 if (stylesheet.isEmpty()) {
448 stylesheet = QString(
"\n\
450 color: %textcolor;\n\
451 font-size: %fontsize;\n\
452 font-family: %fontfamily;\n\
454 a:active { color: %activatedlink; }\n\
455 a:link { color: %link; }\n\
456 a:visited { color: %visitedlink; }\n\
457 a:hover { color: %hoveredlink; text-decoration: none; }\n\
459 stylesheet = processStyleSheet(stylesheet);
460 cachedStyleSheets.insert(DEFAULTSTYLE, stylesheet);
464 }
else if (css ==
"SVG") {
465 stylesheet = cachedStyleSheets.value(SVGSTYLE);
466 if (stylesheet.isEmpty()) {
467 QString skel =
".ColorScheme-%1{color:%2;}";
469 stylesheet += skel.arg(
"Text",
"%textcolor");
470 stylesheet += skel.arg(
"Background",
"%backgroundcolor");
472 stylesheet += skel.arg(
"ButtonText",
"%buttontextcolor");
473 stylesheet += skel.arg(
"ButtonBackground",
"%buttonbackgroundcolor");
474 stylesheet += skel.arg(
"ButtonHover",
"%buttonhovercolor");
475 stylesheet += skel.arg(
"ButtonFocus",
"%buttonfocuscolor");
477 stylesheet += skel.arg(
"ViewText",
"%viewtextcolor");
478 stylesheet += skel.arg(
"ViewBackground",
"%viewbackgroundcolor");
479 stylesheet += skel.arg(
"ViewHover",
"%viewhovercolor");
480 stylesheet += skel.arg(
"ViewFocus",
"%viewfocuscolor");
482 stylesheet = processStyleSheet(stylesheet);
483 cachedStyleSheets.insert(SVGSTYLE, stylesheet);
491 QHash<QString, QString> elements;
494 elements[
"%textcolor"] = q->color(Theme::TextColor).name();
495 elements[
"%backgroundcolor"] = q->color(Theme::BackgroundColor).name();
496 elements[
"%visitedlink"] = q->color(Theme::VisitedLinkColor).name();
497 elements[
"%activatedlink"] = q->color(Theme::HighlightColor).name();
498 elements[
"%hoveredlink"] = q->color(Theme::HighlightColor).name();
499 elements[
"%link"] = q->color(Theme::LinkColor).name();
500 elements[
"%buttontextcolor"] = q->color(Theme::ButtonTextColor).name();
501 elements[
"%buttonbackgroundcolor"] = q->color(Theme::ButtonBackgroundColor).name();
502 elements[
"%buttonhovercolor"] = q->color(Theme::ButtonHoverColor).name();
503 elements[
"%buttonfocuscolor"] = q->color(Theme::ButtonFocusColor).name();
504 elements[
"%viewtextcolor"] = q->color(Theme::ViewTextColor).name();
505 elements[
"%viewbackgroundcolor"] = q->color(Theme::ViewBackgroundColor).name();
506 elements[
"%viewhovercolor"] = q->color(Theme::ViewHoverColor).name();
507 elements[
"%viewfocuscolor"] = q->color(Theme::ViewFocusColor).name();
509 QFont font = q->font(Theme::DefaultFont);
510 elements[
"%fontsize"] = QString(
"%1pt").arg(font.pointSize());
511 elements[
"%fontfamily"] = font.family().split(
'[').first();
512 elements[
"%smallfontsize"] = QString(
"%1pt").arg(KGlobalSettings::smallestReadableFont().pointSize());
514 QHash<QString, QString>::const_iterator it = elements.constBegin();
515 QHash<QString, QString>::const_iterator itEnd = elements.constEnd();
516 for ( ; it != itEnd; ++it) {
517 stylesheet.replace(it.key(), it.value());
527 self.d->isDefault =
true;
530 KDirWatch::self()->addFile(KStandardDirs::locateLocal(
"config", ThemePrivate::themeRcFile));
531 QObject::connect(KDirWatch::self(), SIGNAL(created(QString)),
532 &self, SLOT(settingsFileChanged(QString)),
533 Qt::UniqueConnection);
534 QObject::connect(KDirWatch::self(), SIGNAL(dirty(QString)),
535 &self, SLOT(settingsFileChanged(QString)),
536 Qt::UniqueConnection);
542K_GLOBAL_STATIC(ThemeSingleton, privateThemeSelf)
546 return &privateThemeSelf->self;
551 d(new ThemePrivate(this))
554 if (QCoreApplication::instance()) {
555 connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()),
556 this, SLOT(onAppExitCleanup()));
560Theme::Theme(
const QString &themeName,
QObject *parent)
562 d(new ThemePrivate(this))
565 bool useCache = d->cacheTheme;
566 d->cacheTheme =
false;
568 d->cacheTheme = useCache;
569 if (QCoreApplication::instance()) {
570 connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()),
571 this, SLOT(onAppExitCleanup()));
577 if (d->svgElementsCache) {
578 QHashIterator<QString, QSet<QString> > it(d->invalidElements);
579 while (it.hasNext()) {
581 KConfigGroup imageGroup(d->svgElementsCache, it.key());
582 imageGroup.writeEntry(
"invalidElements", it.value().toList());
586 d->onAppExitCleanup();
592 if (!ThemePrivate::packageStructure) {
593 ThemePrivate::packageStructure =
new ThemePackage();
596 return ThemePrivate::packageStructure;
599KPluginInfo::List Theme::listThemeInfo()
601 const QStringList themes = KGlobal::dirs()->findAllResources(
"data",
"desktoptheme/*/metadata.desktop",
602 KStandardDirs::NoDuplicates);
603 return KPluginInfo::fromFiles(themes);
606void ThemePrivate::settingsFileChanged(
const QString &file)
608 if (file == themeMetadataPath) {
609 const KPluginInfo pluginInfo(themeMetadataPath);
610 if (themeVersion != pluginInfo.version()) {
611 scheduleThemeChangeNotification(SvgElementsCache);
613 }
else if (file.endsWith(themeRcFile)) {
614 config().config()->reparseConfiguration();
615 q->settingsChanged();
619void Theme::settingsChanged()
621 KConfigGroup cg = d->config();
622 d->setThemeName(cg.readEntry(
"name", ThemePrivate::defaultTheme),
false);
623 cg = KConfigGroup(cg.config(),
"PlasmaToolTips");
624 d->toolTipDelay = cg.readEntry(
"Delay", 700);
627void Theme::setThemeName(
const QString &themeName)
632void ThemePrivate::processWallpaperSettings(KConfigBase *metadata)
639 if (metadata->hasGroup(
"Wallpaper")) {
642 cg = KConfigGroup(metadata,
"Wallpaper");
651 defaultWallpaperWidth = cg.readEntry(
"defaultWidth", DEFAULT_WALLPAPER_WIDTH);
652 defaultWallpaperHeight = cg.readEntry(
"defaultHeight", DEFAULT_WALLPAPER_HEIGHT);
655void ThemePrivate::processAnimationSettings(
const QString &theme, KConfigBase *metadata)
657 KConfigGroup cg(metadata,
"Animations");
658 const QString animDir = QLatin1Literal(
"desktoptheme/") % theme % QLatin1Literal(
"/animations/");
659 foreach (
const QString &path, cg.keyList()) {
660 const QStringList anims = cg.readEntry(path, QStringList());
661 foreach (
const QString &anim, anims) {
662 if (!animationMapping.contains(anim)) {
663 kDebug() <<
"Registering animation. animDir: " << animDir
664 <<
"\tanim: " << anim
665 <<
"\tpath: " << path <<
"\t*******\n\n\n";
668 animationMapping.insert(anim, animDir % path);
670 kDebug() <<
"************Animation already registered!\n\n\n";
677void ThemePrivate::setThemeName(
const QString &tempThemeName,
bool writeSettings)
680 QString theme = tempThemeName;
681 if (theme.isEmpty() || theme == themeName) {
683 if (themeName.isEmpty()) {
684 theme = ThemePrivate::defaultTheme;
692 bool realTheme = theme != systemColorsTheme;
694 QString themePath = KStandardDirs::locate(
"data", QLatin1Literal(
"desktoptheme/") % theme % QLatin1Char(
'/'));
695 if (themePath.isEmpty() && themeName.isEmpty()) {
696 themePath = KStandardDirs::locate(
"data",
"desktoptheme/default/");
698 if (themePath.isEmpty()) {
702 theme = ThemePrivate::defaultTheme;
707 if (themeName == theme) {
714 const QString colorsFile = realTheme ? KStandardDirs::locate(
"data", QLatin1Literal(
"desktoptheme/") % theme % QLatin1Literal(
"/colors"))
721 const QString metadataPath(KStandardDirs::locate(
"data", QLatin1Literal(
"desktoptheme/") % theme % QLatin1Literal(
"/metadata.desktop")));
722 KConfig metadata(metadataPath);
724 processWallpaperSettings(&metadata);
726 AnimationScriptEngine::clearAnimations();
727 animationMapping.clear();
728 processAnimationSettings(themeName, &metadata);
730 KConfigGroup cg(&metadata,
"Settings");
731 useNativeWidgetStyle = cg.readEntry(
"UseNativeWidgetStyle",
false);
732 QString fallback = cg.readEntry(
"FallbackTheme", QString());
734 fallbackThemes.clear();
735 while (!fallback.isEmpty() && !fallbackThemes.contains(fallback)) {
736 fallbackThemes.append(fallback);
738 QString metadataPath(KStandardDirs::locate(
"data", QLatin1Literal(
"desktoptheme/") % theme % QLatin1Literal(
"/metadata.desktop")));
739 KConfig metadata(metadataPath);
740 KConfigGroup cg(&metadata,
"Settings");
741 fallback = cg.readEntry(
"FallbackTheme", QString());
744 if (!fallbackThemes.contains(
"oxygen")) {
745 fallbackThemes.append(
"oxygen");
748 if (!fallbackThemes.contains(ThemePrivate::defaultTheme)) {
749 fallbackThemes.append(ThemePrivate::defaultTheme);
752 foreach (
const QString &theme, fallbackThemes) {
753 QString metadataPath(KStandardDirs::locate(
"data", QLatin1Literal(
"desktoptheme/") % theme % QLatin1Literal(
"/metadata.desktop")));
754 KConfig metadata(metadataPath);
755 processAnimationSettings(theme, &metadata);
756 processWallpaperSettings(&metadata);
760 if (colorsFile.isEmpty()) {
762 QObject::connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()),
763 q, SLOT(colorsChanged()), Qt::UniqueConnection);
765 QObject::disconnect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()),
766 q, SLOT(colorsChanged()));
767 colors = KSharedConfig::openConfig(colorsFile);
770 colorScheme = KColorScheme(QPalette::Active, KColorScheme::Window, colors);
771 buttonColorScheme = KColorScheme(QPalette::Active, KColorScheme::Button, colors);
772 viewColorScheme = KColorScheme(QPalette::Active, KColorScheme::View, colors);
773 hasWallpapers = KStandardDirs::exists(KStandardDirs::locateLocal(
"data", QLatin1Literal(
"desktoptheme/") % theme % QLatin1Literal(
"/wallpapers/")));
775 if (realTheme && isDefault && writeSettings) {
777 KConfigGroup &cg = config();
778 if (ThemePrivate::defaultTheme == themeName) {
779 cg.deleteEntry(
"name");
781 cg.writeEntry(
"name", themeName);
786 scheduleThemeChangeNotification(SvgElementsCache);
789QString Theme::themeName()
const
794QString Theme::imagePath(
const QString &name)
const
797 if (name.contains(
"../") || name.isEmpty()) {
803 const QString svgzName = name % QLatin1Literal(
".svgz");
804 QString path = d->findInTheme(svgzName, d->themeName);
806 if (path.isEmpty()) {
808 const QString svgName = name % QLatin1Literal(
".svg");
809 path = d->findInTheme(svgName, d->themeName);
812 for (
int i = 0; path.isEmpty() && i < d->fallbackThemes.count(); ++i) {
813 if (d->themeName == d->fallbackThemes[i]) {
818 path = d->findInTheme(svgzName, d->fallbackThemes[i]);
820 if (path.isEmpty()) {
822 path = d->findInTheme(svgName, d->fallbackThemes[i]);
836QString Theme::styleSheet(
const QString &css)
const
838 return d->processStyleSheet(css);
841QString Theme::animationPath(
const QString &name)
const
843 const QString path = d->animationMapping.value(name);
844 if (path.isEmpty()) {
849 return KStandardDirs::locate(
"data", path);
852QString Theme::wallpaperPath(
const QSize &size)
const
855 QString image = d->defaultWallpaperTheme;
857 image.append(
"/contents/images/%1x%2").append(d->defaultWallpaperSuffix);
858 QString defaultImage = image.arg(d->defaultWallpaperWidth).arg(d->defaultWallpaperHeight);
860 if (size.isValid()) {
865 image = image.arg(size.width()).arg(size.height());
867 image = defaultImage;
873 if (d->hasWallpapers) {
875 fullPath = d->findInTheme(QLatin1Literal(
"wallpapers/") % image, d->themeName);
877 if (fullPath.isEmpty()) {
878 fullPath = d->findInTheme(QLatin1Literal(
"wallpapers/") % defaultImage, d->themeName);
882 if (fullPath.isEmpty()) {
885 fullPath = KStandardDirs::locate(
"wallpaper", image);
888 if (fullPath.isEmpty()) {
892 fullPath = KStandardDirs::locate(
"wallpaper", defaultImage);
894 if (fullPath.isEmpty()) {
895 kDebug() <<
"exhausted every effort to find a wallpaper.";
902bool Theme::currentThemeHasImage(
const QString &name)
const
904 if (name.contains(
"../")) {
909 return !(d->findInTheme(name % QLatin1Literal(
".svgz"), d->themeName,
false).isEmpty()) ||
910 !(d->findInTheme(name % QLatin1Literal(
".svg"), d->themeName,
false).isEmpty());
913KSharedConfigPtr Theme::colorScheme()
const
922 return d->colorScheme.foreground(KColorScheme::NormalText).color();
925 return d->colorScheme.decoration(KColorScheme::HoverColor).color();
928 return d->colorScheme.background(KColorScheme::NormalBackground).color();
931 return d->buttonColorScheme.foreground(KColorScheme::NormalText).color();
934 return d->buttonColorScheme.background(KColorScheme::NormalBackground).color();
937 return d->buttonColorScheme.decoration(KColorScheme::HoverColor).color();
940 return d->buttonColorScheme.decoration(KColorScheme::FocusColor).color();
943 return d->viewColorScheme.foreground(KColorScheme::NormalText).color();
946 return d->viewColorScheme.background(KColorScheme::NormalBackground).color();
949 return d->viewColorScheme.decoration(KColorScheme::HoverColor).color();
952 return d->viewColorScheme.decoration(KColorScheme::FocusColor).color();
955 return d->viewColorScheme.foreground(KColorScheme::LinkText).color();
958 return d->viewColorScheme.foreground(KColorScheme::VisitedText).color();
964void Theme::setFont(
const QFont &font,
FontRole role)
967 d->generalFont =
font;
974 KConfigGroup cg(KGlobal::config(),
"General");
975 return cg.readEntry(
"desktopFont", d->generalFont);
981 return d->generalFont;
985 return KGlobalSettings::smallestReadableFont();
989 return d->generalFont;
992QFontMetrics Theme::fontMetrics()
const
995 return QFontMetrics(d->generalFont);
998bool Theme::windowTranslucencyEnabled()
const
1000 return d->compositingActive;
1003void Theme::setUseGlobalSettings(
bool useGlobal)
1005 if (d->useGlobal == useGlobal) {
1009 d->useGlobal = useGlobal;
1010 d->cfg = KConfigGroup();
1011 d->themeName.clear();
1015bool Theme::useGlobalSettings()
const
1017 return d->useGlobal;
1020bool Theme::useNativeWidgetStyle()
const
1022 return d->useNativeWidgetStyle;
1025bool Theme::findInCache(
const QString &key, QPixmap &pix)
1027 if (d->useCache()) {
1028 const QString
id = d->keysToCache.value(key);
1029 if (d->pixmapsToCache.contains(
id)) {
1030 pix = d->pixmapsToCache.value(
id);
1031 return !pix.isNull();
1035 if (d->pixmapCache->findPixmap(key, &temp) && !temp.isNull()) {
1045bool Theme::findInCache(
const QString &key, QPixmap &pix,
unsigned int lastModified)
1047 if (d->useCache() && lastModified > uint(d->pixmapCache->lastModifiedTime())) {
1054void Theme::insertIntoCache(
const QString& key,
const QPixmap& pix)
1056 if (d->useCache()) {
1057 d->pixmapCache->insertPixmap(key, pix);
1061void Theme::insertIntoCache(
const QString& key,
const QPixmap& pix,
const QString&
id)
1063 if (d->useCache()) {
1064 d->pixmapsToCache.insert(
id, pix);
1066 if (d->idsToCache.contains(
id)) {
1067 d->keysToCache.remove(d->idsToCache[
id]);
1070 d->keysToCache.insert(key,
id);
1071 d->idsToCache.insert(
id, key);
1072 d->saveTimer->start();
1076bool Theme::findInRectsCache(
const QString &image,
const QString &element, QRectF &rect)
const
1078 if (!d->useCache()) {
1082 KConfigGroup imageGroup(d->svgElementsCache, image);
1083 rect = imageGroup.readEntry(element % QLatin1Literal(
"Size"), QRectF());
1085 if (rect.isValid()) {
1091 if (element.indexOf(
'_') <= 0) {
1095 bool invalid =
false;
1097 QHash<QString, QSet<QString> >::iterator it = d->invalidElements.find(image);
1098 if (it == d->invalidElements.end()) {
1099 QSet<QString> elements = imageGroup.readEntry(
"invalidElements", QStringList()).toSet();
1100 d->invalidElements.insert(image, elements);
1101 invalid = elements.contains(element);
1103 invalid = it.value().contains(element);
1109QStringList Theme::listCachedRectKeys(
const QString &image)
const
1111 if (!d->useCache()) {
1112 return QStringList();
1115 KConfigGroup imageGroup(d->svgElementsCache, image);
1116 QStringList keys = imageGroup.keyList();
1118 QMutableListIterator<QString> i(keys);
1119 while (i.hasNext()) {
1120 QString key = i.next();
1121 if (key.endsWith(
"Size")) {
1123 key.resize(key.size() - 4);
1132void Theme::insertIntoRectsCache(
const QString& image,
const QString &element,
const QRectF &rect)
1134 if (!d->useCache()) {
1138 if (rect.isValid()) {
1139 KConfigGroup imageGroup(d->svgElementsCache, image);
1140 imageGroup.writeEntry(element % QLatin1Literal(
"Size"), rect);
1142 QHash<QString, QSet<QString> >::iterator it = d->invalidElements.find(image);
1143 if (it == d->invalidElements.end()) {
1144 d->invalidElements[image].insert(element);
1145 }
else if (!it.value().contains(element)) {
1146 if (it.value().count() > 1000) {
1147 it.value().erase(it.value().begin());
1150 it.value().insert(element);
1155void Theme::invalidateRectsCache(
const QString& image)
1157 if (d->useCache()) {
1158 KConfigGroup imageGroup(d->svgElementsCache, image);
1159 imageGroup.deleteGroup();
1162 d->invalidElements.remove(image);
1165void Theme::releaseRectsCache(
const QString &image)
1167 QHash<QString, QSet<QString> >::iterator it = d->invalidElements.find(image);
1168 if (it != d->invalidElements.end()) {
1169 if (d->useCache()) {
1170 KConfigGroup imageGroup(d->svgElementsCache, it.key());
1171 imageGroup.writeEntry(
"invalidElements", it.value().toList());
1174 d->invalidElements.erase(it);
1178void Theme::setCacheLimit(
int kbytes)
1181 if (d->useCache()) {
1188KUrl Theme::homepage()
const
1190 const QString metadataPath(KStandardDirs::locate(
"data", QLatin1Literal(
"desktoptheme/") % d->themeName % QLatin1Literal(
"/metadata.desktop")));
1191 KConfig metadata(metadataPath);
1192 KConfigGroup brandConfig(&metadata,
"Branding");
1193 return brandConfig.readEntry(
"homepage", KUrl(
"http://www.kde.org"));
1196int Theme::toolTipDelay()
const
1198 return d->toolTipDelay;
KSharedPtr< PackageStructure > Ptr
Interface to the Plasma theme.
void setThemeName(const QString &themeName)
Sets the current theme being used.
void settingsChanged()
Notifies the Theme object that the theme settings have changed and should be read from the config fil...
bool findInCache(const QString &key, QPixmap &pix)
Tries to load pixmap with the specified key from cache.
Q_INVOKABLE QFont font(FontRole role) const
Returns the font to be used by themed items.
@ DefaultFont
The standard text font.
@ DesktopFont
The standard text font.
@ SmallestFont
The smallest readable font.
@ ViewBackgroundColor
text color for views
@ ButtonHoverColor
color visited clickable links
@ ButtonFocusColor
color for hover effect on buttons
@ VisitedLinkColor
color for clickable links
@ HighlightColor
the text higlight color to be used by items resting on the background
@ LinkColor
background color for buttons
@ ButtonBackgroundColor
text color for buttons
@ ViewHoverColor
background color for views
@ BackgroundColor
the default background color
@ ViewFocusColor
color for hover effect on view
@ TextColor
the text color to be used by items resting on the background
@ ViewTextColor
color for focus effect on buttons
Namespace for everything in libplasma.
PackageStructure::Ptr packageStructure(const QString &language, ComponentType type)
Loads an appropriate PackageStructure for the given language and type.
static const int DEFAULT_WALLPAPER_WIDTH
static const int DEFAULT_WALLPAPER_HEIGHT
#define DEFAULT_WALLPAPER_THEME
#define DEFAULT_WALLPAPER_SUFFIX