File indexing completed on 2024-11-10 04:56:47
0001 /* 0002 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 #include "previewbridge.h" 0007 #include "previewclient.h" 0008 #include "previewitem.h" 0009 #include "previewsettings.h" 0010 0011 #include <KDecoration2/DecoratedClient> 0012 #include <KDecoration2/Decoration> 0013 0014 #include <KCModule> 0015 #include <KCMultiDialog> 0016 #include <KPluginFactory> 0017 #include <KPluginMetaData> 0018 0019 #include <QDBusConnection> 0020 #include <QDBusMessage> 0021 #include <QDebug> 0022 #include <QDialog> 0023 #include <QDialogButtonBox> 0024 #include <QPushButton> 0025 #include <QQuickItem> 0026 #include <QQuickRenderControl> 0027 #include <QQuickWindow> 0028 #include <QVBoxLayout> 0029 #include <QWindow> 0030 0031 namespace KDecoration2 0032 { 0033 namespace Preview 0034 { 0035 0036 static const QString s_pluginName = QStringLiteral("org.kde.kdecoration2"); 0037 static const QString s_kcmName = QStringLiteral("org.kde.kdecoration2.kcm"); 0038 0039 PreviewBridge::PreviewBridge(QObject *parent) 0040 : DecorationBridge(parent) 0041 , m_lastCreatedClient(nullptr) 0042 , m_lastCreatedSettings(nullptr) 0043 , m_valid(false) 0044 { 0045 connect(this, &PreviewBridge::pluginChanged, this, &PreviewBridge::createFactory); 0046 } 0047 0048 PreviewBridge::~PreviewBridge() = default; 0049 0050 std::unique_ptr<DecoratedClientPrivate> PreviewBridge::createClient(DecoratedClient *client, Decoration *decoration) 0051 { 0052 auto ptr = std::unique_ptr<PreviewClient>(new PreviewClient(client, decoration)); 0053 m_lastCreatedClient = ptr.get(); 0054 return ptr; 0055 } 0056 0057 std::unique_ptr<DecorationSettingsPrivate> PreviewBridge::settings(DecorationSettings *parent) 0058 { 0059 auto ptr = std::unique_ptr<PreviewSettings>(new PreviewSettings(parent)); 0060 m_lastCreatedSettings = ptr.get(); 0061 return ptr; 0062 } 0063 0064 void PreviewBridge::registerPreviewItem(PreviewItem *item) 0065 { 0066 m_previewItems.append(item); 0067 } 0068 0069 void PreviewBridge::unregisterPreviewItem(PreviewItem *item) 0070 { 0071 m_previewItems.removeAll(item); 0072 } 0073 0074 void PreviewBridge::setPlugin(const QString &plugin) 0075 { 0076 if (m_plugin == plugin) { 0077 return; 0078 } 0079 m_plugin = plugin; 0080 Q_EMIT pluginChanged(); 0081 } 0082 0083 QString PreviewBridge::theme() const 0084 { 0085 return m_theme; 0086 } 0087 0088 void PreviewBridge::setTheme(const QString &theme) 0089 { 0090 if (m_theme == theme) { 0091 return; 0092 } 0093 m_theme = theme; 0094 Q_EMIT themeChanged(); 0095 } 0096 0097 QString PreviewBridge::kcmoduleName() const 0098 { 0099 return m_kcmoduleName; 0100 } 0101 0102 void PreviewBridge::setKcmoduleName(const QString &kcmoduleName) 0103 { 0104 if (m_kcmoduleName == kcmoduleName) { 0105 return; 0106 } 0107 m_kcmoduleName = kcmoduleName; 0108 Q_EMIT themeChanged(); 0109 } 0110 0111 QString PreviewBridge::plugin() const 0112 { 0113 return m_plugin; 0114 } 0115 0116 void PreviewBridge::createFactory() 0117 { 0118 m_factory.clear(); 0119 0120 if (m_plugin.isNull()) { 0121 setValid(false); 0122 qWarning() << "Plugin not set"; 0123 return; 0124 } 0125 0126 const auto offers = KPluginMetaData::findPlugins(s_pluginName); 0127 auto item = std::find_if(offers.constBegin(), offers.constEnd(), [this](const auto &plugin) { 0128 return plugin.pluginId() == m_plugin; 0129 }); 0130 if (item != offers.constEnd()) { 0131 m_factory = KPluginFactory::loadFactory(*item).plugin; 0132 } 0133 0134 setValid(!m_factory.isNull()); 0135 } 0136 0137 bool PreviewBridge::isValid() const 0138 { 0139 return m_valid; 0140 } 0141 0142 void PreviewBridge::setValid(bool valid) 0143 { 0144 if (m_valid == valid) { 0145 return; 0146 } 0147 m_valid = valid; 0148 Q_EMIT validChanged(); 0149 } 0150 0151 Decoration *PreviewBridge::createDecoration(QObject *parent) 0152 { 0153 if (!m_valid) { 0154 return nullptr; 0155 } 0156 QVariantMap args({{QStringLiteral("bridge"), QVariant::fromValue(this)}}); 0157 if (!m_theme.isNull()) { 0158 args.insert(QStringLiteral("theme"), m_theme); 0159 } 0160 return m_factory->create<KDecoration2::Decoration>(parent, QVariantList({args})); 0161 } 0162 0163 DecorationButton *PreviewBridge::createButton(KDecoration2::Decoration *decoration, KDecoration2::DecorationButtonType type, QObject *parent) 0164 { 0165 if (!m_valid) { 0166 return nullptr; 0167 } 0168 return m_factory->create<KDecoration2::DecorationButton>(parent, QVariantList({QVariant::fromValue(type), QVariant::fromValue(decoration)})); 0169 } 0170 0171 void PreviewBridge::configure(QQuickItem *ctx) 0172 { 0173 if (!m_valid) { 0174 qWarning() << "Cannot show an invalid decoration's configuration dialog"; 0175 return; 0176 } 0177 0178 KCMultiDialog *dialog = new KCMultiDialog; 0179 dialog->setAttribute(Qt::WA_DeleteOnClose); 0180 0181 if (m_lastCreatedClient) { 0182 dialog->setWindowTitle(m_lastCreatedClient->caption()); 0183 } 0184 0185 QVariantMap args; 0186 if (!m_theme.isNull()) { 0187 args.insert(QStringLiteral("theme"), m_theme); 0188 } 0189 Q_ASSERT(!m_kcmoduleName.isEmpty()); 0190 0191 dialog->addModule(KPluginMetaData(s_kcmName + QLatin1Char('/') + m_kcmoduleName), {args}); 0192 0193 connect(dialog, &KCMultiDialog::configCommitted, this, [this] { 0194 if (m_lastCreatedSettings) { 0195 Q_EMIT m_lastCreatedSettings->decorationSettings()->reconfigured(); 0196 } 0197 // Send signal to all kwin instances 0198 QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KWin"), 0199 QStringLiteral("org.kde.KWin"), 0200 QStringLiteral("reloadConfig")); 0201 QDBusConnection::sessionBus().send(message); 0202 }); 0203 0204 if (ctx->window()) { 0205 dialog->winId(); // so it creates windowHandle 0206 dialog->windowHandle()->setTransientParent(QQuickRenderControl::renderWindowFor(ctx->window())); 0207 dialog->setModal(true); 0208 } 0209 0210 dialog->show(); 0211 } 0212 0213 BridgeItem::BridgeItem(QObject *parent) 0214 : QObject(parent) 0215 , m_bridge(new PreviewBridge()) 0216 { 0217 connect(m_bridge, &PreviewBridge::themeChanged, this, &BridgeItem::themeChanged); 0218 connect(m_bridge, &PreviewBridge::pluginChanged, this, &BridgeItem::pluginChanged); 0219 connect(m_bridge, &PreviewBridge::validChanged, this, &BridgeItem::validChanged); 0220 connect(m_bridge, &PreviewBridge::kcmoduleNameChanged, this, &BridgeItem::kcmoduleNameChanged); 0221 } 0222 0223 BridgeItem::~BridgeItem() 0224 { 0225 m_bridge->deleteLater(); 0226 } 0227 0228 } 0229 } 0230 0231 #include "moc_previewbridge.cpp"