1 /*
2     KWin - the KDE window manager
3     This file is part of the KDE project.
4 
5     SPDX-FileCopyrightText: 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6     SPDX-FileCopyrightText: 2003 Lubos Lunak <l.lunak@kde.org>
7     SPDX-FileCopyrightText: 2012 Martin Gräßlin <m.graesslin@kde.org>
8 
9     SPDX-License-Identifier: GPL-2.0-or-later
10 */
11 
12 #include "options.h"
13 #include "config-kwin.h"
14 #include "utils.h"
15 #include "platform.h"
16 
17 #ifndef KCMRULES
18 
19 #include <QProcess>
20 
21 #include "screens.h"
22 #include "settings.h"
23 #include <kwinglplatform.h>
24 #include <QOpenGLContext>
25 
26 #endif //KCMRULES
27 
28 namespace KWin
29 {
30 
31 #ifndef KCMRULES
32 
Options(QObject * parent)33 Options::Options(QObject *parent)
34     : QObject(parent)
35     , m_settings(new Settings(kwinApp()->config()))
36     , m_focusPolicy(ClickToFocus)
37     , m_nextFocusPrefersMouse(false)
38     , m_clickRaise(false)
39     , m_autoRaise(false)
40     , m_autoRaiseInterval(0)
41     , m_delayFocusInterval(0)
42     , m_shadeHover(false)
43     , m_shadeHoverInterval(0)
44     , m_separateScreenFocus(false)
45     , m_activeMouseScreen(false)
46     , m_placement(Placement::NoPlacement)
47     , m_borderSnapZone(0)
48     , m_windowSnapZone(0)
49     , m_centerSnapZone(0)
50     , m_snapOnlyWhenOverlapping(false)
51     , m_rollOverDesktops(false)
52     , m_focusStealingPreventionLevel(0)
53     , m_killPingTimeout(0)
54     , m_hideUtilityWindowsForInactive(false)
55     , m_xwaylandCrashPolicy(Options::defaultXwaylandCrashPolicy())
56     , m_xwaylandMaxCrashCount(Options::defaultXwaylandMaxCrashCount())
57     , m_latencyPolicy(Options::defaultLatencyPolicy())
58     , m_renderTimeEstimator(Options::defaultRenderTimeEstimator())
59     , m_compositingMode(Options::defaultCompositingMode())
60     , m_useCompositing(Options::defaultUseCompositing())
61     , m_hiddenPreviews(Options::defaultHiddenPreviews())
62     , m_glSmoothScale(Options::defaultGlSmoothScale())
63     , m_glStrictBinding(Options::defaultGlStrictBinding())
64     , m_glStrictBindingFollowsDriver(Options::defaultGlStrictBindingFollowsDriver())
65     , m_glCoreProfile(Options::defaultGLCoreProfile())
66     , m_glPreferBufferSwap(Options::defaultGlPreferBufferSwap())
67     , m_glPlatformInterface(Options::defaultGlPlatformInterface())
68     , m_windowsBlockCompositing(true)
69     , m_MoveMinimizedWindowsToEndOfTabBoxFocusChain(false)
70     , OpTitlebarDblClick(Options::defaultOperationTitlebarDblClick())
71     , CmdActiveTitlebar1(Options::defaultCommandActiveTitlebar1())
72     , CmdActiveTitlebar2(Options::defaultCommandActiveTitlebar2())
73     , CmdActiveTitlebar3(Options::defaultCommandActiveTitlebar3())
74     , CmdInactiveTitlebar1(Options::defaultCommandInactiveTitlebar1())
75     , CmdInactiveTitlebar2(Options::defaultCommandInactiveTitlebar2())
76     , CmdInactiveTitlebar3(Options::defaultCommandInactiveTitlebar3())
77     , CmdTitlebarWheel(Options::defaultCommandTitlebarWheel())
78     , CmdWindow1(Options::defaultCommandWindow1())
79     , CmdWindow2(Options::defaultCommandWindow2())
80     , CmdWindow3(Options::defaultCommandWindow3())
81     , CmdWindowWheel(Options::defaultCommandWindowWheel())
82     , CmdAll1(Options::defaultCommandAll1())
83     , CmdAll2(Options::defaultCommandAll2())
84     , CmdAll3(Options::defaultCommandAll3())
85     , CmdAllWheel(Options::defaultCommandAllWheel())
86     , CmdAllModKey(Options::defaultKeyCmdAllModKey())
87     , electric_border_maximize(false)
88     , electric_border_tiling(false)
89     , electric_border_corner_ratio(0.0)
90     , borderless_maximized_windows(false)
91     , show_geometry_tip(false)
92     , condensed_title(false)
93 {
94     m_settings->setDefaults();
95     syncFromKcfgc();
96 
97     m_configWatcher = KConfigWatcher::create(m_settings->sharedConfig());
98     connect(m_configWatcher.data(), &KConfigWatcher::configChanged, this, [this](const KConfigGroup &group, const QByteArrayList &names) {
99         if (group.name() == QLatin1String("KDE") && names.contains(QByteArrayLiteral("AnimationDurationFactor"))) {
100             Q_EMIT animationSpeedChanged();
101         }
102     });
103 }
104 
~Options()105 Options::~Options()
106 {
107 }
108 
setFocusPolicy(FocusPolicy focusPolicy)109 void Options::setFocusPolicy(FocusPolicy focusPolicy)
110 {
111     if (m_focusPolicy == focusPolicy) {
112         return;
113     }
114     m_focusPolicy = focusPolicy;
115     Q_EMIT focusPolicyChanged();
116     if (m_focusPolicy == ClickToFocus) {
117         setAutoRaise(false);
118         setAutoRaiseInterval(0);
119         setDelayFocusInterval(0);
120     }
121 }
122 
setNextFocusPrefersMouse(bool nextFocusPrefersMouse)123 void Options::setNextFocusPrefersMouse(bool nextFocusPrefersMouse)
124 {
125     if (m_nextFocusPrefersMouse == nextFocusPrefersMouse) {
126         return;
127     }
128     m_nextFocusPrefersMouse = nextFocusPrefersMouse;
129     Q_EMIT nextFocusPrefersMouseChanged();
130 }
131 
setXwaylandCrashPolicy(XwaylandCrashPolicy crashPolicy)132 void Options::setXwaylandCrashPolicy(XwaylandCrashPolicy crashPolicy)
133 {
134     if (m_xwaylandCrashPolicy == crashPolicy) {
135         return;
136     }
137     m_xwaylandCrashPolicy = crashPolicy;
138     Q_EMIT xwaylandCrashPolicyChanged();
139 }
140 
setXwaylandMaxCrashCount(int maxCrashCount)141 void Options::setXwaylandMaxCrashCount(int maxCrashCount)
142 {
143     if (m_xwaylandMaxCrashCount == maxCrashCount) {
144         return;
145     }
146     m_xwaylandMaxCrashCount = maxCrashCount;
147     Q_EMIT xwaylandMaxCrashCountChanged();
148 }
149 
setClickRaise(bool clickRaise)150 void Options::setClickRaise(bool clickRaise)
151 {
152     if (m_autoRaise) {
153         // important: autoRaise implies ClickRaise
154         clickRaise = true;
155     }
156     if (m_clickRaise == clickRaise) {
157         return;
158     }
159     m_clickRaise = clickRaise;
160     Q_EMIT clickRaiseChanged();
161 }
162 
setAutoRaise(bool autoRaise)163 void Options::setAutoRaise(bool autoRaise)
164 {
165     if (m_focusPolicy == ClickToFocus) {
166         autoRaise = false;
167     }
168     if (m_autoRaise == autoRaise) {
169         return;
170     }
171     m_autoRaise = autoRaise;
172     if (m_autoRaise) {
173         // important: autoRaise implies ClickRaise
174         setClickRaise(true);
175     }
176     Q_EMIT autoRaiseChanged();
177 }
178 
setAutoRaiseInterval(int autoRaiseInterval)179 void Options::setAutoRaiseInterval(int autoRaiseInterval)
180 {
181     if (m_focusPolicy == ClickToFocus) {
182         autoRaiseInterval = 0;
183     }
184     if (m_autoRaiseInterval == autoRaiseInterval) {
185         return;
186     }
187     m_autoRaiseInterval = autoRaiseInterval;
188     Q_EMIT autoRaiseIntervalChanged();
189 }
190 
setDelayFocusInterval(int delayFocusInterval)191 void Options::setDelayFocusInterval(int delayFocusInterval)
192 {
193     if (m_focusPolicy == ClickToFocus) {
194         delayFocusInterval = 0;
195     }
196     if (m_delayFocusInterval == delayFocusInterval) {
197         return;
198     }
199     m_delayFocusInterval = delayFocusInterval;
200     Q_EMIT delayFocusIntervalChanged();
201 }
202 
setShadeHover(bool shadeHover)203 void Options::setShadeHover(bool shadeHover)
204 {
205     if (m_shadeHover == shadeHover) {
206         return;
207     }
208     m_shadeHover = shadeHover;
209     Q_EMIT shadeHoverChanged();
210 }
211 
setShadeHoverInterval(int shadeHoverInterval)212 void Options::setShadeHoverInterval(int shadeHoverInterval)
213 {
214     if (m_shadeHoverInterval == shadeHoverInterval) {
215         return;
216     }
217     m_shadeHoverInterval = shadeHoverInterval;
218     Q_EMIT shadeHoverIntervalChanged();
219 }
220 
setSeparateScreenFocus(bool separateScreenFocus)221 void Options::setSeparateScreenFocus(bool separateScreenFocus)
222 {
223     if (m_separateScreenFocus == separateScreenFocus) {
224         return;
225     }
226     m_separateScreenFocus = separateScreenFocus;
227     Q_EMIT separateScreenFocusChanged(m_separateScreenFocus);
228 }
229 
setActiveMouseScreen(bool activeMouseScreen)230 void Options::setActiveMouseScreen(bool activeMouseScreen)
231 {
232     if (m_activeMouseScreen == activeMouseScreen) {
233         return;
234     }
235     m_activeMouseScreen = activeMouseScreen;
236     Q_EMIT activeMouseScreenChanged();
237 }
238 
setPlacement(int placement)239 void Options::setPlacement(int placement)
240 {
241     if (m_placement == static_cast<Placement::Policy>(placement)) {
242         return;
243     }
244     m_placement = static_cast<Placement::Policy>(placement);
245     Q_EMIT placementChanged();
246 }
247 
setBorderSnapZone(int borderSnapZone)248 void Options::setBorderSnapZone(int borderSnapZone)
249 {
250     if (m_borderSnapZone == borderSnapZone) {
251         return;
252     }
253     m_borderSnapZone = borderSnapZone;
254     Q_EMIT borderSnapZoneChanged();
255 }
256 
setWindowSnapZone(int windowSnapZone)257 void Options::setWindowSnapZone(int windowSnapZone)
258 {
259     if (m_windowSnapZone == windowSnapZone) {
260         return;
261     }
262     m_windowSnapZone = windowSnapZone;
263     Q_EMIT windowSnapZoneChanged();
264 }
265 
setCenterSnapZone(int centerSnapZone)266 void Options::setCenterSnapZone(int centerSnapZone)
267 {
268     if (m_centerSnapZone == centerSnapZone) {
269         return;
270     }
271     m_centerSnapZone = centerSnapZone;
272     Q_EMIT centerSnapZoneChanged();
273 }
274 
setSnapOnlyWhenOverlapping(bool snapOnlyWhenOverlapping)275 void Options::setSnapOnlyWhenOverlapping(bool snapOnlyWhenOverlapping)
276 {
277     if (m_snapOnlyWhenOverlapping == snapOnlyWhenOverlapping) {
278         return;
279     }
280     m_snapOnlyWhenOverlapping = snapOnlyWhenOverlapping;
281     Q_EMIT snapOnlyWhenOverlappingChanged();
282 }
283 
setRollOverDesktops(bool rollOverDesktops)284 void Options::setRollOverDesktops(bool rollOverDesktops)
285 {
286     if (m_rollOverDesktops == rollOverDesktops) {
287         return;
288     }
289     m_rollOverDesktops = rollOverDesktops;
290     Q_EMIT rollOverDesktopsChanged(m_rollOverDesktops);
291 }
292 
setFocusStealingPreventionLevel(int focusStealingPreventionLevel)293 void Options::setFocusStealingPreventionLevel(int focusStealingPreventionLevel)
294 {
295     if (!focusPolicyIsReasonable()) {
296         focusStealingPreventionLevel = 0;
297     }
298     if (m_focusStealingPreventionLevel == focusStealingPreventionLevel) {
299         return;
300     }
301     m_focusStealingPreventionLevel = qMax(0, qMin(4, focusStealingPreventionLevel));
302     Q_EMIT focusStealingPreventionLevelChanged();
303 }
304 
setOperationTitlebarDblClick(WindowOperation operationTitlebarDblClick)305 void Options::setOperationTitlebarDblClick(WindowOperation operationTitlebarDblClick)
306 {
307     if (OpTitlebarDblClick == operationTitlebarDblClick) {
308         return;
309     }
310     OpTitlebarDblClick = operationTitlebarDblClick;
311     Q_EMIT operationTitlebarDblClickChanged();
312 }
313 
setOperationMaxButtonLeftClick(WindowOperation op)314 void Options::setOperationMaxButtonLeftClick(WindowOperation op)
315 {
316     if (opMaxButtonLeftClick == op) {
317         return;
318     }
319     opMaxButtonLeftClick = op;
320     Q_EMIT operationMaxButtonLeftClickChanged();
321 }
322 
setOperationMaxButtonRightClick(WindowOperation op)323 void Options::setOperationMaxButtonRightClick(WindowOperation op)
324 {
325     if (opMaxButtonRightClick == op) {
326         return;
327     }
328     opMaxButtonRightClick = op;
329     Q_EMIT operationMaxButtonRightClickChanged();
330 }
331 
setOperationMaxButtonMiddleClick(WindowOperation op)332 void Options::setOperationMaxButtonMiddleClick(WindowOperation op)
333 {
334     if (opMaxButtonMiddleClick == op) {
335         return;
336     }
337     opMaxButtonMiddleClick = op;
338     Q_EMIT operationMaxButtonMiddleClickChanged();
339 }
340 
setCommandActiveTitlebar1(MouseCommand commandActiveTitlebar1)341 void Options::setCommandActiveTitlebar1(MouseCommand commandActiveTitlebar1)
342 {
343     if (CmdActiveTitlebar1 == commandActiveTitlebar1) {
344         return;
345     }
346     CmdActiveTitlebar1 = commandActiveTitlebar1;
347     Q_EMIT commandActiveTitlebar1Changed();
348 }
349 
setCommandActiveTitlebar2(MouseCommand commandActiveTitlebar2)350 void Options::setCommandActiveTitlebar2(MouseCommand commandActiveTitlebar2)
351 {
352     if (CmdActiveTitlebar2 == commandActiveTitlebar2) {
353         return;
354     }
355     CmdActiveTitlebar2 = commandActiveTitlebar2;
356     Q_EMIT commandActiveTitlebar2Changed();
357 }
358 
setCommandActiveTitlebar3(MouseCommand commandActiveTitlebar3)359 void Options::setCommandActiveTitlebar3(MouseCommand commandActiveTitlebar3)
360 {
361     if (CmdActiveTitlebar3 == commandActiveTitlebar3) {
362         return;
363     }
364     CmdActiveTitlebar3 = commandActiveTitlebar3;
365     Q_EMIT commandActiveTitlebar3Changed();
366 }
367 
setCommandInactiveTitlebar1(MouseCommand commandInactiveTitlebar1)368 void Options::setCommandInactiveTitlebar1(MouseCommand commandInactiveTitlebar1)
369 {
370     if (CmdInactiveTitlebar1 == commandInactiveTitlebar1) {
371         return;
372     }
373     CmdInactiveTitlebar1 = commandInactiveTitlebar1;
374     Q_EMIT commandInactiveTitlebar1Changed();
375 }
376 
setCommandInactiveTitlebar2(MouseCommand commandInactiveTitlebar2)377 void Options::setCommandInactiveTitlebar2(MouseCommand commandInactiveTitlebar2)
378 {
379     if (CmdInactiveTitlebar2 == commandInactiveTitlebar2) {
380         return;
381     }
382     CmdInactiveTitlebar2 = commandInactiveTitlebar2;
383     Q_EMIT commandInactiveTitlebar2Changed();
384 }
385 
setCommandInactiveTitlebar3(MouseCommand commandInactiveTitlebar3)386 void Options::setCommandInactiveTitlebar3(MouseCommand commandInactiveTitlebar3)
387 {
388     if (CmdInactiveTitlebar3 == commandInactiveTitlebar3) {
389         return;
390     }
391     CmdInactiveTitlebar3 = commandInactiveTitlebar3;
392     Q_EMIT commandInactiveTitlebar3Changed();
393 }
394 
setCommandWindow1(MouseCommand commandWindow1)395 void Options::setCommandWindow1(MouseCommand commandWindow1)
396 {
397     if (CmdWindow1 == commandWindow1) {
398         return;
399     }
400     CmdWindow1 = commandWindow1;
401     Q_EMIT commandWindow1Changed();
402 }
403 
setCommandWindow2(MouseCommand commandWindow2)404 void Options::setCommandWindow2(MouseCommand commandWindow2)
405 {
406     if (CmdWindow2 == commandWindow2) {
407         return;
408     }
409     CmdWindow2 = commandWindow2;
410     Q_EMIT commandWindow2Changed();
411 }
412 
setCommandWindow3(MouseCommand commandWindow3)413 void Options::setCommandWindow3(MouseCommand commandWindow3)
414 {
415     if (CmdWindow3 == commandWindow3) {
416         return;
417     }
418     CmdWindow3 = commandWindow3;
419     Q_EMIT commandWindow3Changed();
420 }
421 
setCommandWindowWheel(MouseCommand commandWindowWheel)422 void Options::setCommandWindowWheel(MouseCommand commandWindowWheel)
423 {
424     if (CmdWindowWheel == commandWindowWheel) {
425         return;
426     }
427     CmdWindowWheel = commandWindowWheel;
428     Q_EMIT commandWindowWheelChanged();
429 }
430 
setCommandAll1(MouseCommand commandAll1)431 void Options::setCommandAll1(MouseCommand commandAll1)
432 {
433     if (CmdAll1 == commandAll1) {
434         return;
435     }
436     CmdAll1 = commandAll1;
437     Q_EMIT commandAll1Changed();
438 }
439 
setCommandAll2(MouseCommand commandAll2)440 void Options::setCommandAll2(MouseCommand commandAll2)
441 {
442     if (CmdAll2 == commandAll2) {
443         return;
444     }
445     CmdAll2 = commandAll2;
446     Q_EMIT commandAll2Changed();
447 }
448 
setCommandAll3(MouseCommand commandAll3)449 void Options::setCommandAll3(MouseCommand commandAll3)
450 {
451     if (CmdAll3 == commandAll3) {
452         return;
453     }
454     CmdAll3 = commandAll3;
455     Q_EMIT commandAll3Changed();
456 }
457 
setKeyCmdAllModKey(uint keyCmdAllModKey)458 void Options::setKeyCmdAllModKey(uint keyCmdAllModKey)
459 {
460     if (CmdAllModKey == keyCmdAllModKey) {
461         return;
462     }
463     CmdAllModKey = keyCmdAllModKey;
464     Q_EMIT keyCmdAllModKeyChanged();
465 }
466 
setShowGeometryTip(bool showGeometryTip)467 void Options::setShowGeometryTip(bool showGeometryTip)
468 {
469     if (show_geometry_tip == showGeometryTip) {
470         return;
471     }
472     show_geometry_tip = showGeometryTip;
473     Q_EMIT showGeometryTipChanged();
474 }
475 
setCondensedTitle(bool condensedTitle)476 void Options::setCondensedTitle(bool condensedTitle)
477 {
478     if (condensed_title == condensedTitle) {
479         return;
480     }
481     condensed_title = condensedTitle;
482     Q_EMIT condensedTitleChanged();
483 }
484 
setElectricBorderMaximize(bool electricBorderMaximize)485 void Options::setElectricBorderMaximize(bool electricBorderMaximize)
486 {
487     if (electric_border_maximize == electricBorderMaximize) {
488         return;
489     }
490     electric_border_maximize = electricBorderMaximize;
491     Q_EMIT electricBorderMaximizeChanged();
492 }
493 
setElectricBorderTiling(bool electricBorderTiling)494 void Options::setElectricBorderTiling(bool electricBorderTiling)
495 {
496     if (electric_border_tiling == electricBorderTiling) {
497         return;
498     }
499     electric_border_tiling = electricBorderTiling;
500     Q_EMIT electricBorderTilingChanged();
501 }
502 
setElectricBorderCornerRatio(float electricBorderCornerRatio)503 void Options::setElectricBorderCornerRatio(float electricBorderCornerRatio)
504 {
505     if (electric_border_corner_ratio == electricBorderCornerRatio) {
506         return;
507     }
508     electric_border_corner_ratio = electricBorderCornerRatio;
509     Q_EMIT electricBorderCornerRatioChanged();
510 }
511 
setBorderlessMaximizedWindows(bool borderlessMaximizedWindows)512 void Options::setBorderlessMaximizedWindows(bool borderlessMaximizedWindows)
513 {
514     if (borderless_maximized_windows == borderlessMaximizedWindows) {
515         return;
516     }
517     borderless_maximized_windows = borderlessMaximizedWindows;
518     Q_EMIT borderlessMaximizedWindowsChanged();
519 }
520 
setKillPingTimeout(int killPingTimeout)521 void Options::setKillPingTimeout(int killPingTimeout)
522 {
523     if (m_killPingTimeout == killPingTimeout) {
524         return;
525     }
526     m_killPingTimeout = killPingTimeout;
527     Q_EMIT killPingTimeoutChanged();
528 }
529 
setHideUtilityWindowsForInactive(bool hideUtilityWindowsForInactive)530 void Options::setHideUtilityWindowsForInactive(bool hideUtilityWindowsForInactive)
531 {
532     if (m_hideUtilityWindowsForInactive == hideUtilityWindowsForInactive) {
533         return;
534     }
535     m_hideUtilityWindowsForInactive = hideUtilityWindowsForInactive;
536     Q_EMIT hideUtilityWindowsForInactiveChanged();
537 }
538 
setCompositingMode(int compositingMode)539 void Options::setCompositingMode(int compositingMode)
540 {
541     if (m_compositingMode == static_cast<CompositingType>(compositingMode)) {
542         return;
543     }
544     m_compositingMode = static_cast<CompositingType>(compositingMode);
545     Q_EMIT compositingModeChanged();
546 }
547 
setUseCompositing(bool useCompositing)548 void Options::setUseCompositing(bool useCompositing)
549 {
550     if (m_useCompositing == useCompositing) {
551         return;
552     }
553     m_useCompositing = useCompositing;
554     Q_EMIT useCompositingChanged();
555 }
556 
setHiddenPreviews(int hiddenPreviews)557 void Options::setHiddenPreviews(int hiddenPreviews)
558 {
559     if (m_hiddenPreviews == static_cast<HiddenPreviews>(hiddenPreviews)) {
560         return;
561     }
562     m_hiddenPreviews = static_cast<HiddenPreviews>(hiddenPreviews);
563     Q_EMIT hiddenPreviewsChanged();
564 }
565 
setGlSmoothScale(int glSmoothScale)566 void Options::setGlSmoothScale(int glSmoothScale)
567 {
568     if (m_glSmoothScale == glSmoothScale) {
569         return;
570     }
571     m_glSmoothScale = glSmoothScale;
572     Q_EMIT glSmoothScaleChanged();
573 }
574 
setGlStrictBinding(bool glStrictBinding)575 void Options::setGlStrictBinding(bool glStrictBinding)
576 {
577     if (m_glStrictBinding == glStrictBinding) {
578         return;
579     }
580     m_glStrictBinding = glStrictBinding;
581     Q_EMIT glStrictBindingChanged();
582 }
583 
setGlStrictBindingFollowsDriver(bool glStrictBindingFollowsDriver)584 void Options::setGlStrictBindingFollowsDriver(bool glStrictBindingFollowsDriver)
585 {
586     if (m_glStrictBindingFollowsDriver == glStrictBindingFollowsDriver) {
587         return;
588     }
589     m_glStrictBindingFollowsDriver = glStrictBindingFollowsDriver;
590     Q_EMIT glStrictBindingFollowsDriverChanged();
591 }
592 
setGLCoreProfile(bool value)593 void Options::setGLCoreProfile(bool value)
594 {
595     if (m_glCoreProfile == value) {
596         return;
597     }
598     m_glCoreProfile = value;
599     Q_EMIT glCoreProfileChanged();
600 }
601 
setWindowsBlockCompositing(bool value)602 void Options::setWindowsBlockCompositing(bool value)
603 {
604     if (m_windowsBlockCompositing == value) {
605         return;
606     }
607     m_windowsBlockCompositing = value;
608     Q_EMIT windowsBlockCompositingChanged();
609 }
610 
setMoveMinimizedWindowsToEndOfTabBoxFocusChain(bool value)611 void Options::setMoveMinimizedWindowsToEndOfTabBoxFocusChain(bool value)
612 {
613     if (m_MoveMinimizedWindowsToEndOfTabBoxFocusChain == value) {
614         return;
615     }
616     m_MoveMinimizedWindowsToEndOfTabBoxFocusChain = value;
617 
618 }
619 
setGlPreferBufferSwap(char glPreferBufferSwap)620 void Options::setGlPreferBufferSwap(char glPreferBufferSwap)
621 {
622     if (glPreferBufferSwap == 'a') {
623         // buffer copying is very fast with the nvidia blob
624         // but due to restrictions in DRI2 *incredibly* slow for all MESA drivers
625         // see https://www.x.org/releases/X11R7.7/doc/dri2proto/dri2proto.txt, item 2.5
626         if (GLPlatform::instance()->driver() == Driver_NVidia)
627             glPreferBufferSwap = CopyFrontBuffer;
628         else if (GLPlatform::instance()->driver() != Driver_Unknown) // undetected, finally resolved when context is initialized
629             glPreferBufferSwap = ExtendDamage;
630     }
631     if (m_glPreferBufferSwap == (GlSwapStrategy)glPreferBufferSwap) {
632         return;
633     }
634     m_glPreferBufferSwap = (GlSwapStrategy)glPreferBufferSwap;
635     Q_EMIT glPreferBufferSwapChanged();
636 }
637 
latencyPolicy() const638 LatencyPolicy Options::latencyPolicy() const
639 {
640     return m_latencyPolicy;
641 }
642 
setLatencyPolicy(LatencyPolicy policy)643 void Options::setLatencyPolicy(LatencyPolicy policy)
644 {
645     if (m_latencyPolicy == policy) {
646         return;
647     }
648     m_latencyPolicy = policy;
649     Q_EMIT latencyPolicyChanged();
650 }
651 
renderTimeEstimator() const652 RenderTimeEstimator Options::renderTimeEstimator() const
653 {
654     return m_renderTimeEstimator;
655 }
656 
setRenderTimeEstimator(RenderTimeEstimator estimator)657 void Options::setRenderTimeEstimator(RenderTimeEstimator estimator)
658 {
659     if (m_renderTimeEstimator == estimator) {
660         return;
661     }
662     m_renderTimeEstimator = estimator;
663     Q_EMIT renderTimeEstimatorChanged();
664 }
665 
setGlPlatformInterface(OpenGLPlatformInterface interface)666 void Options::setGlPlatformInterface(OpenGLPlatformInterface interface)
667 {
668     // check environment variable
669     const QByteArray envOpenGLInterface(qgetenv("KWIN_OPENGL_INTERFACE"));
670     if (!envOpenGLInterface.isEmpty()) {
671         if (qstrcmp(envOpenGLInterface, "egl") == 0) {
672             qCDebug(KWIN_CORE) << "Forcing EGL native interface through environment variable";
673             interface = EglPlatformInterface;
674         } else if (qstrcmp(envOpenGLInterface, "glx") == 0) {
675             qCDebug(KWIN_CORE) << "Forcing GLX native interface through environment variable";
676             interface = GlxPlatformInterface;
677         }
678     }
679     if (kwinApp()->shouldUseWaylandForCompositing() && interface == GlxPlatformInterface) {
680         // Glx is impossible on Wayland, enforce egl
681         qCDebug(KWIN_CORE) << "Forcing EGL native interface for Wayland mode";
682         interface = EglPlatformInterface;
683     }
684 #if !HAVE_EPOXY_GLX
685     qCDebug(KWIN_CORE) << "Forcing EGL native interface as compiled without GLX support";
686     interface = EglPlatformInterface;
687 #endif
688     if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) {
689         qCDebug(KWIN_CORE) << "Forcing EGL native interface as Qt uses OpenGL ES";
690         interface = EglPlatformInterface;
691     } else if (qstrcmp(qgetenv("KWIN_COMPOSE"), "O2ES") == 0) {
692         qCDebug(KWIN_CORE) << "Forcing EGL native interface as OpenGL ES requested through KWIN_COMPOSE environment variable.";
693         interface = EglPlatformInterface;
694     }
695 
696     if (m_glPlatformInterface == interface) {
697         return;
698     }
699     m_glPlatformInterface = interface;
700     Q_EMIT glPlatformInterfaceChanged();
701 }
702 
reparseConfiguration()703 void Options::reparseConfiguration()
704 {
705     m_settings->config()->reparseConfiguration();
706 }
707 
updateSettings()708 void Options::updateSettings()
709 {
710     loadConfig();
711     // Read button tooltip animation effect from kdeglobals
712     // Since we want to allow users to enable window decoration tooltips
713     // and not kstyle tooltips and vise-versa, we don't read the
714     // "EffectNoTooltip" setting from kdeglobals.
715 
716 
717 //    QToolTip::setGloballyEnabled( d->show_tooltips );
718 // KDE4 this probably needs to be done manually in clients
719 
720     // Driver-specific config detection
721     reloadCompositingSettings();
722 
723     Q_EMIT configChanged();
724 }
725 
loadConfig()726 void Options::loadConfig()
727 {
728     m_settings->load();
729 
730     syncFromKcfgc();
731 
732     // Electric borders
733     KConfigGroup config(m_settings->config(), "Windows");
734     OpTitlebarDblClick = windowOperation(config.readEntry("TitlebarDoubleClickCommand", "Maximize"), true);
735     setOperationMaxButtonLeftClick(windowOperation(config.readEntry("MaximizeButtonLeftClickCommand", "Maximize"), true));
736     setOperationMaxButtonMiddleClick(windowOperation(config.readEntry("MaximizeButtonMiddleClickCommand", "Maximize (vertical only)"), true));
737     setOperationMaxButtonRightClick(windowOperation(config.readEntry("MaximizeButtonRightClickCommand", "Maximize (horizontal only)"), true));
738 
739     // Mouse bindings
740     config = KConfigGroup(m_settings->config(), "MouseBindings");
741     // TODO: add properties for missing options
742     CmdTitlebarWheel = mouseWheelCommand(config.readEntry("CommandTitlebarWheel", "Nothing"));
743     CmdAllModKey = (config.readEntry("CommandAllKey", "Meta") == QStringLiteral("Meta")) ? Qt::Key_Meta : Qt::Key_Alt;
744     CmdAllWheel = mouseWheelCommand(config.readEntry("CommandAllWheel", "Nothing"));
745     setCommandActiveTitlebar1(mouseCommand(config.readEntry("CommandActiveTitlebar1", "Raise"), true));
746     setCommandActiveTitlebar2(mouseCommand(config.readEntry("CommandActiveTitlebar2", "Nothing"), true));
747     setCommandActiveTitlebar3(mouseCommand(config.readEntry("CommandActiveTitlebar3", "Operations menu"), true));
748     setCommandInactiveTitlebar1(mouseCommand(config.readEntry("CommandInactiveTitlebar1", "Activate and raise"), true));
749     setCommandInactiveTitlebar2(mouseCommand(config.readEntry("CommandInactiveTitlebar2", "Nothing"), true));
750     setCommandInactiveTitlebar3(mouseCommand(config.readEntry("CommandInactiveTitlebar3", "Operations menu"), true));
751     setCommandWindow1(mouseCommand(config.readEntry("CommandWindow1", "Activate, raise and pass click"), false));
752     setCommandWindow2(mouseCommand(config.readEntry("CommandWindow2", "Activate and pass click"), false));
753     setCommandWindow3(mouseCommand(config.readEntry("CommandWindow3", "Activate and pass click"), false));
754     setCommandWindowWheel(mouseCommand(config.readEntry("CommandWindowWheel", "Scroll"), false));
755     setCommandAll1(mouseCommand(config.readEntry("CommandAll1", "Move"), false));
756     setCommandAll2(mouseCommand(config.readEntry("CommandAll2", "Toggle raise and lower"), false));
757     setCommandAll3(mouseCommand(config.readEntry("CommandAll3", "Resize"), false));
758 
759     // Modifier Only Shortcuts
760     config = KConfigGroup(m_settings->config(), "ModifierOnlyShortcuts");
761     m_modifierOnlyShortcuts.clear();
762     if (config.hasKey("Shift")) {
763         m_modifierOnlyShortcuts.insert(Qt::ShiftModifier, config.readEntry("Shift", QStringList()));
764     }
765     if (config.hasKey("Control")) {
766         m_modifierOnlyShortcuts.insert(Qt::ControlModifier, config.readEntry("Control", QStringList()));
767     }
768     if (config.hasKey("Alt")) {
769         m_modifierOnlyShortcuts.insert(Qt::AltModifier, config.readEntry("Alt", QStringList()));
770     }
771     m_modifierOnlyShortcuts.insert(Qt::MetaModifier, config.readEntry("Meta", QStringList{QStringLiteral("org.kde.plasmashell"),
772                                                                                           QStringLiteral("/PlasmaShell"),
773                                                                                           QStringLiteral("org.kde.PlasmaShell"),
774                                                                                           QStringLiteral("activateLauncherMenu")}));
775 }
776 
syncFromKcfgc()777 void Options::syncFromKcfgc()
778 {
779     setShowGeometryTip(m_settings->geometryTip());
780     setCondensedTitle(m_settings->condensedTitle());
781     setFocusPolicy(m_settings->focusPolicy());
782     setNextFocusPrefersMouse(m_settings->nextFocusPrefersMouse());
783     setSeparateScreenFocus(m_settings->separateScreenFocus());
784     setActiveMouseScreen(m_settings->activeMouseScreen());
785     setRollOverDesktops(m_settings->rollOverDesktops());
786     setFocusStealingPreventionLevel(m_settings->focusStealingPreventionLevel());
787     setXwaylandCrashPolicy(m_settings->xwaylandCrashPolicy());
788     setXwaylandMaxCrashCount(m_settings->xwaylandMaxCrashCount());
789 
790 #ifdef KWIN_BUILD_DECORATIONS
791     setPlacement(m_settings->placement());
792 #else
793     setPlacement(Placement::Maximizing);
794 #endif
795 
796     setAutoRaise(m_settings->autoRaise());
797     setAutoRaiseInterval(m_settings->autoRaiseInterval());
798     setDelayFocusInterval(m_settings->delayFocusInterval());
799     setShadeHover(m_settings->shadeHover());
800     setShadeHoverInterval(m_settings->shadeHoverInterval());
801     setClickRaise(m_settings->clickRaise());
802     setBorderSnapZone(m_settings->borderSnapZone());
803     setWindowSnapZone(m_settings->windowSnapZone());
804     setCenterSnapZone(m_settings->centerSnapZone());
805     setSnapOnlyWhenOverlapping(m_settings->snapOnlyWhenOverlapping());
806     setKillPingTimeout(m_settings->killPingTimeout());
807     setHideUtilityWindowsForInactive(m_settings->hideUtilityWindowsForInactive());
808     setBorderlessMaximizedWindows(m_settings->borderlessMaximizedWindows());
809     setElectricBorderMaximize(m_settings->electricBorderMaximize());
810     setElectricBorderTiling(m_settings->electricBorderTiling());
811     setElectricBorderCornerRatio(m_settings->electricBorderCornerRatio());
812     setWindowsBlockCompositing(m_settings->windowsBlockCompositing());
813     setMoveMinimizedWindowsToEndOfTabBoxFocusChain(m_settings->moveMinimizedWindowsToEndOfTabBoxFocusChain());
814     setLatencyPolicy(m_settings->latencyPolicy());
815     setRenderTimeEstimator(m_settings->renderTimeEstimator());
816 }
817 
loadCompositingConfig(bool force)818 bool Options::loadCompositingConfig (bool force)
819 {
820     KConfigGroup config(m_settings->config(), "Compositing");
821 
822     bool useCompositing = false;
823     CompositingType compositingMode = NoCompositing;
824     QString compositingBackend = config.readEntry("Backend", "OpenGL");
825     if (compositingBackend == "QPainter")
826         compositingMode = QPainterCompositing;
827     else
828         compositingMode = OpenGLCompositing;
829 
830     if (const char *c = getenv("KWIN_COMPOSE")) {
831         switch(c[0]) {
832         case 'O':
833             qCDebug(KWIN_CORE) << "Compositing forced to OpenGL mode by environment variable";
834             compositingMode = OpenGLCompositing;
835             useCompositing = true;
836             break;
837         case 'Q':
838             qCDebug(KWIN_CORE) << "Compositing forced to QPainter mode by environment variable";
839             compositingMode = QPainterCompositing;
840             useCompositing = true;
841             break;
842         case 'N':
843             if (getenv("KDE_FAILSAFE"))
844                 qCDebug(KWIN_CORE) << "Compositing disabled forcefully by KDE failsafe mode";
845             else
846                 qCDebug(KWIN_CORE) << "Compositing disabled forcefully by environment variable";
847             compositingMode = NoCompositing;
848             break;
849         default:
850             qCDebug(KWIN_CORE) << "Unknown KWIN_COMPOSE mode set, ignoring";
851             break;
852         }
853     }
854     setCompositingMode(compositingMode);
855 
856     const bool platformSupportsNoCompositing = kwinApp()->platform()->supportedCompositors().contains(NoCompositing);
857     if (m_compositingMode == NoCompositing && platformSupportsNoCompositing) {
858         setUseCompositing(false);
859         return false; // do not even detect compositing preferences if explicitly disabled
860     }
861 
862     // it's either enforced by env or by initial resume from "suspend" or we check the settings
863     setUseCompositing(useCompositing || force || config.readEntry("Enabled", Options::defaultUseCompositing() || !platformSupportsNoCompositing));
864 
865     if (!m_useCompositing)
866         return false; // not enforced or necessary and not "enabled" by settings
867     return true;
868 }
869 
reloadCompositingSettings(bool force)870 void Options::reloadCompositingSettings(bool force)
871 {
872     if (!loadCompositingConfig(force)) {
873         return;
874     }
875     m_settings->load();
876     syncFromKcfgc();
877 
878     // Compositing settings
879     KConfigGroup config(m_settings->config(), "Compositing");
880 
881     setGlSmoothScale(qBound(-1, config.readEntry("GLTextureFilter", Options::defaultGlSmoothScale()), 2));
882     setGlStrictBindingFollowsDriver(!config.hasKey("GLStrictBinding"));
883     if (!isGlStrictBindingFollowsDriver()) {
884         setGlStrictBinding(config.readEntry("GLStrictBinding", Options::defaultGlStrictBinding()));
885     }
886     setGLCoreProfile(config.readEntry("GLCore", Options::defaultGLCoreProfile()));
887 
888     char c = 0;
889     const QString s = config.readEntry("GLPreferBufferSwap", QString(Options::defaultGlPreferBufferSwap()));
890     if (!s.isEmpty())
891         c = s.at(0).toLatin1();
892     if (c != 'a' && c != 'c' && c != 'p' && c != 'e')
893         c = Options::defaultGlPreferBufferSwap();
894     setGlPreferBufferSwap(c);
895 
896     HiddenPreviews previews = Options::defaultHiddenPreviews();
897     // 4 - off, 5 - shown, 6 - always, other are old values
898     int hps = config.readEntry("HiddenPreviews", 5);
899     if (hps == 4)
900         previews = HiddenPreviewsNever;
901     else if (hps == 5)
902         previews = HiddenPreviewsShown;
903     else if (hps == 6)
904         previews = HiddenPreviewsAlways;
905     setHiddenPreviews(previews);
906 
907     auto interfaceToKey = [](OpenGLPlatformInterface interface) {
908         switch (interface) {
909         case GlxPlatformInterface:
910             return QStringLiteral("glx");
911         case EglPlatformInterface:
912             return QStringLiteral("egl");
913         default:
914             return QString();
915         }
916     };
917     auto keyToInterface = [](const QString &key) {
918         if (key == QStringLiteral("glx")) {
919             return GlxPlatformInterface;
920         } else if (key == QStringLiteral("egl")) {
921             return EglPlatformInterface;
922         }
923         return defaultGlPlatformInterface();
924     };
925     setGlPlatformInterface(keyToInterface(config.readEntry("GLPlatformInterface", interfaceToKey(m_glPlatformInterface))));
926 }
927 
928 // restricted should be true for operations that the user may not be able to repeat
929 // if the window is moved out of the workspace (e.g. if the user moves a window
930 // by the titlebar, and moves it too high beneath Kicker at the top edge, they
931 // may not be able to move it back, unless they know about Meta+LMB)
windowOperation(const QString & name,bool restricted)932 Options::WindowOperation Options::windowOperation(const QString &name, bool restricted)
933 {
934     if (name == QStringLiteral("Move"))
935         return restricted ? MoveOp : UnrestrictedMoveOp;
936     else if (name == QStringLiteral("Resize"))
937         return restricted ? ResizeOp : UnrestrictedResizeOp;
938     else if (name == QStringLiteral("Maximize"))
939         return MaximizeOp;
940     else if (name == QStringLiteral("Minimize"))
941         return MinimizeOp;
942     else if (name == QStringLiteral("Close"))
943         return CloseOp;
944     else if (name == QStringLiteral("OnAllDesktops"))
945         return OnAllDesktopsOp;
946     else if (name == QStringLiteral("Shade"))
947         return ShadeOp;
948     else if (name == QStringLiteral("Operations"))
949         return OperationsOp;
950     else if (name == QStringLiteral("Maximize (vertical only)"))
951         return VMaximizeOp;
952     else if (name == QStringLiteral("Maximize (horizontal only)"))
953         return HMaximizeOp;
954     else if (name == QStringLiteral("Lower"))
955         return LowerOp;
956     return NoOp;
957 }
958 
mouseCommand(const QString & name,bool restricted)959 Options::MouseCommand Options::mouseCommand(const QString &name, bool restricted)
960 {
961     QString lowerName = name.toLower();
962     if (lowerName == QStringLiteral("raise")) return MouseRaise;
963     if (lowerName == QStringLiteral("lower")) return MouseLower;
964     if (lowerName == QStringLiteral("operations menu")) return MouseOperationsMenu;
965     if (lowerName == QStringLiteral("toggle raise and lower")) return MouseToggleRaiseAndLower;
966     if (lowerName == QStringLiteral("activate and raise")) return MouseActivateAndRaise;
967     if (lowerName == QStringLiteral("activate and lower")) return MouseActivateAndLower;
968     if (lowerName == QStringLiteral("activate")) return MouseActivate;
969     if (lowerName == QStringLiteral("activate, raise and pass click")) return MouseActivateRaiseAndPassClick;
970     if (lowerName == QStringLiteral("activate and pass click")) return MouseActivateAndPassClick;
971     if (lowerName == QStringLiteral("scroll")) return MouseNothing;
972     if (lowerName == QStringLiteral("activate and scroll")) return MouseActivateAndPassClick;
973     if (lowerName == QStringLiteral("activate, raise and scroll")) return MouseActivateRaiseAndPassClick;
974     if (lowerName == QStringLiteral("activate, raise and move"))
975         return restricted ? MouseActivateRaiseAndMove : MouseActivateRaiseAndUnrestrictedMove;
976     if (lowerName == QStringLiteral("move")) return restricted ? MouseMove : MouseUnrestrictedMove;
977     if (lowerName == QStringLiteral("resize")) return restricted ? MouseResize : MouseUnrestrictedResize;
978     if (lowerName == QStringLiteral("shade")) return MouseShade;
979     if (lowerName == QStringLiteral("minimize")) return MouseMinimize;
980     if (lowerName == QStringLiteral("close")) return MouseClose;
981     if (lowerName == QStringLiteral("increase opacity")) return MouseOpacityMore;
982     if (lowerName == QStringLiteral("decrease opacity")) return MouseOpacityLess;
983     if (lowerName == QStringLiteral("nothing")) return MouseNothing;
984     return MouseNothing;
985 }
986 
mouseWheelCommand(const QString & name)987 Options::MouseWheelCommand Options::mouseWheelCommand(const QString &name)
988 {
989     QString lowerName = name.toLower();
990     if (lowerName == QStringLiteral("raise/lower")) return MouseWheelRaiseLower;
991     if (lowerName == QStringLiteral("shade/unshade")) return MouseWheelShadeUnshade;
992     if (lowerName == QStringLiteral("maximize/restore")) return MouseWheelMaximizeRestore;
993     if (lowerName == QStringLiteral("above/below")) return MouseWheelAboveBelow;
994     if (lowerName == QStringLiteral("previous/next desktop")) return MouseWheelPreviousNextDesktop;
995     if (lowerName == QStringLiteral("change opacity")) return MouseWheelChangeOpacity;
996     if (lowerName == QStringLiteral("nothing")) return MouseWheelNothing;
997     return MouseWheelNothing;
998 }
999 
showGeometryTip() const1000 bool Options::showGeometryTip() const
1001 {
1002     return show_geometry_tip;
1003 }
1004 
condensedTitle() const1005 bool Options::condensedTitle() const
1006 {
1007     return condensed_title;
1008 }
1009 
wheelToMouseCommand(MouseWheelCommand com,int delta) const1010 Options::MouseCommand Options::wheelToMouseCommand(MouseWheelCommand com, int delta) const
1011 {
1012     switch(com) {
1013     case MouseWheelRaiseLower:
1014         return delta > 0 ? MouseRaise : MouseLower;
1015     case MouseWheelShadeUnshade:
1016         return delta > 0 ? MouseSetShade : MouseUnsetShade;
1017     case MouseWheelMaximizeRestore:
1018         return delta > 0 ? MouseMaximize : MouseRestore;
1019     case MouseWheelAboveBelow:
1020         return delta > 0 ? MouseAbove : MouseBelow;
1021     case MouseWheelPreviousNextDesktop:
1022         return delta > 0 ? MousePreviousDesktop : MouseNextDesktop;
1023     case MouseWheelChangeOpacity:
1024         return delta > 0 ? MouseOpacityMore : MouseOpacityLess;
1025     default:
1026         return MouseNothing;
1027     }
1028 }
1029 #endif
1030 
animationTimeFactor() const1031 double Options::animationTimeFactor() const
1032 {
1033  #ifndef KCMRULES
1034     return m_settings->animationDurationFactor();
1035 #else
1036     return 0;
1037 #endif
1038 }
1039 
operationMaxButtonClick(Qt::MouseButtons button) const1040 Options::WindowOperation Options::operationMaxButtonClick(Qt::MouseButtons button) const
1041 {
1042     return button == Qt::RightButton ? opMaxButtonRightClick :
1043            button == Qt::MiddleButton ?   opMaxButtonMiddleClick :
1044            opMaxButtonLeftClick;
1045 }
1046 
modifierOnlyDBusShortcut(Qt::KeyboardModifier mod) const1047 QStringList Options::modifierOnlyDBusShortcut(Qt::KeyboardModifier mod) const
1048 {
1049     return m_modifierOnlyShortcuts.value(mod);
1050 }
1051 
isUseCompositing() const1052 bool Options::isUseCompositing() const
1053 {
1054     return m_useCompositing || kwinApp()->platform()->requiresCompositing();
1055 }
1056 
1057 } // namespace
1058