1 /*
2     KWin - the KDE window manager
3     This file is part of the KDE project.
4 
5     SPDX-FileCopyrightText: 2008 Martin Gräßlin <mgraesslin@kde.org>
6     SPDX-FileCopyrightText: 2009 Lucas Murray <lmurray@undefinedfire.com>
7     SPDX-FileCopyrightText: 2020 Cyril Rossi <cyril.rossi@enioka.com>
8 
9     SPDX-License-Identifier: GPL-2.0-or-later
10 */
11 
12 #include "main.h"
13 #include <effect_builtins.h>
14 #include <kwin_effects_interface.h>
15 
16 #include <KAboutData>
17 #include <KConfigGroup>
18 #include <KLocalizedString>
19 #include <KPluginFactory>
20 #include <KPackage/Package>
21 #include <KPackage/PackageLoader>
22 #include <QtDBus>
23 #include <QVBoxLayout>
24 
25 #include "kwinscreenedgeconfigform.h"
26 #include "kwinscreenedgedata.h"
27 #include "kwinscreenedgesettings.h"
28 #include "kwinscreenedgescriptsettings.h"
29 
30 K_PLUGIN_FACTORY(KWinScreenEdgesConfigFactory, registerPlugin<KWin::KWinScreenEdgesConfig>(); registerPlugin<KWin::KWinScreenEdgeData>();)
31 
32 namespace KWin
33 {
34 
KWinScreenEdgesConfig(QWidget * parent,const QVariantList & args)35 KWinScreenEdgesConfig::KWinScreenEdgesConfig(QWidget *parent, const QVariantList &args)
36     : KCModule(parent, args)
37     , m_form(new KWinScreenEdgesConfigForm(this))
38     , m_config(KSharedConfig::openConfig("kwinrc"))
39     , m_data(new KWinScreenEdgeData(this))
40 {
41     QVBoxLayout *layout = new QVBoxLayout(this);
42     layout->addWidget(m_form);
43 
44     addConfig(m_data->settings(), m_form);
45 
46     monitorInit();
47 
48     connect(this, &KWinScreenEdgesConfig::defaultsIndicatorsVisibleChanged, m_form, &KWinScreenEdgesConfigForm::setDefaultsIndicatorsVisible);
49     connect(m_form, &KWinScreenEdgesConfigForm::saveNeededChanged, this, &KWinScreenEdgesConfig::unmanagedWidgetChangeState);
50     connect(m_form, &KWinScreenEdgesConfigForm::defaultChanged, this, &KWinScreenEdgesConfig::unmanagedWidgetDefaultState);
51 }
52 
~KWinScreenEdgesConfig()53 KWinScreenEdgesConfig::~KWinScreenEdgesConfig()
54 {
55 }
56 
load()57 void KWinScreenEdgesConfig::load()
58 {
59     KCModule::load();
60     m_data->settings()->load();
61     for (KWinScreenEdgeScriptSettings *setting : qAsConst(m_scriptSettings)) {
62         setting->load();
63     }
64 
65     monitorLoadSettings();
66     monitorLoadDefaultSettings();
67     m_form->setElectricBorderCornerRatio(m_data->settings()->electricBorderCornerRatio());
68     m_form->setDefaultElectricBorderCornerRatio(m_data->settings()->defaultElectricBorderCornerRatioValue());
69     m_form->reload();
70 }
71 
save()72 void KWinScreenEdgesConfig::save()
73 {
74     monitorSaveSettings();
75     m_data->settings()->setElectricBorderCornerRatio(m_form->electricBorderCornerRatio());
76     m_data->settings()->save();
77     for (KWinScreenEdgeScriptSettings *setting : qAsConst(m_scriptSettings)) {
78         setting->save();
79     }
80 
81     // Reload saved settings to ScreenEdge UI
82     monitorLoadSettings();
83     m_form->setElectricBorderCornerRatio(m_data->settings()->electricBorderCornerRatio());
84     m_form->reload();
85 
86     // Reload KWin.
87     QDBusMessage message = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
88     QDBusConnection::sessionBus().send(message);
89     // and reconfigure the effects
90     OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"),
91                                              QStringLiteral("/Effects"),
92                                              QDBusConnection::sessionBus());
93     interface.reconfigureEffect(BuiltInEffects::nameForEffect(BuiltInEffect::Overview));
94     interface.reconfigureEffect(BuiltInEffects::nameForEffect(BuiltInEffect::PresentWindows));
95     interface.reconfigureEffect(BuiltInEffects::nameForEffect(BuiltInEffect::DesktopGrid));
96 
97     KCModule::save();
98 }
99 
defaults()100 void KWinScreenEdgesConfig::defaults()
101 {
102     m_form->setDefaults();
103 
104     KCModule::defaults();
105 }
106 
showEvent(QShowEvent * e)107 void KWinScreenEdgesConfig::showEvent(QShowEvent *e)
108 {
109     KCModule::showEvent(e);
110 
111     monitorShowEvent();
112 }
113 
114 // Copied from kcmkwin/kwincompositing/main.cpp
effectEnabled(const BuiltInEffect & effect,const KConfigGroup & cfg) const115 bool KWinScreenEdgesConfig::effectEnabled(const BuiltInEffect &effect, const KConfigGroup &cfg) const
116 {
117     return cfg.readEntry(BuiltInEffects::nameForEffect(effect) + "Enabled", BuiltInEffects::enabledByDefault(effect));
118 }
119 
120 //-----------------------------------------------------------------------------
121 // Monitor
122 
monitorInit()123 void KWinScreenEdgesConfig::monitorInit()
124 {
125     m_form->monitorAddItem(i18n("No Action"));
126     m_form->monitorAddItem(i18n("Show Desktop"));
127     m_form->monitorAddItem(i18n("Lock Screen"));
128     m_form->monitorAddItem(i18n("Show KRunner"));
129     m_form->monitorAddItem(i18n("Activity Manager"));
130     m_form->monitorAddItem(i18n("Application Launcher"));
131 
132     // Add the effects
133     const QString presentWindowsName = BuiltInEffects::effectData(BuiltInEffect::PresentWindows).displayName;
134     m_form->monitorAddItem(i18n("%1 - All Desktops", presentWindowsName));
135     m_form->monitorAddItem(i18n("%1 - Current Desktop", presentWindowsName));
136     m_form->monitorAddItem(i18n("%1 - Current Application", presentWindowsName));
137     m_form->monitorAddItem(BuiltInEffects::effectData(BuiltInEffect::DesktopGrid).displayName);
138 
139     m_form->monitorAddItem(i18n("Toggle window switching"));
140     m_form->monitorAddItem(i18n("Toggle alternative window switching"));
141 
142     m_form->monitorAddItem(i18n("Toggle Overview"));
143 
144     const QString scriptFolder = QStringLiteral("kwin/scripts/");
145     const auto scripts = KPackage::PackageLoader::self()->listPackages(QStringLiteral("KWin/Script"), scriptFolder);
146 
147     KConfigGroup config(m_config, "Plugins");
148     for (const KPluginMetaData &script: scripts) {
149         if (script.value(QStringLiteral("X-KWin-Border-Activate")) != QLatin1String("true")) {
150             continue;
151         }
152 
153         if (!config.readEntry(script.pluginId() + QStringLiteral("Enabled"), script.isEnabledByDefault())) {
154             continue;
155         }
156         m_scripts << script.pluginId();
157         m_form->monitorAddItem(script.name());
158         m_scriptSettings[script.pluginId()] = new KWinScreenEdgeScriptSettings(script.pluginId(), this);
159     }
160 
161     monitorShowEvent();
162 }
163 
monitorLoadSettings()164 void KWinScreenEdgesConfig::monitorLoadSettings()
165 {
166     // Load ElectricBorderActions
167     m_form->monitorChangeEdge(ElectricTop, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->top()));
168     m_form->monitorChangeEdge(ElectricTopRight, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->topRight()));
169     m_form->monitorChangeEdge(ElectricRight, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->right()));
170     m_form->monitorChangeEdge(ElectricBottomRight, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->bottomRight()));
171     m_form->monitorChangeEdge(ElectricBottom, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->bottom()));
172     m_form->monitorChangeEdge(ElectricBottomLeft, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->bottomLeft()));
173     m_form->monitorChangeEdge(ElectricLeft, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->left()));
174     m_form->monitorChangeEdge(ElectricTopLeft, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->topLeft()));
175 
176     // Load effect-specific actions:
177 
178     // PresentWindows BorderActivateAll
179     m_form->monitorChangeEdge(m_data->settings()->borderActivateAll(), PresentWindowsAll);
180 
181     // PresentWindows BorderActivate
182     m_form->monitorChangeEdge(m_data->settings()->borderActivatePresentWindows(), PresentWindowsCurrent);
183 
184     // PresentWindows BorderActivateClass
185     m_form->monitorChangeEdge(m_data->settings()->borderActivateClass(), PresentWindowsClass);
186 
187     // Desktop Grid
188     m_form->monitorChangeEdge(m_data->settings()->borderActivateDesktopGrid(), DesktopGrid);
189 
190     // TabBox
191     m_form->monitorChangeEdge(m_data->settings()->borderActivateTabBox(), TabBox);
192     // Alternative TabBox
193     m_form->monitorChangeEdge(m_data->settings()->borderAlternativeActivate(), TabBoxAlternative);
194 
195     // Overview
196     m_form->monitorChangeEdge(m_data->settings()->borderActivateOverview(), Overview);
197 
198     // Scripts
199     for (int i = 0; i < m_scripts.size(); i++) {
200         int index = EffectCount + i;
201         m_form->monitorChangeEdge(m_scriptSettings[m_scripts[i]]->borderActivate(), index);
202     }
203 }
204 
monitorLoadDefaultSettings()205 void KWinScreenEdgesConfig::monitorLoadDefaultSettings()
206 {
207     // Load ElectricBorderActions
208     m_form->monitorChangeDefaultEdge(ElectricTop, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->defaultTopValue()));
209     m_form->monitorChangeDefaultEdge(ElectricTopRight, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->defaultTopRightValue()));
210     m_form->monitorChangeDefaultEdge(ElectricRight, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->defaultRightValue()));
211     m_form->monitorChangeDefaultEdge(ElectricBottomRight, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->defaultBottomRightValue()));
212     m_form->monitorChangeDefaultEdge(ElectricBottom, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->defaultBottomValue()));
213     m_form->monitorChangeDefaultEdge(ElectricBottomLeft, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->defaultBottomLeftValue()));
214     m_form->monitorChangeDefaultEdge(ElectricLeft, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->defaultLeftValue()));
215     m_form->monitorChangeDefaultEdge(ElectricTopLeft, KWinScreenEdgesConfig::electricBorderActionFromString(m_data->settings()->defaultTopLeftValue()));
216 
217     // Load effect-specific actions:
218 
219     // PresentWindows BorderActivateAll
220     m_form->monitorChangeDefaultEdge(m_data->settings()->defaultBorderActivateAllValue(), PresentWindowsAll);
221 
222     // PresentWindows BorderActivate
223     m_form->monitorChangeDefaultEdge(m_data->settings()->defaultBorderActivatePresentWindowsValue(), PresentWindowsCurrent);
224 
225     // PresentWindows BorderActivateClass
226     m_form->monitorChangeDefaultEdge(m_data->settings()->defaultBorderActivateClassValue(), PresentWindowsClass);
227 
228     // Desktop Grid
229     m_form->monitorChangeDefaultEdge(m_data->settings()->defaultBorderActivateDesktopGridValue(), DesktopGrid);
230 
231     // TabBox
232     m_form->monitorChangeDefaultEdge(m_data->settings()->defaultBorderActivateTabBoxValue(), TabBox);
233     // Alternative TabBox
234     m_form->monitorChangeDefaultEdge(m_data->settings()->defaultBorderAlternativeActivateValue(), TabBoxAlternative);
235 
236     // Overview
237     m_form->monitorChangeDefaultEdge(m_data->settings()->defaultBorderActivateOverviewValue(), Overview);
238 }
239 
monitorSaveSettings()240 void KWinScreenEdgesConfig::monitorSaveSettings()
241 {
242     // Save ElectricBorderActions
243     m_data->settings()->setTop(KWinScreenEdgesConfig::electricBorderActionToString(m_form->selectedEdgeItem(ElectricTop)));
244     m_data->settings()->setTopRight(KWinScreenEdgesConfig::electricBorderActionToString(m_form->selectedEdgeItem(ElectricTopRight)));
245     m_data->settings()->setRight(KWinScreenEdgesConfig::electricBorderActionToString(m_form->selectedEdgeItem(ElectricRight)));
246     m_data->settings()->setBottomRight(KWinScreenEdgesConfig::electricBorderActionToString(m_form->selectedEdgeItem(ElectricBottomRight)));
247     m_data->settings()->setBottom(KWinScreenEdgesConfig::electricBorderActionToString(m_form->selectedEdgeItem(ElectricBottom)));
248     m_data->settings()->setBottomLeft(KWinScreenEdgesConfig::electricBorderActionToString(m_form->selectedEdgeItem(ElectricBottomLeft)));
249     m_data->settings()->setLeft(KWinScreenEdgesConfig::electricBorderActionToString(m_form->selectedEdgeItem(ElectricLeft)));
250     m_data->settings()->setTopLeft(KWinScreenEdgesConfig::electricBorderActionToString(m_form->selectedEdgeItem(ElectricTopLeft)));
251 
252     // Save effect-specific actions:
253 
254     // Present Windows
255     m_data->settings()->setBorderActivateAll(m_form->monitorCheckEffectHasEdge(PresentWindowsAll));
256     m_data->settings()->setBorderActivatePresentWindows(m_form->monitorCheckEffectHasEdge(PresentWindowsCurrent));
257     m_data->settings()->setBorderActivateClass(m_form->monitorCheckEffectHasEdge(PresentWindowsClass));
258 
259     // Desktop Grid
260     m_data->settings()->setBorderActivateDesktopGrid(m_form->monitorCheckEffectHasEdge(DesktopGrid));
261 
262     // TabBox
263     m_data->settings()->setBorderActivateTabBox(m_form->monitorCheckEffectHasEdge(TabBox));
264     m_data->settings()->setBorderAlternativeActivate(m_form->monitorCheckEffectHasEdge(TabBoxAlternative));
265 
266     // Overview
267     m_data->settings()->setBorderActivateOverview(m_form->monitorCheckEffectHasEdge(Overview));
268 
269     // Scripts
270     for (int i = 0; i < m_scripts.size(); i++) {
271         int index = EffectCount + i;
272         m_scriptSettings[m_scripts[i]]->setBorderActivate(m_form->monitorCheckEffectHasEdge(index));
273     }
274 }
275 
monitorShowEvent()276 void KWinScreenEdgesConfig::monitorShowEvent()
277 {
278     // Check if they are enabled
279     KConfigGroup config(m_config, "Plugins");
280 
281     // Present Windows
282     bool enabled = effectEnabled(BuiltInEffect::PresentWindows, config);
283     m_form->monitorItemSetEnabled(PresentWindowsCurrent, enabled);
284     m_form->monitorItemSetEnabled(PresentWindowsAll, enabled);
285 
286     // Desktop Grid
287     enabled = effectEnabled(BuiltInEffect::DesktopGrid, config);
288     m_form->monitorItemSetEnabled(DesktopGrid, enabled);
289 
290     // Overview
291     enabled = effectEnabled(BuiltInEffect::Overview, config);
292     m_form->monitorItemSetEnabled(Overview, enabled);
293 
294     // tabbox, depends on reasonable focus policy.
295     KConfigGroup config2(m_config, "Windows");
296     QString focusPolicy = config2.readEntry("FocusPolicy", QString());
297     bool reasonable = focusPolicy != "FocusStrictlyUnderMouse" && focusPolicy != "FocusUnderMouse";
298     m_form->monitorItemSetEnabled(TabBox, reasonable);
299     m_form->monitorItemSetEnabled(TabBoxAlternative, reasonable);
300 
301     // Disable Edge if ElectricBorders group entries are immutable
302     m_form->monitorEnableEdge(ElectricTop, !m_data->settings()->isTopImmutable());
303     m_form->monitorEnableEdge(ElectricTopRight, !m_data->settings()->isTopRightImmutable());
304     m_form->monitorEnableEdge(ElectricRight, !m_data->settings()->isRightImmutable());
305     m_form->monitorEnableEdge(ElectricBottomRight, !m_data->settings()->isBottomRightImmutable());
306     m_form->monitorEnableEdge(ElectricBottom, !m_data->settings()->isBottomImmutable());
307     m_form->monitorEnableEdge(ElectricBottomLeft, !m_data->settings()->isBottomLeftImmutable());
308     m_form->monitorEnableEdge(ElectricLeft, !m_data->settings()->isLeftImmutable());
309     m_form->monitorEnableEdge(ElectricTopLeft, !m_data->settings()->isTopLeftImmutable());
310 
311     // Disable ElectricBorderCornerRatio if entry is immutable
312     m_form->setElectricBorderCornerRatioEnabled(!m_data->settings()->isElectricBorderCornerRatioImmutable());
313 }
314 
electricBorderActionFromString(const QString & string)315 ElectricBorderAction KWinScreenEdgesConfig::electricBorderActionFromString(const QString &string)
316 {
317     QString lowerName = string.toLower();
318     if (lowerName == QStringLiteral("showdesktop")) {
319         return ElectricActionShowDesktop;
320     }
321     if (lowerName == QStringLiteral("lockscreen")) {
322         return ElectricActionLockScreen;
323     }
324     if (lowerName == QStringLiteral("krunner")) {
325         return ElectricActionKRunner;
326     }
327     if (lowerName == QStringLiteral("activitymanager")) {
328         return ElectricActionActivityManager;
329     }
330     if (lowerName == QStringLiteral("applicationlauncher")) {
331         return ElectricActionApplicationLauncher;
332     }
333     return ElectricActionNone;
334 }
335 
electricBorderActionToString(int action)336 QString KWinScreenEdgesConfig::electricBorderActionToString(int action)
337 {
338     switch (action) {
339     case 1:
340         return QStringLiteral("ShowDesktop");
341     case 2:
342         return QStringLiteral("LockScreen");
343     case 3:
344         return QStringLiteral("KRunner");
345     case 4:
346         return QStringLiteral("ActivityManager");
347     case 5:
348         return QStringLiteral("ApplicationLauncher");
349     default:
350         return QStringLiteral("None");
351     }
352 }
353 
354 } // namespace
355 
356 #include "main.moc"
357