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;