diff --git a/kcmkwin/kwindecoration/declarative-plugin/previewbridge.cpp b/kcmkwin/kwindecoration/declarative-plugin/previewbridge.cpp index bad4cc119..83a9bd9e6 100644 --- a/kcmkwin/kwindecoration/declarative-plugin/previewbridge.cpp +++ b/kcmkwin/kwindecoration/declarative-plugin/previewbridge.cpp @@ -1,247 +1,259 @@ /* * Copyright 2014 Martin Gräßlin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "previewbridge.h" #include "previewclient.h" #include "previewitem.h" #include "previewsettings.h" #include #include #include #include #include #include #include #include #include #include #include #include +#include +#include +#include #include +#include namespace KDecoration2 { namespace Preview { static const QString s_pluginName = QStringLiteral("org.kde.kdecoration2"); PreviewBridge::PreviewBridge(QObject *parent) : DecorationBridge(parent) , m_lastCreatedClient(nullptr) , m_lastCreatedSettings(nullptr) , m_valid(false) { connect(this, &PreviewBridge::pluginChanged, this, &PreviewBridge::createFactory); } PreviewBridge::~PreviewBridge() = default; std::unique_ptr PreviewBridge::createClient(DecoratedClient *client, Decoration *decoration) { auto ptr = std::unique_ptr(new PreviewClient(client, decoration)); m_lastCreatedClient = ptr.get(); return ptr; } void PreviewBridge::update(Decoration *decoration, const QRect &geometry) { Q_UNUSED(geometry) auto it = std::find_if(m_previewItems.constBegin(), m_previewItems.constEnd(), [decoration](PreviewItem *item) { return item->decoration() == decoration; }); if (it != m_previewItems.constEnd()) { (*it)->update(); } } std::unique_ptr PreviewBridge::settings(DecorationSettings *parent) { auto ptr = std::unique_ptr(new PreviewSettings(parent)); m_lastCreatedSettings = ptr.get(); return ptr; } void PreviewBridge::registerPreviewItem(PreviewItem *item) { m_previewItems.append(item); } void PreviewBridge::unregisterPreviewItem(PreviewItem *item) { m_previewItems.removeAll(item); } void PreviewBridge::setPlugin(const QString &plugin) { if (m_plugin == plugin) { return; } m_plugin = plugin; emit pluginChanged(); } QString PreviewBridge::theme() const { return m_theme; } void PreviewBridge::setTheme(const QString &theme) { if (m_theme == theme) { return; } m_theme = theme; emit themeChanged(); } QString PreviewBridge::plugin() const { return m_plugin; } void PreviewBridge::createFactory() { m_factory.clear(); if (m_plugin.isNull()) { setValid(false); qWarning() << "Plugin not set"; return; } const auto offers = KPluginTrader::self()->query(s_pluginName, s_pluginName); auto item = std::find_if(offers.constBegin(), offers.constEnd(), [this](const auto &plugin) { return plugin.pluginName() == m_plugin; }); if (item != offers.constEnd()) { KPluginLoader loader(item->libraryPath()); m_factory = loader.factory(); } setValid(!m_factory.isNull()); } bool PreviewBridge::isValid() const { return m_valid; } void PreviewBridge::setValid(bool valid) { if (m_valid == valid) { return; } m_valid = valid; emit validChanged(); } Decoration *PreviewBridge::createDecoration(QObject *parent) { if (!m_valid) { return nullptr; } QVariantMap args({ {QStringLiteral("bridge"), QVariant::fromValue(this)} }); if (!m_theme.isNull()) { args.insert(QStringLiteral("theme"), m_theme); } return m_factory->create(parent, QVariantList({args})); } DecorationButton *PreviewBridge::createButton(KDecoration2::Decoration *decoration, KDecoration2::DecorationButtonType type, QObject *parent) { if (!m_valid) { return nullptr; } return m_factory->create(QStringLiteral("button"), parent, QVariantList({QVariant::fromValue(type), QVariant::fromValue(decoration)})); } -void PreviewBridge::configure() +void PreviewBridge::configure(QQuickItem *ctx) { if (!m_valid) { return; } //setup the UI - QDialog dialog; + QDialog *dialog = new QDialog(); + dialog->setAttribute(Qt::WA_DeleteOnClose); if (m_lastCreatedClient) { - dialog.setWindowTitle(m_lastCreatedClient->caption()); + dialog->setWindowTitle(m_lastCreatedClient->caption()); } // create the KCModule through the plugintrader QVariantMap args; if (!m_theme.isNull()) { args.insert(QStringLiteral("theme"), m_theme); } - KCModule *kcm = m_factory->create(QStringLiteral("kcmodule"), &dialog, QVariantList({args})); + KCModule *kcm = m_factory->create(QStringLiteral("kcmodule"), dialog, QVariantList({args})); if (!kcm) { return; } auto save = [this,kcm] { kcm->save(); if (m_lastCreatedSettings) { emit m_lastCreatedSettings->decorationSettings()->reconfigured(); } // Send signal to all kwin instances QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KWin"), QStringLiteral("org.kde.KWin"), QStringLiteral("reloadConfig")); QDBusConnection::sessionBus().send(message); }; - connect(&dialog, &QDialog::accepted, this, save); + connect(dialog, &QDialog::accepted, this, save); QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Reset, - &dialog); + dialog); QPushButton *reset = buttons->button(QDialogButtonBox::Reset); reset->setEnabled(false); // Here we connect our buttons with the dialog - connect(buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); - connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); + connect(buttons, &QDialogButtonBox::accepted, dialog, &QDialog::accept); + connect(buttons, &QDialogButtonBox::rejected, dialog, &QDialog::reject); connect(reset, &QPushButton::clicked, kcm, &KCModule::load); auto changedSignal = static_cast(&KCModule::changed); connect(kcm, changedSignal, reset, &QPushButton::setEnabled); connect(buttons->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, kcm, &KCModule::defaults); - QVBoxLayout *layout = new QVBoxLayout(&dialog); + QVBoxLayout *layout = new QVBoxLayout(dialog); layout->addWidget(kcm); layout->addWidget(buttons); - dialog.exec(); + + if (ctx->window()) { + dialog->winId(); // so it creates windowHandle + dialog->windowHandle()->setTransientParent(QQuickRenderControl::renderWindowFor(ctx->window())); + dialog->setModal(true); + } + + dialog->show(); } BridgeItem::BridgeItem(QObject *parent) : QObject(parent) , m_bridge(new PreviewBridge()) { connect(m_bridge, &PreviewBridge::themeChanged, this, &BridgeItem::themeChanged); connect(m_bridge, &PreviewBridge::pluginChanged, this, &BridgeItem::pluginChanged); connect(m_bridge, &PreviewBridge::validChanged, this, &BridgeItem::validChanged); } BridgeItem::~BridgeItem() { m_bridge->deleteLater(); } } } diff --git a/kcmkwin/kwindecoration/declarative-plugin/previewbridge.h b/kcmkwin/kwindecoration/declarative-plugin/previewbridge.h index 7e1d8f3d4..85fccbeaa 100644 --- a/kcmkwin/kwindecoration/declarative-plugin/previewbridge.h +++ b/kcmkwin/kwindecoration/declarative-plugin/previewbridge.h @@ -1,139 +1,141 @@ /* * Copyright 2014 Martin Gräßlin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef KDECOARTIONS_PREVIEW_BRIDGE_H #define KDECOARTIONS_PREVIEW_BRIDGE_H #include #include #include #include +class QQuickItem; + class KPluginFactory; namespace KDecoration2 { namespace Preview { class PreviewClient; class PreviewItem; class PreviewSettings; class PreviewBridge : public DecorationBridge { Q_OBJECT Q_PROPERTY(QString plugin READ plugin WRITE setPlugin NOTIFY pluginChanged) Q_PROPERTY(QString theme READ theme WRITE setTheme NOTIFY themeChanged) Q_PROPERTY(bool valid READ isValid NOTIFY validChanged) public: explicit PreviewBridge(QObject *parent = nullptr); ~PreviewBridge() override; std::unique_ptr createClient(DecoratedClient *client, Decoration *decoration) override; void update(Decoration* decoration, const QRect& geometry) override; std::unique_ptr settings(DecorationSettings *parent) override; PreviewClient *lastCreatedClient() { return m_lastCreatedClient; } PreviewSettings *lastCreatedSettings() { return m_lastCreatedSettings; } void registerPreviewItem(PreviewItem *item); void unregisterPreviewItem(PreviewItem *item); void setPlugin(const QString &plugin); QString plugin() const; void setTheme(const QString &theme); QString theme() const; bool isValid() const; KDecoration2::Decoration *createDecoration(QObject *parent = nullptr); KDecoration2::DecorationButton *createButton(KDecoration2::Decoration *decoration, KDecoration2::DecorationButtonType type, QObject *parent = nullptr); public Q_SLOTS: - void configure(); + void configure(QQuickItem *ctx); Q_SIGNALS: void pluginChanged(); void themeChanged(); void validChanged(); private: void createFactory(); void setValid(bool valid); PreviewClient *m_lastCreatedClient; PreviewSettings *m_lastCreatedSettings; QList m_previewItems; QString m_plugin; QString m_theme; QPointer m_factory; bool m_valid; }; class BridgeItem : public QObject { Q_OBJECT Q_PROPERTY(QString plugin READ plugin WRITE setPlugin NOTIFY pluginChanged) Q_PROPERTY(QString theme READ theme WRITE setTheme NOTIFY themeChanged) Q_PROPERTY(bool valid READ isValid NOTIFY validChanged) Q_PROPERTY(KDecoration2::Preview::PreviewBridge *bridge READ bridge CONSTANT) public: explicit BridgeItem(QObject *parent = nullptr); ~BridgeItem() override; void setPlugin(const QString &plugin) { m_bridge->setPlugin(plugin); } QString plugin() const { return m_bridge->plugin(); } void setTheme(const QString &theme) { m_bridge->setTheme(theme); } QString theme() const { return m_bridge->theme(); } bool isValid() const { return m_bridge->isValid(); } PreviewBridge *bridge() const { return m_bridge; } Q_SIGNALS: void pluginChanged(); void themeChanged(); void validChanged(); private: PreviewBridge *m_bridge; }; } } Q_DECLARE_METATYPE(KDecoration2::Preview::PreviewBridge *) #endif diff --git a/kcmkwin/kwindecoration/package/contents/ui/Themes.qml b/kcmkwin/kwindecoration/package/contents/ui/Themes.qml index 28e5899db..1eeb4cd0b 100644 --- a/kcmkwin/kwindecoration/package/contents/ui/Themes.qml +++ b/kcmkwin/kwindecoration/package/contents/ui/Themes.qml @@ -1,119 +1,120 @@ /* * Copyright 2014 Martin Gräßlin * Copyright (c) 2019 Valerio Pilo * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import QtQuick 2.7 import org.kde.kcm 1.1 as KCM import org.kde.kirigami 2.2 as Kirigami import org.kde.kwin.private.kdecoration 1.0 as KDecoration KCM.GridView { function updateDecoration(item, marginTopLeft, marginBottomRight) { var mainMargin = units.largeSpacing var shd = item.shadow item.anchors.leftMargin = mainMargin + marginTopLeft - (shd ? shd.paddingLeft : 0) item.anchors.rightMargin = mainMargin + marginBottomRight - (shd ? shd.paddingRight : 0) item.anchors.topMargin = mainMargin + marginTopLeft - (shd ? shd.paddingTop : 0) item.anchors.bottomMargin = mainMargin + marginBottomRight - (shd ? shd.paddingBottom : 0) } view.model: kcm.themesModel view.currentIndex: kcm.theme view.onContentHeightChanged: view.positionViewAtIndex(view.currentIndex, GridView.Visible) view.implicitCellWidth: Kirigami.Units.gridUnit * 18 view.delegate: KCM.GridDelegate { + id: delegate text: model.display thumbnailAvailable: true thumbnail: Rectangle { anchors.fill: parent color: palette.base clip: true KDecoration.Bridge { id: bridgeItem plugin: model.plugin theme: model.theme } KDecoration.Settings { id: settingsItem bridge: bridgeItem.bridge } KDecoration.Decoration { id: inactivePreview bridge: bridgeItem.bridge settings: settingsItem anchors.fill: parent onShadowChanged: updateDecoration(inactivePreview, 0, client.decoration.titleBar.height) Component.onCompleted: { client.active = false client.caption = model.display updateDecoration(inactivePreview, 0, client.decoration.titleBar.height) } } KDecoration.Decoration { id: activePreview bridge: bridgeItem.bridge settings: settingsItem anchors.fill: parent onShadowChanged: updateDecoration(activePreview, client.decoration.titleBar.height, 0) Component.onCompleted: { client.active = true client.caption = model.display updateDecoration(activePreview, client.decoration.titleBar.height, 0) } } MouseArea { anchors.fill: parent onClicked: { kcm.theme = index view.currentIndex = index } } Connections { target: kcm onBorderSizeChanged: settingsItem.borderSizesIndex = kcm.borderSize } } actions: [ Kirigami.Action { iconName: "edit-entry" tooltip: i18n("Edit %1 Theme", model.display) enabled: model.configureable onTriggered: { kcm.theme = index view.currentIndex = index - bridgeItem.bridge.configure() + bridgeItem.bridge.configure(delegate) } } ] onClicked: { kcm.theme = index view.currentIndex = index } } Connections { target: kcm onThemeChanged: view.currentIndex = kcm.theme } }