diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2ed012d8b6..d632294c8f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/cursor.cpp b/src/cursor.cpp index 15b062db45..7024428a82 100644 --- a/src/cursor.cpp +++ b/src/cursor.cpp @@ -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() { diff --git a/src/cursor.h b/src/cursor.h index 0ba2c72684..a6ff8d996f 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -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 m_cursors; QPoint m_pos; - QPoint m_hotspot; - QImage m_image; int m_mousePollingCounter; int m_cursorTrackingCounter; QString m_themeName; diff --git a/src/cursorsource.cpp b/src/cursorsource.cpp new file mode 100644 index 0000000000..ef4ea4bc70 --- /dev/null +++ b/src/cursorsource.cpp @@ -0,0 +1,39 @@ +/* + SPDX-FileCopyrightText: 2022 Vlad Zahorodnii + + 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 diff --git a/src/cursorsource.h b/src/cursorsource.h new file mode 100644 index 0000000000..64c24df43a --- /dev/null +++ b/src/cursorsource.h @@ -0,0 +1,53 @@ +/* + SPDX-FileCopyrightText: 2022 Vlad Zahorodnii + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#pragma once + +#include + +#include +#include +#include + +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 diff --git a/src/input.cpp b/src/input.cpp index b8e4ea9ffd..1215a9a8b6 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -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()) { + 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(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 m_surface; + std::unique_ptr 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; } diff --git a/src/pointer_input.cpp b/src/pointer_input.cpp index 20540466cc..4dfafdb8aa 100644 --- a/src/pointer_input.cpp +++ b/src/pointer_input.cpp @@ -13,6 +13,7 @@ #include #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(); + m_fallbackCursor = std::make_unique(); + m_moveResizeCursor = std::make_unique(); + m_windowSelectionCursor = std::make_unique(); + m_decoration.cursor = std::make_unique(); + m_drag.cursor = std::make_unique(); + m_serverCursor.cursor = std::make_unique(); + 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(c->surface()->buffer()); + if (buffer) { + image = buffer->data().copy(); + image.setDevicePixelRatio(c->surface()->bufferScale()); + hotspot = c->hotspot(); } - return; - } - auto buffer = qobject_cast(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(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(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(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 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(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) diff --git a/src/pointer_input.h b/src/pointer_input.h index ecaa426d48..269474519c 100644 --- a/src/pointer_input.h +++ b/src/pointer_input.h @@ -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 m_effectsCursor; + std::unique_ptr m_fallbackCursor; + std::unique_ptr m_moveResizeCursor; + std::unique_ptr m_windowSelectionCursor; + struct { - WaylandCursorImage::Image cursor; + std::unique_ptr cursor; + QMetaObject::Connection connection; + } m_decoration; + struct + { + std::unique_ptr cursor; QMetaObject::Connection connection; } m_drag; struct { QMetaObject::Connection connection; - WaylandCursorImage::Image cursor; + std::unique_ptr cursor; } m_serverCursor; };