diff --git a/CMakeLists.txt b/CMakeLists.txt
index c042ff78f7..108d646693 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -409,7 +409,6 @@ set(kwin_KDEINIT_SRCS
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
index 4bb816869e..d10913c44d 100644
--- a/composite.cpp
+++ b/composite.cpp
@@ -30,7 +30,6 @@ along with this program. If not, see .
#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 @@ along with this program. If not, see .
#include
#include
#include
+#include
+#include
#include
#include
@@ -199,54 +200,73 @@ void Compositor::slotCompositingOptionsInitialized()
}
}
- 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);
-
- m_scene = SceneOpenGL::createScene(this);
-
- kwinApp()->platform()->createOpenGLSafePoint(Platform::OpenGLSafePoint::PostInit);
-
- if (m_scene && !m_scene->initFailed()) {
- connect(static_cast(m_scene), &SceneOpenGL::resetCompositing, this, &Compositor::restart);
- break; // -->
+ 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();
}
- 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();
+
+ if (!m_scene) {
+ switch(options->compositingMode()) {
+ case OpenGLCompositing: {
+ qCDebug(KWIN_CORE) << "Initializing OpenGL compositing";
+
+ // 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);
+
+ m_scene = SceneOpenGL::createScene(this);
+
+ 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;
+ }
+
+ // 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
index 4f5d231d20..8900680251 100644
--- a/data/org_kde_kwin.categories
+++ b/data/org_kde_kwin.categories
@@ -16,3 +16,4 @@ kwin_scripting KWin Scripting
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
index e216e2687a..17d184bda9 100644
--- a/decorations/decorationrenderer.h
+++ b/decorations/decorationrenderer.h
@@ -25,6 +25,8 @@ along with this program. If not, see .
#include
+#include
+
class QTimer;
namespace KWin
@@ -37,7 +39,7 @@ namespace Decoration
class DecoratedClientImpl;
-class Renderer : public QObject
+class KWIN_EXPORT Renderer : public QObject
{
Q_OBJECT
public:
diff --git a/effects.h b/effects.h
index ba24902b08..b9eb3d36a7 100644
--- a/effects.h
+++ b/effects.h
@@ -393,7 +393,7 @@ private:
Group* group;
};
-class EffectFrameImpl
+class KWIN_EXPORT EffectFrameImpl
: public QObject, public EffectFrame
{
Q_OBJECT
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
index 3a06fa63fb..da3eed351a 100644
--- a/plugins/CMakeLists.txt
+++ b/plugins/CMakeLists.txt
@@ -2,6 +2,7 @@ add_subdirectory(kglobalaccel)
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
index 0000000000..b93ce5b957
--- /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
index 0000000000..8e8c67ed37
--- /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.cpp b/plugins/scenes/xrender/scene_xrender.cpp
similarity index 99%
rename from scene_xrender.cpp
rename to plugins/scenes/xrender/scene_xrender.cpp
index 4334807874..df1702699d 100644
--- a/scene_xrender.cpp
+++ b/plugins/scenes/xrender/scene_xrender.cpp
@@ -25,6 +25,7 @@ along with this program. If not, see .
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
+#include "logging.h"
#include "toplevel.h"
#include "client.h"
#include "composite.h"
@@ -96,7 +97,7 @@ void XRenderBackend::setBuffer(xcb_render_picture_t buffer)
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 @@ void SceneXRenderDecorationRenderer::reparent(Deleted *deleted)
#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/scene_xrender.h b/plugins/scenes/xrender/scene_xrender.h
similarity index 96%
rename from scene_xrender.h
rename to plugins/scenes/xrender/scene_xrender.h
index d4dacd3610..04bc66caea 100644
--- a/scene_xrender.h
+++ b/plugins/scenes/xrender/scene_xrender.h
@@ -341,6 +341,19 @@ private:
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/plugins/scenes/xrender/xrender.json b/plugins/scenes/xrender/xrender.json
new file mode 100644
index 0000000000..d2af878b9b
--- /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.cpp b/scene.cpp
index a51bbe9be2..bf5b7778d0 100644
--- a/scene.cpp
+++ b/scene.cpp
@@ -1124,4 +1124,13 @@ Scene::EffectFrame::~EffectFrame()
{
}
+SceneFactory::SceneFactory(QObject *parent)
+ : QObject(parent)
+{
+}
+
+SceneFactory::~SceneFactory()
+{
+}
+
} // namespace
diff --git a/scene.h b/scene.h
index e7c885ac98..5d9865ecac 100644
--- a/scene.h
+++ b/scene.h
@@ -245,6 +245,24 @@ private:
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 @@ private:
* 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 @@ const QSize &WindowPixmap::size() const
} // namespace
+Q_DECLARE_INTERFACE(KWin::SceneFactory, "org.kde.kwin.Scene")
+
#endif
diff --git a/shadow.h b/shadow.h
index d47ff88b99..b64cf7a471 100644
--- a/shadow.h
+++ b/shadow.h
@@ -58,7 +58,7 @@ class Toplevel;
* @author Martin Gräßlin
* @todo React on Toplevel size changes.
**/
-class Shadow : public QObject
+class KWIN_EXPORT Shadow : public QObject
{
Q_OBJECT
public: