File indexing completed on 2026-07-12 16:17:44

0001 /*
0002     SPDX-FileCopyrightText: 2019 Valerio Pilo <vpilo@coldshock.net>
0003     SPDX-FileCopyrightText: 2019 Cyril Rossi <cyril.rossi@enioka.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 #include "kcm.h"
0008 
0009 #include <config-kwin.h>
0010 
0011 #include "declarative-plugin/buttonsmodel.h"
0012 #include "decorationmodel.h"
0013 
0014 #include <KAboutData>
0015 #include <KConfigGroup>
0016 #include <KLocalizedString>
0017 #include <KNSCore/Engine>
0018 #include <KPluginFactory>
0019 
0020 #include <QDBusConnection>
0021 #include <QDBusMessage>
0022 #include <QDebug>
0023 #include <QQuickItem>
0024 #include <QQuickWindow>
0025 #include <QSortFilterProxyModel>
0026 
0027 #include "kwindecorationdata.h"
0028 #include "kwindecorationsettings.h"
0029 
0030 K_PLUGIN_FACTORY_WITH_JSON(KCMKWinDecorationFactory, "kcm_kwindecoration.json", registerPlugin<KCMKWinDecoration>(); registerPlugin<KWinDecorationData>();)
0031 
0032 Q_DECLARE_METATYPE(KDecoration2::BorderSize)
0033 
0034 namespace
0035 {
0036 const KDecoration2::BorderSize s_defaultRecommendedBorderSize = KDecoration2::BorderSize::Normal;
0037 }
0038 
0039 KCMKWinDecoration::KCMKWinDecoration(QObject *parent, const QVariantList &arguments)
0040     : KQuickAddons::ManagedConfigModule(parent, arguments)
0041     , m_themesModel(new KDecoration2::Configuration::DecorationsModel(this))
0042     , m_proxyThemesModel(new QSortFilterProxyModel(this))
0043     , m_leftButtonsModel(new KDecoration2::Preview::ButtonsModel(DecorationButtonsList(), this))
0044     , m_rightButtonsModel(new KDecoration2::Preview::ButtonsModel(DecorationButtonsList(), this))
0045     , m_availableButtonsModel(new KDecoration2::Preview::ButtonsModel(this))
0046     , m_data(new KWinDecorationData(this))
0047 {
0048     auto about = new KAboutData(QStringLiteral("kcm_kwindecoration"),
0049                                 i18n("Window Decorations"),
0050                                 QStringLiteral("1.0"),
0051                                 QString(),
0052                                 KAboutLicense::GPL);
0053     about->addAuthor(i18n("Valerio Pilo"),
0054                      i18n("Author"),
0055                      QStringLiteral("vpilo@coldshock.net"));
0056     setAboutData(about);
0057     setButtons(Apply | Default | Help);
0058     qmlRegisterAnonymousType<QAbstractListModel>("org.kde.kwin.KWinDecoration", 1);
0059     qmlRegisterAnonymousType<QSortFilterProxyModel>("org.kde.kwin.KWinDecoration", 1);
0060     qmlRegisterAnonymousType<KWinDecorationSettings>("org.kde.kwin.KWinDecoration", 1);
0061     m_proxyThemesModel->setSourceModel(m_themesModel);
0062     m_proxyThemesModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
0063     m_proxyThemesModel->setSortCaseSensitivity(Qt::CaseInsensitive);
0064     m_proxyThemesModel->sort(0);
0065 
0066     connect(m_data->settings(), &KWinDecorationSettings::themeChanged, this, &KCMKWinDecoration::themeChanged);
0067     connect(m_data->settings(), &KWinDecorationSettings::borderSizeChanged, this, &KCMKWinDecoration::borderSizeChanged);
0068 
0069     connect(m_data->settings(), &KWinDecorationSettings::borderSizeAutoChanged, this, &KCMKWinDecoration::borderIndexChanged);
0070     connect(this, &KCMKWinDecoration::borderSizeChanged, this, &KCMKWinDecoration::borderIndexChanged);
0071     connect(this, &KCMKWinDecoration::themeChanged, this, &KCMKWinDecoration::borderIndexChanged);
0072 
0073     connect(this, &KCMKWinDecoration::themeChanged, this, [this]() {
0074         if (m_data->settings()->borderSizeAuto()) {
0075             setBorderSize(recommendedBorderSize());
0076         }
0077     });
0078 
0079     connect(m_leftButtonsModel, &QAbstractItemModel::rowsInserted, this, &KCMKWinDecoration::onLeftButtonsChanged);
0080     connect(m_leftButtonsModel, &QAbstractItemModel::rowsMoved, this, &KCMKWinDecoration::onLeftButtonsChanged);
0081     connect(m_leftButtonsModel, &QAbstractItemModel::rowsRemoved, this, &KCMKWinDecoration::onLeftButtonsChanged);
0082     connect(m_leftButtonsModel, &QAbstractItemModel::modelReset, this, &KCMKWinDecoration::onLeftButtonsChanged);
0083 
0084     connect(m_rightButtonsModel, &QAbstractItemModel::rowsInserted, this, &KCMKWinDecoration::onRightButtonsChanged);
0085     connect(m_rightButtonsModel, &QAbstractItemModel::rowsMoved, this, &KCMKWinDecoration::onRightButtonsChanged);
0086     connect(m_rightButtonsModel, &QAbstractItemModel::rowsRemoved, this, &KCMKWinDecoration::onRightButtonsChanged);
0087     connect(m_rightButtonsModel, &QAbstractItemModel::modelReset, this, &KCMKWinDecoration::onRightButtonsChanged);
0088 
0089     connect(this, &KCMKWinDecoration::borderSizeChanged, this, &KCMKWinDecoration::settingsChanged);
0090 
0091     // Update the themes when the color scheme or a theme's settings change
0092     QDBusConnection::sessionBus()
0093         .connect(QString(), QStringLiteral("/KWin"), QStringLiteral("org.kde.KWin"), QStringLiteral("reloadConfig"),
0094                  this, SLOT(reloadKWinSettings()));
0095 
0096     QMetaObject::invokeMethod(m_themesModel, &KDecoration2::Configuration::DecorationsModel::init, Qt::QueuedConnection);
0097 }
0098 
0099 KWinDecorationSettings *KCMKWinDecoration::settings() const
0100 {
0101     return m_data->settings();
0102 }
0103 
0104 void KCMKWinDecoration::reloadKWinSettings()
0105 {
0106     QMetaObject::invokeMethod(m_themesModel, &KDecoration2::Configuration::DecorationsModel::init, Qt::QueuedConnection);
0107 }
0108 
0109 void KCMKWinDecoration::load()
0110 {
0111     ManagedConfigModule::load();
0112 
0113     m_leftButtonsModel->replace(Utils::buttonsFromString(settings()->buttonsOnLeft()));
0114     m_rightButtonsModel->replace(Utils::buttonsFromString(settings()->buttonsOnRight()));
0115 
0116     setBorderSize(borderSizeIndexFromString(settings()->borderSize()));
0117 
0118     Q_EMIT themeChanged();
0119 }
0120 
0121 void KCMKWinDecoration::save()
0122 {
0123     if (!settings()->borderSizeAuto()) {
0124         settings()->setBorderSize(borderSizeIndexToString(m_borderSizeIndex));
0125     } else {
0126         settings()->setBorderSize(settings()->defaultBorderSizeValue());
0127     }
0128 
0129     ManagedConfigModule::save();
0130 
0131     // Send a signal to all kwin instances
0132     QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KWin"),
0133                                                       QStringLiteral("org.kde.KWin"),
0134                                                       QStringLiteral("reloadConfig"));
0135     QDBusConnection::sessionBus().send(message);
0136 }
0137 
0138 void KCMKWinDecoration::defaults()
0139 {
0140     ManagedConfigModule::defaults();
0141 
0142     setBorderSize(recommendedBorderSize());
0143 
0144     m_leftButtonsModel->replace(Utils::buttonsFromString(settings()->buttonsOnLeft()));
0145     m_rightButtonsModel->replace(Utils::buttonsFromString(settings()->buttonsOnRight()));
0146 }
0147 
0148 void KCMKWinDecoration::onLeftButtonsChanged()
0149 {
0150     settings()->setButtonsOnLeft(Utils::buttonsToString(m_leftButtonsModel->buttons()));
0151 }
0152 
0153 void KCMKWinDecoration::onRightButtonsChanged()
0154 {
0155     settings()->setButtonsOnRight(Utils::buttonsToString(m_rightButtonsModel->buttons()));
0156 }
0157 
0158 QSortFilterProxyModel *KCMKWinDecoration::themesModel() const
0159 {
0160     return m_proxyThemesModel;
0161 }
0162 
0163 QAbstractListModel *KCMKWinDecoration::leftButtonsModel()
0164 {
0165     return m_leftButtonsModel;
0166 }
0167 
0168 QAbstractListModel *KCMKWinDecoration::rightButtonsModel()
0169 {
0170     return m_rightButtonsModel;
0171 }
0172 
0173 QAbstractListModel *KCMKWinDecoration::availableButtonsModel() const
0174 {
0175     return m_availableButtonsModel;
0176 }
0177 
0178 QStringList KCMKWinDecoration::borderSizesModel() const
0179 {
0180     // Use index 0 for borderSizeAuto == true
0181     // The rest of indexes get offset by 1
0182     QStringList model = Utils::getBorderSizeNames().values();
0183     model.insert(0, i18nc("%1 is the name of a border size", "Theme's default (%1)", model.at(recommendedBorderSize())));
0184     return model;
0185 }
0186 
0187 int KCMKWinDecoration::borderIndex() const
0188 {
0189     return settings()->borderSizeAuto() ? 0 : m_borderSizeIndex + 1;
0190 }
0191 
0192 void KCMKWinDecoration::setBorderIndex(int index)
0193 {
0194     const bool borderAuto = (index == 0);
0195     settings()->setBorderSizeAuto(borderAuto);
0196     setBorderSize(borderAuto ? recommendedBorderSize() : index - 1);
0197 }
0198 
0199 int KCMKWinDecoration::borderSize() const
0200 {
0201     return m_borderSizeIndex;
0202 }
0203 
0204 int KCMKWinDecoration::recommendedBorderSize() const
0205 {
0206     typedef KDecoration2::Configuration::DecorationsModel::DecorationRole DecoRole;
0207     const QModelIndex proxyIndex = m_proxyThemesModel->index(theme(), 0);
0208     if (proxyIndex.isValid()) {
0209         const QModelIndex index = m_proxyThemesModel->mapToSource(proxyIndex);
0210         if (index.isValid()) {
0211             QVariant ret = m_themesModel->data(index, DecoRole::RecommendedBorderSizeRole);
0212             return Utils::getBorderSizeNames().keys().indexOf(Utils::stringToBorderSize(ret.toString()));
0213         }
0214     }
0215     return Utils::getBorderSizeNames().keys().indexOf(s_defaultRecommendedBorderSize);
0216 }
0217 
0218 int KCMKWinDecoration::theme() const
0219 {
0220     return m_proxyThemesModel->mapFromSource(m_themesModel->findDecoration(settings()->pluginName(), settings()->theme())).row();
0221 }
0222 
0223 void KCMKWinDecoration::setBorderSize(int index)
0224 {
0225     if (m_borderSizeIndex != index) {
0226         m_borderSizeIndex = index;
0227         Q_EMIT borderSizeChanged();
0228     }
0229 }
0230 
0231 void KCMKWinDecoration::setBorderSize(KDecoration2::BorderSize size)
0232 {
0233     settings()->setBorderSize(Utils::borderSizeToString(size));
0234 }
0235 
0236 void KCMKWinDecoration::setTheme(int index)
0237 {
0238     QModelIndex dataIndex = m_proxyThemesModel->index(index, 0);
0239     if (dataIndex.isValid()) {
0240         settings()->setTheme(m_proxyThemesModel->data(dataIndex, KDecoration2::Configuration::DecorationsModel::ThemeNameRole).toString());
0241         settings()->setPluginName(m_proxyThemesModel->data(dataIndex, KDecoration2::Configuration::DecorationsModel::PluginNameRole).toString());
0242         Q_EMIT themeChanged();
0243     }
0244 }
0245 
0246 bool KCMKWinDecoration::isSaveNeeded() const
0247 {
0248     return !settings()->borderSizeAuto() && borderSizeIndexFromString(settings()->borderSize()) != m_borderSizeIndex;
0249 }
0250 
0251 int KCMKWinDecoration::borderSizeIndexFromString(const QString &size) const
0252 {
0253     return Utils::getBorderSizeNames().keys().indexOf(Utils::stringToBorderSize(size));
0254 }
0255 
0256 QString KCMKWinDecoration::borderSizeIndexToString(int index) const
0257 {
0258     return Utils::borderSizeToString(Utils::getBorderSizeNames().keys().at(index));
0259 }
0260 
0261 #include "kcm.moc"
0262 #include "moc_kcm.cpp"