File indexing completed on 2026-07-12 13:08:07

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2013 Antonis Tsiapaliokas <kok3rs@gmail.com>
0006     SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "ui_compositing.h"
0012 #include <kwin_compositing_interface.h>
0013 
0014 #include <QAction>
0015 #include <QApplication>
0016 #include <QLayout>
0017 
0018 #include <KPluginFactory>
0019 #include <KWindowSystem>
0020 #include <kcmodule.h>
0021 #include <kservice.h>
0022 
0023 #include <algorithm>
0024 #include <functional>
0025 
0026 #include "kwincompositing_setting.h"
0027 #include "kwincompositingdata.h"
0028 
0029 static bool isRunningPlasma()
0030 {
0031     return qgetenv("XDG_CURRENT_DESKTOP") == "KDE";
0032 }
0033 
0034 class KWinCompositingKCM : public KCModule
0035 {
0036     Q_OBJECT
0037 public:
0038     explicit KWinCompositingKCM(QWidget *parent = nullptr, const QVariantList &args = QVariantList());
0039 
0040 public Q_SLOTS:
0041     void load() override;
0042     void save() override;
0043     void defaults() override;
0044 
0045 private Q_SLOTS:
0046     void reenableGl();
0047 
0048 private:
0049     void init();
0050     void updateUnmanagedItemStatus();
0051     bool compositingRequired() const;
0052 
0053     Ui_CompositingForm m_form;
0054 
0055     OrgKdeKwinCompositingInterface *m_compositingInterface;
0056     KWinCompositingSetting *m_settings;
0057 };
0058 
0059 static const QVector<qreal> s_animationMultipliers = {8, 4, 2, 1, 0.5, 0.25, 0.125, 0};
0060 
0061 bool KWinCompositingKCM::compositingRequired() const
0062 {
0063     return m_compositingInterface->platformRequiresCompositing();
0064 }
0065 
0066 KWinCompositingKCM::KWinCompositingKCM(QWidget *parent, const QVariantList &args)
0067     : KCModule(parent, args)
0068     , m_compositingInterface(new OrgKdeKwinCompositingInterface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Compositor"), QDBusConnection::sessionBus(), this))
0069     , m_settings(new KWinCompositingSetting(this))
0070 {
0071     m_form.setupUi(this);
0072 
0073     // AnimationDurationFactor should be written to the same place as the lnf to avoid conflicts
0074     m_settings->findItem("AnimationDurationFactor")->setWriteFlags(KConfigBase::Global | KConfigBase::Notify);
0075 
0076     addConfig(m_settings, this);
0077 
0078     m_form.glCrashedWarning->setIcon(QIcon::fromTheme(QStringLiteral("dialog-warning")));
0079     QAction *reenableGlAction = new QAction(i18n("Re-enable OpenGL detection"), this);
0080     connect(reenableGlAction, &QAction::triggered, this, &KWinCompositingKCM::reenableGl);
0081     connect(reenableGlAction, &QAction::triggered, m_form.glCrashedWarning, &KMessageWidget::animatedHide);
0082     m_form.glCrashedWarning->addAction(reenableGlAction);
0083     m_form.windowThumbnailWarning->setIcon(QIcon::fromTheme(QStringLiteral("dialog-warning")));
0084 
0085     m_form.kcfg_Enabled->setVisible(!compositingRequired());
0086     m_form.kcfg_WindowsBlockCompositing->setVisible(!compositingRequired());
0087     m_form.compositingLabel->setVisible(!compositingRequired());
0088     m_form.kcfg_AllowTearing->setVisible(compositingRequired());
0089 
0090     connect(this, &KWinCompositingKCM::defaultsIndicatorsVisibleChanged, this, &KWinCompositingKCM::updateUnmanagedItemStatus);
0091 
0092     if (KWindowSystem::isPlatformWayland()) {
0093         m_form.kcfg_HiddenPreviews->setVisible(false);
0094         m_form.label_HiddenPreviews->setVisible(false);
0095     }
0096     init();
0097 }
0098 
0099 void KWinCompositingKCM::reenableGl()
0100 {
0101     m_settings->setLastFailureTimestamp(0);
0102     m_settings->save();
0103 }
0104 
0105 void KWinCompositingKCM::init()
0106 {
0107     auto currentIndexChangedSignal = static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged);
0108 
0109     // animation speed
0110     m_form.animationDurationFactor->setMaximum(s_animationMultipliers.size() - 1);
0111     connect(m_form.animationDurationFactor, &QSlider::valueChanged, this, [this]() {
0112         updateUnmanagedItemStatus();
0113         m_settings->setAnimationDurationFactor(s_animationMultipliers[m_form.animationDurationFactor->value()]);
0114     });
0115 
0116     if (isRunningPlasma()) {
0117         m_form.animationSpeedLabel->hide();
0118         m_form.animationSpeedControls->hide();
0119     }
0120 
0121     // windowThumbnail
0122     connect(m_form.kcfg_HiddenPreviews, currentIndexChangedSignal, this, [this](int index) {
0123         if (index == 2) {
0124             m_form.windowThumbnailWarning->animatedShow();
0125         } else {
0126             m_form.windowThumbnailWarning->animatedHide();
0127         }
0128     });
0129 
0130     if (m_settings->lastFailureTimestamp() > 0) {
0131         m_form.glCrashedWarning->animatedShow();
0132     }
0133 }
0134 
0135 void KWinCompositingKCM::updateUnmanagedItemStatus()
0136 {
0137     const auto animationDuration = s_animationMultipliers[m_form.animationDurationFactor->value()];
0138 
0139     const bool inPlasma = isRunningPlasma();
0140 
0141     bool changed = false;
0142     if (!inPlasma) {
0143         changed |= (animationDuration != m_settings->animationDurationFactor());
0144     }
0145     unmanagedWidgetChangeState(changed);
0146 
0147     bool defaulted = true;
0148     if (!inPlasma) {
0149         defaulted &= animationDuration == m_settings->defaultAnimationDurationFactorValue();
0150     }
0151 
0152     unmanagedWidgetDefaultState(defaulted);
0153 }
0154 
0155 void KWinCompositingKCM::load()
0156 {
0157     KCModule::load();
0158 
0159     // unmanaged items
0160     m_settings->findItem("AnimationDurationFactor")->readConfig(m_settings->config());
0161     const double multiplier = m_settings->animationDurationFactor();
0162     auto const it = std::lower_bound(s_animationMultipliers.begin(), s_animationMultipliers.end(), multiplier, std::greater<qreal>());
0163     const int index = static_cast<int>(std::distance(s_animationMultipliers.begin(), it));
0164     m_form.animationDurationFactor->setValue(index);
0165     m_form.animationDurationFactor->setDisabled(m_settings->isAnimationDurationFactorImmutable());
0166 }
0167 
0168 void KWinCompositingKCM::defaults()
0169 {
0170     KCModule::defaults();
0171 
0172     // unmanaged widgets
0173     if (!isRunningPlasma()) {
0174         // corresponds to 1.0 seconds in s_animationMultipliers
0175         m_form.animationDurationFactor->setValue(3);
0176     }
0177 }
0178 
0179 void KWinCompositingKCM::save()
0180 {
0181     if (!isRunningPlasma()) {
0182         const auto animationDuration = s_animationMultipliers[m_form.animationDurationFactor->value()];
0183         m_settings->setAnimationDurationFactor(animationDuration);
0184     }
0185     m_settings->save();
0186 
0187     KCModule::save();
0188 
0189     // This clears up old entries that are now migrated to kdeglobals
0190     KConfig("kwinrc", KConfig::NoGlobals).group("KDE").revertToDefault("AnimationDurationFactor");
0191 
0192     // Send signal to all kwin instances
0193     QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/Compositor"),
0194                                                       QStringLiteral("org.kde.kwin.Compositing"),
0195                                                       QStringLiteral("reinit"));
0196     QDBusConnection::sessionBus().send(message);
0197 }
0198 
0199 K_PLUGIN_FACTORY_WITH_JSON(KWinCompositingConfigFactory, "kwincompositing.json",
0200                            registerPlugin<KWinCompositingKCM>();
0201                            registerPlugin<KWinCompositingData>();)
0202 
0203 #include "main.moc"