From 17be1332cfd82f2e96c869f1773e8d8d296f03b3 Mon Sep 17 00:00:00 2001 From: David Edmundson Date: Thu, 15 Feb 2024 22:19:12 +0000 Subject: [PATCH] Port to asynchronous roundtrip When a resize is driven client side we wait for the compositor to have a chance to reconfigure us before submitting the next frame. Using a blocking round trip caused an issue. Instead block isExposed and trigger an expose event whilst a sync is in progress. --- src/qwaylandlayersurface.cpp | 52 +++++++++++++++++++++++++++++++----- src/qwaylandlayersurface_p.h | 9 ++++++- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/src/qwaylandlayersurface.cpp b/src/qwaylandlayersurface.cpp index 44cc382..d186df8 100644 --- a/src/qwaylandlayersurface.cpp +++ b/src/qwaylandlayersurface.cpp @@ -79,6 +79,9 @@ QWaylandLayerSurface::QWaylandLayerSurface(QWaylandLayerShellIntegration *shell, QWaylandLayerSurface::~QWaylandLayerSurface() { + if (m_waitForSyncCallback) { + wl_callback_destroy(m_waitForSyncCallback); + } destroy(); } @@ -97,11 +100,7 @@ void QWaylandLayerSurface::zwlr_layer_surface_v1_configure(uint32_t serial, uint if (!m_configured) { m_configured = true; window()->resizeFromApplyConfigure(m_pendingSize); -#if QT_VERSION < QT_VERSION_CHECK(6, 7, 0) - window()->handleExpose(QRect(QPoint(), m_pendingSize)); -#else - window()->sendRecursiveExposeEvent(); -#endif + sendExpose(); } else { // Later configures are resizes, so we have to queue them up for a time when we // are not painting to the window. @@ -161,6 +160,11 @@ void QWaylandLayerSurface::setLayer(uint32_t layer) void QWaylandLayerSurface::setWindowGeometry(const QRect &geometry) { + // if we are setting it to the last size we were configured at, we don't need to do anything + if (geometry.size() == m_pendingSize && !m_waitForSyncCallback) { + return; + } + const bool horizontallyConstrained = m_interface->anchors().testFlags({Window::AnchorLeft, Window::AnchorRight}); const bool verticallyConstrained = m_interface->anchors().testFlags({Window::AnchorTop, Window::AnchorBottom}); @@ -172,7 +176,7 @@ void QWaylandLayerSurface::setWindowGeometry(const QRect &geometry) size.setHeight(0); } set_size(size.width(), size.height()); - wl_display_roundtrip(m_window->display()->wl_display()); + requestWaylandSync(); } bool QWaylandLayerSurface::requestActivate() @@ -221,7 +225,43 @@ void QWaylandLayerSurface::requestXdgActivationToken(quint32 serial) Q_EMIT window()->xdgActivationTokenCreated(token); }); connect(tokenProvider, &QWaylandXdgActivationTokenV1::done, tokenProvider, &QObject::deleteLater); +} +const wl_callback_listener QWaylandLayerSurface::syncCallbackListener = { + .done = [](void *data, struct wl_callback *callback, uint32_t time){ + Q_UNUSED(time); + wl_callback_destroy(callback); + QWaylandLayerSurface *layerSurface = static_cast(data); + layerSurface->m_waitForSyncCallback = nullptr; + layerSurface->sendExpose(); + } +}; + +void QWaylandLayerSurface::requestWaylandSync() +{ + if (m_waitForSyncCallback) { + return; + } + + m_waitForSyncCallback = wl_display_sync(m_window->display()->wl_display()); + wl_callback_add_listener(m_waitForSyncCallback, &syncCallbackListener, this); +} + +void QWaylandLayerSurface::handleWaylandSyncDone() +{ + if (!window()->isExposed()) { + return; + } + sendExpose(); +} + +void QWaylandLayerSurface::sendExpose() +{ +#if QT_VERSION < QT_VERSION_CHECK(6, 7, 0) + window()->handleExpose(QRect(QPoint(), m_pendingSize)); +#else + window()->sendRecursiveExposeEvent(); +#endif } } diff --git a/src/qwaylandlayersurface_p.h b/src/qwaylandlayersurface_p.h index 65e8385..c4f7e12 100644 --- a/src/qwaylandlayersurface_p.h +++ b/src/qwaylandlayersurface_p.h @@ -30,7 +30,7 @@ public: bool isExposed() const override { - return m_configured; + return m_configured && !m_waitForSyncCallback; } void attachPopup(QtWaylandClient::QWaylandShellSurface *popup) override; @@ -49,6 +49,9 @@ public: void requestXdgActivationToken(quint32 serial) override; private: + void requestWaylandSync(); + void handleWaylandSyncDone(); + void sendExpose(); void zwlr_layer_surface_v1_configure(uint32_t serial, uint32_t width, uint32_t height) override; void zwlr_layer_surface_v1_closed() override; @@ -57,7 +60,11 @@ private: QtWaylandClient::QWaylandWindow *m_window; QSize m_pendingSize; QString m_activationToken; + bool m_configured = false; + + static const wl_callback_listener syncCallbackListener; + struct wl_callback *m_waitForSyncCallback = nullptr; }; }