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"