kwin/kcmkwin/kwindecoration/kcm.cpp

337 lines
13 KiB
C++
Raw Normal View History

/*
* Copyright (c) 2019 Valerio Pilo <vpilo@coldshock.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License version 2 as published by the Free Software Foundation.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "kcm.h"
#include "decorationmodel.h"
#include "declarative-plugin/buttonsmodel.h"
#include <config-kwin.h>
#include <KAboutData>
#include <KConfigGroup>
#include <KLocalizedString>
#include <KPluginFactory>
#include <KNSCore/Engine>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDebug>
#include <QQuickItem>
#include <QQuickWindow>
#include <QSortFilterProxyModel>
#include <KNewStuff3/KNS3/DownloadDialog>
K_PLUGIN_FACTORY_WITH_JSON(KCMKWinDecorationFactory, "kwindecoration.json", registerPlugin<KCMKWinDecoration>();)
Q_DECLARE_METATYPE(KDecoration2::BorderSize)
namespace
{
const QString s_configFile { QStringLiteral("kwinrc") };
const QString s_configGroup { QStringLiteral("org.kde.kdecoration2") };
const QString s_configPlugin { QStringLiteral("library") };
const QString s_configTheme { QStringLiteral("theme") };
const QString s_configBorderSize { QStringLiteral("BorderSize") };
const QString s_configCloseOnDoubleClickOnMenu { QStringLiteral("CloseOnDoubleClickOnMenu") };
const QString s_configShowToolTips { QStringLiteral("ShowToolTips") };
const QString s_configDecoButtonsOnLeft { QStringLiteral("ButtonsOnLeft") };
const QString s_configDecoButtonsOnRight { QStringLiteral("ButtonsOnRight") };
const KDecoration2::BorderSize s_defaultBorderSize = KDecoration2::BorderSize::Normal;
const bool s_defaultCloseOnDoubleClickOnMenu = false;
const bool s_defaultShowToolTips = true;
const DecorationButtonsList s_defaultDecoButtonsOnLeft {
KDecoration2::DecorationButtonType::Menu,
KDecoration2::DecorationButtonType::OnAllDesktops
};
const DecorationButtonsList s_defaultDecoButtonsOnRight {
KDecoration2::DecorationButtonType::ContextHelp,
KDecoration2::DecorationButtonType::Minimize,
KDecoration2::DecorationButtonType::Maximize,
KDecoration2::DecorationButtonType::Close
};
#if HAVE_BREEZE_DECO
const QString s_defaultPlugin { QStringLiteral(BREEZE_KDECORATION_PLUGIN_ID) };
const QString s_defaultTheme { QStringLiteral("Breeze") };
#else
const QString s_defaultPlugin { QStringLiteral("org.kde.kwin.aurorae") };
const QString s_defaultTheme { QStringLiteral("kwin4_decoration_qml_plastik") };
#endif
}
KCMKWinDecoration::KCMKWinDecoration(QObject *parent, const QVariantList &arguments)
: KQuickAddons::ConfigModule(parent, arguments)
, m_themesModel(new KDecoration2::Configuration::DecorationsModel(this))
, m_proxyThemesModel(new QSortFilterProxyModel(this))
, m_leftButtonsModel(new KDecoration2::Preview::ButtonsModel(DecorationButtonsList(), this))
, m_rightButtonsModel(new KDecoration2::Preview::ButtonsModel(DecorationButtonsList(), this))
, m_availableButtonsModel(new KDecoration2::Preview::ButtonsModel(this))
, m_savedSettings{ s_defaultBorderSize, -2 /* for setTheme() */, false, s_defaultShowToolTips, s_defaultDecoButtonsOnLeft, s_defaultDecoButtonsOnRight }
, m_currentSettings(m_savedSettings)
{
auto about = new KAboutData(QStringLiteral("kcm_kwindecoration"),
i18n("Window Decorations"),
QStringLiteral("1.0"),
QString(),
KAboutLicense::GPL);
about->addAuthor(i18n("Valerio Pilo"),
i18n("Author"),
QStringLiteral("vpilo@coldshock.net"));
setAboutData(about);
qmlRegisterType<QAbstractListModel>();
qmlRegisterType<QSortFilterProxyModel>();
m_proxyThemesModel->setSourceModel(m_themesModel);
m_proxyThemesModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
m_proxyThemesModel->setSortCaseSensitivity(Qt::CaseInsensitive);
m_proxyThemesModel->sort(0);
connect(m_leftButtonsModel, &QAbstractItemModel::rowsInserted, this, &KCMKWinDecoration::updateNeedsSave);
connect(m_leftButtonsModel, &QAbstractItemModel::rowsMoved, this, &KCMKWinDecoration::updateNeedsSave);
connect(m_leftButtonsModel, &QAbstractItemModel::rowsRemoved, this, &KCMKWinDecoration::updateNeedsSave);
connect(m_leftButtonsModel, &QAbstractItemModel::modelReset, this, &KCMKWinDecoration::updateNeedsSave);
connect(m_rightButtonsModel, &QAbstractItemModel::rowsInserted, this, &KCMKWinDecoration::updateNeedsSave);
connect(m_rightButtonsModel, &QAbstractItemModel::rowsMoved, this, &KCMKWinDecoration::updateNeedsSave);
connect(m_rightButtonsModel, &QAbstractItemModel::rowsRemoved, this, &KCMKWinDecoration::updateNeedsSave);
connect(m_rightButtonsModel, &QAbstractItemModel::modelReset, this, &KCMKWinDecoration::updateNeedsSave);
// Update the themes when the color scheme or a theme's settings change
QDBusConnection::sessionBus()
.connect(QString(), QStringLiteral("/KWin"), QStringLiteral("org.kde.KWin"), QStringLiteral("reloadConfig"),
this, SLOT(reloadKWinSettings()));
QMetaObject::invokeMethod(m_themesModel, "init", Qt::QueuedConnection);
}
void KCMKWinDecoration::reloadKWinSettings()
{
QMetaObject::invokeMethod(m_themesModel, "init", Qt::QueuedConnection);
}
void KCMKWinDecoration::getNewStuff(QQuickItem *context)
{
if (!m_newStuffDialog) {
m_newStuffDialog = new KNS3::DownloadDialog(QStringLiteral("window-decorations.knsrc"));
m_newStuffDialog->setWindowTitle(i18n("Download New Window Decorations"));
m_newStuffDialog->setWindowModality(Qt::WindowModal);
connect(m_newStuffDialog, &KNS3::DownloadDialog::accepted, this, &KCMKWinDecoration::load);
}
if (context && context->window()) {
m_newStuffDialog->winId(); // so it creates the windowHandle()
m_newStuffDialog->windowHandle()->setTransientParent(context->window());
}
connect(m_newStuffDialog, &QDialog::finished, this, &KCMKWinDecoration::reloadKWinSettings);
m_newStuffDialog->show();
}
void KCMKWinDecoration::load()
{
const KConfigGroup config = KSharedConfig::openConfig(s_configFile)->group(s_configGroup);
const QString plugin = config.readEntry(s_configPlugin, s_defaultPlugin);
const QString theme = config.readEntry(s_configTheme, s_defaultTheme);
int themeIndex = m_proxyThemesModel->mapFromSource(m_themesModel->findDecoration(plugin, theme)).row();
if (themeIndex < 0) {
qWarning() << "Plugin" << plugin << "and theme" << theme << "not found";
} else {
qDebug() << "Current theme: plugin" << plugin << "and theme" << theme;
}
setTheme(themeIndex);
setCloseOnDoubleClickOnMenu(config.readEntry(s_configCloseOnDoubleClickOnMenu, s_defaultCloseOnDoubleClickOnMenu));
setShowToolTips(config.readEntry(s_configShowToolTips, s_defaultShowToolTips));
const QString defaultSizeName = Utils::borderSizeToString(s_defaultBorderSize);
setBorderSize(Utils::stringToBorderSize(config.readEntry(s_configBorderSize, defaultSizeName)));
m_leftButtonsModel->replace(Utils::readDecorationButtons(config, s_configDecoButtonsOnLeft, s_defaultDecoButtonsOnLeft));
m_rightButtonsModel->replace(Utils::readDecorationButtons(config, s_configDecoButtonsOnRight, s_defaultDecoButtonsOnRight));
m_currentSettings.buttonsOnLeft = m_leftButtonsModel->buttons();
m_currentSettings.buttonsOnRight = m_rightButtonsModel->buttons();
m_savedSettings = m_currentSettings;
updateNeedsSave();
}
void KCMKWinDecoration::save()
{
KConfigGroup config = KSharedConfig::openConfig(s_configFile)->group(s_configGroup);
if (m_currentSettings.themeIndex >= 0) {
const QModelIndex index = m_proxyThemesModel->index(m_currentSettings.themeIndex, 0);
if (index.isValid()) {
const QString plugin = index.data(KDecoration2::Configuration::DecorationsModel::PluginNameRole).toString();
const QString theme = index.data(KDecoration2::Configuration::DecorationsModel::ThemeNameRole).toString();
config.writeEntry(s_configPlugin, plugin);
config.writeEntry(s_configTheme, theme);
qDebug() << "Saved theme: plugin" << plugin << "and theme" << theme;
} else {
qWarning() << "Cannot match theme index" << m_currentSettings.themeIndex << "in model";
}
}
config.writeEntry(s_configCloseOnDoubleClickOnMenu, m_currentSettings.closeOnDoubleClickOnMenu);
config.writeEntry(s_configShowToolTips, m_currentSettings.showToolTips);
config.writeEntry(s_configBorderSize, Utils::borderSizeToString(m_currentSettings.borderSize));
config.writeEntry(s_configDecoButtonsOnLeft, Utils::buttonsToString(m_currentSettings.buttonsOnLeft));
config.writeEntry(s_configDecoButtonsOnRight, Utils::buttonsToString(m_currentSettings.buttonsOnRight));
config.sync();
m_savedSettings = m_currentSettings;
// Send a signal to all kwin instances
QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KWin"),
QStringLiteral("org.kde.KWin"),
QStringLiteral("reloadConfig"));
QDBusConnection::sessionBus().send(message);
updateNeedsSave();
}
void KCMKWinDecoration::defaults()
{
int themeIndex = m_proxyThemesModel->mapFromSource(m_themesModel->findDecoration(s_defaultPlugin, s_defaultTheme)).row();
if (themeIndex < 0) {
qWarning() << "Default plugin" << s_defaultPlugin << "and theme" << s_defaultTheme << "not found";
}
setTheme(themeIndex);
setBorderSize(s_defaultBorderSize);
setCloseOnDoubleClickOnMenu(s_defaultCloseOnDoubleClickOnMenu);
setShowToolTips(s_defaultShowToolTips);
m_leftButtonsModel->replace(s_defaultDecoButtonsOnLeft);
m_rightButtonsModel->replace(s_defaultDecoButtonsOnRight);
updateNeedsSave();
}
void KCMKWinDecoration::updateNeedsSave()
{
m_currentSettings.buttonsOnLeft = m_leftButtonsModel->buttons();
m_currentSettings.buttonsOnRight = m_rightButtonsModel->buttons();
setNeedsSave(m_savedSettings.closeOnDoubleClickOnMenu != m_currentSettings.closeOnDoubleClickOnMenu
|| m_savedSettings.showToolTips != m_currentSettings.showToolTips
|| m_savedSettings.borderSize != m_currentSettings.borderSize
|| m_savedSettings.themeIndex != m_currentSettings.themeIndex
|| m_savedSettings.buttonsOnLeft != m_currentSettings.buttonsOnLeft
|| m_savedSettings.buttonsOnRight != m_currentSettings.buttonsOnRight);
}
QSortFilterProxyModel *KCMKWinDecoration::themesModel() const
{
return m_proxyThemesModel;
}
QAbstractListModel *KCMKWinDecoration::leftButtonsModel()
{
return m_leftButtonsModel;
}
QAbstractListModel *KCMKWinDecoration::rightButtonsModel()
{
return m_rightButtonsModel;
}
QAbstractListModel *KCMKWinDecoration::availableButtonsModel() const
{
return m_availableButtonsModel;
}
QStringList KCMKWinDecoration::borderSizesModel() const
{
return Utils::getBorderSizeNames().values();
}
int KCMKWinDecoration::borderSize() const
{
return Utils::getBorderSizeNames().keys().indexOf(m_currentSettings.borderSize);
}
int KCMKWinDecoration::theme() const
{
return m_currentSettings.themeIndex;
}
bool KCMKWinDecoration::closeOnDoubleClickOnMenu() const
{
return m_currentSettings.closeOnDoubleClickOnMenu;
}
bool KCMKWinDecoration::showToolTips() const
{
return m_currentSettings.showToolTips;
}
void KCMKWinDecoration::setBorderSize(int index)
{
setBorderSize(Utils::getBorderSizeNames().keys().at(index));
}
void KCMKWinDecoration::setBorderSize(KDecoration2::BorderSize size)
{
if (m_currentSettings.borderSize == size) {
return;
}
m_currentSettings.borderSize = size;
emit borderSizeChanged();
updateNeedsSave();
}
void KCMKWinDecoration::setTheme(int index)
{
// The initial themeIndex is set to -2 to always initially apply a theme, any theme
if (m_currentSettings.themeIndex == index) {
return;
}
m_currentSettings.themeIndex = index;
emit themeChanged();
updateNeedsSave();
}
void KCMKWinDecoration::setCloseOnDoubleClickOnMenu(bool enable)
{
if (m_currentSettings.closeOnDoubleClickOnMenu == enable) {
return;
}
m_currentSettings.closeOnDoubleClickOnMenu = enable;
emit closeOnDoubleClickOnMenuChanged();
updateNeedsSave();
}
void KCMKWinDecoration::setShowToolTips(bool show)
{
if (m_currentSettings.showToolTips == show) {
return;
}
m_currentSettings.showToolTips = show;
emit showToolTipsChanged();
updateNeedsSave();
}
#include "kcm.moc"