File indexing completed on 2024-05-12 05:31:25

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 "compositor.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     s_buttonNames[KDecoration2::DecorationButtonType::Spacer] = QChar('_');
0084 }
0085 
0086 static QString buttonsToString(const QList<KDecoration2::DecorationButtonType> &buttons)
0087 {
0088     auto buttonToString = [](KDecoration2::DecorationButtonType button) -> QChar {
0089         const auto it = s_buttonNames.constFind(button);
0090         if (it != s_buttonNames.constEnd()) {
0091             return it.value();
0092         }
0093         return QChar();
0094     };
0095     QString ret;
0096     for (auto button : buttons) {
0097         ret.append(buttonToString(button));
0098     }
0099     return ret;
0100 }
0101 
0102 QList<KDecoration2::DecorationButtonType> SettingsImpl::readDecorationButtons(const KConfigGroup &config,
0103                                                                               const char *key,
0104                                                                               const QList<KDecoration2::DecorationButtonType> &defaultValue) const
0105 {
0106     initButtons();
0107     auto buttonsFromString = [](const QString &buttons) -> QList<KDecoration2::DecorationButtonType> {
0108         QList<KDecoration2::DecorationButtonType> ret;
0109         for (auto it = buttons.begin(); it != buttons.end(); ++it) {
0110             for (auto it2 = s_buttonNames.constBegin(); it2 != s_buttonNames.constEnd(); ++it2) {
0111                 if (it2.value() == (*it)) {
0112                     ret << it2.key();
0113                 }
0114             }
0115         }
0116         return ret;
0117     };
0118     return buttonsFromString(config.readEntry(key, buttonsToString(defaultValue)));
0119 }
0120 
0121 static KDecoration2::BorderSize stringToSize(const QString &name)
0122 {
0123     static const QMap<QString, KDecoration2::BorderSize> s_sizes = QMap<QString, KDecoration2::BorderSize>({{QStringLiteral("None"), KDecoration2::BorderSize::None},
0124                                                                                                             {QStringLiteral("NoSides"), KDecoration2::BorderSize::NoSides},
0125                                                                                                             {QStringLiteral("Tiny"), KDecoration2::BorderSize::Tiny},
0126                                                                                                             {QStringLiteral("Normal"), KDecoration2::BorderSize::Normal},
0127                                                                                                             {QStringLiteral("Large"), KDecoration2::BorderSize::Large},
0128                                                                                                             {QStringLiteral("VeryLarge"), KDecoration2::BorderSize::VeryLarge},
0129                                                                                                             {QStringLiteral("Huge"), KDecoration2::BorderSize::Huge},
0130                                                                                                             {QStringLiteral("VeryHuge"), KDecoration2::BorderSize::VeryHuge},
0131                                                                                                             {QStringLiteral("Oversized"), KDecoration2::BorderSize::Oversized}});
0132     auto it = s_sizes.constFind(name);
0133     if (it == s_sizes.constEnd()) {
0134         // non sense values are interpreted just like normal
0135         return KDecoration2::BorderSize::Normal;
0136     }
0137     return it.value();
0138 }
0139 
0140 void SettingsImpl::readSettings()
0141 {
0142     KConfigGroup config = kwinApp()->config()->group(QStringLiteral("org.kde.kdecoration2"));
0143     const auto &left = readDecorationButtons(config, "ButtonsOnLeft", QList<KDecoration2::DecorationButtonType>({KDecoration2::DecorationButtonType::Menu, KDecoration2::DecorationButtonType::OnAllDesktops}));
0144     if (left != m_leftButtons) {
0145         m_leftButtons = left;
0146         Q_EMIT decorationSettings()->decorationButtonsLeftChanged(m_leftButtons);
0147     }
0148     const auto &right = readDecorationButtons(config, "ButtonsOnRight", QList<KDecoration2::DecorationButtonType>({KDecoration2::DecorationButtonType::ContextHelp, KDecoration2::DecorationButtonType::Minimize, KDecoration2::DecorationButtonType::Maximize, KDecoration2::DecorationButtonType::Close}));
0149     if (right != m_rightButtons) {
0150         m_rightButtons = right;
0151         Q_EMIT decorationSettings()->decorationButtonsRightChanged(m_rightButtons);
0152     }
0153     Workspace::self()->applicationMenu()->setViewEnabled(left.contains(KDecoration2::DecorationButtonType::ApplicationMenu) || right.contains(KDecoration2::DecorationButtonType::ApplicationMenu));
0154     const bool close = config.readEntry("CloseOnDoubleClickOnMenu", false);
0155     if (close != m_closeDoubleClickMenu) {
0156         m_closeDoubleClickMenu = close;
0157         Q_EMIT decorationSettings()->closeOnDoubleClickOnMenuChanged(m_closeDoubleClickMenu);
0158     }
0159     m_autoBorderSize = config.readEntry("BorderSizeAuto", true);
0160 
0161     auto size = stringToSize(config.readEntry("BorderSize", QStringLiteral("Normal")));
0162     if (m_autoBorderSize) {
0163         /* Falls back to Normal border size, if the plugin does not provide a valid recommendation. */
0164         size = stringToSize(Workspace::self()->decorationBridge()->recommendedBorderSize());
0165     }
0166     if (size != m_borderSize) {
0167         m_borderSize = size;
0168         Q_EMIT decorationSettings()->borderSizeChanged(m_borderSize);
0169     }
0170     const QFont font = QFontDatabase::systemFont(QFontDatabase::TitleFont);
0171     if (font != m_font) {
0172         m_font = font;
0173         Q_EMIT decorationSettings()->fontChanged(m_font);
0174     }
0175 
0176     Q_EMIT decorationSettings()->reconfigured();
0177 }
0178 
0179 }
0180 }
0181 
0182 #include "moc_settings.cpp"