KWin
Loading...
Searching...
No Matches
decorationbridge.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9#include "decorationbridge.h"
10
11#include <config-kwin.h>
12
13#include "decoratedclient.h"
14#include "decorations_logging.h"
15#include "settings.h"
16// KWin core
18#include "wayland_server.h"
19#include "window.h"
20#include "workspace.h"
21
22// KDecoration
23#include <KDecoration2/DecoratedClient>
24#include <KDecoration2/Decoration>
25#include <KDecoration2/DecorationSettings>
26
27// Frameworks
28#include <KPluginFactory>
29#include <KPluginMetaData>
30
31// Qt
32#include <QMetaProperty>
33#include <QPainter>
34
35namespace KWin
36{
37namespace Decoration
38{
39
40static const QString s_aurorae = QStringLiteral("org.kde.kwin.aurorae");
41static const QString s_pluginName = QStringLiteral("org.kde.kdecoration2");
42#if HAVE_BREEZE_DECO
43static const QString s_defaultPlugin = BREEZE_KDECORATION_PLUGIN_ID;
44#else
45static const QString s_defaultPlugin = s_aurorae;
46#endif
47
49 : m_factory(nullptr)
50 , m_showToolTips(false)
51 , m_settings()
52 , m_noPlugin(false)
53{
54 readDecorationOptions();
55}
56
57QString DecorationBridge::readPlugin()
58{
59 return kwinApp()->config()->group(s_pluginName).readEntry("library", s_defaultPlugin);
60}
61
62static bool readNoPlugin()
63{
64 return kwinApp()->config()->group(s_pluginName).readEntry("NoPlugin", false);
65}
66
67QString DecorationBridge::readTheme() const
68{
69 return kwinApp()->config()->group(s_pluginName).readEntry("theme", m_defaultTheme);
70}
71
72void DecorationBridge::readDecorationOptions()
73{
74 m_showToolTips = kwinApp()->config()->group(s_pluginName).readEntry("ShowToolTips", true);
75}
76
78{
79 const DecorationBridge *bridge = workspace()->decorationBridge();
80 if (!bridge) {
81 return false;
82 }
83 return !bridge->m_noPlugin && bridge->m_factory;
84}
85
87{
88 m_noPlugin = readNoPlugin();
89 if (m_noPlugin) {
90 if (waylandServer()) {
92 }
93 return;
94 }
95 m_plugin = readPlugin();
96 m_settings = std::make_shared<KDecoration2::DecorationSettings>(this);
97 if (!initPlugin()) {
98 if (m_plugin != s_defaultPlugin) {
99 // try loading default plugin
100 m_plugin = s_defaultPlugin;
101 initPlugin();
102 }
103 // default plugin failed to load, try fallback
104 if (!m_factory) {
105 m_plugin = s_aurorae;
106 initPlugin();
107 }
108 }
109 if (waylandServer()) {
111 }
112}
113
114bool DecorationBridge::initPlugin()
115{
116 const KPluginMetaData metaData = KPluginMetaData::findPluginById(s_pluginName, m_plugin);
117 if (!metaData.isValid()) {
118 qCWarning(KWIN_DECORATIONS) << "Could not locate decoration plugin" << m_plugin;
119 return false;
120 }
121 qCDebug(KWIN_DECORATIONS) << "Trying to load decoration plugin: " << metaData.fileName();
122 if (auto factoryResult = KPluginFactory::loadFactory(metaData)) {
123 m_factory.reset(factoryResult.plugin);
124 loadMetaData(metaData.rawData());
125 return true;
126 } else {
127 qCWarning(KWIN_DECORATIONS) << "Error loading plugin:" << factoryResult.errorText;
128 return false;
129 }
130}
131
132static void recreateDecorations()
133{
134 Workspace::self()->forEachWindow([](Window *window) {
135 window->invalidateDecoration();
136 });
137}
138
140{
141 readDecorationOptions();
142
143 if (m_noPlugin != readNoPlugin()) {
144 m_noPlugin = !m_noPlugin;
145 // no plugin setting changed
146 if (m_noPlugin) {
147 // decorations disabled now
148 m_plugin = QString();
149 m_factory.reset();
150 m_settings.reset();
151 } else {
152 // decorations enabled now
153 init();
154 }
155 recreateDecorations();
156 return;
157 }
158
159 const QString newPlugin = readPlugin();
160 if (newPlugin != m_plugin) {
161 // plugin changed, recreate everything
162 auto oldFactory = std::move(m_factory);
163 const auto oldPluginName = m_plugin;
164 m_plugin = newPlugin;
165 if (!initPlugin()) {
166 // loading new plugin failed
167 m_factory = std::move(oldFactory);
168 m_plugin = oldPluginName;
169 } else {
170 recreateDecorations();
171 // TODO: unload and destroy old plugin
172 }
173 } else {
174 // same plugin, but theme might have changed
175 const QString oldTheme = m_theme;
176 m_theme = readTheme();
177 if (m_theme != oldTheme) {
178 recreateDecorations();
179 }
180 }
181}
182
183void DecorationBridge::loadMetaData(const QJsonObject &object)
184{
185 // reset all settings
186 m_recommendedBorderSize = QString();
187 m_theme = QString();
188 m_defaultTheme = QString();
189
190 // load the settings
191 const QJsonValue decoSettings = object.value(s_pluginName);
192 if (decoSettings.isUndefined()) {
193 // no settings
194 return;
195 }
196 const QVariantMap decoSettingsMap = decoSettings.toObject().toVariantMap();
197 auto recBorderSizeIt = decoSettingsMap.find(QStringLiteral("recommendedBorderSize"));
198 if (recBorderSizeIt != decoSettingsMap.end()) {
199 m_recommendedBorderSize = recBorderSizeIt.value().toString();
200 }
201 findTheme(decoSettingsMap);
202
203 Q_EMIT metaDataLoaded();
204}
205
206void DecorationBridge::findTheme(const QVariantMap &map)
207{
208 auto it = map.find(QStringLiteral("themes"));
209 if (it == map.end()) {
210 return;
211 }
212 if (!it.value().toBool()) {
213 return;
214 }
215 it = map.find(QStringLiteral("defaultTheme"));
216 m_defaultTheme = it != map.end() ? it.value().toString() : QString();
217 m_theme = readTheme();
218}
219
220std::unique_ptr<KDecoration2::DecoratedClientPrivate> DecorationBridge::createClient(KDecoration2::DecoratedClient *client, KDecoration2::Decoration *decoration)
221{
222 return std::unique_ptr<DecoratedClientImpl>(new DecoratedClientImpl(static_cast<Window *>(decoration->parent()), client, decoration));
223}
224
225std::unique_ptr<KDecoration2::DecorationSettingsPrivate> DecorationBridge::settings(KDecoration2::DecorationSettings *parent)
226{
227 return std::unique_ptr<SettingsImpl>(new SettingsImpl(parent));
228}
229
230KDecoration2::Decoration *DecorationBridge::createDecoration(Window *window)
231{
232 if (m_noPlugin) {
233 return nullptr;
234 }
235 if (!m_factory) {
236 return nullptr;
237 }
238 QVariantMap args({{QStringLiteral("bridge"), QVariant::fromValue(this)}});
239
240 if (!m_theme.isEmpty()) {
241 args.insert(QStringLiteral("theme"), m_theme);
242 }
243 auto deco = m_factory->create<KDecoration2::Decoration>(window, QVariantList{args});
244 deco->setSettings(m_settings);
245 deco->init();
246 return deco;
247}
248
249static QString settingsProperty(const QVariant &variant)
250{
251 if (QLatin1String(variant.typeName()) == QLatin1String("KDecoration2::BorderSize")) {
252 return QString::number(variant.toInt());
253 } else if (QLatin1String(variant.typeName()) == QLatin1String("QList<KDecoration2::DecorationButtonType>")) {
254 const auto &b = variant.value<QList<KDecoration2::DecorationButtonType>>();
255 QString buffer;
256 for (auto it = b.begin(); it != b.end(); ++it) {
257 if (it != b.begin()) {
258 buffer.append(QStringLiteral(", "));
259 }
260 buffer.append(QString::number(int(*it)));
261 }
262 return buffer;
263 }
264 return variant.toString();
265}
266
268{
269 QString b;
270 if (m_noPlugin) {
271 b.append(QStringLiteral("Decorations are disabled"));
272 } else {
273 b.append(QStringLiteral("Plugin: %1\n").arg(m_plugin));
274 b.append(QStringLiteral("Theme: %1\n").arg(m_theme));
275 b.append(QStringLiteral("Plugin recommends border size: %1\n").arg(m_recommendedBorderSize.isNull() ? "No" : m_recommendedBorderSize));
276 const QMetaObject *metaOptions = m_settings->metaObject();
277 for (int i = 0; i < metaOptions->propertyCount(); ++i) {
278 const QMetaProperty property = metaOptions->property(i);
279 if (QLatin1String(property.name()) == QLatin1String("objectName")) {
280 continue;
281 }
282 b.append(QStringLiteral("%1: %2\n").arg(property.name(), settingsProperty(m_settings->property(property.name()))));
283 }
284 }
285 return b;
286}
287
288} // Decoration
289} // KWin
290
291#include "moc_decorationbridge.cpp"
std::unique_ptr< KDecoration2::DecoratedClientPrivate > createClient(KDecoration2::DecoratedClient *client, KDecoration2::Decoration *decoration) override
KDecoration2::Decoration * createDecoration(Window *window)
const std::shared_ptr< KDecoration2::DecorationSettings > & settings() const
ServerSideDecorationManagerInterface * decorationManager() const
void forEachWindow(std::function< void(Window *)> func)
Decoration::DecorationBridge * decorationBridge() const
static Workspace * self()
Definition workspace.h:91
WaylandServer * waylandServer()
Workspace * workspace()
Definition workspace.h:830