KColorScheme

kcolorschememanager.cpp
1/*
2 This file is part of the KDE project
3 SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "kcolorschememanager.h"
9#include "kcolorschememanager_p.h"
10
11#include "kcolorschememodel.h"
12
13#include <KConfigGroup>
14#include <KConfigGui>
15#include <KLocalizedString>
16#include <KSharedConfig>
17#include <kcolorscheme.h>
18
19#include <QDir>
20#include <QFileInfo>
21#include <QGuiApplication>
22#include <QIcon>
23#include <QPainter>
24#include <QPointer>
25#include <QStandardPaths>
26
27#include <private/qguiapplication_p.h>
28#include <qpa/qplatformtheme.h>
29
30// ensure we are linking KConfigGui, so QColor I/O from KConfig works
31KCONFIGGUI_EXPORT int initKConfigGroupGui();
32static int s_init = initKConfigGroupGui();
33
34constexpr int defaultSchemeRow = 0;
35
36static bool isKdePlatformTheme() {
37 return QGuiApplicationPrivate::platformTheme() && QGuiApplicationPrivate::platformTheme()->name() == QLatin1String("kde");
38}
39
40void KColorSchemeManagerPrivate::activateSchemeInternal(const QString &colorSchemePath)
41{
42 // hint for plasma-integration to synchronize the color scheme with the window manager/compositor
43 // The property needs to be set before the palette change because is is checked upon the
44 // ApplicationPaletteChange event.
45 qApp->setProperty("KDE_COLOR_SCHEME_PATH", colorSchemePath);
46 if (colorSchemePath.isEmpty()) {
47 qApp->setPalette(QPalette());
48 } else {
49 qApp->setPalette(KColorScheme::createApplicationPalette(KSharedConfig::openConfig(colorSchemePath)));
50 }
51}
52
53// The meaning of the Default entry depends on the platform
54// On KDE we apply a default KColorScheme
55// On other platforms we automatically apply Breeze/Breeze Dark depending on the system preference
56QString KColorSchemeManagerPrivate::automaticColorSchemePath() const
57{
58 if (!m_colorSchemeWatcher) {
59 return QString();
60 }
61
62 const QString colorSchemeId = m_colorSchemeWatcher->systemPreference() == KColorSchemeWatcher::PreferDark ? getDarkColorScheme() : getLightColorScheme();
63 return indexForSchemeId(colorSchemeId).data(KColorSchemeModel::PathRole).toString();
64}
65
66QIcon KColorSchemeManagerPrivate::createPreview(const QString &path)
67{
68 KSharedConfigPtr schemeConfig = KSharedConfig::openConfig(path, KConfig::SimpleConfig);
69 QIcon result;
70
71 KColorScheme activeWindow(QPalette::Active, KColorScheme::Window, schemeConfig);
72 KColorScheme activeButton(QPalette::Active, KColorScheme::Button, schemeConfig);
73 KColorScheme activeView(QPalette::Active, KColorScheme::View, schemeConfig);
74 KColorScheme activeSelection(QPalette::Active, KColorScheme::Selection, schemeConfig);
75
76 auto pixmap = [&](int size) {
77 QPixmap pix(size, size);
78 pix.fill(Qt::black);
79 QPainter p;
80 p.begin(&pix);
81 const int itemSize = size / 2 - 1;
82 p.fillRect(1, 1, itemSize, itemSize, activeWindow.background());
83 p.fillRect(1 + itemSize, 1, itemSize, itemSize, activeButton.background());
84 p.fillRect(1, 1 + itemSize, itemSize, itemSize, activeView.background());
85 p.fillRect(1 + itemSize, 1 + itemSize, itemSize, itemSize, activeSelection.background());
86 p.end();
87 result.addPixmap(pix);
88 };
89 // 16x16
90 pixmap(16);
91 // 24x24
92 pixmap(24);
93
94 return result;
95}
96
97KColorSchemeManagerPrivate::KColorSchemeManagerPrivate()
98 : model(new KColorSchemeModel())
99{
100}
101
102KColorSchemeManager::KColorSchemeManager(GuardApplicationConstructor, QGuiApplication *app)
103 : QObject(app)
104 , d(new KColorSchemeManagerPrivate)
105{
106 init();
107}
108
109#if KCOLORSCHEME_BUILD_DEPRECATED_SINCE(6, 6)
110KColorSchemeManager::KColorSchemeManager(QObject *parent)
111 : QObject(parent)
112 , d(new KColorSchemeManagerPrivate())
113{
114 init();
115}
116#endif
117
118KColorSchemeManager::~KColorSchemeManager()
119{
120}
121
122void KColorSchemeManager::init()
123{
124 QString platformThemeSchemePath = qApp->property("KDE_COLOR_SCHEME_PATH").toString();
125 if (!isKdePlatformTheme() && platformThemeSchemePath.isEmpty()) {
126 d->m_colorSchemeWatcher.emplace();
127 QObject::connect(&*d->m_colorSchemeWatcher, &KColorSchemeWatcher::systemPreferenceChanged, this, [this]() {
128 if (!d->m_activatedScheme.isEmpty()) {
129 // Don't override what has been manually set
130 return;
131 }
132
133 d->activateSchemeInternal(d->automaticColorSchemePath());
134 });
135 }
136
137 KSharedConfigPtr config = KSharedConfig::openConfig();
138 KConfigGroup cg(config, QStringLiteral("UiSettings"));
139 const QString scheme = cg.readEntry("ColorScheme", QString());
140
141 QString schemePath;
142
143 if (scheme.isEmpty() || scheme == QLatin1String("Default")) {
144 // Color scheme might be already set from a platform theme
145 // This is used for example by QGnomePlatform that can set color scheme
146 // matching GNOME settings. This avoids issues where QGnomePlatform sets
147 // QPalette for dark theme, but end up mixing it also with Breeze light
148 // that is going to be used as a fallback for apps using KColorScheme.
149 // BUG: 447029
150 if (platformThemeSchemePath.isEmpty()) {
151 schemePath = d->automaticColorSchemePath();
152 }
153 } else {
154 const auto index = indexForScheme(scheme);
155 schemePath = index.data(KColorSchemeModel::PathRole).toString();
156 d->m_activatedScheme = index.data(KColorSchemeModel::IdRole).toString();
157 }
158
159 if (!schemePath.isEmpty()) {
160 d->activateSchemeInternal(schemePath);
161 }
162}
163
165{
166 return d->model.get();
167}
168
169QModelIndex KColorSchemeManagerPrivate::indexForSchemeId(const QString &id) const
170{
171 for (int i = 1; i < model->rowCount(); ++i) {
172 QModelIndex index = model->index(i);
173 if (index.data(KColorSchemeModel::IdRole).toString() == id) {
174 return index;
175 }
176 }
177 return QModelIndex();
178}
179
181{
182 d->m_autosaveChanges = autosaveChanges;
183}
184
186{
187 // Empty string is mapped to "reset to the system scheme"
188 if (id.isEmpty()) {
189 return d->model->index(defaultSchemeRow);
190 }
191 return d->indexForSchemeId(id);
192}
193
195{
196 // Empty string is mapped to "reset to the system scheme"
197 if (name.isEmpty()) {
198 return d->model->index(defaultSchemeRow);
199 }
200 for (int i = 1; i < d->model->rowCount(); ++i) {
201 QModelIndex index = d->model->index(i);
202 if (index.data(KColorSchemeModel::NameRole).toString() == name) {
203 return index;
204 }
205 }
206 return QModelIndex();
207}
208
210{
211 const bool isDefaultEntry = index.data(KColorSchemeModel::PathRole).toString().isEmpty();
212
213 if (index.isValid() && index.model() == d->model.get() && !isDefaultEntry) {
214 d->activateSchemeInternal(index.data(KColorSchemeModel::PathRole).toString());
215 d->m_activatedScheme = index.data(KColorSchemeModel::IdRole).toString();
216 if (d->m_autosaveChanges) {
217 saveSchemeToConfigFile(index.data(KColorSchemeModel::NameRole).toString());
218 }
219 } else {
220 d->activateSchemeInternal(d->automaticColorSchemePath());
221 d->m_activatedScheme = QString();
222 if (d->m_autosaveChanges) {
224 }
225 }
226}
227
229{
230 KSharedConfigPtr config = KSharedConfig::openConfig();
231 KConfigGroup cg(config, QStringLiteral("UiSettings"));
232 cg.writeEntry("ColorScheme", KLocalizedString::removeAcceleratorMarker(schemeName));
233 cg.sync();
234}
235
237{
238 return d->m_activatedScheme;
239}
240
242{
243 return d->indexForSchemeId(d->m_activatedScheme).data(KColorSchemeModel::NameRole).toString();
244}
245
247{
248 Q_ASSERT(qApp);
249 static QPointer<KColorSchemeManager> manager;
250 if (!manager) {
251 manager = new KColorSchemeManager(GuardApplicationConstructor{}, qApp);
252 }
253 return manager;
254}
255
256#include "moc_kcolorschememanager.cpp"
A small helper to get access to all available color schemes and activating a scheme in the QApplicati...
QAbstractItemModel * model() const
A QAbstractItemModel of all available color schemes.
QString activeSchemeId() const
Returns the id of the currently active scheme or an empty string if the default scheme is active.
QModelIndex indexForScheme(const QString &name) const
Returns the model index for the scheme with the given name.
QModelIndex indexForSchemeId(const QString &id) const
Returns the model index for the scheme with the given id.
static KColorSchemeManager * instance()
Returns the manager for the current application instance.
void activateScheme(const QModelIndex &index)
Activates the KColorScheme identified by the provided index.
QString activeSchemeName() const
Returns the name of the currently active scheme or an empty string if the default scheme is active.
void saveSchemeToConfigFile(const QString &schemeName) const
Saves the color scheme to config file.
void setAutosaveChanges(bool autosaveChanges)
Sets color scheme autosaving.
A model listing the KColorSchemes available in the system.
void systemPreferenceChanged()
A set of methods used to work with colors.
static QPalette createApplicationPalette(const KSharedConfigPtr &config)
Used to obtain the QPalette that will be used to set the application palette from KDE Platform theme.
@ View
Views; for example, frames, input fields, etc.
@ Window
Non-editable window elements; for example, menus.
@ Selection
Selected items in views.
@ Button
Buttons and button-like controls.
void writeEntry(const char *key, const char *value, WriteConfigFlags pFlags=Normal)
bool sync() override
static QString removeAcceleratorMarker(const QString &label)
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
void init(KXmlGuiWindow *window, KGameDifficulty *difficulty=nullptr)
void addPixmap(const QPixmap &pixmap, Mode mode, State state)
QVariant data(int role) const const
bool isValid() const const
const QAbstractItemModel * model() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool begin(QPaintDevice *device)
bool end()
void fillRect(const QRect &rectangle, QGradient::Preset preset)
QChar * data()
bool isEmpty() const const
QString toString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Nov 22 2024 12:02:22 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.