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;