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 }