diff --git a/src/plugins/shakecursor/shakecursor.cpp b/src/plugins/shakecursor/shakecursor.cpp index b648b78c5d..0979a08ef4 100644 --- a/src/plugins/shakecursor/shakecursor.cpp +++ b/src/plugins/shakecursor/shakecursor.cpp @@ -6,16 +6,39 @@ #include "plugins/shakecursor/shakecursor.h" #include "cursor.h" +#include "cursorsource.h" #include "effect/effecthandler.h" #include "input_event.h" #include "plugins/shakecursor/shakecursorconfig.h" #include "pointer_input.h" -#include "scene/cursoritem.h" +#include "scene/imageitem.h" +#include "scene/itemrenderer.h" #include "scene/workspacescene.h" namespace KWin { +ShakeCursorItem::ShakeCursorItem(const KXcursorTheme &theme, Item *parent) + : Item(parent) +{ + m_source = std::make_unique(); + m_source->setTheme(theme); + m_source->setShape(Qt::ArrowCursor); + + refresh(); + connect(m_source.get(), &CursorSource::changed, this, &ShakeCursorItem::refresh); +} + +void ShakeCursorItem::refresh() +{ + if (!m_imageItem) { + m_imageItem = scene()->renderer()->createImageItem(this); + } + m_imageItem->setImage(m_source->image()); + m_imageItem->setPosition(-m_source->hotspot()); + m_imageItem->setSize(m_source->image().deviceIndependentSize()); +} + ShakeCursorEffect::ShakeCursorEffect() : m_cursor(Cursors::self()->mouse()) { @@ -121,7 +144,12 @@ void ShakeCursorEffect::magnify(qreal magnification) if (!m_cursorItem) { effects->hideCursor(); - m_cursorItem = std::make_unique(effects->scene()->overlayItem()); + const qreal maxScale = ShakeCursorConfig::magnification() + 4 * ShakeCursorConfig::overMagnification(); + if (m_cursorTheme.name() != m_cursor->themeName() || m_cursorTheme.size() != m_cursor->themeSize() || m_cursorTheme.devicePixelRatio() != maxScale) { + m_cursorTheme = KXcursorTheme(m_cursor->themeName(), m_cursor->themeSize(), maxScale); + } + + m_cursorItem = std::make_unique(m_cursorTheme, effects->scene()->overlayItem()); m_cursorItem->setPosition(m_cursor->pos()); connect(m_cursor, &Cursor::posChanged, m_cursorItem.get(), [this]() { m_cursorItem->setPosition(m_cursor->pos()); diff --git a/src/plugins/shakecursor/shakecursor.h b/src/plugins/shakecursor/shakecursor.h index a298c5f70b..98e52ca73d 100644 --- a/src/plugins/shakecursor/shakecursor.h +++ b/src/plugins/shakecursor/shakecursor.h @@ -9,6 +9,8 @@ #include "effect/effect.h" #include "input_event_spy.h" #include "plugins/shakecursor/shakedetector.h" +#include "scene/cursoritem.h" +#include "utils/xcursortheme.h" #include #include @@ -18,6 +20,21 @@ namespace KWin class Cursor; class CursorItem; +class ShapeCursorSource; + +class ShakeCursorItem : public Item +{ + Q_OBJECT + +public: + ShakeCursorItem(const KXcursorTheme &theme, Item *parent); + +private: + void refresh(); + + std::unique_ptr m_imageItem; + std::unique_ptr m_source; +}; class ShakeCursorEffect : public Effect, public InputEventSpy { @@ -45,7 +62,8 @@ private: ShakeDetector m_shakeDetector; Cursor *m_cursor; - std::unique_ptr m_cursorItem; + std::unique_ptr m_cursorItem; + KXcursorTheme m_cursorTheme; qreal m_targetMagnification = 1.0; qreal m_currentMagnification = 1.0; }; diff --git a/src/utils/xcursortheme.cpp b/src/utils/xcursortheme.cpp index 13e51f13d3..e30df30484 100644 --- a/src/utils/xcursortheme.cpp +++ b/src/utils/xcursortheme.cpp @@ -31,8 +31,15 @@ public: class KXcursorThemePrivate : public QSharedData { public: - void load(const QString &themeName, int size, qreal devicePixelRatio); - void loadCursors(const QString &packagePath, int size, qreal devicePixelRatio); + KXcursorThemePrivate(); + KXcursorThemePrivate(const QString &themeName, int size, qreal devicePixelRatio); + + void load(); + void loadCursors(const QString &packagePath); + + QString name; + int size = 0; + qreal devicePixelRatio = 0; QHash> registry; }; @@ -81,6 +88,17 @@ std::chrono::milliseconds KXcursorSprite::delay() const return d->delay; } +KXcursorThemePrivate::KXcursorThemePrivate() +{ +} + +KXcursorThemePrivate::KXcursorThemePrivate(const QString &themeName, int size, qreal devicePixelRatio) + : name(themeName) + , size(size) + , devicePixelRatio(devicePixelRatio) +{ +} + static QList loadCursor(const QString &filePath, int desiredSize, qreal devicePixelRatio) { QFile file(filePath); @@ -127,7 +145,7 @@ static QList loadCursor(const QString &filePath, int desiredSize return sprites; } -void KXcursorThemePrivate::loadCursors(const QString &packagePath, int size, qreal devicePixelRatio) +void KXcursorThemePrivate::loadCursors(const QString &packagePath) { const QDir dir(packagePath); QFileInfoList entries = dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot); @@ -177,14 +195,14 @@ static QStringList searchPaths() return paths; } -void KXcursorThemePrivate::load(const QString &themeName, int size, qreal devicePixelRatio) +void KXcursorThemePrivate::load() { const QStringList paths = searchPaths(); QStack stack; QSet loaded; - stack.push(themeName); + stack.push(name); while (!stack.isEmpty()) { const QString themeName = stack.pop(); @@ -199,7 +217,7 @@ void KXcursorThemePrivate::load(const QString &themeName, int size, qreal device if (!dir.exists()) { continue; } - loadCursors(dir.filePath(QStringLiteral("cursors")), size, devicePixelRatio); + loadCursors(dir.filePath(QStringLiteral("cursors"))); if (inherits.isEmpty()) { const KConfig config(dir.filePath(QStringLiteral("index.theme")), KConfig::NoGlobals); inherits << KConfigGroup(&config, QStringLiteral("Icon Theme")).readEntry("Inherits", QStringList()); @@ -219,9 +237,9 @@ KXcursorTheme::KXcursorTheme() } KXcursorTheme::KXcursorTheme(const QString &themeName, int size, qreal devicePixelRatio) - : d(new KXcursorThemePrivate) + : d(new KXcursorThemePrivate(themeName, size, devicePixelRatio)) { - d->load(themeName, size, devicePixelRatio); + d->load(); } KXcursorTheme::KXcursorTheme(const KXcursorTheme &other) @@ -249,6 +267,21 @@ bool KXcursorTheme::operator!=(const KXcursorTheme &other) return !(*this == other); } +QString KXcursorTheme::name() const +{ + return d->name; +} + +int KXcursorTheme::size() const +{ + return d->size; +} + +qreal KXcursorTheme::devicePixelRatio() const +{ + return d->devicePixelRatio; +} + bool KXcursorTheme::isEmpty() const { return d->registry.isEmpty(); diff --git a/src/utils/xcursortheme.h b/src/utils/xcursortheme.h index cf66d943ab..9dbffd9a6c 100644 --- a/src/utils/xcursortheme.h +++ b/src/utils/xcursortheme.h @@ -109,6 +109,21 @@ public: bool operator==(const KXcursorTheme &other); bool operator!=(const KXcursorTheme &other); + /** + * The name of the requested Xcursor theme. + */ + QString name() const; + + /** + * The size of the requested Xcursor theme. + */ + int size() const; + + /** + * The scale factor of the requested Xcursor theme. + */ + qreal devicePixelRatio() const; + /** * Returns @c true if the Xcursor theme is empty; otherwise returns @c false. */