diff --git a/autotests/integration/pointer_input.cpp b/autotests/integration/pointer_input.cpp index 0ab348cd59..97e83a5a7b 100644 --- a/autotests/integration/pointer_input.cpp +++ b/autotests/integration/pointer_input.cpp @@ -48,12 +48,7 @@ static PlatformCursorImage loadReferenceThemeCursor_helper(const KXcursorTheme & return PlatformCursorImage(); } - QImage cursorImage = sprites.first().data(); - cursorImage.setDevicePixelRatio(theme.devicePixelRatio()); - - QPoint cursorHotspot = sprites.first().hotspot(); - - return PlatformCursorImage(cursorImage, cursorHotspot); + return PlatformCursorImage(sprites.constFirst().data(), sprites.constFirst().hotspot()); } static PlatformCursorImage loadReferenceThemeCursor(const QByteArray &name) diff --git a/src/pointer_input.cpp b/src/pointer_input.cpp index 70c36fd16d..bf59197d34 100644 --- a/src/pointer_input.cpp +++ b/src/pointer_input.cpp @@ -1318,8 +1318,6 @@ bool WaylandCursorImage::loadThemeCursor_helper(const QByteArray &name, Image *c } cursorImage->image = sprites.first().data(); - cursorImage->image.setDevicePixelRatio(m_cursorTheme.devicePixelRatio()); - cursorImage->hotspot = sprites.first().hotspot(); return true; diff --git a/src/xcursortheme.cpp b/src/xcursortheme.cpp index 58b91a1545..ca2078f710 100644 --- a/src/xcursortheme.cpp +++ b/src/xcursortheme.cpp @@ -25,7 +25,6 @@ class KXcursorThemePrivate : public QSharedData { public: QMap> registry; - qreal devicePixelRatio = 1; }; KXcursorSprite::KXcursorSprite() @@ -72,23 +71,33 @@ std::chrono::milliseconds KXcursorSprite::delay() const return d->delay; } +struct XcursorThemeClosure +{ + QMap> registry; + int desiredSize; +}; + static void load_callback(XcursorImages *images, void *data) { - KXcursorThemePrivate *themePrivate = static_cast(data); + XcursorThemeClosure *closure = static_cast(data); QVector sprites; for (int i = 0; i < images->nimage; ++i) { const XcursorImage *nativeCursorImage = images->images[i]; + const qreal scale = std::max(qreal(1), qreal(nativeCursorImage->size) / closure->desiredSize); const QPoint hotspot(nativeCursorImage->xhot, nativeCursorImage->yhot); const std::chrono::milliseconds delay(nativeCursorImage->delay); QImage data(nativeCursorImage->width, nativeCursorImage->height, QImage::Format_ARGB32_Premultiplied); + data.setDevicePixelRatio(scale); memcpy(data.bits(), nativeCursorImage->pixels, data.sizeInBytes()); - sprites.append(KXcursorSprite(data, hotspot / themePrivate->devicePixelRatio, delay)); + sprites.append(KXcursorSprite(data, hotspot / scale, delay)); } - themePrivate->registry.insert(images->name, sprites); + if (!sprites.isEmpty()) { + closure->registry.insert(images->name, sprites); + } XcursorImagesDestroy(images); } @@ -97,6 +106,12 @@ KXcursorTheme::KXcursorTheme() { } +KXcursorTheme::KXcursorTheme(const QMap> ®istry) + : KXcursorTheme() +{ + d->registry = registry; +} + KXcursorTheme::KXcursorTheme(const KXcursorTheme &other) : d(other.d) { @@ -112,11 +127,6 @@ KXcursorTheme &KXcursorTheme::operator=(const KXcursorTheme &other) return *this; } -qreal KXcursorTheme::devicePixelRatio() const -{ - return d->devicePixelRatio; -} - bool KXcursorTheme::isEmpty() const { return d->registry.isEmpty(); @@ -129,14 +139,18 @@ QVector KXcursorTheme::shape(const QByteArray &name) const KXcursorTheme KXcursorTheme::fromTheme(const QString &themeName, int size, qreal dpr) { - KXcursorTheme theme; - KXcursorThemePrivate *themePrivate = theme.d; - themePrivate->devicePixelRatio = dpr; + // Xcursors don't support HiDPI natively so we fake it by scaling the desired cursor + // size. The device pixel ratio argument acts only as a hint. The real scale factor + // of every cursor sprite will be computed in the loading closure. + XcursorThemeClosure closure; + closure.desiredSize = size; + xcursor_load_theme(themeName.toUtf8().constData(), size * dpr, load_callback, &closure); - const QByteArray nativeThemeName = themeName.toUtf8(); - xcursor_load_theme(nativeThemeName, size * dpr, load_callback, themePrivate); + if (closure.registry.isEmpty()) { + return KXcursorTheme(); + } - return theme; + return KXcursorTheme(closure.registry); } } // namespace KWin diff --git a/src/xcursortheme.h b/src/xcursortheme.h index ca3eb10b14..2d511182e8 100644 --- a/src/xcursortheme.h +++ b/src/xcursortheme.h @@ -99,11 +99,6 @@ public: */ KXcursorTheme &operator=(const KXcursorTheme &other); - /** - * Returns the ratio between device pixels and logical pixels for the Xcursor theme. - */ - qreal devicePixelRatio() const; - /** * Returns @c true if the Xcursor theme is empty; otherwise returns @c false. */ @@ -115,11 +110,14 @@ public: QVector shape(const QByteArray &name) const; /** - * Attempts to load the Xcursor theme with the given @a themeName and @a size. + * Loads the Xcursor theme with the given @ themeName and the desired @a size. + * The @a dpr specifies the desired scale factor. If no theme with the provided + * name exists, an empty KXcursorTheme is returned. */ static KXcursorTheme fromTheme(const QString &themeName, int size, qreal dpr); private: + KXcursorTheme(const QMap> ®istry); QSharedDataPointer d; };