diff --git a/dbusinterface.cpp b/dbusinterface.cpp index 302355bd9..17ab6bd26 100644 --- a/dbusinterface.cpp +++ b/dbusinterface.cpp @@ -1,265 +1,270 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2012 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 . *********************************************************************/ // own #include "dbusinterface.h" #include "compositingadaptor.h" // kwin #include "atoms.h" #include "composite.h" #include "debug_console.h" #include "main.h" #include "placement.h" #include "platform.h" #include "kwinadaptor.h" #include "scene.h" #include "workspace.h" #include "virtualdesktops.h" #ifdef KWIN_BUILD_ACTIVITIES #include "activities.h" #endif // Qt #include #include namespace KWin { DBusInterface::DBusInterface(QObject *parent) : QObject(parent) , m_serviceName(QStringLiteral("org.kde.KWin")) { (void) new KWinAdaptor(this); QDBusConnection dbus = QDBusConnection::sessionBus(); dbus.registerObject(QStringLiteral("/KWin"), this); const QByteArray dBusSuffix = qgetenv("KWIN_DBUS_SERVICE_SUFFIX"); if (!dBusSuffix.isNull()) { m_serviceName = m_serviceName + QLatin1Char('.') + dBusSuffix; } if (!dbus.registerService(m_serviceName)) { QDBusServiceWatcher *dog = new QDBusServiceWatcher(m_serviceName, dbus, QDBusServiceWatcher::WatchForUnregistration, this); connect (dog, SIGNAL(serviceUnregistered(QString)), SLOT(becomeKWinService(QString))); } else { announceService(); } dbus.connect(QString(), QStringLiteral("/KWin"), QStringLiteral("org.kde.KWin"), QStringLiteral("reloadConfig"), Workspace::self(), SLOT(slotReloadConfig())); } void DBusInterface::becomeKWinService(const QString &service) { // TODO: this watchdog exists to make really safe that we at some point get the service // but it's probably no longer needed since we explicitly unregister the service with the deconstructor if (service == m_serviceName && QDBusConnection::sessionBus().registerService(m_serviceName) && sender()) { sender()->deleteLater(); // bye doggy :'( announceService(); } } DBusInterface::~DBusInterface() { QDBusConnection::sessionBus().unregisterService(m_serviceName); // KApplication automatically also grabs org.kde.kwin, so it's often been used externally - ensure to free it as well QDBusConnection::sessionBus().unregisterService(QStringLiteral("org.kde.kwin")); xcb_delete_property(connection(), rootWindow(), atoms->kwin_dbus_service); } void DBusInterface::announceService() { const QByteArray service = m_serviceName.toUtf8(); xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, rootWindow(), atoms->kwin_dbus_service, atoms->utf8_string, 8, service.size(), service.constData()); } // wrap void methods with no arguments to Workspace #define WRAP(name) \ void DBusInterface::name() \ {\ Workspace::self()->name();\ } WRAP(reconfigure) #undef WRAP void DBusInterface::killWindow() { Workspace::self()->slotKillWindow(); } #define WRAP(name) \ void DBusInterface::name() \ {\ Placement::self()->name();\ } WRAP(cascadeDesktop) WRAP(unclutterDesktop) #undef WRAP // wrap returning methods with no arguments to Workspace #define WRAP( rettype, name ) \ rettype DBusInterface::name( ) \ {\ return Workspace::self()->name(); \ } WRAP(QString, supportInformation) #undef WRAP bool DBusInterface::startActivity(const QString &in0) { #ifdef KWIN_BUILD_ACTIVITIES if (!Activities::self()) { return false; } return Activities::self()->start(in0); #else Q_UNUSED(in0) return false; #endif } bool DBusInterface::stopActivity(const QString &in0) { #ifdef KWIN_BUILD_ACTIVITIES if (!Activities::self()) { return false; } return Activities::self()->stop(in0); #else Q_UNUSED(in0) return false; #endif } int DBusInterface::currentDesktop() { return VirtualDesktopManager::self()->current(); } bool DBusInterface::setCurrentDesktop(int desktop) { return VirtualDesktopManager::self()->setCurrent(desktop); } void DBusInterface::nextDesktop() { VirtualDesktopManager::self()->moveTo(); } void DBusInterface::previousDesktop() { VirtualDesktopManager::self()->moveTo(); } void DBusInterface::showDebugConsole() { DebugConsole *console = new DebugConsole; console->show(); } CompositorDBusInterface::CompositorDBusInterface(Compositor *parent) : QObject(parent) , m_compositor(parent) { connect(m_compositor, &Compositor::compositingToggled, this, &CompositorDBusInterface::compositingToggled); new CompositingAdaptor(this); QDBusConnection dbus = QDBusConnection::sessionBus(); dbus.registerObject(QStringLiteral("/Compositor"), this); dbus.connect(QString(), QStringLiteral("/Compositor"), QStringLiteral("org.kde.kwin.Compositing"), QStringLiteral("reinit"), m_compositor, SLOT(slotReinitialize())); } QString CompositorDBusInterface::compositingNotPossibleReason() const { return kwinApp()->platform()->compositingNotPossibleReason(); } QString CompositorDBusInterface::compositingType() const { if (!m_compositor->hasScene()) { return QStringLiteral("none"); } switch (m_compositor->scene()->compositingType()) { case XRenderCompositing: return QStringLiteral("xrender"); case OpenGL2Compositing: if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) { return QStringLiteral("gles"); } else { return QStringLiteral("gl2"); } case QPainterCompositing: return QStringLiteral("qpainter"); case NoCompositing: default: return QStringLiteral("none"); } } bool CompositorDBusInterface::isActive() const { return m_compositor->isActive(); } bool CompositorDBusInterface::isCompositingPossible() const { return kwinApp()->platform()->compositingPossible(); } bool CompositorDBusInterface::isOpenGLBroken() const { return kwinApp()->platform()->openGLCompositingIsBroken(); } +bool CompositorDBusInterface::platformRequiresCompositing() const +{ + return kwinApp()->platform()->requiresCompositing(); +} + void CompositorDBusInterface::resume() { m_compositor->resume(Compositor::ScriptSuspend); } void CompositorDBusInterface::suspend() { m_compositor->suspend(Compositor::ScriptSuspend); } QStringList CompositorDBusInterface::supportedOpenGLPlatformInterfaces() const { QStringList interfaces; bool supportsGlx = false; #if HAVE_EPOXY_GLX supportsGlx = (kwinApp()->operationMode() == Application::OperationModeX11); #endif if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) { supportsGlx = false; } if (supportsGlx) { interfaces << QStringLiteral("glx"); } interfaces << QStringLiteral("egl"); return interfaces; } } // namespace diff --git a/dbusinterface.h b/dbusinterface.h index edec3248d..5781a28e8 100644 --- a/dbusinterface.h +++ b/dbusinterface.h @@ -1,169 +1,171 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2012 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 . *********************************************************************/ #ifndef KWIN_DBUS_INTERFACE_H #define KWIN_DBUS_INTERFACE_H #include #include namespace KWin { class Compositor; /** * @brief This class is a wrapper for the org.kde.KWin D-Bus interface. * * The main purpose of this class is to be exported on the D-Bus as object /KWin. * It is a pure wrapper to provide the deprecated D-Bus methods which have been * removed from Workspace which used to implement the complete D-Bus interface. * * Nowadays the D-Bus interfaces are distributed, parts of it are exported on * /Compositor, parts on /Effects and parts on /KWin. The implementation in this * class just delegates the method calls to the actual implementation in one of the * three singletons. * * @author Martin Gräßlin **/ class DBusInterface: public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.KWin") public: explicit DBusInterface(QObject *parent); virtual ~DBusInterface(); public: // PROPERTIES public Q_SLOTS: // METHODS Q_NOREPLY void cascadeDesktop(); int currentDesktop(); Q_NOREPLY void killWindow(); void nextDesktop(); void previousDesktop(); Q_NOREPLY void reconfigure(); bool setCurrentDesktop(int desktop); bool startActivity(const QString &in0); bool stopActivity(const QString &in0); QString supportInformation(); Q_NOREPLY void unclutterDesktop(); Q_NOREPLY void showDebugConsole(); private Q_SLOTS: void becomeKWinService(const QString &service); private: void announceService(); QString m_serviceName; }; class CompositorDBusInterface : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.kwin.Compositing") /** * @brief Whether the Compositor is active. That is a Scene is present and the Compositor is * not shutting down itself. **/ Q_PROPERTY(bool active READ isActive) /** * @brief Whether compositing is possible. Mostly means whether the required X extensions * are available. **/ Q_PROPERTY(bool compositingPossible READ isCompositingPossible) /** * @brief The reason why compositing is not possible. Empty String if compositing is possible. **/ Q_PROPERTY(QString compositingNotPossibleReason READ compositingNotPossibleReason) /** * @brief Whether OpenGL has failed badly in the past (crash) and is considered as broken. **/ Q_PROPERTY(bool openGLIsBroken READ isOpenGLBroken) /** * The type of the currently used Scene: * @li @c none No Compositing * @li @c xrender XRender * @li @c gl1 OpenGL 1 * @li @c gl2 OpenGL 2 * @li @c gles OpenGL ES 2 **/ Q_PROPERTY(QString compositingType READ compositingType) /** * @brief All currently supported OpenGLPlatformInterfaces. * * Possible values: * @li glx * @li egl * * Values depend on operation mode and compile time options. **/ Q_PROPERTY(QStringList supportedOpenGLPlatformInterfaces READ supportedOpenGLPlatformInterfaces) + Q_PROPERTY(bool platformRequiresCompositing READ platformRequiresCompositing) public: explicit CompositorDBusInterface(Compositor *parent); virtual ~CompositorDBusInterface() = default; bool isActive() const; bool isCompositingPossible() const; QString compositingNotPossibleReason() const; bool isOpenGLBroken() const; QString compositingType() const; QStringList supportedOpenGLPlatformInterfaces() const; + bool platformRequiresCompositing() const; public Q_SLOTS: /** * @brief Suspends the Compositor if it is currently active. * * Note: it is possible that the Compositor is not able to suspend. Use @link isActive to check * whether the Compositor has been suspended. * * @return void * @see resume * @see isActive **/ void suspend(); /** * @brief Resumes the Compositor if it is currently suspended. * * Note: it is possible that the Compositor cannot be resumed, that is there might be Clients * blocking the usage of Compositing or the Scene might be broken. Use @link isActive to check * whether the Compositor has been resumed. Also check @link isCompositingPossible and * @link isOpenGLBroken. * * Note: The starting of the Compositor can require some time and is partially done threaded. * After this method returns the setup may not have been completed. * * @return void * @see suspend * @see isActive * @see isCompositingPossible * @see isOpenGLBroken **/ void resume(); Q_SIGNALS: void compositingToggled(bool active); private: Compositor *m_compositor; }; } // namespace #endif // KWIN_DBUS_INTERFACE_H diff --git a/kcmkwin/kwincompositing/compositing.cpp b/kcmkwin/kwincompositing/compositing.cpp index 5f0815b6e..85cfe975b 100644 --- a/kcmkwin/kwincompositing/compositing.cpp +++ b/kcmkwin/kwincompositing/compositing.cpp @@ -1,542 +1,555 @@ /************************************************************************** * 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 "compositing.h" #include #include #include #include #include #include #include #include #include namespace KWin { namespace Compositing { Compositing::Compositing(QObject *parent) : QObject(parent) , m_animationSpeed(0) , m_windowThumbnail(0) , m_glScaleFilter(0) , m_xrScaleFilter(false) , m_glSwapStrategy(0) , m_glColorCorrection(false) , m_compositingType(0) , m_compositingEnabled(true) , m_changed(false) , m_openGLPlatformInterfaceModel(new OpenGLPlatformInterfaceModel(this)) , m_openGLPlatformInterface(0) , m_windowsBlockCompositing(true) + , m_compositingInterface(new OrgKdeKwinCompositingInterface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Compositor"), QDBusConnection::sessionBus(), this)) { reset(); connect(this, &Compositing::animationSpeedChanged, this, &Compositing::changed); connect(this, &Compositing::windowThumbnailChanged, this, &Compositing::changed); connect(this, &Compositing::glScaleFilterChanged, this, &Compositing::changed); connect(this, &Compositing::xrScaleFilterChanged, this, &Compositing::changed); connect(this, &Compositing::glSwapStrategyChanged, this, &Compositing::changed); connect(this, &Compositing::glColorCorrectionChanged, this, &Compositing::changed); connect(this, &Compositing::compositingTypeChanged, this, &Compositing::changed); connect(this, &Compositing::compositingEnabledChanged, this, &Compositing::changed); connect(this, &Compositing::openGLPlatformInterfaceChanged, this, &Compositing::changed); connect(this, &Compositing::windowsBlockCompositingChanged, this, &Compositing::changed); connect(this, &Compositing::changed, [this]{ m_changed = true; }); } void Compositing::reset() { KConfigGroup kwinConfig(KSharedConfig::openConfig(QStringLiteral("kwinrc")), QStringLiteral("Compositing")); setAnimationSpeed(kwinConfig.readEntry("AnimationSpeed", 3)); setWindowThumbnail(kwinConfig.readEntry("HiddenPreviews", 5) - 4); setGlScaleFilter(kwinConfig.readEntry("GLTextureFilter", 2)); setXrScaleFilter(kwinConfig.readEntry("XRenderSmoothScale", false)); setCompositingEnabled(kwinConfig.readEntry("Enabled", true)); auto swapStrategy = [&kwinConfig]() { const QString glSwapStrategyValue = kwinConfig.readEntry("GLPreferBufferSwap", "a"); if (glSwapStrategyValue == "n") { return 0; } else if (glSwapStrategyValue == "a") { return 1; } else if (glSwapStrategyValue == "e") { return 2; } else if (glSwapStrategyValue == "p") { return 3; } else if (glSwapStrategyValue == "c") { return 4; } return 0; }; setGlSwapStrategy(swapStrategy()); setGlColorCorrection(kwinConfig.readEntry("GLColorCorrection", false)); auto type = [&kwinConfig]{ const QString backend = kwinConfig.readEntry("Backend", "OpenGL"); const bool glCore = kwinConfig.readEntry("GLCore", false); if (backend == QStringLiteral("OpenGL")) { if (glCore) { return CompositingType::OPENGL31_INDEX; } else { return CompositingType::OPENGL20_INDEX; } } else { return CompositingType::XRENDER_INDEX; } }; setCompositingType(type()); const QModelIndex index = m_openGLPlatformInterfaceModel->indexForKey(kwinConfig.readEntry("GLPlatformInterface", "glx")); setOpenGLPlatformInterface(index.isValid() ? index.row() : 0); setWindowsBlockCompositing(kwinConfig.readEntry("WindowsBlockCompositing", true)); m_changed = false; } void Compositing::defaults() { setAnimationSpeed(3); setWindowThumbnail(1); setGlScaleFilter(2); setXrScaleFilter(false); setGlSwapStrategy(1); setGlColorCorrection(false); setCompositingType(CompositingType::OPENGL20_INDEX); const QModelIndex index = m_openGLPlatformInterfaceModel->indexForKey(QStringLiteral("glx")); setOpenGLPlatformInterface(index.isValid() ? index.row() : 0); setWindowsBlockCompositing(true); m_changed = true; } bool Compositing::OpenGLIsUnsafe() const { KConfigGroup kwinConfig(KSharedConfig::openConfig("kwinrc"), "Compositing"); return kwinConfig.readEntry("OpenGLIsUnsafe", true); } bool Compositing::OpenGLIsBroken() { - OrgKdeKwinCompositingInterface interface(QStringLiteral("org.kde.KWin"), - QStringLiteral("/Compositor"), - QDBusConnection::sessionBus()); KConfigGroup kwinConfig(KSharedConfig::openConfig("kwinrc"), "Compositing"); QString oldBackend = kwinConfig.readEntry("Backend", "OpenGL"); kwinConfig.writeEntry("Backend", "OpenGL"); kwinConfig.sync(); - if (interface.openGLIsBroken()) { + if (m_compositingInterface->openGLIsBroken()) { kwinConfig.writeEntry("Backend", oldBackend); kwinConfig.sync(); return true; } kwinConfig.writeEntry("OpenGLIsUnsafe", false); kwinConfig.sync(); return false; } void Compositing::reenableOpenGLDetection() { KConfigGroup kwinConfig(KSharedConfig::openConfig("kwinrc"), "Compositing"); kwinConfig.writeEntry("OpenGLIsUnsafe", false); kwinConfig.sync(); } int Compositing::animationSpeed() const { return m_animationSpeed; } int Compositing::windowThumbnail() const { return m_windowThumbnail; } int Compositing::glScaleFilter() const { return m_glScaleFilter; } bool Compositing::xrScaleFilter() const { return m_xrScaleFilter; } int Compositing::glSwapStrategy() const { return m_glSwapStrategy; } bool Compositing::glColorCorrection() const { return m_glColorCorrection; } int Compositing::compositingType() const { return m_compositingType; } bool Compositing::compositingEnabled() const { return m_compositingEnabled; } void Compositing::setAnimationSpeed(int speed) { if (speed == m_animationSpeed) { return; } m_animationSpeed = speed; emit animationSpeedChanged(speed); } void Compositing::setGlColorCorrection(bool correction) { if (correction == m_glColorCorrection) { return; } m_glColorCorrection = correction; emit glColorCorrectionChanged(correction); } void Compositing::setGlScaleFilter(int index) { if (index == m_glScaleFilter) { return; } m_glScaleFilter = index; emit glScaleFilterChanged(index); } void Compositing::setGlSwapStrategy(int strategy) { if (strategy == m_glSwapStrategy) { return; } m_glSwapStrategy = strategy; emit glSwapStrategyChanged(strategy); } void Compositing::setWindowThumbnail(int index) { if (index == m_windowThumbnail) { return; } m_windowThumbnail = index; emit windowThumbnailChanged(index); } void Compositing::setXrScaleFilter(bool filter) { if (filter == m_xrScaleFilter) { return; } m_xrScaleFilter = filter; emit xrScaleFilterChanged(filter); } void Compositing::setCompositingType(int index) { if (index == m_compositingType) { return; } m_compositingType = index; emit compositingTypeChanged(index); } void Compositing::setCompositingEnabled(bool enabled) { + if (compositingRequired()) { + return; + } if (enabled == m_compositingEnabled) { return; } m_compositingEnabled = enabled; emit compositingEnabledChanged(enabled); } void Compositing::save() { KConfigGroup kwinConfig(KSharedConfig::openConfig(QStringLiteral("kwinrc")), "Compositing"); kwinConfig.writeEntry("AnimationSpeed", animationSpeed()); kwinConfig.writeEntry("HiddenPreviews", windowThumbnail() + 4); kwinConfig.writeEntry("GLTextureFilter", glScaleFilter()); kwinConfig.writeEntry("XRenderSmoothScale", xrScaleFilter()); - kwinConfig.writeEntry("Enabled", compositingEnabled()); + if (!compositingRequired()) { + kwinConfig.writeEntry("Enabled", compositingEnabled()); + } auto swapStrategy = [this] { switch (glSwapStrategy()) { case 0: return QStringLiteral("n"); case 2: return QStringLiteral("e"); case 3: return QStringLiteral("p"); case 4: return QStringLiteral("c"); case 1: default: return QStringLiteral("a"); } }; kwinConfig.writeEntry("GLPreferBufferSwap", swapStrategy()); kwinConfig.writeEntry("GLColorCorrection", glColorCorrection()); QString backend; bool glCore = false; switch (compositingType()) { case CompositingType::OPENGL31_INDEX: backend = "OpenGL"; glCore = true; break; case CompositingType::OPENGL20_INDEX: backend = "OpenGL"; glCore = false; break; case CompositingType::XRENDER_INDEX: backend = "XRender"; glCore = false; break; } kwinConfig.writeEntry("Backend", backend); kwinConfig.writeEntry("GLCore", glCore); const QModelIndex glIndex = m_openGLPlatformInterfaceModel->index(m_openGLPlatformInterface); if (glIndex.isValid()) { kwinConfig.writeEntry("GLPlatformInterface", glIndex.data(Qt::UserRole).toString()); } - kwinConfig.writeEntry("WindowsBlockCompositing", windowsBlockCompositing()); + if (!compositingRequired()) { + kwinConfig.writeEntry("WindowsBlockCompositing", windowsBlockCompositing()); + } kwinConfig.sync(); if (m_changed) { // Send signal to all kwin instances QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/Compositor"), QStringLiteral("org.kde.kwin.Compositing"), QStringLiteral("reinit")); QDBusConnection::sessionBus().send(message); m_changed = false; } } OpenGLPlatformInterfaceModel *Compositing::openGLPlatformInterfaceModel() const { return m_openGLPlatformInterfaceModel; } int Compositing::openGLPlatformInterface() const { return m_openGLPlatformInterface; } void Compositing::setOpenGLPlatformInterface(int interface) { if (m_openGLPlatformInterface == interface) { return; } m_openGLPlatformInterface = interface; emit openGLPlatformInterfaceChanged(interface); } bool Compositing::windowsBlockCompositing() const { return m_windowsBlockCompositing; } void Compositing::setWindowsBlockCompositing(bool set) { + if (compositingRequired()) { + return; + } if (m_windowsBlockCompositing == set) { return; } m_windowsBlockCompositing = set; emit windowsBlockCompositingChanged(set); } +bool Compositing::compositingRequired() const +{ + return m_compositingInterface->platformRequiresCompositing(); +} + CompositingType::CompositingType(QObject *parent) : QAbstractItemModel(parent) { generateCompositing(); } void CompositingType::generateCompositing() { QHash compositingTypes; compositingTypes[i18n("OpenGL 3.1")] = CompositingType::OPENGL31_INDEX; compositingTypes[i18n("OpenGL 2.0")] = CompositingType::OPENGL20_INDEX; compositingTypes[i18n("XRender")] = CompositingType::XRENDER_INDEX; CompositingData data; beginResetModel(); auto it = compositingTypes.begin(); while (it != compositingTypes.end()) { data.name = it.key(); data.type = it.value(); m_compositingList << data; it++; } qSort(m_compositingList.begin(), m_compositingList.end(), [](const CompositingData &a, const CompositingData &b) { return a.type < b.type; }); endResetModel(); } QHash< int, QByteArray > CompositingType::roleNames() const { QHash roleNames; roleNames[NameRole] = "NameRole"; roleNames[TypeRole] = QByteArrayLiteral("type"); return roleNames; } QModelIndex CompositingType::index(int row, int column, const QModelIndex &parent) const { if (parent.isValid() || column > 0 || column < 0 || row < 0 || row >= m_compositingList.count()) { return QModelIndex(); } return createIndex(row, column); } QModelIndex CompositingType::parent(const QModelIndex &child) const { Q_UNUSED(child) return QModelIndex(); } int CompositingType::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent) return 1; } int CompositingType::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_compositingList.count(); } QVariant CompositingType::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } switch (role) { case Qt::DisplayRole: case NameRole: return m_compositingList.at(index.row()).name; case TypeRole: return m_compositingList.at(index.row()).type; default: return QVariant(); } } int CompositingType::compositingTypeForIndex(int row) const { return index(row, 0).data(TypeRole).toInt(); } int CompositingType::indexForCompositingType(int type) const { for (int i = 0; i < m_compositingList.count(); ++i) { if (m_compositingList.at(i).type == type) { return i; } } return -1; } OpenGLPlatformInterfaceModel::OpenGLPlatformInterfaceModel(QObject *parent) : QAbstractListModel(parent) { beginResetModel(); OrgKdeKwinCompositingInterface interface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Compositor"), QDBusConnection::sessionBus()); m_keys << interface.supportedOpenGLPlatformInterfaces(); for (const QString &key : m_keys) { if (key == QStringLiteral("egl")) { m_names << i18nc("OpenGL Platform Interface", "EGL"); } else if (key == QStringLiteral("glx")) { m_names << i18nc("OpenGL Platform Interface", "GLX"); } else { m_names << key; } } endResetModel(); } OpenGLPlatformInterfaceModel::~OpenGLPlatformInterfaceModel() = default; int OpenGLPlatformInterfaceModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_keys.count(); } QHash< int, QByteArray > OpenGLPlatformInterfaceModel::roleNames() const { return QHash({ {Qt::DisplayRole, QByteArrayLiteral("display")}, {Qt::UserRole, QByteArrayLiteral("openglPlatformInterface")} }); } QVariant OpenGLPlatformInterfaceModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.row() < 0 || index.row() >= m_keys.size() || index.column() != 0) { return QVariant(); } switch (role) { case Qt::DisplayRole: return m_names.at(index.row()); case Qt::UserRole: return m_keys.at(index.row()); default: return QVariant(); } } QModelIndex OpenGLPlatformInterfaceModel::indexForKey(const QString &key) const { const int keyIndex = m_keys.indexOf(key); if (keyIndex < 0) { return QModelIndex(); } return createIndex(keyIndex, 0); } }//end namespace Compositing }//end namespace KWin diff --git a/kcmkwin/kwincompositing/compositing.h b/kcmkwin/kwincompositing/compositing.h index e739b2531..04a447834 100644 --- a/kcmkwin/kwincompositing/compositing.h +++ b/kcmkwin/kwincompositing/compositing.h @@ -1,180 +1,186 @@ /************************************************************************** * KWin - the KDE window manager * * This file is part of the KDE project. * * * * Copyright (C) 2013 Antonis Tsiapaliokas * * * * 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 . * **************************************************************************/ #ifndef COMPOSITING_H #define COMPOSITING_H #include #include +class OrgKdeKwinCompositingInterface; + namespace KWin { namespace Compositing { class OpenGLPlatformInterfaceModel; class Compositing : public QObject { Q_OBJECT Q_PROPERTY(int animationSpeed READ animationSpeed WRITE setAnimationSpeed NOTIFY animationSpeedChanged) Q_PROPERTY(int windowThumbnail READ windowThumbnail WRITE setWindowThumbnail NOTIFY windowThumbnailChanged) Q_PROPERTY(int glScaleFilter READ glScaleFilter WRITE setGlScaleFilter NOTIFY glScaleFilterChanged) Q_PROPERTY(bool xrScaleFilter READ xrScaleFilter WRITE setXrScaleFilter NOTIFY xrScaleFilterChanged) Q_PROPERTY(int glSwapStrategy READ glSwapStrategy WRITE setGlSwapStrategy NOTIFY glSwapStrategyChanged) Q_PROPERTY(bool glColorCorrection READ glColorCorrection WRITE setGlColorCorrection NOTIFY glColorCorrectionChanged) Q_PROPERTY(int compositingType READ compositingType WRITE setCompositingType NOTIFY compositingTypeChanged) Q_PROPERTY(bool compositingEnabled READ compositingEnabled WRITE setCompositingEnabled NOTIFY compositingEnabledChanged) Q_PROPERTY(KWin::Compositing::OpenGLPlatformInterfaceModel *openGLPlatformInterfaceModel READ openGLPlatformInterfaceModel CONSTANT) Q_PROPERTY(int openGLPlatformInterface READ openGLPlatformInterface WRITE setOpenGLPlatformInterface NOTIFY openGLPlatformInterfaceChanged) Q_PROPERTY(bool windowsBlockCompositing READ windowsBlockCompositing WRITE setWindowsBlockCompositing NOTIFY windowsBlockCompositingChanged) + Q_PROPERTY(bool compositingRequired READ compositingRequired CONSTANT) public: explicit Compositing(QObject *parent = 0); Q_INVOKABLE bool OpenGLIsUnsafe() const; Q_INVOKABLE bool OpenGLIsBroken(); Q_INVOKABLE void reenableOpenGLDetection(); int animationSpeed() const; int windowThumbnail() const; int glScaleFilter() const; bool xrScaleFilter() const; int glSwapStrategy() const; bool glColorCorrection() const; int compositingType() const; bool compositingEnabled() const; int openGLPlatformInterface() const; bool windowsBlockCompositing() const; + bool compositingRequired() const; OpenGLPlatformInterfaceModel *openGLPlatformInterfaceModel() const; void setAnimationSpeed(int speed); void setWindowThumbnail(int index); void setGlScaleFilter(int index); void setXrScaleFilter(bool filter); void setGlSwapStrategy(int strategy); void setGlColorCorrection(bool correction); void setCompositingType(int index); void setCompositingEnabled(bool enalbed); void setOpenGLPlatformInterface(int interface); void setWindowsBlockCompositing(bool set); void save(); public Q_SLOTS: void reset(); void defaults(); Q_SIGNALS: void changed(); void animationSpeedChanged(int); void windowThumbnailChanged(int); void glScaleFilterChanged(int); void xrScaleFilterChanged(int); void glSwapStrategyChanged(int); void glColorCorrectionChanged(bool); void compositingTypeChanged(int); void compositingEnabledChanged(bool); void openGLPlatformInterfaceChanged(int); void windowsBlockCompositingChanged(bool); private: int m_animationSpeed; int m_windowThumbnail; int m_glScaleFilter; bool m_xrScaleFilter; int m_glSwapStrategy; bool m_glColorCorrection; int m_compositingType; bool m_compositingEnabled; bool m_changed; OpenGLPlatformInterfaceModel *m_openGLPlatformInterfaceModel; int m_openGLPlatformInterface; bool m_windowsBlockCompositing; + bool m_windowsBlockingCompositing; + OrgKdeKwinCompositingInterface *m_compositingInterface; }; struct CompositingData; class CompositingType : public QAbstractItemModel { Q_OBJECT Q_ENUMS(CompositingTypeIndex) public: enum CompositingTypeIndex { OPENGL31_INDEX = 0, OPENGL20_INDEX, XRENDER_INDEX }; enum CompositingTypeRoles { NameRole = Qt::UserRole +1, TypeRole = Qt::UserRole +2 }; explicit CompositingType(QObject *parent = 0); QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &child) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; virtual QHash< int, QByteArray > roleNames() const override; Q_INVOKABLE int compositingTypeForIndex(int row) const; Q_INVOKABLE int indexForCompositingType(int type) const; private: void generateCompositing(); QList m_compositingList; }; struct CompositingData { QString name; CompositingType::CompositingTypeIndex type; }; class OpenGLPlatformInterfaceModel : public QAbstractListModel { Q_OBJECT public: explicit OpenGLPlatformInterfaceModel(QObject *parent = nullptr); virtual ~OpenGLPlatformInterfaceModel(); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; QModelIndex indexForKey(const QString &key) const; QHash< int, QByteArray > roleNames() const override; private: QStringList m_keys; QStringList m_names; }; }//end namespace Compositing }//end namespace KWin Q_DECLARE_METATYPE(KWin::Compositing::OpenGLPlatformInterfaceModel*) #endif diff --git a/kcmkwin/kwincompositing/main.cpp b/kcmkwin/kwincompositing/main.cpp index cd4aac682..a5d7cdeca 100644 --- a/kcmkwin/kwincompositing/main.cpp +++ b/kcmkwin/kwincompositing/main.cpp @@ -1,273 +1,276 @@ /************************************************************************** * 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 "compositing.h" #include "model.h" #include "ui_compositing.h" #include #include #include #include class KWinCompositingKCM : public KCModule { Q_OBJECT public: virtual ~KWinCompositingKCM(); public Q_SLOTS: void save() override; void load() override; void defaults() override; protected: explicit KWinCompositingKCM(QWidget* parent, const QVariantList& args, KWin::Compositing::EffectView::ViewType viewType); private: QScopedPointer m_view; }; class KWinDesktopEffects : public KWinCompositingKCM { Q_OBJECT public: explicit KWinDesktopEffects(QWidget* parent = 0, const QVariantList& args = QVariantList()) : KWinCompositingKCM(parent, args, KWin::Compositing::EffectView::DesktopEffectsView) {} }; class KWinCompositingSettings : public KCModule { Q_OBJECT public: explicit KWinCompositingSettings(QWidget *parent = 0, const QVariantList &args = QVariantList()); public Q_SLOTS: void load() override; void save() override; void defaults() override; private: void init(); KWin::Compositing::Compositing *m_compositing; Ui_CompositingForm m_form; }; KWinCompositingSettings::KWinCompositingSettings(QWidget *parent, const QVariantList &args) : KCModule(parent, args) , m_compositing(new KWin::Compositing::Compositing(this)) { m_form.setupUi(this); m_form.glCrashedWarning->setIcon(QIcon::fromTheme(QStringLiteral("dialog-warning"))); QAction *reenableGLAction = new QAction(i18n("Re-enable OpenGL detection"), this); connect(reenableGLAction, &QAction::triggered, m_compositing, &KWin::Compositing::Compositing::reenableOpenGLDetection); 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.compositingEnabled->setVisible(!m_compositing->compositingRequired()); + m_form.windowsBlockCompositing->setVisible(!m_compositing->compositingRequired()); + init(); } void KWinCompositingSettings::init() { using namespace KWin::Compositing; auto currentIndexChangedSignal = static_cast(&QComboBox::currentIndexChanged); connect(m_compositing, &Compositing::changed, this, static_cast(&KWinCompositingSettings::changed)); // enabled check box m_form.compositingEnabled->setChecked(m_compositing->compositingEnabled()); connect(m_compositing, &Compositing::compositingEnabledChanged, m_form.compositingEnabled, &QCheckBox::setChecked); connect(m_form.compositingEnabled, &QCheckBox::toggled, m_compositing, &Compositing::setCompositingEnabled); // animation speed m_form.animationSpeed->setValue(m_compositing->animationSpeed()); connect(m_compositing, &Compositing::animationSpeedChanged, m_form.animationSpeed, &QSlider::setValue); connect(m_form.animationSpeed, &QSlider::valueChanged, m_compositing, &Compositing::setAnimationSpeed); // gl scale filter m_form.glScaleFilter->setCurrentIndex(m_compositing->glScaleFilter()); connect(m_compositing, &Compositing::glScaleFilterChanged, m_form.glScaleFilter, &QComboBox::setCurrentIndex); connect(m_form.glScaleFilter, currentIndexChangedSignal, m_compositing, &Compositing::setGlScaleFilter); connect(m_form.glScaleFilter, currentIndexChangedSignal, [this](int index) { if (index == 2) { m_form.scaleWarning->animatedShow(); } else { m_form.scaleWarning->animatedHide(); } } ); // xrender scale filter m_form.xrScaleFilter->setCurrentIndex(m_compositing->xrScaleFilter()); connect(m_compositing, &Compositing::xrScaleFilterChanged, m_form.xrScaleFilter, &QComboBox::setCurrentIndex); connect(m_form.xrScaleFilter, currentIndexChangedSignal, m_compositing, &Compositing::setXrScaleFilter); // tearing prevention m_form.tearingPrevention->setCurrentIndex(m_compositing->glSwapStrategy()); connect(m_compositing, &Compositing::glSwapStrategyChanged, m_form.tearingPrevention, &QComboBox::setCurrentIndex); connect(m_form.tearingPrevention, currentIndexChangedSignal, m_compositing, &Compositing::setGlSwapStrategy); connect(m_form.tearingPrevention, currentIndexChangedSignal, [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 m_form.windowThumbnail->setCurrentIndex(m_compositing->windowThumbnail()); connect(m_compositing, &Compositing::windowThumbnailChanged, m_form.windowThumbnail, &QComboBox::setCurrentIndex); connect(m_form.windowThumbnail, currentIndexChangedSignal, m_compositing, &Compositing::setWindowThumbnail); connect(m_form.windowThumbnail, currentIndexChangedSignal, [this](int index) { if (index == 2) { m_form.windowThumbnailWarning->animatedShow(); } else { m_form.windowThumbnailWarning->animatedHide(); } } ); // color correction m_form.colorCorrection->setChecked(m_compositing->glColorCorrection()); connect(m_compositing, &Compositing::glColorCorrectionChanged, m_form.colorCorrection, &QCheckBox::setChecked); connect(m_form.colorCorrection, &QCheckBox::toggled, m_compositing, &Compositing::setGlColorCorrection); // windows blocking compositing m_form.windowsBlockCompositing->setChecked(m_compositing->windowsBlockCompositing()); connect(m_compositing, &Compositing::windowsBlockCompositingChanged, m_form.windowsBlockCompositing, &QCheckBox::setChecked); connect(m_form.windowsBlockCompositing, &QCheckBox::toggled, m_compositing, &Compositing::setWindowsBlockCompositing); // compositing type CompositingType *type = new CompositingType(this); m_form.type->setModel(type); auto updateCompositingType = [this, type]() { m_form.type->setCurrentIndex(type->indexForCompositingType(m_compositing->compositingType())); }; updateCompositingType(); connect(m_compositing, &Compositing::compositingTypeChanged, [updateCompositingType]() { updateCompositingType(); } ); auto showHideBasedOnType = [this, type]() { const int currentType = type->compositingTypeForIndex(m_form.type->currentIndex()); m_form.glScaleFilter->setVisible(currentType != CompositingType::XRENDER_INDEX); m_form.glScaleFilterLabel->setVisible(currentType != CompositingType::XRENDER_INDEX); m_form.xrScaleFilter->setVisible(currentType == CompositingType::XRENDER_INDEX); m_form.xrScaleFilterLabel->setVisible(currentType == CompositingType::XRENDER_INDEX); m_form.colorCorrection->setEnabled(currentType == CompositingType::OPENGL31_INDEX || currentType == CompositingType::OPENGL20_INDEX); }; showHideBasedOnType(); connect(m_form.type, currentIndexChangedSignal, [this, type, showHideBasedOnType]() { m_compositing->setCompositingType(type->compositingTypeForIndex(m_form.type->currentIndex())); showHideBasedOnType(); } ); if (m_compositing->OpenGLIsUnsafe()) { m_form.glCrashedWarning->animatedShow(); } } void KWinCompositingSettings::load() { KCModule::load(); m_compositing->reset(); } void KWinCompositingSettings::defaults() { KCModule::defaults(); m_compositing->defaults(); } void KWinCompositingSettings::save() { KCModule::save(); m_compositing->save(); } KWinCompositingKCM::KWinCompositingKCM(QWidget* parent, const QVariantList& args, KWin::Compositing::EffectView::ViewType viewType) : KCModule(parent, args) , m_view(new KWin::Compositing::EffectView(viewType)) { QVBoxLayout *vl = new QVBoxLayout(this); QWidget *w = QWidget::createWindowContainer(m_view.data(), this); connect(m_view.data(), &QWindow::minimumWidthChanged, w, &QWidget::setMinimumWidth); connect(m_view.data(), &QWindow::minimumHeightChanged, w, &QWidget::setMinimumHeight); w->setMinimumSize(m_view->initialSize()); vl->addWidget(w); setLayout(vl); connect(m_view.data(), &KWin::Compositing::EffectView::changed, [this]{ emit changed(true); }); w->setFocusPolicy(Qt::StrongFocus); } KWinCompositingKCM::~KWinCompositingKCM() { } void KWinCompositingKCM::save() { m_view->save(); KCModule::save(); } void KWinCompositingKCM::load() { m_view->load(); KCModule::load(); } void KWinCompositingKCM::defaults() { m_view->defaults(); KCModule::defaults(); } K_PLUGIN_FACTORY(KWinCompositingConfigFactory, registerPlugin("effects"); registerPlugin("compositing"); ) #include "main.moc" diff --git a/org.kde.kwin.Compositing.xml b/org.kde.kwin.Compositing.xml index d98732e12..88ff9e429 100644 --- a/org.kde.kwin.Compositing.xml +++ b/org.kde.kwin.Compositing.xml @@ -1,18 +1,19 @@ +