[wayland] Add support for a "software" cursor
At least the framebuffer backend does not have support for an overlay cursor. Thus the cursor needs to be rendered by the scene. This change allows a backend to set that it needs a software cursor which triggers tracking in the AbstractBackend. A repaint for the old cursor region is triggered whenever the cursor pos changes. So far only the QPainter/framebuffer scene is adjusted to render the software cursor. This is done after rendering a frame with the up to date cursor position. There is one problem, though: the KWin internal cursors don't work as we need to get it from the theme. Using wayland-cursor doesn't help as it gives us a (client) wl_buffer* and we cannot read the memory back.
This commit is contained in:
parent
de3788c094
commit
c5693270db
5 changed files with 102 additions and 0 deletions
|
@ -18,7 +18,13 @@ You should have received a copy of the GNU General Public License
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#include "abstract_backend.h"
|
||||
#include "composite.h"
|
||||
#include "cursor.h"
|
||||
#include "wayland_server.h"
|
||||
// KWayland
|
||||
#include <KWayland/Server/buffer_interface.h>
|
||||
#include <KWayland/Server/seat_interface.h>
|
||||
#include <KWayland/Server/surface_interface.h>
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#ifndef KWIN_ABSTRACT_BACKEND_H
|
||||
#define KWIN_ABSTRACT_BACKEND_H
|
||||
#include <kwin_export.h>
|
||||
#include <QImage>
|
||||
#include <QObject>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ namespace KWin
|
|||
FramebufferBackend::FramebufferBackend(QObject *parent)
|
||||
: AbstractBackend(parent)
|
||||
{
|
||||
setSoftWareCursor(true);
|
||||
}
|
||||
|
||||
FramebufferBackend::~FramebufferBackend()
|
||||
|
|
|
@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
// 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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue