Submitted By: Pierre Labastie Date: 2019-12-ce2407 Initial Package Version: 5.14.0 Upstream Status: Applied Origin: Upstream Description: Fixes Stuttering cursor in Wayland. From 36974955d13578071387695adb13a47be33e4d32 Mon Sep 17 00:00:00 2001 From: David Edmundson Date: Thu, 28 Nov 2019 02:31:17 +0100 Subject: Avoid animating single frame cursors Currently to determine if a cursor is animated or not we check the cursor theme delay. This doesn't work in practice as by default many cursor themes have a delay of 50 set even if they don't animate. This comes from xcursorgen which specifies a delay of 50ms if there isn't anything set in the config. (https://github.com/freedesktop/xcursorgen/blob/master/xcursorgen.c#L92) Given many themes will have a delay we should also check the number of images in a given cursor. In order to do that without a double lookup QWaylandCursor needed to return the native wl_cursor, not wl_cursor_image and move the relevant logic. Change-Id: Ie782ace8054910ae76e61cab33ceca0377194929 Reviewed-by: Johan Helsing --- src/client/qwaylandcursor.cpp | 12 ++---------- src/client/qwaylandcursor_p.h | 3 +-- src/client/qwaylandinputdevice.cpp | 16 ++++++++++++---- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/qtwayland/src/client/qwaylandcursor.cpp b/qtwayland/src/client/qwaylandcursor.cpp index 4356b23a..1d3d88be 100644 --- a/qtwayland/src/client/qwaylandcursor.cpp +++ b/qtwayland/src/client/qwaylandcursor.cpp @@ -219,7 +219,7 @@ wl_cursor *QWaylandCursorTheme::requestCursor(WaylandCursor shape) return nullptr; } -::wl_cursor_image *QWaylandCursorTheme::cursorImage(Qt::CursorShape shape, uint millisecondsIntoAnimation) +::wl_cursor *QWaylandCursorTheme::cursor(Qt::CursorShape shape) { struct wl_cursor *waylandCursor = nullptr; @@ -237,15 +237,7 @@ wl_cursor *QWaylandCursorTheme::requestCursor(WaylandCursor shape) return nullptr; } - int frame = wl_cursor_frame(waylandCursor, millisecondsIntoAnimation); - ::wl_cursor_image *image = waylandCursor->images[frame]; - ::wl_buffer *buffer = wl_cursor_image_get_buffer(image); - if (!buffer) { - qCWarning(lcQpaWayland) << "Could not find buffer for cursor"; - return nullptr; - } - - return image; + return waylandCursor; } QWaylandCursor::QWaylandCursor(QWaylandDisplay *display) diff --git a/qtwayland/src/client/qwaylandcursor_p.h b/qtwayland/src/client/qwaylandcursor_p.h index a4605f3d..751ffa68 100644 --- a/qtwayland/src/client/qwaylandcursor_p.h +++ b/qtwayland/src/client/qwaylandcursor_p.h @@ -75,7 +75,7 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandCursorTheme public: static QWaylandCursorTheme *create(QWaylandShm *shm, int size, const QString &themeName); ~QWaylandCursorTheme(); - ::wl_cursor_image *cursorImage(Qt::CursorShape shape, uint millisecondsIntoAnimation = 0); + ::wl_cursor *cursor(Qt::CursorShape shape); private: enum WaylandCursor { @@ -129,7 +129,6 @@ public: void setPos(const QPoint &pos) override; static QSharedPointer cursorBitmapBuffer(QWaylandDisplay *display, const QCursor *cursor); - struct wl_cursor_image *cursorImage(Qt::CursorShape shape); private: QWaylandDisplay *mDisplay = nullptr; diff --git a/qtwayland/src/client/qwaylandinputdevice.cpp b/qtwayland/src/client/qwaylandinputdevice.cpp index a4098edd..d812918e 100644 --- a/qtwayland/src/client/qwaylandinputdevice.cpp +++ b/qtwayland/src/client/qwaylandinputdevice.cpp @@ -283,8 +283,8 @@ void QWaylandInputDevice::Pointer::updateCursorTheme() if (!mCursor.theme) return; // A warning has already been printed in loadCursorTheme - if (auto *arrow = mCursor.theme->cursorImage(Qt::ArrowCursor)) { - int arrowPixelSize = qMax(arrow->width, arrow->height); // Not all cursor themes are square + if (auto *arrow = mCursor.theme->cursor(Qt::ArrowCursor)) { + int arrowPixelSize = qMax(arrow->images[0]->width, arrow->images[0]->height); // Not all cursor themes are square while (scale > 1 && arrowPixelSize / scale < cursorSize()) --scale; } else { @@ -326,12 +326,20 @@ void QWaylandInputDevice::Pointer::updateCursor() // Set from shape using theme uint time = seat()->mCursor.animationTimer.elapsed(); - if (struct ::wl_cursor_image *image = mCursor.theme->cursorImage(shape, time)) { + + if (struct ::wl_cursor *waylandCursor = mCursor.theme->cursor(shape)) { + int frame = wl_cursor_frame(waylandCursor, time); + ::wl_cursor_image *image = waylandCursor->images[frame]; + struct wl_buffer *buffer = wl_cursor_image_get_buffer(image); + if (!buffer) { + qCWarning(lcQpaWayland) << "Could not find buffer for cursor" << shape; + return; + } int bufferScale = mCursor.themeBufferScale; QPoint hotspot = QPoint(image->hotspot_x, image->hotspot_y) / bufferScale; QSize size = QSize(image->width, image->height) / bufferScale; - bool animated = image->delay > 0; + bool animated = waylandCursor->image_count > 1 && image->delay > 0; getOrCreateCursorSurface()->update(buffer, hotspot, size, bufferScale, animated); return; } -- cgit v1.2.1