File indexing completed on 2024-11-10 04:56:51

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2008 Martin Gräßlin <mgraesslin@kde.org>
0006     SPDX-FileCopyrightText: 2009 Lucas Murray <lmurray@undefinedfire.com>
0007     SPDX-FileCopyrightText: 2020 Cyril Rossi <cyril.rossi@enioka.com>
0008 
0009     SPDX-License-Identifier: GPL-2.0-or-later
0010 */
0011 
0012 #include "main.h"
0013 #include <kwin_effects_interface.h>
0014 
0015 #include <KConfigGroup>
0016 #include <KLocalizedString>
0017 #include <KPackage/Package>
0018 #include <KPackage/PackageLoader>
0019 #include <KPluginFactory>
0020 #include <QDBusConnection>
0021 #include <QVBoxLayout>
0022 
0023 #include "kwinscreenedgeconfigform.h"
0024 #include "kwinscreenedgedata.h"
0025 #include "kwinscreenedgeeffectsettings.h"
0026 #include "kwinscreenedgescriptsettings.h"
0027 #include "kwinscreenedgesettings.h"
0028 
0029 K_PLUGIN_FACTORY_WITH_JSON(KWinScreenEdgesConfigFactory, "kcm_kwinscreenedges.json", registerPlugin<KWin::KWinScreenEdgesConfig>(); registerPlugin<KWin::KWinScreenEdgeData>();)
0030 
0031 namespace KWin
0032 {
0033 
0034 KWinScreenEdgesConfig::KWinScreenEdgesConfig(QObject *parent, const KPluginMetaData &data)
0035     : KCModule(parent, data)
0036     , m_form(new KWinScreenEdgesConfigForm(widget()))
0037     , m_config(KSharedConfig::openConfig("kwinrc"))
0038     , m_data(new KWinScreenEdgeData(this))
0039 {
0040     QVBoxLayout *layout = new QVBoxLayout(widget());
0041     layout->addWidget(m_form);
0042 
0043     addConfig(m_data->settings(), m_form);
0044 
0045     monitorInit();
0046 
0047     connect(this, &KWinScreenEdgesConfig::defaultsIndicatorsVisibleChanged, m_form, [this]() {
0048         m_form->setDefaultsIndicatorsVisible(defaultsIndicatorsVisible());
0049     });
0050     connect(m_form, &KWinScreenEdgesConfigForm::saveNeededChanged, this, &KWinScreenEdgesConfig::unmanagedWidgetChangeState);
0051     connect(m_form, &KWinScreenEdgesConfigForm::defaultChanged, this, &KWinScreenEdgesConfig::unmanagedWidgetDefaultState);
0052 }
0053 
0054 KWinScreenEdgesConfig::~KWinScreenEdgesConfig()
0055 {
0056 }
0057 
0058 void KWinScreenEdgesConfig::load()
0059 {
0060     KCModule::load();
0061     m_data->settings()->load();
0062     for (KWinScreenEdgeScriptSettings *setting : std::as_const(m_scriptSettings)) {
0063         setting->load();
0064     }
0065     for (KWinScreenEdgeEffectSettings *setting : std::as_const(m_effectSettings)) {
0066         setting->load();
0067     }
0068 
0069     monitorLoadSettings();
0070     monitorLoadDefaultSettings();
0071     m_form->setRemainActiveOnFullscreen(m_data->settings()->remainActiveOnFullscreen());
0072     m_form->setElectricBorderCornerRatio(m_data->settings()->electricBorderCornerRatio());
0073     m_form->setDefaultElectricBorderCornerRatio(m_data->settings()->defaultElectricBorderCornerRatioValue());
0074     m_form->reload();
0075 }
0076 
0077 void KWinScreenEdgesConfig::save()
0078 {
0079     monitorSaveSettings();
0080     m_data->settings()->setRemainActiveOnFullscreen(m_form->remainActiveOnFullscreen());
0081     m_data->settings()->setElectricBorderCornerRatio(m_form->electricBorderCornerRatio());
0082     m_data->settings()->save();
0083     for (KWinScreenEdgeScriptSettings *setting : std::as_const(m_scriptSettings)) {
0084         setting->save();
0085     }
0086     for (KWinScreenEdgeEffectSettings *setting : std::as_const(m_effectSettings)) {
0087         setting->save();
0088     }
0089 
0090     // Reload saved settings to ScreenEdge UI
0091     monitorLoadSettings();
0092     m_form->setElectricBorderCornerRatio(m_data->settings()->electricBorderCornerRatio());
0093     m_form->setRemainActiveOnFullscreen(m_data->settings()->remainActiveOnFullscreen());
0094     m_form->reload();
0095 
0096     // Reload KWin.
0097     QDBusMessage message = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
0098     QDBusConnection::sessionBus().send(message);
0099     // and reconfigure the effects
0100     OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"),
0101                                          QStringLiteral("/Effects"),
0102                                          QDBusConnection::sessionBus());
0103 
0104     interface.reconfigureEffect(QStringLiteral("overview"));
0105     interface.reconfigureEffect(QStringLiteral("windowview"));
0106 
0107     for (const auto &effectId : std::as_const(m_effects)) {
0108         interface.reconfigureEffect(effectId);
0109     }
0110 
0111     KCModule::save();
0112 }
0113 
0114 void KWinScreenEdgesConfig::defaults()
0115 {
0116     m_form->setDefaults();
0117 
0118     KCModule::defaults();
0119 }
0120 
0121 //-----------------------------------------------------------------------------
0122 // Monitor
0123 
0124 static QList<KPluginMetaData> listBuiltinEffects()
0125 {
0126     const QString rootDirectory = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
0127                                                          QStringLiteral("kwin/builtin-effects"),
0128                                                          QStandardPaths::LocateDirectory);
0129 
0130     QList<KPluginMetaData> ret;
0131 
0132     const QStringList nameFilters{QStringLiteral("*.json")};
0133     QDirIterator it(rootDirectory, nameFilters, QDir::Files);
0134     while (it.hasNext()) {
0135         it.next();
0136         if (const KPluginMetaData metaData = KPluginMetaData::fromJsonFile(it.filePath()); metaData.isValid()) {
0137             ret.append(metaData);
0138         }
0139     }
0140 
0141     return ret;
0142 }
0143 
0144 static QList<KPluginMetaData> listScriptedEffects()
0145 {
0146     return KPackage::PackageLoader::self()->listPackages(QStringLiteral("KWin/Effect"), QStringLiteral("kwin/effects/"));
0147 }
0148 
0149 void KWinScreenEdgesConfig::monitorInit()
0150 {
0151     m_form->monitorAddItem(i18n("No Action"));
0152     m_form->monitorAddItem(i18n("Peek at Desktop"));
0153     m_form->monitorAddItem(i18n("Lock Screen"));
0154     m_form->monitorAddItem(i18n("Show KRunner"));
0155     m_form->monitorAddItem(i18n("Activity Manager"));
0156     m_form->monitorAddItem(i18n("Application Launcher"));
0157 
0158     // TODO: Find a better way to get the display name of the present windows,
0159     // Maybe install metadata.json files?
0160     const QString presentWindowsName = i18n("Present Windows");
0161     m_form->monitorAddItem(i18n("%1 - All Desktops", presentWindowsName));
0162     m_form->monitorAddItem(i18n("%1 - Current Desktop", presentWindowsName));
0163     m_form->monitorAddItem(i18n("%1 - Current Application", presentWindowsName));
0164 
0165     m_form->monitorAddItem(i18n("Overview"));
0166 
0167     m_form->monitorAddItem(i18n("Toggle window switching"));
0168     m_form->monitorAddItem(i18n("Toggle alternative window switching"));
0169 
0170     KConfigGroup config(m_config, QStringLiteral("Plugins"));
0171     const auto effects = listBuiltinEffects() << listScriptedEffects();
0172 
0173     for (const KPluginMetaData &effect : effects) {
0174         if (!effect.value(QStringLiteral("X-KWin-Border-Activate"), false)) {
0175             continue;
0176         }
0177 
0178         if (!config.readEntry(effect.pluginId() + QStringLiteral("Enabled"), effect.isEnabledByDefault())) {
0179             continue;
0180         }
0181         m_effects << effect.pluginId();
0182         m_form->monitorAddItem(effect.name());
0183         m_effectSettings[effect.pluginId()] = new KWinScreenEdgeEffectSettings(effect.pluginId(), this);
0184     }
0185 
0186     const QString scriptFolder = QStringLiteral("kwin/scripts/");
0187     const auto scripts = KPackage::PackageLoader::self()->listPackages(QStringLiteral("KWin/Script"), scriptFolder);
0188 
0189     for (const KPluginMetaData &script : scripts) {
0190         if (script.value(QStringLiteral("X-KWin-Border-Activate"), false) != true) {
0191             continue;
0192         }
0193 
0194         if (!config.readEntry(script.pluginId() + QStringLiteral("Enabled"), script.isEnabledByDefault())) {
0195             continue;
0196         }
0197         m_scripts << script.pluginId();
0198         m_form->monitorAddItem(script.name());
0199         m_scriptSettings[script.pluginId()] = new KWinScreenEdgeScriptSettings(script.pluginId(), this);
0200     }
0201 
0202     monitorShowEvent();
0203 }
0204 
0205 void KWinScreenEdgesConfig::monitorLoadSettings()
0206 {
0207     // Load ElectricBorderActions
0208     m_form->monitorChangeEdge(ElectricTop, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->top()));
0209     m_form->monitorChangeEdge(ElectricTopRight, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->topRight()));
0210     m_form->monitorChangeEdge(ElectricRight, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->right()));
0211     m_form->monitorChangeEdge(ElectricBottomRight, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->bottomRight()));
0212     m_form->monitorChangeEdge(ElectricBottom, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->bottom()));
0213     m_form->monitorChangeEdge(ElectricBottomLeft, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->bottomLeft()));
0214     m_form->monitorChangeEdge(ElectricLeft, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->left()));
0215     m_form->monitorChangeEdge(ElectricTopLeft, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->topLeft()));
0216 
0217     // Load effect-specific actions:
0218 
0219     // PresentWindows BorderActivateAll
0220     m_form->monitorChangeEdge(m_data->settings()->borderActivateAll(), PresentWindowsAll);
0221 
0222     // PresentWindows BorderActivate
0223     m_form->monitorChangeEdge(m_data->settings()->borderActivatePresentWindows(), PresentWindowsCurrent);
0224 
0225     // PresentWindows BorderActivateClass
0226     m_form->monitorChangeEdge(m_data->settings()->borderActivateClass(), PresentWindowsClass);
0227 
0228     // Overview
0229     m_form->monitorChangeEdge(m_data->settings()->borderActivateOverview(), Overview);
0230 
0231     // TabBox
0232     m_form->monitorChangeEdge(m_data->settings()->borderActivateTabBox(), TabBox);
0233     // Alternative TabBox
0234     m_form->monitorChangeEdge(m_data->settings()->borderAlternativeActivate(), TabBoxAlternative);
0235 
0236     // Dinamically loaded effects
0237     int lastIndex = EffectCount;
0238     for (int i = 0; i < m_effects.size(); i++) {
0239         m_form->monitorChangeEdge(m_effectSettings[m_effects[i]]->borderActivate(), lastIndex);
0240         ++lastIndex;
0241     }
0242 
0243     // Scripts
0244     for (int i = 0; i < m_scripts.size(); i++) {
0245         m_form->monitorChangeEdge(m_scriptSettings[m_scripts[i]]->borderActivate(), lastIndex);
0246         ++lastIndex;
0247     }
0248 }
0249 
0250 void KWinScreenEdgesConfig::monitorLoadDefaultSettings()
0251 {
0252     // Load ElectricBorderActions
0253     m_form->monitorChangeDefaultEdge(ElectricTop, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->defaultTopValue()));
0254     m_form->monitorChangeDefaultEdge(ElectricTopRight, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->defaultTopRightValue()));
0255     m_form->monitorChangeDefaultEdge(ElectricRight, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->defaultRightValue()));
0256     m_form->monitorChangeDefaultEdge(ElectricBottomRight, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->defaultBottomRightValue()));
0257     m_form->monitorChangeDefaultEdge(ElectricBottom, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->defaultBottomValue()));
0258     m_form->monitorChangeDefaultEdge(ElectricBottomLeft, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->defaultBottomLeftValue()));
0259     m_form->monitorChangeDefaultEdge(ElectricLeft, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->defaultLeftValue()));
0260     m_form->monitorChangeDefaultEdge(ElectricTopLeft, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->defaultTopLeftValue()));
0261 
0262     // Load effect-specific actions:
0263 
0264     // PresentWindows BorderActivateAll
0265     m_form->monitorChangeDefaultEdge(m_data->settings()->defaultBorderActivateAllValue(), PresentWindowsAll);
0266 
0267     // PresentWindows BorderActivate
0268     m_form->monitorChangeDefaultEdge(m_data->settings()->defaultBorderActivatePresentWindowsValue(), PresentWindowsCurrent);
0269 
0270     // PresentWindows BorderActivateClass
0271     m_form->monitorChangeDefaultEdge(m_data->settings()->defaultBorderActivateClassValue(), PresentWindowsClass);
0272 
0273     // Overview
0274     m_form->monitorChangeDefaultEdge(m_data->settings()->defaultBorderActivateOverviewValue(), Overview);
0275 
0276     // TabBox
0277     m_form->monitorChangeDefaultEdge(m_data->settings()->defaultBorderActivateTabBoxValue(), TabBox);
0278     // Alternative TabBox
0279     m_form->monitorChangeDefaultEdge(m_data->settings()->defaultBorderAlternativeActivateValue(), TabBoxAlternative);
0280 }
0281 
0282 void KWinScreenEdgesConfig::monitorSaveSettings()
0283 {
0284     // Save ElectricBorderActions
0285     m_data->settings()->setTop(KWinScreenEdgesConfig::electricBorderActionToString(m_form->selectedEdgeItem(ElectricTop)));
0286     m_data->settings()->setTopRight(KWinScreenEdgesConfig::electricBorderActionToString(m_form->selectedEdgeItem(ElectricTopRight)));
0287     m_data->settings()->setRight(KWinScreenEdgesConfig::electricBorderActionToString(m_form->selectedEdgeItem(ElectricRight)));
0288     m_data->settings()->setBottomRight(KWinScreenEdgesConfig::electricBorderActionToString(m_form->selectedEdgeItem(ElectricBottomRight)));
0289     m_data->settings()->setBottom(KWinScreenEdgesConfig::electricBorderActionToString(m_form->selectedEdgeItem(ElectricBottom)));
0290     m_data->settings()->setBottomLeft(KWinScreenEdgesConfig::electricBorderActionToString(m_form->selectedEdgeItem(ElectricBottomLeft)));
0291     m_data->settings()->setLeft(KWinScreenEdgesConfig::electricBorderActionToString(m_form->selectedEdgeItem(ElectricLeft)));
0292     m_data->settings()->setTopLeft(KWinScreenEdgesConfig::electricBorderActionToString(m_form->selectedEdgeItem(ElectricTopLeft)));
0293 
0294     // Save effect-specific actions:
0295 
0296     // Present Windows
0297     m_data->settings()->setBorderActivateAll(m_form->monitorCheckEffectHasEdge(PresentWindowsAll));
0298     m_data->settings()->setBorderActivatePresentWindows(m_form->monitorCheckEffectHasEdge(PresentWindowsCurrent));
0299     m_data->settings()->setBorderActivateClass(m_form->monitorCheckEffectHasEdge(PresentWindowsClass));
0300 
0301     // Overview
0302     m_data->settings()->setBorderActivateOverview(m_form->monitorCheckEffectHasEdge(Overview));
0303 
0304     // TabBox
0305     m_data->settings()->setBorderActivateTabBox(m_form->monitorCheckEffectHasEdge(TabBox));
0306     m_data->settings()->setBorderAlternativeActivate(m_form->monitorCheckEffectHasEdge(TabBoxAlternative));
0307 
0308     // Dinamically loaded effects
0309     int lastIndex = EffectCount;
0310     for (int i = 0; i < m_effects.size(); i++) {
0311         m_effectSettings[m_effects[i]]->setBorderActivate(m_form->monitorCheckEffectHasEdge(lastIndex));
0312         ++lastIndex;
0313     }
0314 
0315     // Scripts
0316     for (int i = 0; i < m_scripts.size(); i++) {
0317         m_scriptSettings[m_scripts[i]]->setBorderActivate(m_form->monitorCheckEffectHasEdge(lastIndex));
0318         ++lastIndex;
0319     }
0320 }
0321 
0322 void KWinScreenEdgesConfig::monitorShowEvent()
0323 {
0324     // Check if they are enabled
0325     KConfigGroup config(m_config, QStringLiteral("Plugins"));
0326 
0327     // Present Windows
0328     bool enabled = config.readEntry("windowviewEnabled", true);
0329     m_form->monitorItemSetEnabled(PresentWindowsCurrent, enabled);
0330     m_form->monitorItemSetEnabled(PresentWindowsAll, enabled);
0331 
0332     // Overview
0333     m_form->monitorItemSetEnabled(Overview, config.readEntry("overviewEnabled", true));
0334 
0335     // tabbox, depends on reasonable focus policy.
0336     KConfigGroup config2(m_config, QStringLiteral("Windows"));
0337     QString focusPolicy = config2.readEntry("FocusPolicy", QString());
0338     bool reasonable = focusPolicy != "FocusStrictlyUnderMouse" && focusPolicy != "FocusUnderMouse";
0339     m_form->monitorItemSetEnabled(TabBox, reasonable);
0340     m_form->monitorItemSetEnabled(TabBoxAlternative, reasonable);
0341 
0342     // Disable Edge if ElectricBorders group entries are immutable
0343     m_form->monitorEnableEdge(ElectricTop, !m_data->settings()->isTopImmutable());
0344     m_form->monitorEnableEdge(ElectricTopRight, !m_data->settings()->isTopRightImmutable());
0345     m_form->monitorEnableEdge(ElectricRight, !m_data->settings()->isRightImmutable());
0346     m_form->monitorEnableEdge(ElectricBottomRight, !m_data->settings()->isBottomRightImmutable());
0347     m_form->monitorEnableEdge(ElectricBottom, !m_data->settings()->isBottomImmutable());
0348     m_form->monitorEnableEdge(ElectricBottomLeft, !m_data->settings()->isBottomLeftImmutable());
0349     m_form->monitorEnableEdge(ElectricLeft, !m_data->settings()->isLeftImmutable());
0350     m_form->monitorEnableEdge(ElectricTopLeft, !m_data->settings()->isTopLeftImmutable());
0351 
0352     // Disable ElectricBorderCornerRatio if entry is immutable
0353     m_form->setElectricBorderCornerRatioEnabled(!m_data->settings()->isElectricBorderCornerRatioImmutable());
0354 }
0355 
0356 ElectricBorderAction KWinScreenEdgesConfig::electricBorderActionFromString(const QString &string)
0357 {
0358     QString lowerName = string.toLower();
0359     if (lowerName == QStringLiteral("showdesktop")) {
0360         return ElectricActionShowDesktop;
0361     }
0362     if (lowerName == QStringLiteral("lockscreen")) {
0363         return ElectricActionLockScreen;
0364     }
0365     if (lowerName == QStringLiteral("krunner")) {
0366         return ElectricActionKRunner;
0367     }
0368     if (lowerName == QStringLiteral("activitymanager")) {
0369         return ElectricActionActivityManager;
0370     }
0371     if (lowerName == QStringLiteral("applicationlauncher")) {
0372         return ElectricActionApplicationLauncher;
0373     }
0374     return ElectricActionNone;
0375 }
0376 
0377 QString KWinScreenEdgesConfig::electricBorderActionToString(int action)
0378 {
0379     switch (action) {
0380     case 1:
0381         return QStringLiteral("ShowDesktop");
0382     case 2:
0383         return QStringLiteral("LockScreen");
0384     case 3:
0385         return QStringLiteral("KRunner");
0386     case 4:
0387         return QStringLiteral("ActivityManager");
0388     case 5:
0389         return QStringLiteral("ApplicationLauncher");
0390     default:
0391         return QStringLiteral("None");
0392     }
0393 }
0394 
0395 } // namespace
0396 
0397 #include "main.moc"
0398 
0399 #include "moc_main.cpp"