File indexing completed on 2024-11-10 04:56:52
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2009 Martin Gräßlin <mgraesslin@kde.org> 0006 SPDX-FileCopyrightText: 2020 Cyril Rossi <cyril.rossi@enioka.com> 0007 SPDX-FileCopyrightText: 2023 Ismael Asensio <isma.af@gmail.com> 0008 0009 SPDX-License-Identifier: GPL-2.0-or-later 0010 */ 0011 #include "main.h" 0012 #include <kwin_effects_interface.h> 0013 0014 // Qt 0015 #include <QDBusConnection> 0016 #include <QDBusMessage> 0017 #include <QDialog> 0018 #include <QDialogButtonBox> 0019 #include <QHBoxLayout> 0020 #include <QPointer> 0021 #include <QPushButton> 0022 #include <QSpacerItem> 0023 #include <QStandardItemModel> 0024 #include <QStandardPaths> 0025 #include <QTabWidget> 0026 #include <QVBoxLayout> 0027 0028 // KDE 0029 #include <KLocalizedString> 0030 #include <KNSWidgets/Button> 0031 #include <KPluginFactory> 0032 #include <KTitleWidget> 0033 // Plasma 0034 #include <KPackage/Package> 0035 #include <KPackage/PackageLoader> 0036 0037 // own 0038 #include "kwinpluginssettings.h" 0039 #include "kwintabboxconfigform.h" 0040 #include "kwintabboxdata.h" 0041 #include "kwintabboxsettings.h" 0042 #include "layoutpreview.h" 0043 #include "shortcutsettings.h" 0044 0045 K_PLUGIN_FACTORY_WITH_JSON(KWinTabBoxConfigFactory, "kcm_kwintabbox.json", registerPlugin<KWin::KWinTabBoxConfig>(); registerPlugin<KWin::TabBox::KWinTabboxData>();) 0046 0047 namespace KWin 0048 { 0049 0050 using namespace TabBox; 0051 0052 KWinTabBoxConfig::KWinTabBoxConfig(QObject *parent, const KPluginMetaData &data) 0053 : KCModule(parent, data) 0054 , m_config(KSharedConfig::openConfig("kwinrc")) 0055 , m_data(new KWinTabboxData(this)) 0056 { 0057 QTabWidget *tabWidget = new QTabWidget(widget()); 0058 m_primaryTabBoxUi = new KWinTabBoxConfigForm(KWinTabBoxConfigForm::TabboxType::Main, 0059 m_data->tabBoxConfig(), 0060 m_data->shortcutConfig(), 0061 tabWidget); 0062 m_alternativeTabBoxUi = new KWinTabBoxConfigForm(KWinTabBoxConfigForm::TabboxType::Alternative, 0063 m_data->tabBoxAlternativeConfig(), 0064 m_data->shortcutConfig(), 0065 tabWidget); 0066 tabWidget->addTab(m_primaryTabBoxUi, i18n("Main")); 0067 tabWidget->addTab(m_alternativeTabBoxUi, i18n("Alternative")); 0068 0069 KNSWidgets::Button *ghnsButton = new KNSWidgets::Button(i18n("Get New Task Switchers..."), QStringLiteral("kwinswitcher.knsrc"), widget()); 0070 connect(ghnsButton, &KNSWidgets::Button::dialogFinished, this, [this](auto changedEntries) { 0071 if (!changedEntries.isEmpty()) { 0072 initLayoutLists(); 0073 } 0074 }); 0075 0076 QHBoxLayout *buttonBar = new QHBoxLayout(); 0077 QSpacerItem *buttonBarSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); 0078 buttonBar->addItem(buttonBarSpacer); 0079 buttonBar->addWidget(ghnsButton); 0080 0081 QVBoxLayout *layout = new QVBoxLayout(widget()); 0082 KTitleWidget *infoLabel = new KTitleWidget(tabWidget); 0083 infoLabel->setText(i18n("Focus policy settings limit the functionality of navigating through windows."), 0084 KTitleWidget::InfoMessage); 0085 infoLabel->setIcon(KTitleWidget::InfoMessage, KTitleWidget::ImageLeft); 0086 layout->addWidget(infoLabel, 0); 0087 layout->addWidget(tabWidget, 1); 0088 layout->addLayout(buttonBar); 0089 widget()->setLayout(layout); 0090 0091 addConfig(m_data->tabBoxConfig(), m_primaryTabBoxUi); 0092 addConfig(m_data->tabBoxAlternativeConfig(), m_alternativeTabBoxUi); 0093 0094 initLayoutLists(); 0095 0096 createConnections(m_primaryTabBoxUi); 0097 createConnections(m_alternativeTabBoxUi); 0098 0099 // check focus policy - we don't offer configs for unreasonable focus policies 0100 KConfigGroup config(m_config, QStringLiteral("Windows")); 0101 QString policy = config.readEntry("FocusPolicy", "ClickToFocus"); 0102 if ((policy == "FocusUnderMouse") || (policy == "FocusStrictlyUnderMouse")) { 0103 tabWidget->setEnabled(false); 0104 infoLabel->show(); 0105 } else { 0106 infoLabel->hide(); 0107 } 0108 } 0109 0110 KWinTabBoxConfig::~KWinTabBoxConfig() 0111 { 0112 } 0113 0114 static QList<KPackage::Package> availableLnFPackages() 0115 { 0116 QList<KPackage::Package> packages; 0117 QStringList paths; 0118 const QStringList dataPaths = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); 0119 0120 for (const QString &path : dataPaths) { 0121 QDir dir(path + QLatin1String("/plasma/look-and-feel")); 0122 paths << dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); 0123 } 0124 0125 const auto &p = paths; 0126 for (const QString &path : p) { 0127 KPackage::Package pkg = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/LookAndFeel")); 0128 pkg.setPath(path); 0129 pkg.setFallbackPackage(KPackage::Package()); 0130 if (!pkg.filePath("defaults").isEmpty()) { 0131 KSharedConfigPtr conf = KSharedConfig::openConfig(pkg.filePath("defaults")); 0132 KConfigGroup cg = KConfigGroup(conf, QStringLiteral("kwinrc")); 0133 cg = KConfigGroup(&cg, QStringLiteral("WindowSwitcher")); 0134 if (!cg.readEntry("LayoutName", QString()).isEmpty()) { 0135 packages << pkg; 0136 } 0137 } 0138 } 0139 0140 return packages; 0141 } 0142 0143 void KWinTabBoxConfig::initLayoutLists() 0144 { 0145 QList<KPluginMetaData> offers = KPackage::PackageLoader::self()->listPackages("KWin/WindowSwitcher"); 0146 QStandardItemModel *model = new QStandardItemModel; 0147 0148 auto addToModel = [model](const QString &name, const QString &pluginId, const QString &path) { 0149 QStandardItem *item = new QStandardItem(name); 0150 item->setData(pluginId, Qt::UserRole); 0151 item->setData(path, KWinTabBoxConfigForm::LayoutPath); 0152 item->setData(true, KWinTabBoxConfigForm::AddonEffect); 0153 model->appendRow(item); 0154 }; 0155 0156 const auto lnfPackages = availableLnFPackages(); 0157 for (const auto &package : lnfPackages) { 0158 const auto &metaData = package.metadata(); 0159 const QString switcherFile = package.filePath("windowswitcher", QStringLiteral("WindowSwitcher.qml")); 0160 if (switcherFile.isEmpty()) { 0161 // Skip lnfs that don't actually ship a switcher 0162 continue; 0163 } 0164 0165 addToModel(metaData.name(), metaData.pluginId(), switcherFile); 0166 } 0167 0168 for (const auto &offer : offers) { 0169 const QString pluginName = offer.pluginId(); 0170 const QString scriptFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, 0171 QLatin1String("kwin/tabbox/") + pluginName + QLatin1String("/contents/ui/main.qml")); 0172 if (scriptFile.isEmpty()) { 0173 qWarning() << "scriptfile is null" << pluginName; 0174 continue; 0175 } 0176 0177 addToModel(offer.name(), pluginName, scriptFile); 0178 } 0179 0180 model->sort(0); 0181 0182 m_primaryTabBoxUi->setEffectComboModel(model); 0183 m_alternativeTabBoxUi->setEffectComboModel(model); 0184 } 0185 0186 void KWinTabBoxConfig::createConnections(KWinTabBoxConfigForm *form) 0187 { 0188 connect(form, &KWinTabBoxConfigForm::effectConfigButtonClicked, this, &KWinTabBoxConfig::configureEffectClicked); 0189 connect(form, &KWinTabBoxConfigForm::configChanged, this, &KWinTabBoxConfig::updateUnmanagedState); 0190 0191 connect(this, &KWinTabBoxConfig::defaultsIndicatorsVisibleChanged, form, [form, this]() { 0192 form->setDefaultIndicatorVisible(defaultsIndicatorsVisible()); 0193 }); 0194 } 0195 0196 void KWinTabBoxConfig::updateUnmanagedState() 0197 { 0198 const bool isNeedSave = m_data->tabBoxConfig()->isSaveNeeded() 0199 || m_data->tabBoxAlternativeConfig()->isSaveNeeded() 0200 || m_data->shortcutConfig()->isSaveNeeded(); 0201 0202 unmanagedWidgetChangeState(isNeedSave); 0203 0204 const bool isDefault = m_data->tabBoxConfig()->isDefaults() 0205 && m_data->tabBoxAlternativeConfig()->isDefaults() 0206 && m_data->shortcutConfig()->isDefaults(); 0207 0208 unmanagedWidgetDefaultState(isDefault); 0209 } 0210 0211 void KWinTabBoxConfig::load() 0212 { 0213 KCModule::load(); 0214 0215 m_data->tabBoxConfig()->load(); 0216 m_data->tabBoxAlternativeConfig()->load(); 0217 m_data->shortcutConfig()->load(); 0218 0219 m_data->pluginsConfig()->load(); 0220 0221 m_primaryTabBoxUi->updateUiFromConfig(); 0222 m_alternativeTabBoxUi->updateUiFromConfig(); 0223 0224 updateUnmanagedState(); 0225 } 0226 0227 void KWinTabBoxConfig::save() 0228 { 0229 // effects 0230 const bool highlightWindows = m_primaryTabBoxUi->highlightWindows() || m_alternativeTabBoxUi->highlightWindows(); 0231 0232 // activate effects if they are used otherwise deactivate them. 0233 m_data->pluginsConfig()->setHighlightwindowEnabled(highlightWindows); 0234 m_data->pluginsConfig()->save(); 0235 0236 m_data->tabBoxConfig()->save(); 0237 m_data->tabBoxAlternativeConfig()->save(); 0238 m_data->shortcutConfig()->save(); 0239 0240 KCModule::save(); 0241 updateUnmanagedState(); 0242 0243 // Reload KWin. 0244 QDBusMessage message = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig"); 0245 QDBusConnection::sessionBus().send(message); 0246 } 0247 0248 void KWinTabBoxConfig::defaults() 0249 { 0250 m_data->tabBoxConfig()->setDefaults(); 0251 m_data->tabBoxAlternativeConfig()->setDefaults(); 0252 m_data->shortcutConfig()->setDefaults(); 0253 0254 m_primaryTabBoxUi->updateUiFromConfig(); 0255 m_alternativeTabBoxUi->updateUiFromConfig(); 0256 0257 KCModule::defaults(); 0258 updateUnmanagedState(); 0259 } 0260 void KWinTabBoxConfig::configureEffectClicked() 0261 { 0262 auto form = qobject_cast<KWinTabBoxConfigForm *>(sender()); 0263 Q_ASSERT(form); 0264 0265 if (form->effectComboCurrentData(KWinTabBoxConfigForm::AddonEffect).toBool()) { 0266 // Show the preview for addon effect 0267 new LayoutPreview(form->effectComboCurrentData(KWinTabBoxConfigForm::LayoutPath).toString(), 0268 form->config()->showDesktopMode(), 0269 this); 0270 } 0271 } 0272 0273 } // namespace 0274 0275 #include "main.moc" 0276 0277 #include "moc_main.cpp"