diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2018-10-30 03:03:23 +0100 |
---|---|---|
committer | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2018-10-30 03:03:23 +0100 |
commit | 3bd008ae85a51cbcfec1e6710271f117a44b3f92 (patch) | |
tree | f063445d9a69eb349d9dd57e3455308751a2efeb | |
parent | add794a5b732608dcd5d99a433f4a61d20838482 (diff) | |
parent | 52876056ff3dcda97f93932bc8c6e1c0fbce9d5e (diff) |
Merge remote-tracking branch 'origin/5.12' into dev
Change-Id: I1d9281750b06f7584e55759994dc6fcbcc5b2455
-rw-r--r-- | src/client/qwaylandshmbackingstore.cpp | 3 | ||||
-rw-r--r-- | src/client/qwaylandwindow.cpp | 27 | ||||
-rw-r--r-- | src/client/qwaylandwindow_p.h | 5 | ||||
-rw-r--r-- | src/compositor/compositor_api/qwaylandquickitem.cpp | 12 | ||||
-rw-r--r-- | src/compositor/compositor_api/qwaylandquickitem.h | 1 | ||||
-rw-r--r-- | src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp | 2 | ||||
-rw-r--r-- | src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp | 19 | ||||
-rw-r--r-- | src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6_p.h | 2 | ||||
-rw-r--r-- | src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp | 19 | ||||
-rw-r--r-- | src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h | 2 | ||||
-rw-r--r-- | tests/auto/client/shared/mocksurface.cpp | 12 | ||||
-rw-r--r-- | tests/auto/client/shared/mocksurface.h | 7 | ||||
-rw-r--r-- | tests/auto/client/shared/mockxdgshellv6.cpp | 14 | ||||
-rw-r--r-- | tests/auto/client/shared/mockxdgshellv6.h | 6 | ||||
-rw-r--r-- | tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp | 58 |
15 files changed, 167 insertions, 22 deletions
diff --git a/src/client/qwaylandshmbackingstore.cpp b/src/client/qwaylandshmbackingstore.cpp index 8cc9598fa..34044ec9b 100644 --- a/src/client/qwaylandshmbackingstore.cpp +++ b/src/client/qwaylandshmbackingstore.cpp @@ -233,8 +233,7 @@ void QWaylandShmBackingStore::flush(QWindow *window, const QRegion ®ion, cons mFrontBuffer = mBackBuffer; QMargins margins = windowDecorationMargins(); - - waylandWindow()->commit(mFrontBuffer, region.translated(margins.left(), margins.top())); + waylandWindow()->safeCommit(mFrontBuffer, region.translated(margins.left(), margins.top())); } void QWaylandShmBackingStore::resize(const QSize &size, const QRegion &) diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp index 79646308d..8e8726f02 100644 --- a/src/client/qwaylandwindow.cpp +++ b/src/client/qwaylandwindow.cpp @@ -246,6 +246,7 @@ void QWaylandWindow::reset(bool sendDestroyEvent) } mMask = QRegion(); + mQueuedBuffer = nullptr; } QWaylandWindow *QWaylandWindow::fromWlSurface(::wl_surface *surface) @@ -335,7 +336,9 @@ void QWaylandWindow::setGeometry(const QRect &rect) mSentInitialResize = true; } - sendExposeEvent(QRect(QPoint(), geometry().size())); + QRect exposeGeometry(QPoint(), geometry().size()); + if (exposeGeometry != mLastExposeGeometry) + sendExposeEvent(exposeGeometry); } void QWaylandWindow::resizeFromApplyConfigure(const QSize &sizeWithMargins, const QPoint &offset) @@ -353,6 +356,7 @@ void QWaylandWindow::sendExposeEvent(const QRect &rect) { if (!(mShellSurface && mShellSurface->handleExpose(rect))) QWindowSystemInterface::handleExposeEvent(window(), rect); + mLastExposeGeometry = rect; } @@ -564,8 +568,29 @@ void QWaylandWindow::damage(const QRect &rect) damage(rect.x(), rect.y(), rect.width(), rect.height()); } +void QWaylandWindow::safeCommit(QWaylandBuffer *buffer, const QRegion &damage) +{ + if (isExposed()) { + commit(buffer, damage); + } else { + mQueuedBuffer = buffer; + mQueuedBufferDamage = damage; + } +} + +void QWaylandWindow::handleExpose(const QRegion ®ion) +{ + QWindowSystemInterface::handleExposeEvent(window(), region); + if (mQueuedBuffer) { + commit(mQueuedBuffer, mQueuedBufferDamage); + mQueuedBuffer = nullptr; + mQueuedBufferDamage = QRegion(); + } +} + void QWaylandWindow::commit(QWaylandBuffer *buffer, const QRegion &damage) { + Q_ASSERT(isExposed()); if (buffer->committed()) { qCDebug(lcWaylandBackingstore) << "Buffer already committed, ignoring."; return; diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h index d11ed871b..56ebd3cc6 100644 --- a/src/client/qwaylandwindow_p.h +++ b/src/client/qwaylandwindow_p.h @@ -116,6 +116,8 @@ public: using QtWayland::wl_surface::damage; void damage(const QRect &rect); + void safeCommit(QWaylandBuffer *buffer, const QRegion &damage); + void handleExpose(const QRegion ®ion); void commit(QWaylandBuffer *buffer, const QRegion &damage); void waitForFrameSync(); @@ -231,6 +233,8 @@ protected: Qt::WindowStates mLastReportedWindowStates = Qt::WindowNoState; QWaylandShmBackingStore *mBackingStore = nullptr; + QWaylandBuffer *mQueuedBuffer = nullptr; + QRegion mQueuedBufferDamage; private slots: void handleScreenRemoved(QScreen *qScreen); @@ -250,6 +254,7 @@ private: void handleScreenChanged(); bool mUpdateRequested = false; + QRect mLastExposeGeometry; static const wl_callback_listener callbackListener; static void frameCallback(void *data, struct wl_callback *wl_callback, uint32_t time); diff --git a/src/compositor/compositor_api/qwaylandquickitem.cpp b/src/compositor/compositor_api/qwaylandquickitem.cpp index 19c0656c7..6be5701ff 100644 --- a/src/compositor/compositor_api/qwaylandquickitem.cpp +++ b/src/compositor/compositor_api/qwaylandquickitem.cpp @@ -1036,13 +1036,23 @@ void QWaylandQuickItem::setFocusOnClick(bool focus) * Returns \c true if the input region of this item's surface contains the * position given by \a localPosition. */ -bool QWaylandQuickItem::inputRegionContains(const QPointF &localPosition) +bool QWaylandQuickItem::inputRegionContains(const QPointF &localPosition) const { if (QWaylandSurface *s = surface()) return s->inputRegionContains(mapToSurface(localPosition).toPoint()); return false; } +// Qt 6: Remove the non-const version +/*! + * Returns \c true if the input region of this item's surface contains the + * position given by \a localPosition. + */ +bool QWaylandQuickItem::inputRegionContains(const QPointF &localPosition) +{ + return const_cast<const QWaylandQuickItem *>(this)->inputRegionContains(localPosition); +} + /*! * Maps the given \a point in this item's coordinate system to the equivalent * point within the Wayland surface's coordinate system, and returns the mapped diff --git a/src/compositor/compositor_api/qwaylandquickitem.h b/src/compositor/compositor_api/qwaylandquickitem.h index 6c47be643..6f47c29a4 100644 --- a/src/compositor/compositor_api/qwaylandquickitem.h +++ b/src/compositor/compositor_api/qwaylandquickitem.h @@ -99,6 +99,7 @@ public: bool focusOnClick() const; void setFocusOnClick(bool focus); + bool inputRegionContains(const QPointF &localPosition) const; bool inputRegionContains(const QPointF &localPosition); Q_INVOKABLE QPointF mapToSurface(const QPointF &point) const; Q_INVOKABLE QPointF mapFromSurface(const QPointF &point) const; diff --git a/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp b/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp index ccab131d8..4506c312a 100644 --- a/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp +++ b/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp @@ -179,7 +179,7 @@ void QWaylandWlShellSurface::requestWindowStates(Qt::WindowStates states) m_window->applyConfigureWhenPossible(); } - bool isNormal = ~states & (Qt::WindowMaximized | Qt::WindowFullScreen); + bool isNormal = !(states & Qt::WindowMaximized) && !(states & Qt::WindowFullScreen); if (isNormal && (changedStates & (Qt::WindowMaximized | Qt::WindowFullScreen))) { setTopLevel(); // set normal window // There's usually no configure event after this, so just clear the rest of the pending diff --git a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp index 474a2a3ea..05c86e733 100644 --- a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp +++ b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp @@ -261,9 +261,14 @@ void QWaylandXdgSurfaceV6::setAppId(const QString &appId) m_toplevel->set_app_id(appId); } +bool QWaylandXdgSurfaceV6::isExposed() const +{ + return m_configured || m_pendingConfigureSerial; +} + bool QWaylandXdgSurfaceV6::handleExpose(const QRegion ®ion) { - if (!m_configured && !region.isEmpty()) { + if (!isExposed() && !region.isEmpty()) { m_exposeRegion = region; return true; } @@ -336,10 +341,18 @@ void QWaylandXdgSurfaceV6::setPopup(QWaylandWindow *parent, QWaylandInputDevice void QWaylandXdgSurfaceV6::zxdg_surface_v6_configure(uint32_t serial) { - m_window->applyConfigureWhenPossible(); m_pendingConfigureSerial = serial; + if (!m_configured) { + // We have to do the initial applyConfigure() immediately, since that is the expose. + applyConfigure(); + } else { + // Later configures are probably resizes, so we have to queue them up for a time when we + // are not painting to the window. + m_window->applyConfigureWhenPossible(); + } + if (!m_exposeRegion.isEmpty()) { - QWindowSystemInterface::handleExposeEvent(m_window->window(), m_exposeRegion); + m_window->handleExpose(m_exposeRegion); m_exposeRegion = QRegion(); } } diff --git a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6_p.h b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6_p.h index c88d111d2..d1dacd560 100644 --- a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6_p.h +++ b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6_p.h @@ -82,7 +82,7 @@ public: void setTitle(const QString &title) override; void setAppId(const QString &appId) override; - bool isExposed() const override { return m_configured; } + bool isExposed() const override; bool handleExpose(const QRegion &) override; bool handlesActiveState() const { return m_toplevel; } void applyConfigure() override; diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp index 78b1de311..9ecd4e624 100644 --- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp +++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp @@ -295,9 +295,14 @@ void QWaylandXdgSurface::setWindowFlags(Qt::WindowFlags flags) m_toplevel->requestWindowFlags(flags); } +bool QWaylandXdgSurface::isExposed() const +{ + return m_configured || m_pendingConfigureSerial; +} + bool QWaylandXdgSurface::handleExpose(const QRegion ®ion) { - if (!m_configured && !region.isEmpty()) { + if (!isExposed() && !region.isEmpty()) { m_exposeRegion = region; return true; } @@ -370,10 +375,18 @@ void QWaylandXdgSurface::setPopup(QWaylandWindow *parent, QWaylandInputDevice *d void QWaylandXdgSurface::xdg_surface_configure(uint32_t serial) { - m_window->applyConfigureWhenPossible(); m_pendingConfigureSerial = serial; + if (!m_configured) { + // We have to do the initial applyConfigure() immediately, since that is the expose. + applyConfigure(); + } else { + // Later configures are probably resizes, so we have to queue them up for a time when we + // are not painting to the window. + m_window->applyConfigureWhenPossible(); + } + if (!m_exposeRegion.isEmpty()) { - QWindowSystemInterface::handleExposeEvent(m_window->window(), m_exposeRegion); + m_window->handleExpose(m_exposeRegion); m_exposeRegion = QRegion(); } } diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h index 77d6ec828..902dfaa21 100644 --- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h +++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h @@ -86,7 +86,7 @@ public: void setAppId(const QString &appId) override; void setWindowFlags(Qt::WindowFlags flags) override; - bool isExposed() const override { return m_configured; } + bool isExposed() const override; bool handleExpose(const QRegion &) override; bool handlesActiveState() const { return m_toplevel; } void applyConfigure() override; diff --git a/tests/auto/client/shared/mocksurface.cpp b/tests/auto/client/shared/mocksurface.cpp index c0d51618c..84dcda6b0 100644 --- a/tests/auto/client/shared/mocksurface.cpp +++ b/tests/auto/client/shared/mocksurface.cpp @@ -74,7 +74,7 @@ void Compositor::sendShellSurfaceConfigure(void *data, const QList<QVariant> &pa auto statesBytes = QByteArray::fromRawData(reinterpret_cast<const char *>(states.data()), states.size() * static_cast<int>(sizeof(uint))); toplevel->send_configure(size.width(), size.height(), statesBytes); - toplevel->xdgSurface()->send_configure(compositor->nextSerial()); + toplevel->xdgSurface()->sendConfigure(compositor->nextSerial()); } else if (auto wlShellSurface = surface->wlShellSurface()) { const uint edges = 0; wlShellSurface->send_configure(edges, size.width(), size.height()); @@ -123,13 +123,17 @@ void Surface::surface_destroy(Resource *resource) if (m_wlShellSurface) // on wl-shell the shell surface is automatically destroyed with the surface wl_resource_destroy(m_wlShellSurface->resource()->handle); Q_ASSERT(!m_wlShellSurface); - Q_ASSERT(!m_xdgToplevelV6); + Q_ASSERT(!m_xdgSurfaceV6); wl_resource_destroy(resource->handle); } -void Surface::surface_attach(Resource *resource, - struct wl_resource *buffer, int x, int y) +void Surface::surface_attach(Resource *resource, struct wl_resource *buffer, int x, int y) { + if (m_xdgSurfaceV6) { + // It's a protocol error to attach a buffer to an xdgSurface that's not configured + Q_ASSERT(xdgSurfaceV6()->configureSent()); + } + Q_UNUSED(resource); Q_UNUSED(x); Q_UNUSED(y); diff --git a/tests/auto/client/shared/mocksurface.h b/tests/auto/client/shared/mocksurface.h index 3b0f01fdb..949dc23dd 100644 --- a/tests/auto/client/shared/mocksurface.h +++ b/tests/auto/client/shared/mocksurface.h @@ -50,7 +50,8 @@ public: static Surface *fromResource(struct ::wl_resource *resource); void map(); bool isMapped() const; - XdgToplevelV6 *xdgToplevelV6() const { return m_xdgToplevelV6; } + XdgSurfaceV6 *xdgSurfaceV6() const { return m_xdgSurfaceV6; } + XdgToplevelV6 *xdgToplevelV6() const { return m_xdgSurfaceV6 ? m_xdgSurfaceV6->toplevel() : nullptr; } WlShellSurface *wlShellSurface() const { return m_wlShellSurface; } QSharedPointer<MockSurface> mockSurface() const { return m_mockSurface; } @@ -69,7 +70,7 @@ protected: void surface_commit(Resource *resource) override; private: wl_resource *m_buffer = nullptr; - XdgToplevelV6 *m_xdgToplevelV6 = nullptr; + XdgSurfaceV6 *m_xdgSurfaceV6 = nullptr; WlShellSurface *m_wlShellSurface = nullptr; Compositor *m_compositor = nullptr; @@ -77,7 +78,7 @@ private: QList<wl_resource *> m_frameCallbackList; bool m_mapped = false; - friend class XdgToplevelV6; + friend class XdgSurfaceV6; friend class WlShellSurface; }; diff --git a/tests/auto/client/shared/mockxdgshellv6.cpp b/tests/auto/client/shared/mockxdgshellv6.cpp index 5dc8da599..05eff74ad 100644 --- a/tests/auto/client/shared/mockxdgshellv6.cpp +++ b/tests/auto/client/shared/mockxdgshellv6.cpp @@ -49,6 +49,18 @@ XdgSurfaceV6::XdgSurfaceV6(XdgShellV6 *shell, Surface *surface, wl_client *clien , m_surface(surface) , m_shell(shell) { + m_surface->m_xdgSurfaceV6 = this; +} + +XdgSurfaceV6::~XdgSurfaceV6() +{ + m_surface->m_xdgSurfaceV6 = nullptr; +} + +void XdgSurfaceV6::sendConfigure(uint32_t serial) +{ + send_configure(serial); + m_configureSent = true; } void XdgSurfaceV6::zxdg_surface_v6_get_toplevel(QtWaylandServer::zxdg_surface_v6::Resource *resource, uint32_t id) @@ -78,7 +90,6 @@ XdgToplevelV6::XdgToplevelV6(XdgSurfaceV6 *xdgSurface, wl_client *client, uint32 , m_mockToplevel(new MockXdgToplevelV6(this)) { auto *surface = m_xdgSurface->surface(); - surface->m_xdgToplevelV6 = this; m_xdgSurface->shell()->addToplevel(this); surface->map(); } @@ -86,7 +97,6 @@ XdgToplevelV6::XdgToplevelV6(XdgSurfaceV6 *xdgSurface, wl_client *client, uint32 XdgToplevelV6::~XdgToplevelV6() { m_xdgSurface->shell()->removeToplevel(this); - m_xdgSurface->surface()->m_xdgToplevelV6 = nullptr; m_mockToplevel->m_toplevel = nullptr; } diff --git a/tests/auto/client/shared/mockxdgshellv6.h b/tests/auto/client/shared/mockxdgshellv6.h index bd5e13063..a238fa562 100644 --- a/tests/auto/client/shared/mockxdgshellv6.h +++ b/tests/auto/client/shared/mockxdgshellv6.h @@ -46,8 +46,13 @@ class XdgSurfaceV6 : public QtWaylandServer::zxdg_surface_v6 { public: XdgSurfaceV6(XdgShellV6 *shell, Surface *surface, wl_client *client, uint32_t id); + ~XdgSurfaceV6() override; XdgShellV6 *shell() const { return m_shell; } Surface *surface() const { return m_surface; } + XdgToplevelV6 *toplevel() const { return m_toplevel; } + + void sendConfigure(uint32_t serial); + bool configureSent() const { return m_configureSent; } protected: void zxdg_surface_v6_destroy_resource(Resource *) override { delete this; } @@ -59,6 +64,7 @@ private: Surface *m_surface = nullptr; XdgToplevelV6 *m_toplevel = nullptr; XdgShellV6 *m_shell = nullptr; + bool m_configureSent = false; friend class XdgToplevelV6; }; diff --git a/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp b/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp index 91679cb57..3c822325b 100644 --- a/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp +++ b/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp @@ -58,6 +58,14 @@ public: return QWindow::event(event); } + void exposeEvent(QExposeEvent *event) override + { + ++exposeEventCount; + QWindow::exposeEvent(event); + } + + int exposeEventCount = 0; + signals: void windowStateChangeEventReceived(uint oldState); }; @@ -101,6 +109,8 @@ private slots: void windowStateChangedEvents(); void windowGeometrySimple(); void windowGeometryFixed(); + void flushUnconfiguredXdgSurface(); + void dontSpamExposeEvents(); private: MockCompositor *m_compositor = nullptr; @@ -360,6 +370,54 @@ void tst_WaylandClientXdgShellV6::windowGeometryFixed() QCOMPARE(geometrySpy.takeFirst().at(0).toRect().size(), initialWindowGeometry.size()); } +void tst_WaylandClientXdgShellV6::flushUnconfiguredXdgSurface() +{ + TestWindow window; + window.show(); + + QSharedPointer<MockSurface> surface; + QTRY_VERIFY(surface = m_compositor->surface()); + + // Paint and flush some magenta + QBackingStore backingStore(&window); + QRect rect(QPoint(), window.size()); + backingStore.resize(rect.size()); + backingStore.beginPaint(rect); + QColor color = Qt::magenta; + QPainter p(backingStore.paintDevice()); + p.fillRect(rect, color); + p.end(); + backingStore.endPaint(); + backingStore.flush(rect); + + // We're not allowed to send buffer on this surface since it isn't yet configured. + // So, from the compositor's point of view there should be no buffer data yet. + m_compositor->processWaylandEvents(); + QVERIFY(surface->image.isNull()); + QVERIFY(!window.isExposed()); + + // Finally sending the configure should trigger an attach and commit with the + // right buffer. + m_compositor->sendShellSurfaceConfigure(surface); + QTRY_COMPARE(surface->image.size(), window.frameGeometry().size()); + QTRY_COMPARE(surface->image.pixel(window.frameMargins().left(), window.frameMargins().top()), color.rgba()); + QVERIFY(window.isExposed()); +} + +void tst_WaylandClientXdgShellV6::dontSpamExposeEvents() +{ + TestWindow window; + window.show(); + + QSharedPointer<MockSurface> surface; + QTRY_VERIFY(surface = m_compositor->surface()); + QTRY_VERIFY(window.exposeEventCount == 0); + + m_compositor->sendShellSurfaceConfigure(surface); + QTRY_VERIFY(window.isExposed()); + QTRY_VERIFY(window.exposeEventCount == 1); +} + int main(int argc, char **argv) { setenv("XDG_RUNTIME_DIR", ".", 1); |