File indexing completed on 2024-12-01 13:37:34

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 1999, 2000 Matthias Ettrich <ettrich@kde.org>
0006     SPDX-FileCopyrightText: 2003 Lubos Lunak <l.lunak@kde.org>
0007     SPDX-FileCopyrightText: 2012 Martin Gräßlin <m.graesslin@kde.org>
0008 
0009     SPDX-License-Identifier: GPL-2.0-or-later
0010 */
0011 #include "options.h"
0012 
0013 #include "config-kwin.h"
0014 
0015 #include "core/outputbackend.h"
0016 #include "utils/common.h"
0017 
0018 #ifndef KCMRULES
0019 
0020 #include <QProcess>
0021 
0022 #include "settings.h"
0023 #include "workspace.h"
0024 #include <QOpenGLContext>
0025 #include <kwinglplatform.h>
0026 
0027 #endif // KCMRULES
0028 
0029 namespace KWin
0030 {
0031 
0032 #ifndef KCMRULES
0033 
0034 Options::Options(QObject *parent)
0035     : QObject(parent)
0036     , m_settings(new Settings(kwinApp()->config()))
0037     , m_focusPolicy(ClickToFocus)
0038     , m_nextFocusPrefersMouse(false)
0039     , m_clickRaise(false)
0040     , m_autoRaise(false)
0041     , m_autoRaiseInterval(0)
0042     , m_delayFocusInterval(0)
0043     , m_shadeHover(false)
0044     , m_shadeHoverInterval(0)
0045     , m_separateScreenFocus(false)
0046     , m_activeMouseScreen(false)
0047     , m_placement(PlacementNone)
0048     , m_activationDesktopPolicy(Options::defaultActivationDesktopPolicy())
0049     , m_borderSnapZone(0)
0050     , m_windowSnapZone(0)
0051     , m_centerSnapZone(0)
0052     , m_snapOnlyWhenOverlapping(false)
0053     , m_rollOverDesktops(false)
0054     , m_focusStealingPreventionLevel(0)
0055     , m_killPingTimeout(0)
0056     , m_hideUtilityWindowsForInactive(false)
0057     , m_xwaylandCrashPolicy(Options::defaultXwaylandCrashPolicy())
0058     , m_xwaylandMaxCrashCount(Options::defaultXwaylandMaxCrashCount())
0059     , m_xwaylandEavesdrops(Options::defaultXwaylandEavesdrops())
0060     , m_latencyPolicy(Options::defaultLatencyPolicy())
0061     , m_renderTimeEstimator(Options::defaultRenderTimeEstimator())
0062     , m_compositingMode(Options::defaultCompositingMode())
0063     , m_useCompositing(Options::defaultUseCompositing())
0064     , m_hiddenPreviews(Options::defaultHiddenPreviews())
0065     , m_glSmoothScale(Options::defaultGlSmoothScale())
0066     , m_glStrictBinding(Options::defaultGlStrictBinding())
0067     , m_glStrictBindingFollowsDriver(Options::defaultGlStrictBindingFollowsDriver())
0068     , m_glPreferBufferSwap(Options::defaultGlPreferBufferSwap())
0069     , m_glPlatformInterface(Options::defaultGlPlatformInterface())
0070     , m_windowsBlockCompositing(true)
0071     , m_MoveMinimizedWindowsToEndOfTabBoxFocusChain(false)
0072     , OpTitlebarDblClick(Options::defaultOperationTitlebarDblClick())
0073     , CmdActiveTitlebar1(Options::defaultCommandActiveTitlebar1())
0074     , CmdActiveTitlebar2(Options::defaultCommandActiveTitlebar2())
0075     , CmdActiveTitlebar3(Options::defaultCommandActiveTitlebar3())
0076     , CmdInactiveTitlebar1(Options::defaultCommandInactiveTitlebar1())
0077     , CmdInactiveTitlebar2(Options::defaultCommandInactiveTitlebar2())
0078     , CmdInactiveTitlebar3(Options::defaultCommandInactiveTitlebar3())
0079     , CmdTitlebarWheel(Options::defaultCommandTitlebarWheel())
0080     , CmdWindow1(Options::defaultCommandWindow1())
0081     , CmdWindow2(Options::defaultCommandWindow2())
0082     , CmdWindow3(Options::defaultCommandWindow3())
0083     , CmdWindowWheel(Options::defaultCommandWindowWheel())
0084     , CmdAll1(Options::defaultCommandAll1())
0085     , CmdAll2(Options::defaultCommandAll2())
0086     , CmdAll3(Options::defaultCommandAll3())
0087     , CmdAllWheel(Options::defaultCommandAllWheel())
0088     , CmdAllModKey(Options::defaultKeyCmdAllModKey())
0089     , electric_border_maximize(false)
0090     , electric_border_tiling(false)
0091     , electric_border_corner_ratio(0.0)
0092     , borderless_maximized_windows(false)
0093     , condensed_title(false)
0094 {
0095     m_settings->setDefaults();
0096     syncFromKcfgc();
0097 
0098     m_configWatcher = KConfigWatcher::create(m_settings->sharedConfig());
0099     connect(m_configWatcher.data(), &KConfigWatcher::configChanged, this, [this](const KConfigGroup &group, const QByteArrayList &names) {
0100         if (group.name() == QLatin1String("KDE") && names.contains(QByteArrayLiteral("AnimationDurationFactor"))) {
0101             Q_EMIT animationSpeedChanged();
0102         } else if (group.name() == QLatin1String("Xwayland")) {
0103             workspace()->reconfigure();
0104         }
0105     });
0106 }
0107 
0108 Options::~Options()
0109 {
0110 }
0111 
0112 void Options::setFocusPolicy(FocusPolicy focusPolicy)
0113 {
0114     if (m_focusPolicy == focusPolicy) {
0115         return;
0116     }
0117     m_focusPolicy = focusPolicy;
0118     Q_EMIT focusPolicyChanged();
0119     if (m_focusPolicy == ClickToFocus) {
0120         setAutoRaise(false);
0121         setAutoRaiseInterval(0);
0122         setDelayFocusInterval(0);
0123     }
0124 }
0125 
0126 void Options::setNextFocusPrefersMouse(bool nextFocusPrefersMouse)
0127 {
0128     if (m_nextFocusPrefersMouse == nextFocusPrefersMouse) {
0129         return;
0130     }
0131     m_nextFocusPrefersMouse = nextFocusPrefersMouse;
0132     Q_EMIT nextFocusPrefersMouseChanged();
0133 }
0134 
0135 void Options::setXwaylandCrashPolicy(XwaylandCrashPolicy crashPolicy)
0136 {
0137     if (m_xwaylandCrashPolicy == crashPolicy) {
0138         return;
0139     }
0140     m_xwaylandCrashPolicy = crashPolicy;
0141     Q_EMIT xwaylandCrashPolicyChanged();
0142 }
0143 
0144 void Options::setXwaylandMaxCrashCount(int maxCrashCount)
0145 {
0146     if (m_xwaylandMaxCrashCount == maxCrashCount) {
0147         return;
0148     }
0149     m_xwaylandMaxCrashCount = maxCrashCount;
0150     Q_EMIT xwaylandMaxCrashCountChanged();
0151 }
0152 
0153 void Options::setXwaylandEavesdrops(XwaylandEavesdropsMode mode)
0154 {
0155     if (m_xwaylandEavesdrops == mode) {
0156         return;
0157     }
0158     m_xwaylandEavesdrops = mode;
0159     Q_EMIT xwaylandEavesdropsChanged();
0160 }
0161 
0162 void Options::setClickRaise(bool clickRaise)
0163 {
0164     if (m_autoRaise) {
0165         // important: autoRaise implies ClickRaise
0166         clickRaise = true;
0167     }
0168     if (m_clickRaise == clickRaise) {
0169         return;
0170     }
0171     m_clickRaise = clickRaise;
0172     Q_EMIT clickRaiseChanged();
0173 }
0174 
0175 void Options::setAutoRaise(bool autoRaise)
0176 {
0177     if (m_focusPolicy == ClickToFocus) {
0178         autoRaise = false;
0179     }
0180     if (m_autoRaise == autoRaise) {
0181         return;
0182     }
0183     m_autoRaise = autoRaise;
0184     if (m_autoRaise) {
0185         // important: autoRaise implies ClickRaise
0186         setClickRaise(true);
0187     }
0188     Q_EMIT autoRaiseChanged();
0189 }
0190 
0191 void Options::setAutoRaiseInterval(int autoRaiseInterval)
0192 {
0193     if (m_focusPolicy == ClickToFocus) {
0194         autoRaiseInterval = 0;
0195     }
0196     if (m_autoRaiseInterval == autoRaiseInterval) {
0197         return;
0198     }
0199     m_autoRaiseInterval = autoRaiseInterval;
0200     Q_EMIT autoRaiseIntervalChanged();
0201 }
0202 
0203 void Options::setDelayFocusInterval(int delayFocusInterval)
0204 {
0205     if (m_focusPolicy == ClickToFocus) {
0206         delayFocusInterval = 0;
0207     }
0208     if (m_delayFocusInterval == delayFocusInterval) {
0209         return;
0210     }
0211     m_delayFocusInterval = delayFocusInterval;
0212     Q_EMIT delayFocusIntervalChanged();
0213 }
0214 
0215 void Options::setShadeHover(bool shadeHover)
0216 {
0217     if (m_shadeHover == shadeHover) {
0218         return;
0219     }
0220     m_shadeHover = shadeHover;
0221     Q_EMIT shadeHoverChanged();
0222 }
0223 
0224 void Options::setShadeHoverInterval(int shadeHoverInterval)
0225 {
0226     if (m_shadeHoverInterval == shadeHoverInterval) {
0227         return;
0228     }
0229     m_shadeHoverInterval = shadeHoverInterval;
0230     Q_EMIT shadeHoverIntervalChanged();
0231 }
0232 
0233 void Options::setSeparateScreenFocus(bool separateScreenFocus)
0234 {
0235     if (m_separateScreenFocus == separateScreenFocus) {
0236         return;
0237     }
0238     m_separateScreenFocus = separateScreenFocus;
0239     Q_EMIT separateScreenFocusChanged(m_separateScreenFocus);
0240 }
0241 
0242 void Options::setActiveMouseScreen(bool activeMouseScreen)
0243 {
0244     if (m_activeMouseScreen == activeMouseScreen) {
0245         return;
0246     }
0247     m_activeMouseScreen = activeMouseScreen;
0248     Q_EMIT activeMouseScreenChanged();
0249 }
0250 
0251 void Options::setPlacement(PlacementPolicy placement)
0252 {
0253     if (m_placement == placement) {
0254         return;
0255     }
0256     m_placement = placement;
0257     Q_EMIT placementChanged();
0258 }
0259 
0260 void Options::setActivationDesktopPolicy(ActivationDesktopPolicy activationDesktopPolicy)
0261 {
0262     if (m_activationDesktopPolicy == activationDesktopPolicy) {
0263         return;
0264     }
0265     m_activationDesktopPolicy = activationDesktopPolicy;
0266     Q_EMIT activationDesktopPolicyChanged();
0267 }
0268 
0269 void Options::setBorderSnapZone(int borderSnapZone)
0270 {
0271     if (m_borderSnapZone == borderSnapZone) {
0272         return;
0273     }
0274     m_borderSnapZone = borderSnapZone;
0275     Q_EMIT borderSnapZoneChanged();
0276 }
0277 
0278 void Options::setWindowSnapZone(int windowSnapZone)
0279 {
0280     if (m_windowSnapZone == windowSnapZone) {
0281         return;
0282     }
0283     m_windowSnapZone = windowSnapZone;
0284     Q_EMIT windowSnapZoneChanged();
0285 }
0286 
0287 void Options::setCenterSnapZone(int centerSnapZone)
0288 {
0289     if (m_centerSnapZone == centerSnapZone) {
0290         return;
0291     }
0292     m_centerSnapZone = centerSnapZone;
0293     Q_EMIT centerSnapZoneChanged();
0294 }
0295 
0296 void Options::setSnapOnlyWhenOverlapping(bool snapOnlyWhenOverlapping)
0297 {
0298     if (m_snapOnlyWhenOverlapping == snapOnlyWhenOverlapping) {
0299         return;
0300     }
0301     m_snapOnlyWhenOverlapping = snapOnlyWhenOverlapping;
0302     Q_EMIT snapOnlyWhenOverlappingChanged();
0303 }
0304 
0305 void Options::setRollOverDesktops(bool rollOverDesktops)
0306 {
0307     if (m_rollOverDesktops == rollOverDesktops) {
0308         return;
0309     }
0310     m_rollOverDesktops = rollOverDesktops;
0311     Q_EMIT rollOverDesktopsChanged(m_rollOverDesktops);
0312 }
0313 
0314 void Options::setFocusStealingPreventionLevel(int focusStealingPreventionLevel)
0315 {
0316     if (!focusPolicyIsReasonable()) {
0317         focusStealingPreventionLevel = 0;
0318     }
0319     if (m_focusStealingPreventionLevel == focusStealingPreventionLevel) {
0320         return;
0321     }
0322     m_focusStealingPreventionLevel = std::max(0, std::min(4, focusStealingPreventionLevel));
0323     Q_EMIT focusStealingPreventionLevelChanged();
0324 }
0325 
0326 void Options::setOperationTitlebarDblClick(WindowOperation operationTitlebarDblClick)
0327 {
0328     if (OpTitlebarDblClick == operationTitlebarDblClick) {
0329         return;
0330     }
0331     OpTitlebarDblClick = operationTitlebarDblClick;
0332     Q_EMIT operationTitlebarDblClickChanged();
0333 }
0334 
0335 void Options::setOperationMaxButtonLeftClick(WindowOperation op)
0336 {
0337     if (opMaxButtonLeftClick == op) {
0338         return;
0339     }
0340     opMaxButtonLeftClick = op;
0341     Q_EMIT operationMaxButtonLeftClickChanged();
0342 }
0343 
0344 void Options::setOperationMaxButtonRightClick(WindowOperation op)
0345 {
0346     if (opMaxButtonRightClick == op) {
0347         return;
0348     }
0349     opMaxButtonRightClick = op;
0350     Q_EMIT operationMaxButtonRightClickChanged();
0351 }
0352 
0353 void Options::setOperationMaxButtonMiddleClick(WindowOperation op)
0354 {
0355     if (opMaxButtonMiddleClick == op) {
0356         return;
0357     }
0358     opMaxButtonMiddleClick = op;
0359     Q_EMIT operationMaxButtonMiddleClickChanged();
0360 }
0361 
0362 void Options::setCommandActiveTitlebar1(MouseCommand commandActiveTitlebar1)
0363 {
0364     if (CmdActiveTitlebar1 == commandActiveTitlebar1) {
0365         return;
0366     }
0367     CmdActiveTitlebar1 = commandActiveTitlebar1;
0368     Q_EMIT commandActiveTitlebar1Changed();
0369 }
0370 
0371 void Options::setCommandActiveTitlebar2(MouseCommand commandActiveTitlebar2)
0372 {
0373     if (CmdActiveTitlebar2 == commandActiveTitlebar2) {
0374         return;
0375     }
0376     CmdActiveTitlebar2 = commandActiveTitlebar2;
0377     Q_EMIT commandActiveTitlebar2Changed();
0378 }
0379 
0380 void Options::setCommandActiveTitlebar3(MouseCommand commandActiveTitlebar3)
0381 {
0382     if (CmdActiveTitlebar3 == commandActiveTitlebar3) {
0383         return;
0384     }
0385     CmdActiveTitlebar3 = commandActiveTitlebar3;
0386     Q_EMIT commandActiveTitlebar3Changed();
0387 }
0388 
0389 void Options::setCommandInactiveTitlebar1(MouseCommand commandInactiveTitlebar1)
0390 {
0391     if (CmdInactiveTitlebar1 == commandInactiveTitlebar1) {
0392         return;
0393     }
0394     CmdInactiveTitlebar1 = commandInactiveTitlebar1;
0395     Q_EMIT commandInactiveTitlebar1Changed();
0396 }
0397 
0398 void Options::setCommandInactiveTitlebar2(MouseCommand commandInactiveTitlebar2)
0399 {
0400     if (CmdInactiveTitlebar2 == commandInactiveTitlebar2) {
0401         return;
0402     }
0403     CmdInactiveTitlebar2 = commandInactiveTitlebar2;
0404     Q_EMIT commandInactiveTitlebar2Changed();
0405 }
0406 
0407 void Options::setCommandInactiveTitlebar3(MouseCommand commandInactiveTitlebar3)
0408 {
0409     if (CmdInactiveTitlebar3 == commandInactiveTitlebar3) {
0410         return;
0411     }
0412     CmdInactiveTitlebar3 = commandInactiveTitlebar3;
0413     Q_EMIT commandInactiveTitlebar3Changed();
0414 }
0415 
0416 void Options::setCommandWindow1(MouseCommand commandWindow1)
0417 {
0418     if (CmdWindow1 == commandWindow1) {
0419         return;
0420     }
0421     CmdWindow1 = commandWindow1;
0422     Q_EMIT commandWindow1Changed();
0423 }
0424 
0425 void Options::setCommandWindow2(MouseCommand commandWindow2)
0426 {
0427     if (CmdWindow2 == commandWindow2) {
0428         return;
0429     }
0430     CmdWindow2 = commandWindow2;
0431     Q_EMIT commandWindow2Changed();
0432 }
0433 
0434 void Options::setCommandWindow3(MouseCommand commandWindow3)
0435 {
0436     if (CmdWindow3 == commandWindow3) {
0437         return;
0438     }
0439     CmdWindow3 = commandWindow3;
0440     Q_EMIT commandWindow3Changed();
0441 }
0442 
0443 void Options::setCommandWindowWheel(MouseCommand commandWindowWheel)
0444 {
0445     if (CmdWindowWheel == commandWindowWheel) {
0446         return;
0447     }
0448     CmdWindowWheel = commandWindowWheel;
0449     Q_EMIT commandWindowWheelChanged();
0450 }
0451 
0452 void Options::setCommandAll1(MouseCommand commandAll1)
0453 {
0454     if (CmdAll1 == commandAll1) {
0455         return;
0456     }
0457     CmdAll1 = commandAll1;
0458     Q_EMIT commandAll1Changed();
0459 }
0460 
0461 void Options::setCommandAll2(MouseCommand commandAll2)
0462 {
0463     if (CmdAll2 == commandAll2) {
0464         return;
0465     }
0466     CmdAll2 = commandAll2;
0467     Q_EMIT commandAll2Changed();
0468 }
0469 
0470 void Options::setCommandAll3(MouseCommand commandAll3)
0471 {
0472     if (CmdAll3 == commandAll3) {
0473         return;
0474     }
0475     CmdAll3 = commandAll3;
0476     Q_EMIT commandAll3Changed();
0477 }
0478 
0479 void Options::setKeyCmdAllModKey(uint keyCmdAllModKey)
0480 {
0481     if (CmdAllModKey == keyCmdAllModKey) {
0482         return;
0483     }
0484     CmdAllModKey = keyCmdAllModKey;
0485     Q_EMIT keyCmdAllModKeyChanged();
0486 }
0487 
0488 void Options::setCondensedTitle(bool condensedTitle)
0489 {
0490     if (condensed_title == condensedTitle) {
0491         return;
0492     }
0493     condensed_title = condensedTitle;
0494     Q_EMIT condensedTitleChanged();
0495 }
0496 
0497 void Options::setElectricBorderMaximize(bool electricBorderMaximize)
0498 {
0499     if (electric_border_maximize == electricBorderMaximize) {
0500         return;
0501     }
0502     electric_border_maximize = electricBorderMaximize;
0503     Q_EMIT electricBorderMaximizeChanged();
0504 }
0505 
0506 void Options::setElectricBorderTiling(bool electricBorderTiling)
0507 {
0508     if (electric_border_tiling == electricBorderTiling) {
0509         return;
0510     }
0511     electric_border_tiling = electricBorderTiling;
0512     Q_EMIT electricBorderTilingChanged();
0513 }
0514 
0515 void Options::setElectricBorderCornerRatio(float electricBorderCornerRatio)
0516 {
0517     if (electric_border_corner_ratio == electricBorderCornerRatio) {
0518         return;
0519     }
0520     electric_border_corner_ratio = electricBorderCornerRatio;
0521     Q_EMIT electricBorderCornerRatioChanged();
0522 }
0523 
0524 void Options::setBorderlessMaximizedWindows(bool borderlessMaximizedWindows)
0525 {
0526     if (borderless_maximized_windows == borderlessMaximizedWindows) {
0527         return;
0528     }
0529     borderless_maximized_windows = borderlessMaximizedWindows;
0530     Q_EMIT borderlessMaximizedWindowsChanged();
0531 }
0532 
0533 void Options::setKillPingTimeout(int killPingTimeout)
0534 {
0535     if (m_killPingTimeout == killPingTimeout) {
0536         return;
0537     }
0538     m_killPingTimeout = killPingTimeout;
0539     Q_EMIT killPingTimeoutChanged();
0540 }
0541 
0542 void Options::setHideUtilityWindowsForInactive(bool hideUtilityWindowsForInactive)
0543 {
0544     if (m_hideUtilityWindowsForInactive == hideUtilityWindowsForInactive) {
0545         return;
0546     }
0547     m_hideUtilityWindowsForInactive = hideUtilityWindowsForInactive;
0548     Q_EMIT hideUtilityWindowsForInactiveChanged();
0549 }
0550 
0551 void Options::setCompositingMode(int compositingMode)
0552 {
0553     if (m_compositingMode == static_cast<CompositingType>(compositingMode)) {
0554         return;
0555     }
0556     m_compositingMode = static_cast<CompositingType>(compositingMode);
0557     Q_EMIT compositingModeChanged();
0558 }
0559 
0560 void Options::setUseCompositing(bool useCompositing)
0561 {
0562     if (m_useCompositing == useCompositing) {
0563         return;
0564     }
0565     m_useCompositing = useCompositing;
0566     Q_EMIT useCompositingChanged();
0567 }
0568 
0569 void Options::setHiddenPreviews(int hiddenPreviews)
0570 {
0571     if (m_hiddenPreviews == static_cast<HiddenPreviews>(hiddenPreviews)) {
0572         return;
0573     }
0574     m_hiddenPreviews = static_cast<HiddenPreviews>(hiddenPreviews);
0575     Q_EMIT hiddenPreviewsChanged();
0576 }
0577 
0578 void Options::setGlSmoothScale(int glSmoothScale)
0579 {
0580     if (m_glSmoothScale == glSmoothScale) {
0581         return;
0582     }
0583     m_glSmoothScale = glSmoothScale;
0584     Q_EMIT glSmoothScaleChanged();
0585 }
0586 
0587 void Options::setGlStrictBinding(bool glStrictBinding)
0588 {
0589     if (m_glStrictBinding == glStrictBinding) {
0590         return;
0591     }
0592     m_glStrictBinding = glStrictBinding;
0593     Q_EMIT glStrictBindingChanged();
0594 }
0595 
0596 void Options::setGlStrictBindingFollowsDriver(bool glStrictBindingFollowsDriver)
0597 {
0598     if (m_glStrictBindingFollowsDriver == glStrictBindingFollowsDriver) {
0599         return;
0600     }
0601     m_glStrictBindingFollowsDriver = glStrictBindingFollowsDriver;
0602     Q_EMIT glStrictBindingFollowsDriverChanged();
0603 }
0604 
0605 void Options::setWindowsBlockCompositing(bool value)
0606 {
0607     if (m_windowsBlockCompositing == value) {
0608         return;
0609     }
0610     m_windowsBlockCompositing = value;
0611     Q_EMIT windowsBlockCompositingChanged();
0612 }
0613 
0614 void Options::setMoveMinimizedWindowsToEndOfTabBoxFocusChain(bool value)
0615 {
0616     if (m_MoveMinimizedWindowsToEndOfTabBoxFocusChain == value) {
0617         return;
0618     }
0619     m_MoveMinimizedWindowsToEndOfTabBoxFocusChain = value;
0620 }
0621 
0622 void Options::setGlPreferBufferSwap(char glPreferBufferSwap)
0623 {
0624     if (glPreferBufferSwap == 'a') {
0625         // buffer copying is very fast with the nvidia blob
0626         // but due to restrictions in DRI2 *incredibly* slow for all MESA drivers
0627         // see https://www.x.org/releases/X11R7.7/doc/dri2proto/dri2proto.txt, item 2.5
0628         if (GLPlatform::instance()->driver() == Driver_NVidia) {
0629             glPreferBufferSwap = CopyFrontBuffer;
0630         } else if (GLPlatform::instance()->driver() != Driver_Unknown) { // undetected, finally resolved when context is initialized
0631             glPreferBufferSwap = ExtendDamage;
0632         }
0633     }
0634     if (m_glPreferBufferSwap == (GlSwapStrategy)glPreferBufferSwap) {
0635         return;
0636     }
0637     m_glPreferBufferSwap = (GlSwapStrategy)glPreferBufferSwap;
0638     Q_EMIT glPreferBufferSwapChanged();
0639 }
0640 
0641 LatencyPolicy Options::latencyPolicy() const
0642 {
0643     return m_latencyPolicy;
0644 }
0645 
0646 void Options::setLatencyPolicy(LatencyPolicy policy)
0647 {
0648     if (m_latencyPolicy == policy) {
0649         return;
0650     }
0651     m_latencyPolicy = policy;
0652     Q_EMIT latencyPolicyChanged();
0653 }
0654 
0655 RenderTimeEstimator Options::renderTimeEstimator() const
0656 {
0657     return m_renderTimeEstimator;
0658 }
0659 
0660 void Options::setRenderTimeEstimator(RenderTimeEstimator estimator)
0661 {
0662     if (m_renderTimeEstimator == estimator) {
0663         return;
0664     }
0665     m_renderTimeEstimator = estimator;
0666     Q_EMIT renderTimeEstimatorChanged();
0667 }
0668 
0669 bool Options::allowTearing() const
0670 {
0671     return m_allowTearing;
0672 }
0673 
0674 void Options::setAllowTearing(bool allow)
0675 {
0676     if (allow != m_allowTearing) {
0677         m_allowTearing = allow;
0678         Q_EMIT allowTearingChanged();
0679     }
0680 }
0681 
0682 void Options::setGlPlatformInterface(OpenGLPlatformInterface interface)
0683 {
0684     // check environment variable
0685     const QByteArray envOpenGLInterface(qgetenv("KWIN_OPENGL_INTERFACE"));
0686     if (!envOpenGLInterface.isEmpty()) {
0687         if (qstrcmp(envOpenGLInterface, "egl") == 0) {
0688             qCDebug(KWIN_CORE) << "Forcing EGL native interface through environment variable";
0689             interface = EglPlatformInterface;
0690         } else if (qstrcmp(envOpenGLInterface, "glx") == 0) {
0691             qCDebug(KWIN_CORE) << "Forcing GLX native interface through environment variable";
0692             interface = GlxPlatformInterface;
0693         }
0694     }
0695     if (kwinApp()->shouldUseWaylandForCompositing() && interface == GlxPlatformInterface) {
0696         // Glx is impossible on Wayland, enforce egl
0697         qCDebug(KWIN_CORE) << "Forcing EGL native interface for Wayland mode";
0698         interface = EglPlatformInterface;
0699     }
0700 #if !HAVE_EPOXY_GLX
0701     qCDebug(KWIN_CORE) << "Forcing EGL native interface as compiled without GLX support";
0702     interface = EglPlatformInterface;
0703 #endif
0704     if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) {
0705         qCDebug(KWIN_CORE) << "Forcing EGL native interface as Qt uses OpenGL ES";
0706         interface = EglPlatformInterface;
0707     } else if (qstrcmp(qgetenv("KWIN_COMPOSE"), "O2ES") == 0) {
0708         qCDebug(KWIN_CORE) << "Forcing EGL native interface as OpenGL ES requested through KWIN_COMPOSE environment variable.";
0709         interface = EglPlatformInterface;
0710     }
0711 
0712     if (m_glPlatformInterface == interface) {
0713         return;
0714     }
0715     m_glPlatformInterface = interface;
0716     Q_EMIT glPlatformInterfaceChanged();
0717 }
0718 
0719 void Options::reparseConfiguration()
0720 {
0721     m_settings->config()->reparseConfiguration();
0722 }
0723 
0724 void Options::updateSettings()
0725 {
0726     loadConfig();
0727     // Read button tooltip animation effect from kdeglobals
0728     // Since we want to allow users to enable window decoration tooltips
0729     // and not kstyle tooltips and vise-versa, we don't read the
0730     // "EffectNoTooltip" setting from kdeglobals.
0731 
0732     //    QToolTip::setGloballyEnabled( d->show_tooltips );
0733     // KDE4 this probably needs to be done manually in clients
0734 
0735     // Driver-specific config detection
0736     reloadCompositingSettings();
0737 
0738     Q_EMIT configChanged();
0739 }
0740 
0741 void Options::loadConfig()
0742 {
0743     m_settings->load();
0744 
0745     syncFromKcfgc();
0746 
0747     // Electric borders
0748     KConfigGroup config(m_settings->config(), "Windows");
0749     OpTitlebarDblClick = windowOperation(config.readEntry("TitlebarDoubleClickCommand", "Maximize"), true);
0750     setOperationMaxButtonLeftClick(windowOperation(config.readEntry("MaximizeButtonLeftClickCommand", "Maximize"), true));
0751     setOperationMaxButtonMiddleClick(windowOperation(config.readEntry("MaximizeButtonMiddleClickCommand", "Maximize (vertical only)"), true));
0752     setOperationMaxButtonRightClick(windowOperation(config.readEntry("MaximizeButtonRightClickCommand", "Maximize (horizontal only)"), true));
0753 
0754     // Mouse bindings
0755     config = KConfigGroup(m_settings->config(), "MouseBindings");
0756     // TODO: add properties for missing options
0757     CmdTitlebarWheel = mouseWheelCommand(config.readEntry("CommandTitlebarWheel", "Nothing"));
0758     CmdAllModKey = (config.readEntry("CommandAllKey", "Meta") == QStringLiteral("Meta")) ? Qt::Key_Meta : Qt::Key_Alt;
0759     CmdAllWheel = mouseWheelCommand(config.readEntry("CommandAllWheel", "Nothing"));
0760     setCommandActiveTitlebar1(mouseCommand(config.readEntry("CommandActiveTitlebar1", "Raise"), true));
0761     setCommandActiveTitlebar2(mouseCommand(config.readEntry("CommandActiveTitlebar2", "Nothing"), true));
0762     setCommandActiveTitlebar3(mouseCommand(config.readEntry("CommandActiveTitlebar3", "Operations menu"), true));
0763     setCommandInactiveTitlebar1(mouseCommand(config.readEntry("CommandInactiveTitlebar1", "Activate and raise"), true));
0764     setCommandInactiveTitlebar2(mouseCommand(config.readEntry("CommandInactiveTitlebar2", "Nothing"), true));
0765     setCommandInactiveTitlebar3(mouseCommand(config.readEntry("CommandInactiveTitlebar3", "Operations menu"), true));
0766     setCommandWindow1(mouseCommand(config.readEntry("CommandWindow1", "Activate, raise and pass click"), false));
0767     setCommandWindow2(mouseCommand(config.readEntry("CommandWindow2", "Activate and pass click"), false));
0768     setCommandWindow3(mouseCommand(config.readEntry("CommandWindow3", "Activate and pass click"), false));
0769     setCommandWindowWheel(mouseCommand(config.readEntry("CommandWindowWheel", "Scroll"), false));
0770     setCommandAll1(mouseCommand(config.readEntry("CommandAll1", "Move"), false));
0771     setCommandAll2(mouseCommand(config.readEntry("CommandAll2", "Toggle raise and lower"), false));
0772     setCommandAll3(mouseCommand(config.readEntry("CommandAll3", "Resize"), false));
0773 
0774     // Modifier Only Shortcuts
0775     config = KConfigGroup(m_settings->config(), "ModifierOnlyShortcuts");
0776     m_modifierOnlyShortcuts.clear();
0777     if (config.hasKey("Shift")) {
0778         m_modifierOnlyShortcuts.insert(Qt::ShiftModifier, config.readEntry("Shift", QStringList()));
0779     }
0780     if (config.hasKey("Control")) {
0781         m_modifierOnlyShortcuts.insert(Qt::ControlModifier, config.readEntry("Control", QStringList()));
0782     }
0783     if (config.hasKey("Alt")) {
0784         m_modifierOnlyShortcuts.insert(Qt::AltModifier, config.readEntry("Alt", QStringList()));
0785     }
0786     m_modifierOnlyShortcuts.insert(Qt::MetaModifier, config.readEntry("Meta", QStringList{QStringLiteral("org.kde.plasmashell"), QStringLiteral("/PlasmaShell"), QStringLiteral("org.kde.PlasmaShell"), QStringLiteral("activateLauncherMenu")}));
0787 }
0788 
0789 void Options::syncFromKcfgc()
0790 {
0791     setCondensedTitle(m_settings->condensedTitle());
0792     setFocusPolicy(m_settings->focusPolicy());
0793     setNextFocusPrefersMouse(m_settings->nextFocusPrefersMouse());
0794     setSeparateScreenFocus(m_settings->separateScreenFocus());
0795     setActiveMouseScreen(m_settings->activeMouseScreen());
0796     setRollOverDesktops(m_settings->rollOverDesktops());
0797     setFocusStealingPreventionLevel(m_settings->focusStealingPreventionLevel());
0798     setActivationDesktopPolicy(m_settings->activationDesktopPolicy());
0799     setXwaylandCrashPolicy(m_settings->xwaylandCrashPolicy());
0800     setXwaylandMaxCrashCount(m_settings->xwaylandMaxCrashCount());
0801     setXwaylandEavesdrops(XwaylandEavesdropsMode(m_settings->xwaylandEavesdrops()));
0802     setPlacement(m_settings->placement());
0803     setAutoRaise(m_settings->autoRaise());
0804     setAutoRaiseInterval(m_settings->autoRaiseInterval());
0805     setDelayFocusInterval(m_settings->delayFocusInterval());
0806     setShadeHover(m_settings->shadeHover());
0807     setShadeHoverInterval(m_settings->shadeHoverInterval());
0808     setClickRaise(m_settings->clickRaise());
0809     setBorderSnapZone(m_settings->borderSnapZone());
0810     setWindowSnapZone(m_settings->windowSnapZone());
0811     setCenterSnapZone(m_settings->centerSnapZone());
0812     setSnapOnlyWhenOverlapping(m_settings->snapOnlyWhenOverlapping());
0813     setKillPingTimeout(m_settings->killPingTimeout());
0814     setHideUtilityWindowsForInactive(m_settings->hideUtilityWindowsForInactive());
0815     setBorderlessMaximizedWindows(m_settings->borderlessMaximizedWindows());
0816     setElectricBorderMaximize(m_settings->electricBorderMaximize());
0817     setElectricBorderTiling(m_settings->electricBorderTiling());
0818     setElectricBorderCornerRatio(m_settings->electricBorderCornerRatio());
0819     setWindowsBlockCompositing(m_settings->windowsBlockCompositing());
0820     setMoveMinimizedWindowsToEndOfTabBoxFocusChain(m_settings->moveMinimizedWindowsToEndOfTabBoxFocusChain());
0821     setLatencyPolicy(m_settings->latencyPolicy());
0822     setRenderTimeEstimator(m_settings->renderTimeEstimator());
0823     setAllowTearing(m_settings->allowTearing());
0824 }
0825 
0826 bool Options::loadCompositingConfig(bool force)
0827 {
0828     KConfigGroup config(m_settings->config(), "Compositing");
0829 
0830     bool useCompositing = false;
0831     CompositingType compositingMode = NoCompositing;
0832     QString compositingBackend = config.readEntry("Backend", "OpenGL");
0833     if (compositingBackend == "QPainter") {
0834         compositingMode = QPainterCompositing;
0835     } else {
0836         compositingMode = OpenGLCompositing;
0837     }
0838 
0839     if (const char *c = getenv("KWIN_COMPOSE")) {
0840         switch (c[0]) {
0841         case 'O':
0842             qCDebug(KWIN_CORE) << "Compositing forced to OpenGL mode by environment variable";
0843             compositingMode = OpenGLCompositing;
0844             useCompositing = true;
0845             break;
0846         case 'Q':
0847             qCDebug(KWIN_CORE) << "Compositing forced to QPainter mode by environment variable";
0848             compositingMode = QPainterCompositing;
0849             useCompositing = true;
0850             break;
0851         case 'N':
0852             if (getenv("KDE_FAILSAFE")) {
0853                 qCDebug(KWIN_CORE) << "Compositing disabled forcefully by KDE failsafe mode";
0854             } else {
0855                 qCDebug(KWIN_CORE) << "Compositing disabled forcefully by environment variable";
0856             }
0857             compositingMode = NoCompositing;
0858             break;
0859         default:
0860             qCDebug(KWIN_CORE) << "Unknown KWIN_COMPOSE mode set, ignoring";
0861             break;
0862         }
0863     }
0864     setCompositingMode(compositingMode);
0865 
0866     const bool platformSupportsNoCompositing = kwinApp()->outputBackend()->supportedCompositors().contains(NoCompositing);
0867     if (m_compositingMode == NoCompositing && platformSupportsNoCompositing) {
0868         setUseCompositing(false);
0869         return false; // do not even detect compositing preferences if explicitly disabled
0870     }
0871 
0872     // it's either enforced by env or by initial resume from "suspend" or we check the settings
0873     setUseCompositing(useCompositing || force || config.readEntry("Enabled", Options::defaultUseCompositing() || !platformSupportsNoCompositing));
0874 
0875     if (!m_useCompositing) {
0876         return false; // not enforced or necessary and not "enabled" by settings
0877     }
0878     return true;
0879 }
0880 
0881 void Options::reloadCompositingSettings(bool force)
0882 {
0883     if (!loadCompositingConfig(force)) {
0884         return;
0885     }
0886     m_settings->load();
0887     syncFromKcfgc();
0888 
0889     // Compositing settings
0890     KConfigGroup config(m_settings->config(), "Compositing");
0891 
0892     setGlSmoothScale(std::clamp(config.readEntry("GLTextureFilter", Options::defaultGlSmoothScale()), -1, 2));
0893     setGlStrictBindingFollowsDriver(!config.hasKey("GLStrictBinding"));
0894     if (!isGlStrictBindingFollowsDriver()) {
0895         setGlStrictBinding(config.readEntry("GLStrictBinding", Options::defaultGlStrictBinding()));
0896     }
0897 
0898     char c = 0;
0899     const QString s = config.readEntry("GLPreferBufferSwap", QString(QLatin1Char(Options::defaultGlPreferBufferSwap())));
0900     if (!s.isEmpty()) {
0901         c = s.at(0).toLatin1();
0902     }
0903     if (c != 'a' && c != 'c' && c != 'p' && c != 'e') {
0904         c = Options::defaultGlPreferBufferSwap();
0905     }
0906     setGlPreferBufferSwap(c);
0907 
0908     HiddenPreviews previews = Options::defaultHiddenPreviews();
0909     // 4 - off, 5 - shown, 6 - always, other are old values
0910     int hps = config.readEntry("HiddenPreviews", 5);
0911     if (hps == 4) {
0912         previews = HiddenPreviewsNever;
0913     } else if (hps == 5) {
0914         previews = HiddenPreviewsShown;
0915     } else if (hps == 6) {
0916         previews = HiddenPreviewsAlways;
0917     }
0918     setHiddenPreviews(previews);
0919 
0920     auto interfaceToKey = [](OpenGLPlatformInterface interface) {
0921         switch (interface) {
0922         case GlxPlatformInterface:
0923             return QStringLiteral("glx");
0924         case EglPlatformInterface:
0925             return QStringLiteral("egl");
0926         default:
0927             return QString();
0928         }
0929     };
0930     auto keyToInterface = [](const QString &key) {
0931         if (key == QStringLiteral("glx")) {
0932             return GlxPlatformInterface;
0933         } else if (key == QStringLiteral("egl")) {
0934             return EglPlatformInterface;
0935         }
0936         return defaultGlPlatformInterface();
0937     };
0938     setGlPlatformInterface(keyToInterface(config.readEntry("GLPlatformInterface", interfaceToKey(m_glPlatformInterface))));
0939 }
0940 
0941 // restricted should be true for operations that the user may not be able to repeat
0942 // if the window is moved out of the workspace (e.g. if the user moves a window
0943 // by the titlebar, and moves it too high beneath Kicker at the top edge, they
0944 // may not be able to move it back, unless they know about Meta+LMB)
0945 Options::WindowOperation Options::windowOperation(const QString &name, bool restricted)
0946 {
0947     if (name == QStringLiteral("Move")) {
0948         return restricted ? MoveOp : UnrestrictedMoveOp;
0949     } else if (name == QStringLiteral("Resize")) {
0950         return restricted ? ResizeOp : UnrestrictedResizeOp;
0951     } else if (name == QStringLiteral("Maximize")) {
0952         return MaximizeOp;
0953     } else if (name == QStringLiteral("Minimize")) {
0954         return MinimizeOp;
0955     } else if (name == QStringLiteral("Close")) {
0956         return CloseOp;
0957     } else if (name == QStringLiteral("OnAllDesktops")) {
0958         return OnAllDesktopsOp;
0959     } else if (name == QStringLiteral("Shade")) {
0960         return ShadeOp;
0961     } else if (name == QStringLiteral("Operations")) {
0962         return OperationsOp;
0963     } else if (name == QStringLiteral("Maximize (vertical only)")) {
0964         return VMaximizeOp;
0965     } else if (name == QStringLiteral("Maximize (horizontal only)")) {
0966         return HMaximizeOp;
0967     } else if (name == QStringLiteral("Lower")) {
0968         return LowerOp;
0969     }
0970     return NoOp;
0971 }
0972 
0973 Options::MouseCommand Options::mouseCommand(const QString &name, bool restricted)
0974 {
0975     QString lowerName = name.toLower();
0976     if (lowerName == QStringLiteral("raise")) {
0977         return MouseRaise;
0978     }
0979     if (lowerName == QStringLiteral("lower")) {
0980         return MouseLower;
0981     }
0982     if (lowerName == QStringLiteral("operations menu")) {
0983         return MouseOperationsMenu;
0984     }
0985     if (lowerName == QStringLiteral("toggle raise and lower")) {
0986         return MouseToggleRaiseAndLower;
0987     }
0988     if (lowerName == QStringLiteral("activate and raise")) {
0989         return MouseActivateAndRaise;
0990     }
0991     if (lowerName == QStringLiteral("activate and lower")) {
0992         return MouseActivateAndLower;
0993     }
0994     if (lowerName == QStringLiteral("activate")) {
0995         return MouseActivate;
0996     }
0997     if (lowerName == QStringLiteral("activate, raise and pass click")) {
0998         return MouseActivateRaiseAndPassClick;
0999     }
1000     if (lowerName == QStringLiteral("activate and pass click")) {
1001         return MouseActivateAndPassClick;
1002     }
1003     if (lowerName == QStringLiteral("scroll")) {
1004         return MouseNothing;
1005     }
1006     if (lowerName == QStringLiteral("activate and scroll")) {
1007         return MouseActivateAndPassClick;
1008     }
1009     if (lowerName == QStringLiteral("activate, raise and scroll")) {
1010         return MouseActivateRaiseAndPassClick;
1011     }
1012     if (lowerName == QStringLiteral("activate, raise and move")) {
1013         return restricted ? MouseActivateRaiseAndMove : MouseActivateRaiseAndUnrestrictedMove;
1014     }
1015     if (lowerName == QStringLiteral("move")) {
1016         return restricted ? MouseMove : MouseUnrestrictedMove;
1017     }
1018     if (lowerName == QStringLiteral("resize")) {
1019         return restricted ? MouseResize : MouseUnrestrictedResize;
1020     }
1021     if (lowerName == QStringLiteral("shade")) {
1022         return MouseShade;
1023     }
1024     if (lowerName == QStringLiteral("minimize")) {
1025         return MouseMinimize;
1026     }
1027     if (lowerName == QStringLiteral("close")) {
1028         return MouseClose;
1029     }
1030     if (lowerName == QStringLiteral("increase opacity")) {
1031         return MouseOpacityMore;
1032     }
1033     if (lowerName == QStringLiteral("decrease opacity")) {
1034         return MouseOpacityLess;
1035     }
1036     if (lowerName == QStringLiteral("nothing")) {
1037         return MouseNothing;
1038     }
1039     return MouseNothing;
1040 }
1041 
1042 Options::MouseWheelCommand Options::mouseWheelCommand(const QString &name)
1043 {
1044     QString lowerName = name.toLower();
1045     if (lowerName == QStringLiteral("raise/lower")) {
1046         return MouseWheelRaiseLower;
1047     }
1048     if (lowerName == QStringLiteral("shade/unshade")) {
1049         return MouseWheelShadeUnshade;
1050     }
1051     if (lowerName == QStringLiteral("maximize/restore")) {
1052         return MouseWheelMaximizeRestore;
1053     }
1054     if (lowerName == QStringLiteral("above/below")) {
1055         return MouseWheelAboveBelow;
1056     }
1057     if (lowerName == QStringLiteral("previous/next desktop")) {
1058         return MouseWheelPreviousNextDesktop;
1059     }
1060     if (lowerName == QStringLiteral("change opacity")) {
1061         return MouseWheelChangeOpacity;
1062     }
1063     if (lowerName == QStringLiteral("nothing")) {
1064         return MouseWheelNothing;
1065     }
1066     return MouseWheelNothing;
1067 }
1068 
1069 bool Options::condensedTitle() const
1070 {
1071     return condensed_title;
1072 }
1073 
1074 Options::MouseCommand Options::wheelToMouseCommand(MouseWheelCommand com, int delta) const
1075 {
1076     switch (com) {
1077     case MouseWheelRaiseLower:
1078         return delta > 0 ? MouseRaise : MouseLower;
1079     case MouseWheelShadeUnshade:
1080         return delta > 0 ? MouseSetShade : MouseUnsetShade;
1081     case MouseWheelMaximizeRestore:
1082         return delta > 0 ? MouseMaximize : MouseRestore;
1083     case MouseWheelAboveBelow:
1084         return delta > 0 ? MouseAbove : MouseBelow;
1085     case MouseWheelPreviousNextDesktop:
1086         return delta > 0 ? MousePreviousDesktop : MouseNextDesktop;
1087     case MouseWheelChangeOpacity:
1088         return delta > 0 ? MouseOpacityMore : MouseOpacityLess;
1089     default:
1090         return MouseNothing;
1091     }
1092 }
1093 #endif
1094 
1095 double Options::animationTimeFactor() const
1096 {
1097 #ifndef KCMRULES
1098     return m_settings->animationDurationFactor();
1099 #else
1100     return 0;
1101 #endif
1102 }
1103 
1104 Options::WindowOperation Options::operationMaxButtonClick(Qt::MouseButtons button) const
1105 {
1106     return button == Qt::RightButton ? opMaxButtonRightClick : button == Qt::MiddleButton ? opMaxButtonMiddleClick
1107                                                                                           : opMaxButtonLeftClick;
1108 }
1109 
1110 QStringList Options::modifierOnlyDBusShortcut(Qt::KeyboardModifier mod) const
1111 {
1112     return m_modifierOnlyShortcuts.value(mod);
1113 }
1114 
1115 bool Options::isUseCompositing() const
1116 {
1117     return m_useCompositing;
1118 }
1119 
1120 } // namespace