126 lines
4.6 KiB
Diff
126 lines
4.6 KiB
Diff
From ce15889614f87b5986f997beffd2826471adfe51 Mon Sep 17 00:00:00 2001
|
|
From: "Jan Alexander Steffens (heftig)" <jan.steffens@gmail.com>
|
|
Date: Fri, 13 Dec 2019 22:15:32 +0100
|
|
Subject: Drive cursor animation with a timer
|
|
|
|
Using only wl_surface_frame callbacks to update the cursor does so much
|
|
more often than needed. In addition, at least GNOME and Weston fire the
|
|
callback for the cursor surface immediately, which ends up updating the
|
|
cursor at over 3000 Hz here.
|
|
|
|
Use wl_cursor_frame_and_duration to drive a single shot timer. This
|
|
function is also guaranteed to return 0 for single frame cursors, so we
|
|
can avoid starting the timer at all.
|
|
|
|
We wait for both the surface frame callback and the timer to fire before
|
|
updating the cursor for the next frame of animation. This reduces our
|
|
update rate to the frame rate of the cursor or the rate requested by the
|
|
compositor, whichever is lower.
|
|
|
|
Change-Id: I10277460ebe9b547ebaf7f73424b9ef17614107f
|
|
Reviewed-by: Johan Helsing <johan.helsing@qt.io>
|
|
---
|
|
src/client/qwaylandinputdevice.cpp | 34 +++++++++++++++++++++++++++++++---
|
|
src/client/qwaylandinputdevice_p.h | 5 +++++
|
|
2 files changed, 36 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp
|
|
index 3b26dc42..3f0d61d6 100644
|
|
--- a/src/client/qwaylandinputdevice.cpp
|
|
+++ b/src/client/qwaylandinputdevice.cpp
|
|
@@ -143,6 +143,12 @@ QWaylandWindow *QWaylandInputDevice::Keyboard::focusWindow() const
|
|
QWaylandInputDevice::Pointer::Pointer(QWaylandInputDevice *seat)
|
|
: mParent(seat)
|
|
{
|
|
+#if QT_CONFIG(cursor)
|
|
+ mCursor.frameTimer.setSingleShot(true);
|
|
+ mCursor.frameTimer.callOnTimeout([&]() {
|
|
+ cursorTimerCallback();
|
|
+ });
|
|
+#endif
|
|
}
|
|
|
|
QWaylandInputDevice::Pointer::~Pointer()
|
|
@@ -224,7 +230,7 @@ public:
|
|
if (animated) {
|
|
m_frameCallback.reset(new WlCallback(frame(), [this](uint32_t time){
|
|
Q_UNUSED(time);
|
|
- m_pointer->updateCursor();
|
|
+ m_pointer->cursorFrameCallback();
|
|
}));
|
|
}
|
|
commit();
|
|
@@ -328,7 +334,8 @@ void QWaylandInputDevice::Pointer::updateCursor()
|
|
uint time = seat()->mCursor.animationTimer.elapsed();
|
|
|
|
if (struct ::wl_cursor *waylandCursor = mCursor.theme->cursor(shape)) {
|
|
- int frame = wl_cursor_frame(waylandCursor, time);
|
|
+ uint duration = 0;
|
|
+ int frame = wl_cursor_frame_and_duration(waylandCursor, time, &duration);
|
|
::wl_cursor_image *image = waylandCursor->images[frame];
|
|
|
|
struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);
|
|
@@ -339,7 +346,12 @@ void QWaylandInputDevice::Pointer::updateCursor()
|
|
int bufferScale = mCursor.themeBufferScale;
|
|
QPoint hotspot = QPoint(image->hotspot_x, image->hotspot_y) / bufferScale;
|
|
QSize size = QSize(image->width, image->height) / bufferScale;
|
|
- bool animated = waylandCursor->image_count > 1 && image->delay > 0;
|
|
+ bool animated = duration > 0;
|
|
+ if (animated) {
|
|
+ mCursor.gotFrameCallback = false;
|
|
+ mCursor.gotTimerCallback = false;
|
|
+ mCursor.frameTimer.start(duration);
|
|
+ }
|
|
getOrCreateCursorSurface()->update(buffer, hotspot, size, bufferScale, animated);
|
|
return;
|
|
}
|
|
@@ -354,6 +366,22 @@ CursorSurface *QWaylandInputDevice::Pointer::getOrCreateCursorSurface()
|
|
return mCursor.surface.get();
|
|
}
|
|
|
|
+void QWaylandInputDevice::Pointer::cursorTimerCallback()
|
|
+{
|
|
+ mCursor.gotTimerCallback = true;
|
|
+ if (mCursor.gotFrameCallback) {
|
|
+ updateCursor();
|
|
+ }
|
|
+}
|
|
+
|
|
+void QWaylandInputDevice::Pointer::cursorFrameCallback()
|
|
+{
|
|
+ mCursor.gotFrameCallback = true;
|
|
+ if (mCursor.gotTimerCallback) {
|
|
+ updateCursor();
|
|
+ }
|
|
+}
|
|
+
|
|
#endif // QT_CONFIG(cursor)
|
|
|
|
QWaylandInputDevice::Touch::Touch(QWaylandInputDevice *p)
|
|
diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h
|
|
index 60d6f2c1..a567c57b 100644
|
|
--- a/src/client/qwaylandinputdevice_p.h
|
|
+++ b/src/client/qwaylandinputdevice_p.h
|
|
@@ -286,6 +286,8 @@ public:
|
|
int idealCursorScale() const;
|
|
void updateCursorTheme();
|
|
void updateCursor();
|
|
+ void cursorTimerCallback();
|
|
+ void cursorFrameCallback();
|
|
CursorSurface *getOrCreateCursorSurface();
|
|
#endif
|
|
QWaylandInputDevice *seat() const { return mParent; }
|
|
@@ -325,6 +327,9 @@ public:
|
|
QWaylandCursorTheme *theme = nullptr;
|
|
int themeBufferScale = 0;
|
|
QScopedPointer<CursorSurface> surface;
|
|
+ QTimer frameTimer;
|
|
+ bool gotFrameCallback = false;
|
|
+ bool gotTimerCallback = false;
|
|
} mCursor;
|
|
#endif
|
|
QPointF mSurfacePos;
|
|
--
|
|
cgit v1.2.1
|
|
|