File indexing completed on 2024-05-19 16:34:03

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include <config-kwin.h>
0010 
0011 #include "appmenu.h"
0012 #include "composite.h"
0013 #include "decorationbridge.h"
0014 #include "settings.h"
0015 #include "virtualdesktops.h"
0016 #include "workspace.h"
0017 
0018 #include <KConfigGroup>
0019 #include <KDecoration2/DecorationSettings>
0020 
0021 #include <QFontDatabase>
0022 
0023 namespace KWin
0024 {
0025 namespace Decoration
0026 {
0027 SettingsImpl::SettingsImpl(KDecoration2::DecorationSettings *parent)
0028     : QObject()
0029     , DecorationSettingsPrivate(parent)
0030     , m_borderSize(KDecoration2::BorderSize::Normal)
0031 {
0032     readSettings();
0033 
0034     auto c = connect(Compositor::self(), &Compositor::compositingToggled,
0035                      parent, &KDecoration2::DecorationSettings::alphaChannelSupportedChanged);
0036     connect(VirtualDesktopManager::self(), &VirtualDesktopManager::countChanged, this, [parent](uint previous, uint current) {
0037         if (previous != 1 && current != 1) {
0038             return;
0039         }
0040         Q_EMIT parent->onAllDesktopsAvailableChanged(current > 1);
0041     });
0042     // prevent changes in Decoration due to Compositor being destroyed
0043     connect(Compositor::self(), &Compositor::aboutToDestroy, this, [c]() {
0044         disconnect(c);
0045     });
0046     connect(Workspace::self(), &Workspace::configChanged, this, &SettingsImpl::readSettings);
0047     connect(Workspace::self()->decorationBridge(), &DecorationBridge::metaDataLoaded, this, &SettingsImpl::readSettings);
0048 }
0049 
0050 SettingsImpl::~SettingsImpl() = default;
0051 
0052 bool SettingsImpl::isAlphaChannelSupported() const
0053 {
0054     return Compositor::self()->compositing();
0055 }
0056 
0057 bool SettingsImpl::isOnAllDesktopsAvailable() const
0058 {
0059     return VirtualDesktopManager::self()->count() > 1;
0060 }
0061 
0062 bool SettingsImpl::isCloseOnDoubleClickOnMenu() const
0063 {
0064     return m_closeDoubleClickMenu;
0065 }
0066 
0067 static QHash<KDecoration2::DecorationButtonType, QChar> s_buttonNames;
0068 static void initButtons()
0069 {
0070     if (!s_buttonNames.isEmpty()) {
0071         return;
0072     }
0073     s_buttonNames[KDecoration2::DecorationButtonType::Menu] = QChar('M');
0074     s_buttonNames[KDecoration2::DecorationButtonType::ApplicationMenu] = QChar('N');
0075     s_buttonNames[KDecoration2::DecorationButtonType::OnAllDesktops] = QChar('S');
0076     s_buttonNames[KDecoration2::DecorationButtonType::ContextHelp] = QChar('H');
0077     s_buttonNames[KDecoration2::DecorationButtonType::Minimize] = QChar('I');
0078     s_buttonNames[KDecoration2::DecorationButtonType::Maximize] = QChar('A');
0079     s_buttonNames[KDecoration2::DecorationButtonType::Close] = QChar('X');
0080     s_buttonNames[KDecoration2::DecorationButtonType::KeepAbove] = QChar('F');
0081     s_buttonNames[KDecoration2::DecorationButtonType::KeepBelow] = QChar('B');
0082     s_buttonNames[KDecoration2::DecorationButtonType::Shade] = QChar('L');
0083 }
0084 
0085 static QString buttonsToString(const QVector<KDecoration2::DecorationButtonType> &buttons)
0086 {
0087     auto buttonToString = [](KDecoration2::DecorationButtonType button) -> QChar {
0088         const auto it = s_buttonNames.constFind(button);
0089         if (it != s_buttonNames.constEnd()) {
0090             return it.value();
0091         }
0092         return QChar();
0093     };
0094     QString ret;
0095     for (auto button : buttons) {
0096         ret.append(buttonToString(button));
0097     }
0098     return ret;
0099 }
0100 
0101 QVector<KDecoration2::DecorationButtonType> SettingsImpl::readDecorationButtons(const KConfigGroup &config,
0102                                                                                 const char *key,
0103                                                                                 const QVector<KDecoration2::DecorationButtonType> &defaultValue) const
0104 {
0105     initButtons();
0106     auto buttonsFromString = [](const QString &buttons) -> QVector<KDecoration2::DecorationButtonType> {
0107         QVector<KDecoration2::DecorationButtonType> ret;
0108         for (auto it = buttons.begin(); it != buttons.end(); ++it) {
0109             for (auto it2 = s_buttonNames.constBegin(); it2 != s_buttonNames.constEnd(); ++it2) {
0110                 if (it2.value() == (*it)) {
0111                     ret << it2.key();
0112                 }
0113             }
0114         }
0115         return ret;
0116     };
0117     return buttonsFromString(config.readEntry(key, buttonsToString(defaultValue)));
0118 }
0119 
0120 static KDecoration2::BorderSize stringToSize(const QString &name)
0121 {
0122     static const QMap<QString, KDecoration2::BorderSize> s_sizes = QMap<QString, KDecoration2::BorderSize>({{QStringLiteral("None"), KDecoration2::BorderSize::None},
0123                                                                                                             {QStringLiteral("NoSides"), KDecoration2::BorderSize::NoSides},
0124                                                                                                             {QStringLiteral("Tiny"), KDecoration2::BorderSize::Tiny},
0125                                                                                                             {QStringLiteral("Normal"), KDecoration2::BorderSize::Normal},
0126                                                                                                             {QStringLiteral("Large"), KDecoration2::BorderSize::Large},
0127                                                                                                             {QStringLiteral("VeryLarge"), KDecoration2::BorderSize::VeryLarge},
0128                                                                                                             {QStringLiteral("Huge"), KDecoration2::BorderSize::Huge},
0129                                                                                                             {QStringLiteral("VeryHuge"), KDecoration2::BorderSize::VeryHuge},
0130                                                                                                             {QStringLiteral("Oversized"), KDecoration2::BorderSize::Oversized}});
0131     auto it = s_sizes.constFind(name);
0132     if (it == s_sizes.constEnd()) {
0133         // non sense values are interpreted just like normal
0134         return KDecoration2::BorderSize::Normal;
0135     }
0136     return it.value();
0137 }
0138 
0139 void SettingsImpl::readSettings()
0140 {
0141     KConfigGroup config = kwinApp()->config()->group(QStringLiteral("org.kde.kdecoration2"));
0142     const auto &left = readDecorationButtons(config, "ButtonsOnLeft", QVector<KDecoration2::DecorationButtonType>({KDecoration2::DecorationButtonType::Menu, KDecoration2::DecorationButtonType::OnAllDesktops}));
0143     if (left != m_leftButtons) {
0144         m_leftButtons = left;
0145         Q_EMIT decorationSettings()->decorationButtonsLeftChanged(m_leftButtons);
0146     }
0147     const auto &right = readDecorationButtons(config, "ButtonsOnRight", QVector<KDecoration2::DecorationButtonType>({KDecoration2::DecorationButtonType::ContextHelp, KDecoration2::DecorationButtonType::Minimize, KDecoration2::DecorationButtonType::Maximize, KDecoration2::DecorationButtonType::Close}));
0148     if (right != m_rightButtons) {
0149         m_rightButtons = right;
0150         Q_EMIT decorationSettings()->decorationButtonsRightChanged(m_rightButtons);
0151     }
0152     Workspace::self()->applicationMenu()->setViewEnabled(left.contains(KDecoration2::DecorationButtonType::ApplicationMenu) || right.contains(KDecoration2::DecorationButtonType::ApplicationMenu));
0153     const bool close = config.readEntry("CloseOnDoubleClickOnMenu", false);
0154     if (close != m_closeDoubleClickMenu) {
0155         m_closeDoubleClickMenu = close;
0156         Q_EMIT decorationSettings()->closeOnDoubleClickOnMenuChanged(m_closeDoubleClickMenu);
0157     }
0158     m_autoBorderSize = config.readEntry("BorderSizeAuto", true);
0159 
0160     auto size = stringToSize(config.readEntry("BorderSize", QStringLiteral("Normal")));
0161     if (m_autoBorderSize) {
0162         /* Falls back to Normal border size, if the plugin does not provide a valid recommendation. */
0163         size = stringToSize(Workspace::self()->decorationBridge()->recommendedBorderSize());
0164     }
0165     if (size != m_borderSize) {
0166         m_borderSize = size;
0167         Q_EMIT decorationSettings()->borderSizeChanged(m_borderSize);
0168     }
0169     const QFont font = QFontDatabase::systemFont(QFontDatabase::TitleFont);
0170     if (font != m_font) {
0171         m_font = font;
0172         Q_EMIT decorationSettings()->fontChanged(m_font);
0173     }
0174 
0175     Q_EMIT decorationSettings()->reconfigured();
0176 }
0177 
0178 }
0179 }