diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -409,7 +409,6 @@ toplevel.cpp unmanaged.cpp scene.cpp - scene_xrender.cpp scene_opengl.cpp scene_qpainter.cpp screenlockerwatcher.cpp diff --git a/composite.cpp b/composite.cpp --- a/composite.cpp +++ b/composite.cpp @@ -30,7 +30,6 @@ #include "effects.h" #include "overlaywindow.h" #include "scene.h" -#include "scene_xrender.h" #include "scene_opengl.h" #include "scene_qpainter.h" #include "screens.h" @@ -54,6 +53,8 @@ #include #include #include +#include +#include #include #include @@ -199,54 +200,73 @@ } } - switch(options->compositingMode()) { - case OpenGLCompositing: { - qCDebug(KWIN_CORE) << "Initializing OpenGL compositing"; + const auto availablePlugins = KPluginLoader::findPlugins(QStringLiteral("org.kde.kwin.scenes")); - // Some broken drivers crash on glXQuery() so to prevent constant KWin crashes: - if (kwinApp()->platform()->openGLCompositingIsBroken()) - qCWarning(KWIN_CORE) << "KWin has detected that your OpenGL library is unsafe to use"; - else { - kwinApp()->platform()->createOpenGLSafePoint(Platform::OpenGLSafePoint::PreInit); + const auto pluginIt = std::find_if(availablePlugins.begin(), availablePlugins.end(), + [] (const auto &plugin) { + const auto &metaData = plugin.rawData(); + auto it = metaData.find(QStringLiteral("CompositingType")); + if (it != metaData.end()) { + if ((*it).toInt() == int{options->compositingMode()}) { + return true; + } + } + return false; + }); + if (pluginIt != availablePlugins.end()) { + std::unique_ptr factory{qobject_cast(pluginIt->instantiate())}; + if (factory) { + m_scene = factory->create(this); + if (m_scene) { + qCDebug(KWIN_CORE) << "Instantiated compositing plugin:" << pluginIt->name(); + } + } + } + + if (!m_scene) { + switch(options->compositingMode()) { + case OpenGLCompositing: { + qCDebug(KWIN_CORE) << "Initializing OpenGL compositing"; - m_scene = SceneOpenGL::createScene(this); + // Some broken drivers crash on glXQuery() so to prevent constant KWin crashes: + if (kwinApp()->platform()->openGLCompositingIsBroken()) + qCWarning(KWIN_CORE) << "KWin has detected that your OpenGL library is unsafe to use"; + else { + kwinApp()->platform()->createOpenGLSafePoint(Platform::OpenGLSafePoint::PreInit); - kwinApp()->platform()->createOpenGLSafePoint(Platform::OpenGLSafePoint::PostInit); + m_scene = SceneOpenGL::createScene(this); - if (m_scene && !m_scene->initFailed()) { - connect(static_cast(m_scene), &SceneOpenGL::resetCompositing, this, &Compositor::restart); - break; // --> + kwinApp()->platform()->createOpenGLSafePoint(Platform::OpenGLSafePoint::PostInit); + + if (m_scene && !m_scene->initFailed()) { + connect(static_cast(m_scene), &SceneOpenGL::resetCompositing, this, &Compositor::restart); + break; // --> + } + delete m_scene; + m_scene = NULL; } - delete m_scene; - m_scene = NULL; - } - // Do not Fall back to XRender - it causes problems when selfcheck fails during startup, but works later on - break; - } -#ifdef KWIN_HAVE_XRENDER_COMPOSITING - case XRenderCompositing: - qCDebug(KWIN_CORE) << "Initializing XRender compositing"; - m_scene = SceneXrender::createScene(this); - break; -#endif - case QPainterCompositing: - qCDebug(KWIN_CORE) << "Initializing QPainter compositing"; - m_scene = SceneQPainter::createScene(this); - break; - default: - qCDebug(KWIN_CORE) << "No compositing enabled"; - m_starting = false; - if (cm_selection) { - cm_selection->owning = false; - cm_selection->release(); + // Do not Fall back to XRender - it causes problems when selfcheck fails during startup, but works later on + break; } - if (kwinApp()->platform()->requiresCompositing()) { - qCCritical(KWIN_CORE) << "The used windowing system requires compositing"; - qCCritical(KWIN_CORE) << "We are going to quit KWin now as it is broken"; - qApp->quit(); + case QPainterCompositing: + qCDebug(KWIN_CORE) << "Initializing QPainter compositing"; + m_scene = SceneQPainter::createScene(this); + break; + default: + qCDebug(KWIN_CORE) << "No compositing enabled"; + m_starting = false; + if (cm_selection) { + cm_selection->owning = false; + cm_selection->release(); + } + if (kwinApp()->platform()->requiresCompositing()) { + qCCritical(KWIN_CORE) << "The used windowing system requires compositing"; + qCCritical(KWIN_CORE) << "We are going to quit KWin now as it is broken"; + qApp->quit(); + } + return; } - return; } if (m_scene == NULL || m_scene->initFailed()) { qCCritical(KWIN_CORE) << "Failed to initialize compositing, compositing disabled"; diff --git a/data/org_kde_kwin.categories b/data/org_kde_kwin.categories --- a/data/org_kde_kwin.categories +++ b/data/org_kde_kwin.categories @@ -16,3 +16,4 @@ aurorae KWin Aurorae Window Decoration Engine kwin_xkbcommon KWin xkbcommon integration kwin_qpa_plugin KWin QtPlatformAbstraction plugin +kwin_scene_xrender KWin XRender based compositor scene plugin diff --git a/decorations/decorationrenderer.h b/decorations/decorationrenderer.h --- a/decorations/decorationrenderer.h +++ b/decorations/decorationrenderer.h @@ -25,6 +25,8 @@ #include +#include + class QTimer; namespace KWin @@ -37,7 +39,7 @@ class DecoratedClientImpl; -class Renderer : public QObject +class KWIN_EXPORT Renderer : public QObject { Q_OBJECT public: diff --git a/effects.h b/effects.h --- a/effects.h +++ b/effects.h @@ -393,7 +393,7 @@ Group* group; }; -class EffectFrameImpl +class KWIN_EXPORT EffectFrameImpl : public QObject, public EffectFrame { Q_OBJECT diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -2,6 +2,7 @@ add_subdirectory(qpa) add_subdirectory(idletime) add_subdirectory(platforms) +add_subdirectory(scenes) if(KWIN_BUILD_DECORATIONS) add_subdirectory(kdecorations) diff --git a/plugins/scenes/CMakeLists.txt b/plugins/scenes/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/plugins/scenes/CMakeLists.txt @@ -0,0 +1,3 @@ +if( KWIN_BUILD_XRENDER_COMPOSITING ) + add_subdirectory(xrender) +endif() diff --git a/plugins/scenes/xrender/CMakeLists.txt b/plugins/scenes/xrender/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/plugins/scenes/xrender/CMakeLists.txt @@ -0,0 +1,25 @@ +set(SCENE_XRENDER_SRCS scene_xrender.cpp) + +include(ECMQtDeclareLoggingCategory) +ecm_qt_declare_logging_category( + SCENE_XRENDER_SRCS HEADER + logging.h + IDENTIFIER + KWIN_XRENDER + CATEGORY_NAME + kwin_scene_xrender + DEFAULT_SEVERITY + Critical +) + +add_library(KWinSceneXRender MODULE ${SCENE_XRENDER_SRCS}) +target_link_libraries(KWinSceneXRender + kwin +) + +install( + TARGETS + KWinSceneXRender + DESTINATION + ${PLUGIN_INSTALL_DIR}/org.kde.kwin.scenes/ +) diff --git a/scene_xrender.h b/plugins/scenes/xrender/scene_xrender.h rename from scene_xrender.h rename to plugins/scenes/xrender/scene_xrender.h --- a/scene_xrender.h +++ b/plugins/scenes/xrender/scene_xrender.h @@ -341,6 +341,19 @@ XRenderPicture* m_pictures[int(DecorationPart::Count)]; }; +class KWIN_EXPORT XRenderFactory : public SceneFactory +{ + Q_OBJECT + Q_INTERFACES(KWin::SceneFactory) + Q_PLUGIN_METADATA(IID "org.kde.kwin.Scene" FILE "xrender.json") + +public: + explicit XRenderFactory(QObject *parent = nullptr); + ~XRenderFactory() override; + + Scene *create(QObject *parent = nullptr) const override; +}; + } // namespace #endif diff --git a/scene_xrender.cpp b/plugins/scenes/xrender/scene_xrender.cpp rename from scene_xrender.cpp rename to plugins/scenes/xrender/scene_xrender.cpp --- a/scene_xrender.cpp +++ b/plugins/scenes/xrender/scene_xrender.cpp @@ -25,6 +25,7 @@ #ifdef KWIN_HAVE_XRENDER_COMPOSITING +#include "logging.h" #include "toplevel.h" #include "client.h" #include "composite.h" @@ -96,7 +97,7 @@ void XRenderBackend::setFailed(const QString& reason) { - qCCritical(KWIN_CORE) << "Creating the XRender backend failed: " << reason; + qCCritical(KWIN_XRENDER) << "Creating the XRender backend failed: " << reason; m_failed = true; } @@ -1297,6 +1298,23 @@ #undef DOUBLE_TO_FIXED #undef FIXED_TO_DOUBLE +XRenderFactory::XRenderFactory(QObject *parent) + : SceneFactory(parent) +{ +} + +XRenderFactory::~XRenderFactory() = default; + +Scene *XRenderFactory::create(QObject *parent) const +{ + auto s = SceneXrender::createScene(parent); + if (s && s->initFailed()) { + delete s; + s = nullptr; + } + return s; +} + } // namespace #endif diff --git a/plugins/scenes/xrender/xrender.json b/plugins/scenes/xrender/xrender.json new file mode 100644 --- /dev/null +++ b/plugins/scenes/xrender/xrender.json @@ -0,0 +1,8 @@ +{ + "KPlugin": { + "Description": "KWin Compositor plugin rendering through XRender", + "Id": "KWinSceneXRender", + "Name": "SceneXRender" + }, + "CompositingType": 2 +} diff --git a/scene.h b/scene.h --- a/scene.h +++ b/scene.h @@ -245,6 +245,24 @@ QVector< Window* > stacking_order; }; +/** + * Factory class to create a Scene. Needs to be implemented by the plugins. + **/ +class KWIN_EXPORT SceneFactory : public QObject +{ + Q_OBJECT +public: + virtual ~SceneFactory(); + + /** + * @returns The created Scene, may be @c nullptr. + **/ + virtual Scene *create(QObject *parent = nullptr) const = 0; + +protected: + explicit SceneFactory(QObject *parent); +}; + // The base class for windows representations in composite backends class Scene::Window { @@ -359,7 +377,7 @@ * This class is intended to be inherited for the needs of the compositor backends which need further mapping from * the native pixmap to the respective rendering format. */ -class WindowPixmap +class KWIN_EXPORT WindowPixmap { public: virtual ~WindowPixmap(); @@ -643,4 +661,6 @@ } // namespace +Q_DECLARE_INTERFACE(KWin::SceneFactory, "org.kde.kwin.Scene") + #endif diff --git a/scene.cpp b/scene.cpp --- a/scene.cpp +++ b/scene.cpp @@ -1124,4 +1124,13 @@ { } +SceneFactory::SceneFactory(QObject *parent) + : QObject(parent) +{ +} + +SceneFactory::~SceneFactory() +{ +} + } // namespace diff --git a/shadow.h b/shadow.h --- a/shadow.h +++ b/shadow.h @@ -58,7 +58,7 @@ * @author Martin Gräßlin * @todo React on Toplevel size changes. **/ -class Shadow : public QObject +class KWIN_EXPORT Shadow : public QObject { Q_OBJECT public: