/************************************************************************** * KWin - the KDE window manager * * This file is part of the KDE project. * * * * Copyright (C) 2013 Antonis Tsiapaliokas * * Copyright (C) 2013 Martin Gräßlin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * **************************************************************************/ #include "ui_compositing.h" #include #include #include #include #include #include #include #include #include "kwincompositing_setting.h" static bool isRunningPlasma() { return qgetenv("XDG_CURRENT_DESKTOP") == "KDE"; } class KWinCompositingKCM : public KCModule { Q_OBJECT public: enum CompositingTypeIndex { OPENGL31_INDEX = 0, OPENGL20_INDEX, XRENDER_INDEX }; explicit KWinCompositingKCM(QWidget *parent = nullptr, const QVariantList &args = QVariantList()); public Q_SLOTS: void load() override; void save() override; void defaults() override; private Q_SLOTS: void onBackendChanged(); void reenableGl(); private: void init(); void updateUnmanagedItemStatus(); bool compositingRequired() const; Ui_CompositingForm m_form; OrgKdeKwinCompositingInterface *m_compositingInterface; KWinCompositingSetting *m_settings; // unmanaged states int m_backend; bool m_glCore; double m_animationDurationFactor; }; static const QVector s_animationMultipliers = {8, 4, 2, 1, 0.5, 0.25, 0.125, 0}; bool KWinCompositingKCM::compositingRequired() const { return m_compositingInterface->platformRequiresCompositing(); } KWinCompositingKCM::KWinCompositingKCM(QWidget *parent, const QVariantList &args) : KCModule(parent, args) , m_compositingInterface(new OrgKdeKwinCompositingInterface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Compositor"), QDBusConnection::sessionBus(), this)) , m_settings(new KWinCompositingSetting(this)) { m_form.setupUi(this); addConfig(m_settings, this); m_form.glCrashedWarning->setIcon(QIcon::fromTheme(QStringLiteral("dialog-warning"))); QAction *reenableGlAction = new QAction(i18n("Re-enable OpenGL detection"), this); connect(reenableGlAction, &QAction::triggered, this, &KWinCompositingKCM::reenableGl); connect(reenableGlAction, &QAction::triggered, m_form.glCrashedWarning, &KMessageWidget::animatedHide); m_form.glCrashedWarning->addAction(reenableGlAction); m_form.scaleWarning->setIcon(QIcon::fromTheme(QStringLiteral("dialog-warning"))); m_form.tearingWarning->setIcon(QIcon::fromTheme(QStringLiteral("dialog-warning"))); m_form.windowThumbnailWarning->setIcon(QIcon::fromTheme(QStringLiteral("dialog-warning"))); m_form.kcfg_Enabled->setVisible(!compositingRequired()); m_form.kcfg_WindowsBlockCompositing->setVisible(!compositingRequired()); init(); } void KWinCompositingKCM::reenableGl() { m_settings->setOpenGLIsUnsafe(false); m_settings->save(); } void KWinCompositingKCM::init() { auto currentIndexChangedSignal = static_cast(&QComboBox::currentIndexChanged); // animation speed m_form.animationDurationFactor->setMaximum(s_animationMultipliers.size() - 1); connect(m_form.animationDurationFactor, &QSlider::valueChanged, this, [this]() { m_settings->setAnimationDurationFactor(s_animationMultipliers[m_form.animationDurationFactor->value()]); updateUnmanagedItemStatus(); }); if (isRunningPlasma()) { m_form.animationSpeedLabel->hide(); m_form.animationSpeedControls->hide(); } // gl scale filter connect(m_form.kcfg_glTextureFilter, currentIndexChangedSignal, this, [this](int index) { if (index == 2) { m_form.scaleWarning->animatedShow(); } else { m_form.scaleWarning->animatedHide(); } } ); // tearing prevention connect(m_form.kcfg_glPreferBufferSwap, currentIndexChangedSignal, this, [this](int index) { if (index == 2) { // only when cheap - tearing m_form.tearingWarning->setText(i18n("\"Only when cheap\" only prevents tearing for full screen changes like a video.")); m_form.tearingWarning->animatedShow(); } else if (index == 3) { // full screen repaints m_form.tearingWarning->setText(i18n("\"Full screen repaints\" can cause performance problems.")); m_form.tearingWarning->animatedShow(); } else if (index == 4) { // re-use screen content m_form.tearingWarning->setText(i18n("\"Re-use screen content\" causes severe performance problems on MESA drivers.")); m_form.tearingWarning->animatedShow(); } else { m_form.tearingWarning->animatedHide(); } } ); // windowThumbnail connect(m_form.kcfg_HiddenPreviews, currentIndexChangedSignal, this, [this](int index) { if (index == 2) { m_form.windowThumbnailWarning->animatedShow(); } else { m_form.windowThumbnailWarning->animatedHide(); } } ); // compositing type m_form.backend->addItem(i18n("OpenGL 3.1"), CompositingTypeIndex::OPENGL31_INDEX); m_form.backend->addItem(i18n("OpenGL 2.0"), CompositingTypeIndex::OPENGL20_INDEX); m_form.backend->addItem(i18n("XRender"), CompositingTypeIndex::XRENDER_INDEX); connect(m_form.backend, currentIndexChangedSignal, this, &KWinCompositingKCM::onBackendChanged); if (m_settings->openGLIsUnsafe()) { m_form.glCrashedWarning->animatedShow(); } } void KWinCompositingKCM::onBackendChanged() { const int currentType = m_form.backend->currentData().toInt(); m_form.kcfg_glTextureFilter->setVisible(currentType != CompositingTypeIndex::XRENDER_INDEX); m_form.kcfg_XRenderSmoothScale->setVisible(currentType == CompositingTypeIndex::XRENDER_INDEX); updateUnmanagedItemStatus(); } void KWinCompositingKCM::updateUnmanagedItemStatus() { int backend = KWinCompositingSetting::EnumBackend::OpenGL; bool glCore = true; const int currentType = m_form.backend->currentData().toInt(); switch (currentType) { case CompositingTypeIndex::OPENGL31_INDEX: // default already set break; case CompositingTypeIndex::OPENGL20_INDEX: glCore = false; break; case CompositingTypeIndex::XRENDER_INDEX: backend = KWinCompositingSetting::EnumBackend::XRender; glCore = false; break; } const auto animationDuration = s_animationMultipliers[m_form.animationDurationFactor->value()]; const bool inPlasma = isRunningPlasma(); bool changed = glCore != m_glCore; changed |= backend != m_backend; if (!inPlasma) { changed |= (animationDuration != m_animationDurationFactor); } unmanagedWidgetChangeState(changed); bool defaulted = glCore == m_settings->defaultGlCoreValue(); defaulted &= backend == m_settings->defaultBackendValue(); if (!inPlasma) { defaulted &= animationDuration == m_settings->defaultAnimationDurationFactorValue(); } unmanagedWidgetDefaultState(defaulted); } void KWinCompositingKCM::load() { KCModule::load(); // unmanaged items m_settings->findItem("AnimationDurationFactor")->readConfig(m_settings->config()); const double multiplier = m_settings->animationDurationFactor(); auto const it = std::lower_bound(s_animationMultipliers.begin(), s_animationMultipliers.end(), multiplier, std::greater()); const int index = static_cast(std::distance(s_animationMultipliers.begin(), it)); m_form.animationDurationFactor->setValue(index); m_form.animationDurationFactor->setDisabled(m_settings->isAnimationDurationFactorImmutable()); m_settings->findItem("Backend")->readConfig(m_settings->config()); m_settings->findItem("glCore")->readConfig(m_settings->config()); m_backend = m_settings->backend(); m_glCore = m_settings->glCore(); if (m_backend == KWinCompositingSetting::EnumBackend::OpenGL) { if (m_glCore) { m_form.backend->setCurrentIndex(CompositingTypeIndex::OPENGL31_INDEX); } else { m_form.backend->setCurrentIndex(CompositingTypeIndex::OPENGL20_INDEX); } } else { m_form.backend->setCurrentIndex(CompositingTypeIndex::XRENDER_INDEX); } m_form.backend->setDisabled(m_settings->isBackendImmutable()); onBackendChanged(); } void KWinCompositingKCM::defaults() { KCModule::defaults(); // unmanaged widgets m_form.backend->setCurrentIndex(CompositingTypeIndex::OPENGL20_INDEX); // corresponds to 1.0 seconds in s_animationMultipliers m_form.animationDurationFactor->setValue(3); } void KWinCompositingKCM::save() { int backend = KWinCompositingSetting::EnumBackend::OpenGL; bool glCore = true; const int currentType = m_form.backend->currentData().toInt(); switch (currentType) { case CompositingTypeIndex::OPENGL31_INDEX: // default already set break; case CompositingTypeIndex::OPENGL20_INDEX: backend = KWinCompositingSetting::EnumBackend::OpenGL; glCore = false; break; case CompositingTypeIndex::XRENDER_INDEX: backend = KWinCompositingSetting::EnumBackend::XRender; glCore = false; break; } m_settings->setBackend(backend); m_settings->setGlCore(glCore); const auto animationDuration = s_animationMultipliers[m_form.animationDurationFactor->value()]; m_settings->setAnimationDurationFactor(animationDuration); m_settings->save(); KCModule::save(); // Send signal to all kwin instances QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/Compositor"), QStringLiteral("org.kde.kwin.Compositing"), QStringLiteral("reinit")); QDBusConnection::sessionBus().send(message); } K_PLUGIN_FACTORY(KWinCompositingConfigFactory, registerPlugin("compositing"); ) #include "main.moc"