Libplasma

theme.cpp
1/*
2 SPDX-FileCopyrightText: 2006-2007 Aaron Seigo <aseigo@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "theme.h"
8#include "private/theme_p.h"
9
10#include <QFile>
11#include <QFileInfo>
12#include <QFontDatabase>
13#include <QFontMetrics>
14#include <QMutableListIterator>
15#include <QPair>
16#include <QStringBuilder>
17#include <QThread>
18#include <QTimer>
19
20#include "config-plasma.h"
21
22#include <KColorScheme>
23#include <KConfigGroup>
24#include <KDirWatch>
25#include <KImageCache>
26#include <KWindowEffects>
27#include <QDebug>
28#include <QStandardPaths>
29
30#include "debug_p.h"
31
32namespace Plasma
33{
35 : QObject(parent)
36{
37 if (!ThemePrivate::globalTheme) {
38 ThemePrivate::globalTheme = new ThemePrivate;
39 ThemePrivate::globalTheme->settingsChanged(false);
41 connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, ThemePrivate::globalTheme, &ThemePrivate::onAppExitCleanup);
42 }
43 }
44 ThemePrivate::globalTheme->ref.ref();
45 d = ThemePrivate::globalTheme;
46
47 connect(d, &ThemePrivate::themeChanged, this, &Theme::themeChanged);
48 connect(d, &ThemePrivate::defaultFontChanged, this, &Theme::defaultFontChanged);
49 connect(d, &ThemePrivate::smallestFontChanged, this, &Theme::smallestFontChanged);
50}
51
52Theme::Theme(const QString &themeName, QObject *parent)
53 : QObject(parent)
54{
55 auto &priv = ThemePrivate::themes[themeName];
56 if (!priv) {
57 priv = new ThemePrivate;
59 connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, priv, &ThemePrivate::onAppExitCleanup);
60 }
61 }
62
63 priv->ref.ref();
64 d = priv;
65
66 // turn off caching so we don't accidentally trigger unnecessary disk activity at this point
67 bool useCache = d->cacheTheme;
68 d->cacheTheme = false;
69 d->setThemeName(themeName, false, false);
70 d->cacheTheme = useCache;
71 d->fixedName = true;
72 connect(d, &ThemePrivate::themeChanged, this, &Theme::themeChanged);
73}
74
75Theme::~Theme()
76{
77 if (d == ThemePrivate::globalTheme) {
78 if (!d->ref.deref()) {
79 disconnect(ThemePrivate::globalTheme, nullptr, this, nullptr);
80 delete ThemePrivate::globalTheme;
81 ThemePrivate::globalTheme = nullptr;
82 d = nullptr;
83 }
84 } else {
85 if (!d->ref.deref()) {
86 delete ThemePrivate::themes.take(d->themeName);
87 }
88 }
89}
90
91void Theme::setThemeName(const QString &themeName)
92{
93 if (d->themeName == themeName) {
94 return;
95 }
96
97 if (d != ThemePrivate::globalTheme) {
98 disconnect(QCoreApplication::instance(), nullptr, d, nullptr);
99 if (!d->ref.deref()) {
100 delete ThemePrivate::themes.take(d->themeName);
101 }
102
103 auto &priv = ThemePrivate::themes[themeName];
104 if (!priv) {
105 priv = new ThemePrivate;
107 connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, priv, &ThemePrivate::onAppExitCleanup);
108 }
109 }
110 priv->ref.ref();
111 d = priv;
112 connect(d, &ThemePrivate::themeChanged, this, &Theme::themeChanged);
113 }
114
115 d->setThemeName(themeName, true, true);
116}
117
118QString Theme::themeName() const
119{
120 return d->themeName;
121}
122
124{
125 // look for a compressed svg file in the theme
126 if (name.contains(QLatin1String("../")) || name.isEmpty()) {
127 // we don't support relative paths
128 // qCDebug(LOG_PLASMA) << "Theme says: bad image path " << name;
129 return QString();
130 }
131
132 const QString svgzName = name % QLatin1String(".svgz");
133 QString path = d->findInTheme(svgzName, d->themeName);
134
135 if (path.isEmpty()) {
136 // try for an uncompressed svg file
137 const QString svgName = name % QLatin1String(".svg");
138 path = d->findInTheme(svgName, d->themeName);
139
140 // search in fallback themes if necessary
141 for (int i = 0; path.isEmpty() && i < d->fallbackThemes.count(); ++i) {
142 if (d->themeName == d->fallbackThemes[i]) {
143 continue;
144 }
145
146 // try a compressed svg file in the fallback theme
147 path = d->findInTheme(svgzName, d->fallbackThemes[i]);
148
149 if (path.isEmpty()) {
150 // try an uncompressed svg file in the fallback theme
151 path = d->findInTheme(svgName, d->fallbackThemes[i]);
152 }
153 }
154 }
155
156 return path;
157}
158
159QString Theme::backgroundPath(const QString &image) const
160{
161 return d->imagePath(themeName(), QStringLiteral("/appbackgrounds/"), image);
162}
163
164QPalette Theme::palette() const
165{
166 return d->palette;
167}
168
169QPalette Theme::globalPalette()
170{
171 if (!ThemePrivate::globalTheme) {
172 ThemePrivate::globalTheme = new ThemePrivate;
173 ThemePrivate::globalTheme->settingsChanged(false);
174 }
175 return ThemePrivate::globalTheme->palette;
176}
177
178KSharedConfigPtr Theme::globalColorScheme()
179{
180 if (!ThemePrivate::globalTheme) {
181 ThemePrivate::globalTheme = new ThemePrivate;
182 ThemePrivate::globalTheme->settingsChanged(false);
183 }
184 return ThemePrivate::globalTheme->colors;
185}
186
187QString Theme::wallpaperPath(const QSize &size) const
188{
189 QString fullPath;
190 QString image = d->defaultWallpaperTheme + QStringLiteral("/contents/images/%1x%2") + d->defaultWallpaperSuffix;
191 QString defaultImage = image.arg(d->defaultWallpaperWidth).arg(d->defaultWallpaperHeight);
192
193 if (size.isValid()) {
194 // try to customize the paper to the size requested
195 // TODO: this should do better than just fallback to the default size.
196 // a "best fit" matching would be far better, so we don't end
197 // up returning a 1920x1200 wallpaper for a 640x480 request ;)
198 image = image.arg(size.width()).arg(size.height());
199 } else {
200 image = defaultImage;
201 }
202
203 // TODO: the theme's wallpaper overrides regularly installed wallpapers.
204 // should it be possible for user installed (e.g. locateLocal) wallpapers
205 // to override the theme?
206 if (d->hasWallpapers) {
207 // check in the theme first
208 fullPath = d->findInTheme(QLatin1String("wallpapers/") % image, d->themeName);
209
210 if (fullPath.isEmpty()) {
211 fullPath = d->findInTheme(QLatin1String("wallpapers/") % defaultImage, d->themeName);
212 }
213 }
214
215 if (fullPath.isEmpty()) {
216 // we failed to find it in the theme, so look in the standard directories
217 // qCDebug(LOG_PLASMA) << "looking for" << image;
219 }
220
221 if (fullPath.isEmpty()) {
222 // we still failed to find it in the theme, so look for the default in
223 // the standard directories
224 // qCDebug(LOG_PLASMA) << "looking for" << defaultImage;
225 fullPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("wallpapers/") + defaultImage);
226 }
227
228 return fullPath;
229}
230
231QString Theme::wallpaperPathForSize(int width, int height) const
232{
233 return Plasma::Theme::wallpaperPath(QSize(width, height));
234}
235
237{
238 if (name.contains(QLatin1String("../"))) {
239 // we don't support relative paths
240 return false;
241 }
242
243 QString path = d->findInTheme(name % QLatin1String(".svgz"), d->themeName);
244 if (path.isEmpty()) {
245 path = d->findInTheme(name % QLatin1String(".svg"), d->themeName);
246 }
247 return path.contains(QLatin1String("/" PLASMA_RELATIVE_DATA_INSTALL_DIR "/desktoptheme/") % d->themeName);
248}
249
250KSharedConfigPtr Theme::colorScheme() const
251{
252 return d->colors;
253}
254
255QColor Theme::color(ColorRole role, ColorGroup group) const
256{
257 return d->color(role, group);
258}
259
260void Theme::setUseGlobalSettings(bool useGlobal)
261{
262 if (d->useGlobal == useGlobal) {
263 return;
264 }
265
266 d->useGlobal = useGlobal;
267 d->cfg = KConfigGroup();
268 d->themeName.clear();
269 d->settingsChanged(true);
270}
271
272bool Theme::useGlobalSettings() const
273{
274 return d->useGlobal;
275}
276
278{
279 return d->pluginMetaData;
280}
281
282QFont Theme::defaultFont() const
283{
284 return QGuiApplication::font();
285}
286
287QFont Theme::smallestFont() const
288{
290}
291
292QSizeF Theme::mSize(const QFont &font) const
293{
294 return QFontMetrics(font).boundingRect(QStringLiteral("M")).size();
295}
296
298{
299 return d->backgroundContrastEnabled;
300}
301
303{
304 return d->adaptiveTransparencyEnabled;
305}
306
308{
309 if (qIsNaN(d->backgroundContrast)) {
310 // Make up sensible default values, based on the background color
311 // If we're using a dark background color, darken the background
312 if (qGray(color(Plasma::Theme::BackgroundColor).rgb()) < 127) {
313 return 0.45;
314 // for a light theme lighten up the background
315 } else {
316 return 0.3;
317 }
318 }
319 return d->backgroundContrast;
320}
321
323{
324 if (qIsNaN(d->backgroundIntensity)) {
325 if (qGray(color(Plasma::Theme::BackgroundColor).rgb()) < 127) {
326 return 0.6;
327 } else {
328 return 1.4;
329 }
330 }
331 return d->backgroundIntensity;
332}
333
335{
336 if (qIsNaN(d->backgroundSaturation)) {
337 return 1.7;
338 }
339 return d->backgroundSaturation;
340}
341
343{
344 return d->blurBehindEnabled;
345}
346
347}
348
349#include "moc_theme.cpp"
void defaultFontChanged()
Notifier for change of defaultFont property.
void smallestFontChanged()
Notifier for change of smallestFont property.
qreal backgroundIntensity() const
This method allows Plasma to set a background contrast effect for a given theme, improving readabilit...
Definition theme.cpp:322
bool backgroundContrastEnabled() const
This method allows Plasma to enable and disable the background contrast effect for a given theme,...
Definition theme.cpp:297
Q_INVOKABLE QSizeF mSize(const QFont &font=QGuiApplication::font()) const
Returns the size of the letter "M" as rendered on the screen with the given font.
Definition theme.cpp:292
void setThemeName(const QString &themeName)
Sets the current theme being used.
Definition theme.cpp:91
QString imagePath(const QString &name) const
Retrieve the path for an SVG image in the current theme.
Definition theme.cpp:123
bool blurBehindEnabled() const
This method allows Plasma to enable and disable the blurring of what is behind the background for a g...
Definition theme.cpp:342
Theme(QObject *parent=nullptr)
Default constructor.
Definition theme.cpp:34
void themeChanged()
Emitted when the user changes the theme.
void setUseGlobalSettings(bool useGlobal)
Tells the theme whether to follow the global settings or use application specific settings.
Definition theme.cpp:260
QColor color(ColorRole role, ColorGroup group=NormalColorGroup) const
Returns the text color to be used by items resting on the background.
Definition theme.cpp:255
bool adaptiveTransparencyEnabled() const
This method allows Plasma to enable and disable the adaptive transparency option of the panel,...
Definition theme.cpp:302
KPluginMetaData metadata() const
Definition theme.cpp:277
KSharedConfigPtr colorScheme() const
Returns the color scheme configurationthat goes along this theme.
Definition theme.cpp:250
qreal backgroundSaturation() const
This method allows Plasma to set a background contrast effect for a given theme, improving readabilit...
Definition theme.cpp:334
qreal backgroundContrast() const
This method allows Plasma to set a background contrast effect for a given theme, improving readabilit...
Definition theme.cpp:307
@ BackgroundColor
the default background color
Definition theme.h:56
bool currentThemeHasImage(const QString &name) const
Checks if this theme has an image named in a certain way.
Definition theme.cpp:236
Namespace for everything in libplasma.
QCoreApplication * instance()
QFont systemFont(SystemFont type)
QRect boundingRect(QChar ch) const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
QSize size() const const
int height() const const
bool isValid() const const
int width() const const
QString locate(StandardLocation type, const QString &fileName, LocateOptions options)
QString arg(Args &&... args) const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:34:35 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.