diff --git a/abstract_backend.cpp b/abstract_backend.cpp index 1d523bf51d..e0b9bff6d6 100644 --- a/abstract_backend.cpp +++ b/abstract_backend.cpp @@ -18,7 +18,13 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #include "abstract_backend.h" +#include "composite.h" +#include "cursor.h" #include "wayland_server.h" +// KWayland +#include +#include +#include namespace KWin { @@ -36,6 +42,27 @@ AbstractBackend::~AbstractBackend() void AbstractBackend::installCursorFromServer() { + if (!m_softWareCursor) { + return; + } + if (!waylandServer() || !waylandServer()->seat()->focusedPointer()) { + return; + } + auto c = waylandServer()->seat()->focusedPointer()->cursor(); + if (!c) { + return; + } + auto cursorSurface = c->surface(); + if (cursorSurface.isNull()) { + return; + } + auto buffer = cursorSurface.data()->buffer(); + if (!buffer) { + return; + } + triggerCursorRepaint(); + m_cursor.hotspot = c->hotspot(); + m_cursor.image = buffer->data().copy(); } void AbstractBackend::installCursorImage(Qt::CursorShape shape) @@ -59,4 +86,32 @@ QPainterBackend *AbstractBackend::createQPainterBackend() return nullptr; } +void AbstractBackend::setSoftWareCursor(bool set) +{ + if (m_softWareCursor == set) { + return; + } + m_softWareCursor = set; + if (m_softWareCursor) { + connect(Cursor::self(), &Cursor::posChanged, this, &AbstractBackend::triggerCursorRepaint); + } else { + disconnect(Cursor::self(), &Cursor::posChanged, this, &AbstractBackend::triggerCursorRepaint); + } +} + +void AbstractBackend::triggerCursorRepaint() +{ + if (!Compositor::self() || m_cursor.image.isNull()) { + return; + } + Compositor::self()->addRepaint(m_cursor.lastRenderedPosition.x() - m_cursor.hotspot.x(), + m_cursor.lastRenderedPosition.y() - m_cursor.hotspot.y(), + m_cursor.image.width(), m_cursor.image.height()); +} + +void AbstractBackend::markCursorAsRendered() +{ + m_cursor.lastRenderedPosition = Cursor::pos(); +} + } diff --git a/abstract_backend.h b/abstract_backend.h index 193935dd1a..edfe428910 100644 --- a/abstract_backend.h +++ b/abstract_backend.h @@ -20,6 +20,7 @@ along with this program. If not, see . #ifndef KWIN_ABSTRACT_BACKEND_H #define KWIN_ABSTRACT_BACKEND_H #include +#include #include namespace KWin @@ -41,8 +42,29 @@ public: virtual OpenGLBackend *createOpenGLBackend(); virtual QPainterBackend *createQPainterBackend(); + bool usesSoftwareCursor() const { + return m_softWareCursor; + } + QImage softwareCursor() const { + return m_cursor.image; + } + QPoint softwareCursorHotspot() const { + return m_cursor.hotspot; + } + void markCursorAsRendered(); + protected: explicit AbstractBackend(QObject *parent = nullptr); + void setSoftWareCursor(bool set); + +private: + void triggerCursorRepaint(); + bool m_softWareCursor = false; + struct { + QPoint hotspot; + QImage image; + QPoint lastRenderedPosition; + } m_cursor; }; } diff --git a/fb_backend.cpp b/fb_backend.cpp index 29bf0f612c..9a9759148a 100644 --- a/fb_backend.cpp +++ b/fb_backend.cpp @@ -39,6 +39,7 @@ namespace KWin FramebufferBackend::FramebufferBackend(QObject *parent) : AbstractBackend(parent) { + setSoftWareCursor(true); } FramebufferBackend::~FramebufferBackend() diff --git a/scene_qpainter.cpp b/scene_qpainter.cpp index dd7e44d44d..1966a399ec 100644 --- a/scene_qpainter.cpp +++ b/scene_qpainter.cpp @@ -21,6 +21,7 @@ along with this program. If not, see . // KWin #include "client.h" #include "composite.h" +#include "cursor.h" #include "deleted.h" #include "effects.h" #include "main.h" @@ -79,6 +80,11 @@ void QPainterBackend::setFailed(const QString &reason) m_failed = true; } +void QPainterBackend::renderCursor(QPainter *painter) +{ + Q_UNUSED(painter) +} + #if HAVE_WAYLAND //**************************************** // WaylandQPainterBackend @@ -311,6 +317,21 @@ bool FramebufferQPainterBackend::usesOverlayWindow() const return false; } +void FramebufferQPainterBackend::renderCursor(QPainter *painter) +{ + if (!m_backend->usesSoftwareCursor()) { + return; + } + const QImage img = m_backend->softwareCursor(); + if (img.isNull()) { + return; + } + const QPoint cursorPos = Cursor::pos(); + const QPoint hotspot = m_backend->softwareCursorHotspot(); + painter->drawImage(cursorPos - hotspot, img); + m_backend->markCursorAsRendered(); +} + #endif //**************************************** @@ -380,6 +401,7 @@ qint64 SceneQPainter::paint(QRegion damage, ToplevelList toplevels) } QRegion updateRegion, validRegion; paintScreen(&mask, damage, QRegion(), &updateRegion, &validRegion); + m_backend->renderCursor(m_painter.data()); m_backend->showOverlay(); diff --git a/scene_qpainter.h b/scene_qpainter.h index a422f4e5b6..21f653b6ff 100644 --- a/scene_qpainter.h +++ b/scene_qpainter.h @@ -93,6 +93,7 @@ public: virtual QImage *buffer() = 0; virtual bool needsFullRepaint() const = 0; + virtual void renderCursor(QPainter *painter); protected: QPainterBackend(); @@ -166,6 +167,7 @@ public: bool usesOverlayWindow() const override; void prepareRenderingFrame() override; void present(int mask, const QRegion &damage) override; + void renderCursor(QPainter *painter) override; private: QImage m_renderBuffer;