Add CursorSource

CursorSource acts as a black box providing the contents of the cursor.
That's it, the image and the hotspot.
This commit is contained in:
Vlad Zahorodnii 2022-11-18 20:58:17 +02:00
parent f881bdf51b
commit e552be6cb1
8 changed files with 279 additions and 262 deletions

View file

@ -59,6 +59,7 @@ target_sources(kwin PRIVATE
cursor.cpp
cursordelegate_opengl.cpp
cursordelegate_qpainter.cpp
cursorsource.cpp
dbusinterface.cpp
debug_console.cpp
decorationitem.cpp

View file

@ -11,6 +11,7 @@
// kwin
#include "composite.h"
#include "core/output.h"
#include "cursorsource.h"
#include "input.h"
#include "keyboard_input.h"
#include "main.h"
@ -180,6 +181,22 @@ bool Cursor::isOnOutput(Output *output) const
return !image().isNull();
}
QImage Cursor::image() const
{
if (Q_UNLIKELY(!m_source)) {
return QImage();
}
return m_source->image();
}
QPoint Cursor::hotspot() const
{
if (Q_UNLIKELY(!m_source)) {
return QPoint();
}
return m_source->hotspot();
}
QRect Cursor::geometry() const
{
return rect().translated(m_pos - hotspot());
@ -216,13 +233,6 @@ void Cursor::setPos(int x, int y)
setPos(QPoint(x, y));
}
void Cursor::updateCursor(const QImage &image, const QPoint &hotspot)
{
m_image = image;
m_hotspot = hotspot;
Q_EMIT cursorChanged();
}
void Cursor::markAsRendered(std::chrono::milliseconds timestamp)
{
Q_EMIT rendered(timestamp);
@ -689,6 +699,24 @@ QByteArray CursorShape::name() const
}
}
CursorSource *Cursor::source() const
{
return m_source;
}
void Cursor::setSource(CursorSource *source)
{
if (m_source == source) {
return;
}
if (m_source) {
disconnect(m_source, &CursorSource::changed, this, &Cursor::cursorChanged);
}
m_source = source;
connect(m_source, &CursorSource::changed, this, &Cursor::cursorChanged);
Q_EMIT cursorChanged();
}
InputConfig *InputConfig::s_self = nullptr;
InputConfig *InputConfig::self()
{

View file

@ -24,6 +24,7 @@ class QTimer;
namespace KWin
{
class CursorSource;
class Output;
namespace ExtendedCursor
@ -174,23 +175,19 @@ public:
*/
xcb_cursor_t x11Cursor(const QByteArray &name);
QImage image() const
{
return m_image;
}
QPoint hotspot() const
{
return m_hotspot;
}
QImage image() const;
QPoint hotspot() const;
QRect geometry() const;
QRect rect() const;
CursorSource *source() const;
void setSource(CursorSource *source);
/**
* Returns @c true if the cursor is visible on the given output; otherwise returns @c false.
*/
bool isOnOutput(Output *output) const;
void updateCursor(const QImage &image, const QPoint &hotspot);
void markAsRendered(std::chrono::milliseconds timestamp);
Q_SIGNALS:
@ -261,10 +258,9 @@ private Q_SLOTS:
private:
void updateTheme(const QString &name, int size);
void loadThemeFromKConfig();
CursorSource *m_source = nullptr;
QHash<QByteArray, xcb_cursor_t> m_cursors;
QPoint m_pos;
QPoint m_hotspot;
QImage m_image;
int m_mousePollingCounter;
int m_cursorTrackingCounter;
QString m_themeName;

39
src/cursorsource.cpp Normal file
View file

@ -0,0 +1,39 @@
/*
SPDX-FileCopyrightText: 2022 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "cursorsource.h"
namespace KWin
{
CursorSource::CursorSource(QObject *parent)
: QObject(parent)
{
}
QImage CursorSource::image() const
{
return m_image;
}
QPoint CursorSource::hotspot() const
{
return m_hotspot;
}
ImageCursorSource::ImageCursorSource(QObject *parent)
: CursorSource(parent)
{
}
void ImageCursorSource::update(const QImage &image, const QPoint &hotspot)
{
m_image = image;
m_hotspot = hotspot;
Q_EMIT changed();
}
} // namespace KWin

53
src/cursorsource.h Normal file
View file

@ -0,0 +1,53 @@
/*
SPDX-FileCopyrightText: 2022 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <kwin_export.h>
#include <QImage>
#include <QObject>
#include <QPoint>
namespace KWin
{
/**
* The CursorSource class represents the contents of the Cursor.
*/
class KWIN_EXPORT CursorSource : public QObject
{
Q_OBJECT
public:
explicit CursorSource(QObject *parent = nullptr);
QImage image() const;
QPoint hotspot() const;
Q_SIGNALS:
void changed();
protected:
QImage m_image;
QPoint m_hotspot;
};
/**
* The ImageCursorSource class represents a static raster cursor pixmap.
*/
class KWIN_EXPORT ImageCursorSource : public CursorSource
{
Q_OBJECT
public:
explicit ImageCursorSource(QObject *parent = nullptr);
public Q_SLOTS:
void update(const QImage &image, const QPoint &hotspot);
};
} // namespace KWin

View file

@ -36,6 +36,7 @@
#include "core/output.h"
#include "core/outputbackend.h"
#include "cursor.h"
#include "cursorsource.h"
#include "internalwindow.h"
#include "popup_input_filter.h"
#include "screenedge.h"
@ -1904,9 +1905,24 @@ static KWaylandServer::SeatInterface *findSeat()
class SurfaceCursor : public Cursor
{
public:
explicit SurfaceCursor(QObject *parent)
: Cursor(parent)
explicit SurfaceCursor(KWaylandServer::TabletToolV2Interface *tool)
: Cursor(tool)
, m_source(std::make_unique<ImageCursorSource>())
{
connect(tool, &KWaylandServer::TabletToolV2Interface::cursorChanged, this, [this](KWaylandServer::TabletCursorV2 *tcursor) {
if (!tcursor || tcursor->enteredSerial() == 0) {
static WaylandCursorImage defaultCursor;
defaultCursor.loadThemeCursor(CursorShape(Qt::CrossCursor), m_source.get());
return;
}
auto cursorSurface = tcursor->surface();
if (!cursorSurface) {
m_source->update(QImage(), QPoint());
return;
}
updateCursorSurface(cursorSurface, tcursor->hotspot());
});
}
void updateCursorSurface(KWaylandServer::SurfaceInterface *surface, const QPoint &hotspot)
@ -1930,17 +1946,18 @@ private:
{
auto buffer = qobject_cast<KWaylandServer::ShmClientBuffer *>(m_surface->buffer());
if (!buffer) {
updateCursor({}, {});
m_source->update(QImage(), QPoint());
return;
}
QImage cursorImage;
cursorImage = buffer->data().copy();
cursorImage.setDevicePixelRatio(m_surface->bufferScale());
updateCursor(cursorImage, m_hotspot);
m_source->update(cursorImage, m_hotspot);
}
QPointer<KWaylandServer::SurfaceInterface> m_surface;
std::unique_ptr<ImageCursorSource> m_source;
QPoint m_hotspot;
};
@ -2118,27 +2135,6 @@ public:
Cursors::self()->addCursor(cursor);
m_cursorByTool[tool] = cursor;
connect(tool, &TabletToolV2Interface::cursorChanged, cursor, [cursor](TabletCursorV2 *tcursor) {
static const auto createDefaultCursor = [] {
WaylandCursorImage defaultCursor;
WaylandCursorImage::Image ret;
defaultCursor.loadThemeCursor(CursorShape(Qt::CrossCursor), &ret);
return ret;
};
if (!tcursor || tcursor->enteredSerial() == 0) {
static const auto defaultCursor = createDefaultCursor();
cursor->updateCursor(defaultCursor.image, defaultCursor.hotspot);
return;
}
auto cursorSurface = tcursor->surface();
if (!cursorSurface) {
cursor->updateCursor({}, {});
return;
}
cursor->updateCursorSurface(cursorSurface, tcursor->hotspot());
});
Q_EMIT cursor->cursorChanged();
return tool;
}

View file

@ -13,6 +13,7 @@
#include <config-kwin.h>
#include "core/output.h"
#include "cursorsource.h"
#include "decorations/decoratedclient.h"
#include "effects.h"
#include "input_event.h"
@ -99,8 +100,7 @@ void PointerInputRedirection::init()
connect(Cursors::self()->mouse(), &Cursor::rendered, m_cursor, &CursorImage::markAsRendered);
connect(m_cursor, &CursorImage::changed, Cursors::self()->mouse(), [this] {
auto cursor = Cursors::self()->mouse();
cursor->updateCursor(m_cursor->image(), m_cursor->hotSpot());
Cursors::self()->mouse()->setSource(m_cursor->source());
updateCursorOutputs();
});
Q_EMIT m_cursor->changed();
@ -791,7 +791,7 @@ void PointerInputRedirection::updateCursorOutputs()
return;
}
const QRectF cursorGeometry(m_pos - m_cursor->hotSpot(), surface->size());
const QRectF cursorGeometry(m_pos - m_cursor->source()->hotspot(), surface->size());
surface->setOutputs(waylandServer()->display()->outputsIntersecting(cursorGeometry.toAlignedRect()));
}
@ -886,6 +886,14 @@ CursorImage::CursorImage(PointerInputRedirection *parent)
: QObject(parent)
, m_pointer(parent)
{
m_effectsCursor = std::make_unique<ImageCursorSource>();
m_fallbackCursor = std::make_unique<ImageCursorSource>();
m_moveResizeCursor = std::make_unique<ImageCursorSource>();
m_windowSelectionCursor = std::make_unique<ImageCursorSource>();
m_decoration.cursor = std::make_unique<ImageCursorSource>();
m_drag.cursor = std::make_unique<ImageCursorSource>();
m_serverCursor.cursor = std::make_unique<ImageCursorSource>();
connect(waylandServer()->seat(), &KWaylandServer::SeatInterface::hasPointerChanged,
this, &CursorImage::handlePointerChanged);
connect(waylandServer()->seat(), &KWaylandServer::SeatInterface::dragStarted, this, &CursorImage::updateDrag);
@ -907,31 +915,31 @@ CursorImage::CursorImage(PointerInputRedirection *parent)
const auto clients = workspace()->allClientList();
std::for_each(clients.begin(), clients.end(), setupMoveResizeConnection);
connect(workspace(), &Workspace::windowAdded, this, setupMoveResizeConnection);
loadThemeCursor(Qt::ArrowCursor, &m_fallbackCursor);
loadThemeCursor(Qt::ArrowCursor, m_fallbackCursor.get());
connect(&m_waylandImage, &WaylandCursorImage::themeChanged, this, [this] {
loadThemeCursor(Qt::ArrowCursor, &m_fallbackCursor);
loadThemeCursor(Qt::ArrowCursor, m_fallbackCursor.get());
updateDecorationCursor();
updateMoveResize();
// TODO: update effects
});
handlePointerChanged();
reevaluteSource();
}
CursorImage::~CursorImage() = default;
void CursorImage::markAsRendered(std::chrono::milliseconds timestamp)
{
if (m_currentSource == CursorSource::DragAndDrop) {
if (m_currentSource == m_drag.cursor.get()) {
// always sending a frame rendered to the drag icon surface to not freeze QtWayland (see https://bugreports.qt.io/browse/QTBUG-51599 )
if (const KWaylandServer::DragAndDropIcon *icon = waylandServer()->seat()->dragIcon()) {
icon->surface()->frameRendered(timestamp.count());
}
}
if (m_currentSource != CursorSource::LockScreen
&& m_currentSource != CursorSource::PointerSurface
&& m_currentSource != CursorSource::DragAndDrop) {
if (m_currentSource != m_serverCursor.cursor.get()
&& m_currentSource != m_drag.cursor.get()) {
return;
}
auto p = waylandServer()->seat()->pointer();
@ -975,89 +983,64 @@ void CursorImage::handleFocusedSurfaceChanged()
void CursorImage::updateDecoration()
{
disconnect(m_decorationConnection);
disconnect(m_decoration.connection);
auto deco = m_pointer->decoration();
Window *window = deco ? deco->window() : nullptr;
if (window) {
m_decorationConnection = connect(window, &Window::moveResizeCursorChanged, this, &CursorImage::updateDecorationCursor);
m_decoration.connection = connect(window, &Window::moveResizeCursorChanged, this, &CursorImage::updateDecorationCursor);
} else {
m_decorationConnection = QMetaObject::Connection();
m_decoration.connection = QMetaObject::Connection();
}
updateDecorationCursor();
}
void CursorImage::updateDecorationCursor()
{
m_decorationCursor = {};
auto deco = m_pointer->decoration();
if (Window *window = deco ? deco->window() : nullptr) {
loadThemeCursor(window->cursor(), &m_decorationCursor);
if (m_currentSource == CursorSource::Decoration) {
Q_EMIT changed();
}
loadThemeCursor(window->cursor(), m_decoration.cursor.get());
}
reevaluteSource();
}
void CursorImage::updateMoveResize()
{
m_moveResizeCursor = {};
if (Window *window = workspace()->moveResizeWindow()) {
loadThemeCursor(window->cursor(), &m_moveResizeCursor);
if (m_currentSource == CursorSource::MoveResize) {
Q_EMIT changed();
}
loadThemeCursor(window->cursor(), m_moveResizeCursor.get());
}
reevaluteSource();
}
void CursorImage::updateServerCursor()
{
m_serverCursor.cursor = {};
reevaluteSource();
const bool needsEmit = m_currentSource == CursorSource::LockScreen || m_currentSource == CursorSource::PointerSurface;
auto p = waylandServer()->seat()->pointer();
if (!p) {
if (needsEmit) {
Q_EMIT changed();
}
return;
}
auto c = p->cursor();
if (!c) {
if (needsEmit) {
Q_EMIT changed();
}
return;
}
auto cursorSurface = c->surface();
if (!cursorSurface) {
if (needsEmit) {
Q_EMIT changed();
QImage image;
QPoint hotspot;
if (c->surface()) {
auto buffer = qobject_cast<KWaylandServer::ShmClientBuffer *>(c->surface()->buffer());
if (buffer) {
image = buffer->data().copy();
image.setDevicePixelRatio(c->surface()->bufferScale());
hotspot = c->hotspot();
}
return;
}
auto buffer = qobject_cast<KWaylandServer::ShmClientBuffer *>(cursorSurface->buffer());
if (!buffer) {
if (needsEmit) {
Q_EMIT changed();
}
return;
}
m_serverCursor.cursor.hotspot = c->hotspot();
m_serverCursor.cursor.image = buffer->data().copy();
m_serverCursor.cursor.image.setDevicePixelRatio(cursorSurface->bufferScale());
if (needsEmit) {
Q_EMIT changed();
}
m_serverCursor.cursor->update(image, hotspot);
}
void CursorImage::setEffectsOverrideCursor(Qt::CursorShape shape)
{
loadThemeCursor(shape, &m_effectsCursor);
if (m_currentSource == CursorSource::EffectsOverride) {
Q_EMIT changed();
}
loadThemeCursor(shape, m_effectsCursor.get());
reevaluteSource();
}
@ -1069,12 +1052,9 @@ void CursorImage::removeEffectsOverrideCursor()
void CursorImage::setWindowSelectionCursor(const QByteArray &shape)
{
if (shape.isEmpty()) {
loadThemeCursor(Qt::CrossCursor, &m_windowSelectionCursor);
loadThemeCursor(Qt::CrossCursor, m_windowSelectionCursor.get());
} else {
loadThemeCursor(shape, &m_windowSelectionCursor);
}
if (m_currentSource == CursorSource::WindowSelector) {
Q_EMIT changed();
loadThemeCursor(shape, m_windowSelectionCursor.get());
}
reevaluteSource();
}
@ -1088,7 +1068,6 @@ void CursorImage::updateDrag()
{
using namespace KWaylandServer;
disconnect(m_drag.connection);
m_drag.cursor = {};
reevaluteSource();
if (waylandServer()->seat()->isDragPointer()) {
KWaylandServer::PointerInterface *pointer = waylandServer()->seat()->pointer();
@ -1101,8 +1080,6 @@ void CursorImage::updateDrag()
void CursorImage::updateDragCursor()
{
m_drag.cursor = {};
const bool needsEmit = m_currentSource == CursorSource::DragAndDrop;
QImage additionalIcon;
if (const KWaylandServer::DragAndDropIcon *dragIcon = waylandServer()->seat()->dragIcon()) {
if (auto buffer = qobject_cast<KWaylandServer::ShmClientBuffer *>(dragIcon->surface()->buffer())) {
@ -1113,82 +1090,68 @@ void CursorImage::updateDragCursor()
}
auto p = waylandServer()->seat()->pointer();
if (!p) {
if (needsEmit) {
Q_EMIT changed();
}
return;
}
auto c = p->cursor();
if (!c) {
if (needsEmit) {
Q_EMIT changed();
}
return;
}
auto cursorSurface = c->surface();
if (!cursorSurface) {
if (needsEmit) {
Q_EMIT changed();
}
return;
}
auto buffer = qobject_cast<KWaylandServer::ShmClientBuffer *>(cursorSurface->buffer());
if (!buffer) {
if (needsEmit) {
Q_EMIT changed();
}
return;
}
QImage cursorImage = buffer->data();
cursorImage.setDevicePixelRatio(cursorSurface->bufferScale());
QImage image;
QPoint hotspot;
if (additionalIcon.isNull()) {
m_drag.cursor.image = cursorImage.copy();
m_drag.cursor.hotspot = c->hotspot();
} else {
QRect cursorRect(QPoint(0, 0), cursorImage.size() / cursorImage.devicePixelRatio());
QRect iconRect(QPoint(0, 0), additionalIcon.size() / additionalIcon.devicePixelRatio());
if (c->surface()) {
auto buffer = qobject_cast<KWaylandServer::ShmClientBuffer *>(c->surface()->buffer());
if (buffer) {
QImage cursorImage = buffer->data();
cursorImage.setDevicePixelRatio(c->surface()->bufferScale());
if (-c->hotspot().x() < additionalIcon.offset().x()) {
iconRect.moveLeft(c->hotspot().x() - additionalIcon.offset().x());
} else {
cursorRect.moveLeft(-additionalIcon.offset().x() - c->hotspot().x());
if (additionalIcon.isNull()) {
image = cursorImage.copy();
hotspot = c->hotspot();
} else {
QRect cursorRect(QPoint(0, 0), cursorImage.size() / cursorImage.devicePixelRatio());
QRect iconRect(QPoint(0, 0), additionalIcon.size() / additionalIcon.devicePixelRatio());
if (-c->hotspot().x() < additionalIcon.offset().x()) {
iconRect.moveLeft(c->hotspot().x() - additionalIcon.offset().x());
} else {
cursorRect.moveLeft(-additionalIcon.offset().x() - c->hotspot().x());
}
if (-c->hotspot().y() < additionalIcon.offset().y()) {
iconRect.moveTop(c->hotspot().y() - additionalIcon.offset().y());
} else {
cursorRect.moveTop(-additionalIcon.offset().y() - c->hotspot().y());
}
const QRect viewport = cursorRect.united(iconRect);
const qreal scale = c->surface()->bufferScale();
image = QImage(viewport.size() * scale, QImage::Format_ARGB32_Premultiplied);
image.setDevicePixelRatio(scale);
image.fill(Qt::transparent);
QPainter p(&image);
p.drawImage(iconRect, additionalIcon);
p.drawImage(cursorRect, cursorImage);
p.end();
hotspot = cursorRect.topLeft() + c->hotspot();
}
}
if (-c->hotspot().y() < additionalIcon.offset().y()) {
iconRect.moveTop(c->hotspot().y() - additionalIcon.offset().y());
} else {
cursorRect.moveTop(-additionalIcon.offset().y() - c->hotspot().y());
}
const QRect viewport = cursorRect.united(iconRect);
const qreal scale = cursorSurface->bufferScale();
m_drag.cursor.image = QImage(viewport.size() * scale, QImage::Format_ARGB32_Premultiplied);
m_drag.cursor.image.setDevicePixelRatio(scale);
m_drag.cursor.image.fill(Qt::transparent);
m_drag.cursor.hotspot = cursorRect.topLeft() + c->hotspot();
QPainter p(&m_drag.cursor.image);
p.drawImage(iconRect, additionalIcon);
p.drawImage(cursorRect, cursorImage);
p.end();
}
if (needsEmit) {
Q_EMIT changed();
}
// TODO: add the cursor image
m_drag.cursor->update(image, hotspot);
}
void CursorImage::loadThemeCursor(CursorShape shape, WaylandCursorImage::Image *image)
void CursorImage::loadThemeCursor(CursorShape shape, ImageCursorSource *source)
{
m_waylandImage.loadThemeCursor(shape, image);
m_waylandImage.loadThemeCursor(shape, source);
}
void CursorImage::loadThemeCursor(const QByteArray &shape, WaylandCursorImage::Image *image)
void CursorImage::loadThemeCursor(const QByteArray &shape, ImageCursorSource *source)
{
m_waylandImage.loadThemeCursor(shape, image);
m_waylandImage.loadThemeCursor(shape, source);
}
WaylandCursorImage::WaylandCursorImage(QObject *parent)
@ -1234,24 +1197,24 @@ void WaylandCursorImage::invalidateCursorTheme()
m_cursorTheme = KXcursorTheme();
}
void WaylandCursorImage::loadThemeCursor(const CursorShape &shape, Image *cursorImage)
void WaylandCursorImage::loadThemeCursor(const CursorShape &shape, ImageCursorSource *source)
{
loadThemeCursor(shape.name(), cursorImage);
loadThemeCursor(shape.name(), source);
}
void WaylandCursorImage::loadThemeCursor(const QByteArray &name, Image *cursorImage)
void WaylandCursorImage::loadThemeCursor(const QByteArray &name, ImageCursorSource *source)
{
if (!ensureCursorTheme()) {
return;
}
if (loadThemeCursor_helper(name, cursorImage)) {
if (loadThemeCursor_helper(name, source)) {
return;
}
const auto alternativeNames = Cursor::cursorAlternativeNames(name);
for (const QByteArray &alternativeName : alternativeNames) {
if (loadThemeCursor_helper(alternativeName, cursorImage)) {
if (loadThemeCursor_helper(alternativeName, source)) {
return;
}
}
@ -1259,16 +1222,13 @@ void WaylandCursorImage::loadThemeCursor(const QByteArray &name, Image *cursorIm
qCWarning(KWIN_CORE) << "Failed to load theme cursor for shape" << name;
}
bool WaylandCursorImage::loadThemeCursor_helper(const QByteArray &name, Image *cursorImage)
bool WaylandCursorImage::loadThemeCursor_helper(const QByteArray &name, ImageCursorSource *source)
{
const QVector<KXcursorSprite> sprites = m_cursorTheme.shape(name);
if (sprites.isEmpty()) {
return false;
}
cursorImage->image = sprites.first().data();
cursorImage->hotspot = sprites.first().hotspot();
source->update(sprites.first().data(), sprites.first().hotspot());
return true;
}
@ -1276,38 +1236,43 @@ void CursorImage::reevaluteSource()
{
if (waylandServer()->seat()->isDragPointer()) {
// TODO: touch drag?
setSource(CursorSource::DragAndDrop);
setSource(m_drag.cursor.get());
return;
}
if (waylandServer()->isScreenLocked()) {
setSource(CursorSource::LockScreen);
setSource(m_serverCursor.cursor.get());
return;
}
if (input()->isSelectingWindow()) {
setSource(CursorSource::WindowSelector);
setSource(m_windowSelectionCursor.get());
return;
}
if (effects && static_cast<EffectsHandlerImpl *>(effects)->isMouseInterception()) {
setSource(CursorSource::EffectsOverride);
setSource(m_effectsCursor.get());
return;
}
if (workspace() && workspace()->moveResizeWindow()) {
setSource(CursorSource::MoveResize);
setSource(m_moveResizeCursor.get());
return;
}
if (m_pointer->decoration()) {
setSource(CursorSource::Decoration);
setSource(m_decoration.cursor.get());
return;
}
const KWaylandServer::PointerInterface *pointer = waylandServer()->seat()->pointer();
if (pointer && pointer->focusedSurface()) {
setSource(CursorSource::PointerSurface);
setSource(m_serverCursor.cursor.get());
return;
}
setSource(CursorSource::Fallback);
setSource(m_fallbackCursor.get());
}
void CursorImage::setSource(CursorSource source)
CursorSource *CursorImage::source() const
{
return m_currentSource;
}
void CursorImage::setSource(CursorSource *source)
{
if (m_currentSource == source) {
return;
@ -1316,54 +1281,6 @@ void CursorImage::setSource(CursorSource source)
Q_EMIT changed();
}
QImage CursorImage::image() const
{
switch (m_currentSource) {
case CursorSource::EffectsOverride:
return m_effectsCursor.image;
case CursorSource::MoveResize:
return m_moveResizeCursor.image;
case CursorSource::LockScreen:
case CursorSource::PointerSurface:
// lockscreen also uses server cursor image
return m_serverCursor.cursor.image;
case CursorSource::Decoration:
return m_decorationCursor.image;
case CursorSource::DragAndDrop:
return m_drag.cursor.image;
case CursorSource::Fallback:
return m_fallbackCursor.image;
case CursorSource::WindowSelector:
return m_windowSelectionCursor.image;
default:
Q_UNREACHABLE();
}
}
QPoint CursorImage::hotSpot() const
{
switch (m_currentSource) {
case CursorSource::EffectsOverride:
return m_effectsCursor.hotspot;
case CursorSource::MoveResize:
return m_moveResizeCursor.hotspot;
case CursorSource::LockScreen:
case CursorSource::PointerSurface:
// lockscreen also uses server cursor image
return m_serverCursor.cursor.hotspot;
case CursorSource::Decoration:
return m_decorationCursor.hotspot;
case CursorSource::DragAndDrop:
return m_drag.cursor.hotspot;
case CursorSource::Fallback:
return m_fallbackCursor.hotspot;
case CursorSource::WindowSelector:
return m_windowSelectionCursor.hotspot;
default:
Q_UNREACHABLE();
}
}
InputRedirectionCursor::InputRedirectionCursor(QObject *parent)
: Cursor(parent)
, m_currentButtons(Qt::NoButton)

View file

@ -34,6 +34,7 @@ class CursorImage;
class InputDevice;
class InputRedirection;
class CursorShape;
class ImageCursorSource;
namespace Decoration
{
@ -182,20 +183,14 @@ class WaylandCursorImage : public QObject
public:
explicit WaylandCursorImage(QObject *parent = nullptr);
struct Image
{
QImage image;
QPoint hotspot;
};
void loadThemeCursor(const CursorShape &shape, Image *cursorImage);
void loadThemeCursor(const QByteArray &name, Image *cursorImage);
void loadThemeCursor(const CursorShape &shape, ImageCursorSource *source);
void loadThemeCursor(const QByteArray &name, ImageCursorSource *source);
Q_SIGNALS:
void themeChanged();
private:
bool loadThemeCursor_helper(const QByteArray &name, Image *cursorImage);
bool loadThemeCursor_helper(const QByteArray &name, ImageCursorSource *source);
bool ensureCursorTheme();
void invalidateCursorTheme();
@ -214,8 +209,8 @@ public:
void setWindowSelectionCursor(const QByteArray &shape);
void removeWindowSelectionCursor();
QImage image() const;
QPoint hotSpot() const;
CursorSource *source() const;
void setSource(CursorSource *source);
void markAsRendered(std::chrono::milliseconds timestamp);
Q_SIGNALS:
@ -233,40 +228,32 @@ private:
void handlePointerChanged();
void handleFocusedSurfaceChanged();
void loadThemeCursor(CursorShape shape, WaylandCursorImage::Image *image);
void loadThemeCursor(const QByteArray &shape, WaylandCursorImage::Image *image);
enum class CursorSource {
LockScreen,
EffectsOverride,
MoveResize,
PointerSurface,
Decoration,
DragAndDrop,
Fallback,
WindowSelector
};
void setSource(CursorSource source);
void loadThemeCursor(CursorShape shape, ImageCursorSource *source);
void loadThemeCursor(const QByteArray &shape, ImageCursorSource *source);
PointerInputRedirection *m_pointer;
CursorSource m_currentSource = CursorSource::Fallback;
CursorSource *m_currentSource = nullptr;
WaylandCursorImage m_waylandImage;
WaylandCursorImage::Image m_effectsCursor;
WaylandCursorImage::Image m_decorationCursor;
QMetaObject::Connection m_decorationConnection;
WaylandCursorImage::Image m_fallbackCursor;
WaylandCursorImage::Image m_moveResizeCursor;
WaylandCursorImage::Image m_windowSelectionCursor;
std::unique_ptr<ImageCursorSource> m_effectsCursor;
std::unique_ptr<ImageCursorSource> m_fallbackCursor;
std::unique_ptr<ImageCursorSource> m_moveResizeCursor;
std::unique_ptr<ImageCursorSource> m_windowSelectionCursor;
struct
{
WaylandCursorImage::Image cursor;
std::unique_ptr<ImageCursorSource> cursor;
QMetaObject::Connection connection;
} m_decoration;
struct
{
std::unique_ptr<ImageCursorSource> cursor;
QMetaObject::Connection connection;
} m_drag;
struct
{
QMetaObject::Connection connection;
WaylandCursorImage::Image cursor;
std::unique_ptr<ImageCursorSource> cursor;
} m_serverCursor;
};