diff --git a/scene.h b/scene.h
index 97743e1158..29a5dceb47 100644
--- a/scene.h
+++ b/scene.h
@@ -174,6 +174,8 @@ protected:
// shared implementation, starts painting the screen
void paintScreen(int *mask, const QRegion &damage, const QRegion &repaint,
QRegion *updateRegion, QRegion *validRegion, const QMatrix4x4 &projection = QMatrix4x4(), const QRect &outputGeometry = QRect());
+ // Render cursor texture in case hardware cursor is disabled/non-applicable
+ virtual void paintCursor() = 0;
friend class EffectsHandlerImpl;
// called after all effects had their paintScreen() called
void finalPaintScreen(int mask, QRegion region, ScreenPaintData& data);
diff --git a/scene_opengl.cpp b/scene_opengl.cpp
index 22debbd9f9..7b5423155f 100644
--- a/scene_opengl.cpp
+++ b/scene_opengl.cpp
@@ -42,6 +42,7 @@ along with this program. If not, see .
#include "main.h"
#include "overlaywindow.h"
#include "screens.h"
+#include "cursor.h"
#include "decorations/decoratedclient.h"
#include
@@ -678,6 +679,57 @@ void SceneOpenGL::insertWait()
}
}
+/**
+ * Render cursor texture in case hardware cursor is disabled.
+ * Useful for screen recording apps or backends that can't do planes.
+ */
+void SceneOpenGL2::paintCursor()
+{
+ // don't paint if we use hardware cursor
+ if (!kwinApp()->platform()->usesSoftwareCursor()) {
+ return;
+ }
+
+ // lazy init texture cursor only in case we need software rendering
+ if (!m_cursorTexture) {
+ auto updateCursorTexture = [this] {
+ // don't paint if no image for cursor is set
+ const QImage img = kwinApp()->platform()->softwareCursor();
+ if (img.isNull()) {
+ return;
+ }
+ m_cursorTexture.reset(new GLTexture(img));
+ };
+
+ // init now
+ updateCursorTexture();
+
+ // handle shape update on case cursor image changed
+ connect(Cursor::self(), &Cursor::cursorChanged, this, updateCursorTexture);
+ }
+
+ // get cursor position in projection coordinates
+ const QPoint cursorPos = Cursor::pos() - kwinApp()->platform()->softwareCursorHotspot();
+ const QRect cursorRect(0, 0, m_cursorTexture->width(), m_cursorTexture->height());
+ QMatrix4x4 mvp = m_projectionMatrix;
+ mvp.translate(cursorPos.x(), cursorPos.y());
+
+ // handle transparence
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ // paint texture in cursor offset
+ m_cursorTexture->bind();
+ ShaderBinder binder(ShaderTrait::MapTexture);
+ binder.shader()->setUniform(GLShader::ModelViewProjectionMatrix, mvp);
+ m_cursorTexture->render(QRegion(cursorRect), cursorRect);
+ m_cursorTexture->unbind();
+
+ kwinApp()->platform()->markCursorAsRendered();
+
+ glDisable(GL_BLEND);
+}
+
qint64 SceneOpenGL::paint(QRegion damage, ToplevelList toplevels)
{
// actually paint the frame, flushed with the NEXT frame
@@ -711,6 +763,7 @@ qint64 SceneOpenGL::paint(QRegion damage, ToplevelList toplevels)
int mask = 0;
updateProjectionMatrix();
paintScreen(&mask, damage.intersected(geo), repaint, &update, &valid, projectionMatrix(), geo); // call generic implementation
+ paintCursor();
GLVertexBuffer::streamingBuffer()->endOfFrame();
diff --git a/scene_opengl.h b/scene_opengl.h
index a039eacdc7..f7a7de75e2 100644
--- a/scene_opengl.h
+++ b/scene_opengl.h
@@ -137,6 +137,7 @@ protected:
virtual Scene::Window *createWindow(Toplevel *t);
virtual void finalDrawWindow(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data);
virtual void updateProjectionMatrix() override;
+ void paintCursor() override;
private Q_SLOTS:
void resetLanczosFilter();
@@ -147,6 +148,7 @@ private:
private:
LanczosFilter *m_lanczosFilter;
+ QScopedPointer m_cursorTexture;
QMatrix4x4 m_projectionMatrix;
QMatrix4x4 m_screenProjectionMatrix;
GLuint vao;
diff --git a/scene_qpainter.h b/scene_qpainter.h
index 0c82bc15d7..f1a9c28db0 100644
--- a/scene_qpainter.h
+++ b/scene_qpainter.h
@@ -134,10 +134,10 @@ public:
protected:
virtual void paintBackground(QRegion region) override;
virtual Scene::Window *createWindow(Toplevel *toplevel) override;
+ void paintCursor() override;
private:
explicit SceneQPainter(QPainterBackend *backend, QObject *parent = nullptr);
- void paintCursor();
QScopedPointer m_backend;
QScopedPointer m_painter;
class Window;
diff --git a/scene_xrender.cpp b/scene_xrender.cpp
index 3a3bb1eca9..03c0d156e4 100644
--- a/scene_xrender.cpp
+++ b/scene_xrender.cpp
@@ -1296,3 +1296,9 @@ void SceneXRenderDecorationRenderer::reparent(Deleted *deleted)
} // namespace
#endif
+
+
+void KWin::SceneXrender::paintCursor()
+{
+
+}
diff --git a/scene_xrender.h b/scene_xrender.h
index 6138f29b66..af8d2c2b18 100644
--- a/scene_xrender.h
+++ b/scene_xrender.h
@@ -179,6 +179,7 @@ protected:
virtual void paintBackground(QRegion region);
virtual void paintGenericScreen(int mask, ScreenPaintData data);
virtual void paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data);
+ void paintCursor() override;
private:
explicit SceneXrender(XRenderBackend *backend, QObject *parent = nullptr);
static ScreenPaintData screen_paint;