You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

256 lines
7.8 KiB
C++

/*
* Copyright 2014 Martin Gräßlin <mgraesslin@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "previewbridge.h"
#include "previewclient.h"
#include "previewitem.h"
#include "previewsettings.h"
#include <KDecoration2/DecoratedClient>
#include <KDecoration2/Decoration>
#include <KCModule>
#include <KPluginLoader>
#include <KPluginFactory>
#include <KPluginTrader>
#include <QDebug>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDialog>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QVBoxLayout>
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<DecoratedClientPrivate> PreviewBridge::createClient(DecoratedClient *client, Decoration *decoration)
{
auto ptr = std::unique_ptr<PreviewClient>(new PreviewClient(client, decoration));
m_lastCreatedClient = ptr.get();
return std::move(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<DecorationSettingsPrivate> PreviewBridge::settings(DecorationSettings *parent)
{
auto ptr = std::unique_ptr<PreviewSettings>(new PreviewSettings(parent));
m_lastCreatedSettings = ptr.get();
return std::move(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;
qDebug() << "Plugin changed to: " << m_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);
qDebug() <<"Plugin not set";
return;
}
const auto offers = KPluginTrader::self()->query(s_pluginName,
s_pluginName,
QStringLiteral("[X-KDE-PluginInfo-Name] == '%1'").arg(m_plugin));
if (offers.isEmpty()) {
setValid(false);
qDebug() << "no offers";
return;
}
KPluginLoader loader(offers.first().libraryPath());
m_factory = loader.factory();
qDebug() << "Factory: " << !m_factory.isNull();
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<KDecoration2::Decoration>(parent, QVariantList({args}));
}
DecorationButton *PreviewBridge::createButton(KDecoration2::Decoration *decoration, KDecoration2::DecorationButtonType type, QObject *parent)
{
if (!m_valid) {
return nullptr;
}
return m_factory->create<KDecoration2::DecorationButton>(QStringLiteral("button"), parent, QVariantList({QVariant::fromValue(type), QVariant::fromValue(decoration)}));
}
void PreviewBridge::configure()
{
if (!m_valid) {
return;
}
//setup the UI
QDialog dialog;
if (m_lastCreatedClient) {
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<KCModule>(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);
QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok |
QDialogButtonBox::Cancel |
QDialogButtonBox::Apply |
QDialogButtonBox::RestoreDefaults |
QDialogButtonBox::Reset,
&dialog);
QPushButton *apply = buttons->button(QDialogButtonBox::Apply);
QPushButton *reset = buttons->button(QDialogButtonBox::Reset);
apply->setEnabled(false);
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(apply, &QPushButton::clicked, this, save);
connect(reset, &QPushButton::clicked, kcm, &KCModule::load);
auto changedSignal = static_cast<void(KCModule::*)(bool)>(&KCModule::changed);
connect(kcm, changedSignal, apply, &QPushButton::setEnabled);
connect(kcm, changedSignal, reset, &QPushButton::setEnabled);
connect(buttons->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, kcm, &KCModule::defaults);
QVBoxLayout *layout = new QVBoxLayout(&dialog);
layout->addWidget(kcm);
layout->addWidget(buttons);
dialog.exec();
}
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();
}
}
}