diff options
-rw-r--r-- | .qmake.conf | 2 | ||||
-rw-r--r-- | dist/changes-5.13.2 | 67 | ||||
-rw-r--r-- | src/client/qwaylanddisplay.cpp | 4 | ||||
-rw-r--r-- | src/client/qwaylandinputdevice.cpp | 5 | ||||
-rw-r--r-- | src/client/qwaylandwindow.cpp | 53 | ||||
-rw-r--r-- | src/client/qwaylandwindow_p.h | 1 | ||||
-rw-r--r-- | src/compositor/compositor_api/qwaylandsurface.cpp | 3 | ||||
-rw-r--r-- | src/compositor/extensions/qwaylandwlshell.cpp | 3 | ||||
-rw-r--r-- | src/imports/compositor/WaylandCursorItem.qml | 2 | ||||
-rw-r--r-- | tests/auto/client/fullscreenshellv1/tst_fullscreenshellv1.cpp | 3 | ||||
-rw-r--r-- | tests/auto/client/iviapplication/tst_iviapplication.cpp | 3 | ||||
-rw-r--r-- | tests/auto/client/shared/corecompositor.cpp | 1 | ||||
-rw-r--r-- | tests/auto/client/shared/coreprotocol.h | 25 | ||||
-rw-r--r-- | tests/auto/client/shared/mockcompositor.cpp | 11 | ||||
-rw-r--r-- | tests/auto/client/shared/mockcompositor.h | 1 | ||||
-rw-r--r-- | tests/auto/client/shared/xdgshell.cpp | 2 | ||||
-rw-r--r-- | tests/auto/client/shared_old/mockcompositor.cpp | 2 | ||||
-rw-r--r-- | tests/auto/client/surface/tst_surface.cpp | 41 | ||||
-rw-r--r-- | tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp | 3 |
19 files changed, 173 insertions, 59 deletions
diff --git a/.qmake.conf b/.qmake.conf index 1ed62c5ac..543d0a842 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,3 +1,3 @@ load(qt_build_config) -MODULE_VERSION = 5.13.1 +MODULE_VERSION = 5.13.2 diff --git a/dist/changes-5.13.2 b/dist/changes-5.13.2 new file mode 100644 index 000000000..6248863e1 --- /dev/null +++ b/dist/changes-5.13.2 @@ -0,0 +1,67 @@ +Qt 5.13.2 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.13.0 through 5.13.1. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.13 series is binary compatible with the 5.12.x series. +Applications compiled for 5.12 will continue to run with 5.13. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Compositor * +**************************************************************************** + + - Fixed various rounding errors related to touch and mouse input. + - Fixed touch and click events on right and left surface borders not being + forwarded to clients. + - Fixed a crash when closing windows via XdgToplevel.sendClose(). + - [QTBUG-78969] Fixed a crash when trying to maximize an XdgToplevel with + no WaylandOutput assigned. + + - Important Behavior Changes: + * Between version 5.11 and 5.12 binary compatibility for the wayland + compositor module was broken by adding an additional member to various + classes. This was not apparent from user code as the member was behind + an #ifdef which would only be set while compiling Qt. As several + versions of Qt incompatible to 5.11 have already been released now, + rolling back the incompatible change would introduce further + incompatibility. Therefore, the change is made consistent by + unconditionally adding the member to the headers. + +**************************************************************************** +* QPA plugin * +**************************************************************************** + + - Fixed a bug where key repeat would not be disabled when configured by the + compositor. + - Fixed a freeze that happened when starting a drag-and-drop operation + without a valid source surface. + - Fixed a bug where some windows would never become visible. + - Fixed a bug where clipboard contents would be truncated for large pastes. + - [QTBUG-76504] Fixed a crash that could happen if createPlatformWindow and + createPlatformOpenGLContext were called on the GUI and render thread + simultaneously. + - Fixed a crash that could happen when destroying a window. + - Qt now handles libwayland errors by calling qFatal() instead of exit(1). + This allows applications to clean up. + - Fixed a bug where touch focus would be cleared on any touch point + release, also during multi-touch sequences. + - [QTBUG-77987] Fixed a bug where the cursor rectangle for virtual keyboard + was incorrectly positioned. + - Fixed a freeze that could happen if doing recursive waiting for + compositor frame callbacks. + - Fixed touch rounding errors. Clients now receive fractional instead of + integer positions. + - [QTBUG-78478] Fixed a crash that could happen if setting absurdly long + window titles with UTF-16 code units that convert to multiple bytes in + UTF-8. diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp index 78524f6fc..27e38ccf7 100644 --- a/src/client/qwaylanddisplay.cpp +++ b/src/client/qwaylanddisplay.cpp @@ -109,6 +109,10 @@ struct ::wl_region *QWaylandDisplay::createRegion(const QRegion &qregion) return nullptr; } + // Make sure we don't pass NULL surfaces to libwayland (crashes) + Q_ASSERT(parent->object()); + Q_ASSERT(window->object()); + return mSubCompositor->get_subsurface(window->object(), parent->object()); } diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp index 8f3df8e4d..193ce714b 100644 --- a/src/client/qwaylandinputdevice.cpp +++ b/src/client/qwaylandinputdevice.cpp @@ -1062,7 +1062,10 @@ void QWaylandInputDevice::handleTouchPoint(int id, Qt::TouchPointState state, co tp.area.moveCenter(globalPosition); } - tp.state = state; + // If the touch point was pressed earlier this frame, we don't want to overwrite its state. + if (tp.state != Qt::TouchPointPressed) + tp.state = state; + tp.pressure = tp.state == Qt::TouchPointReleased ? 0 : 1; } diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp index ae26ba049..7098568b4 100644 --- a/src/client/qwaylandwindow.cpp +++ b/src/client/qwaylandwindow.cpp @@ -124,9 +124,10 @@ void QWaylandWindow::initWindow() if (shouldCreateSubSurface()) { Q_ASSERT(!mSubSurfaceWindow); - QWaylandWindow *p = static_cast<QWaylandWindow *>(QPlatformWindow::parent()); - if (::wl_subsurface *ss = mDisplay->createSubSurface(this, p)) { - mSubSurfaceWindow = new QWaylandSubSurface(this, p, ss); + auto *parent = static_cast<QWaylandWindow *>(QPlatformWindow::parent()); + if (parent->object()) { + if (::wl_subsurface *subsurface = mDisplay->createSubSurface(this, parent)) + mSubSurfaceWindow = new QWaylandSubSurface(this, parent, subsurface); } } else if (shouldCreateShellSurface()) { Q_ASSERT(!mShellSurface); @@ -1105,25 +1106,6 @@ QVariant QWaylandWindow::property(const QString &name, const QVariant &defaultVa void QWaylandWindow::timerEvent(QTimerEvent *event) { - if (event->timerId() == mFallbackUpdateTimerId) { - killTimer(mFallbackUpdateTimerId); - mFallbackUpdateTimerId = -1; - qCDebug(lcWaylandBackingstore) << "mFallbackUpdateTimer timed out"; - - if (!isExposed()) { - qCDebug(lcWaylandBackingstore) << "Fallback update timer: Window not exposed," - << "not delivering update request."; - return; - } - - if (mWaitingForUpdate && hasPendingUpdateRequest() && !mWaitingForFrameCallback) { - qCWarning(lcWaylandBackingstore) << "Delivering update request through fallback timer," - << "may not be in sync with display"; - deliverUpdateRequest(); - } - } - - if (mFrameCallbackTimerId.testAndSetOrdered(event->timerId(), -1)) { killTimer(event->timerId()); qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed"; @@ -1135,6 +1117,7 @@ void QWaylandWindow::timerEvent(QTimerEvent *event) void QWaylandWindow::requestUpdate() { + qCDebug(lcWaylandBackingstore) << "requestUpdate"; Q_ASSERT(hasPendingUpdateRequest()); // should be set by QPA // If we have a frame callback all is good and will be taken care of there @@ -1142,20 +1125,17 @@ void QWaylandWindow::requestUpdate() return; // If we've already called deliverUpdateRequest(), but haven't seen any attach+commit/swap yet - if (mWaitingForUpdate) { - // Ideally, we should just have returned here, but we're not guaranteed that the client - // will actually update, so start this timer to deliver another request update after a while - // *IF* the client doesn't update. - int fallbackTimeout = 100; - mFallbackUpdateTimerId = startTimer(fallbackTimeout); - return; - } + // This is a somewhat redundant behavior and might indicate a bug in the calling code, so log + // here so we can get this information when debugging update/frame callback issues. + // Continue as nothing happened, though. + if (mWaitingForUpdate) + qCDebug(lcWaylandBackingstore) << "requestUpdate called twice without committing anything"; // Some applications (such as Qt Quick) depend on updates being delivered asynchronously, // so use invokeMethod to delay the delivery a bit. QMetaObject::invokeMethod(this, [this] { // Things might have changed in the meantime - if (hasPendingUpdateRequest() && !mWaitingForUpdate && !mWaitingForFrameCallback) + if (hasPendingUpdateRequest() && !mWaitingForFrameCallback) deliverUpdateRequest(); }, Qt::QueuedConnection); } @@ -1165,6 +1145,7 @@ void QWaylandWindow::requestUpdate() // Can be called from the render thread (without locking anything) so make sure to not make races in this method. void QWaylandWindow::handleUpdate() { + qCDebug(lcWaylandBackingstore) << "handleUpdate" << QThread::currentThread(); // TODO: Should sync subsurfaces avoid requesting frame callbacks? QReadLocker lock(&mSurfaceLock); if (!isInitialized()) @@ -1175,15 +1156,6 @@ void QWaylandWindow::handleUpdate() mFrameCallback = nullptr; } - if (mFallbackUpdateTimerId != -1) { - // Ideally, we would stop the fallback timer here, but since we're on another thread, - // it's not allowed. Instead we set mFallbackUpdateTimer to -1 here, so we'll just - // ignore it if it times out before it's cleaned up by the invokeMethod call. - int id = mFallbackUpdateTimerId; - mFallbackUpdateTimerId = -1; - QMetaObject::invokeMethod(this, [this, id] { killTimer(id); }, Qt::QueuedConnection); - } - mFrameCallback = frame(); wl_callback_add_listener(mFrameCallback, &QWaylandWindow::callbackListener, this); mWaitingForFrameCallback = true; @@ -1203,6 +1175,7 @@ void QWaylandWindow::handleUpdate() void QWaylandWindow::deliverUpdateRequest() { + qCDebug(lcWaylandBackingstore) << "deliverUpdateRequest"; mWaitingForUpdate = true; QPlatformWindow::deliverUpdateRequest(); } diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h index b03d92e56..e4a1124e7 100644 --- a/src/client/qwaylandwindow_p.h +++ b/src/client/qwaylandwindow_p.h @@ -232,7 +232,6 @@ protected: // True when we have called deliverRequestUpdate, but the client has not yet attached a new buffer bool mWaitingForUpdate = false; - int mFallbackUpdateTimerId = -1; // Started when waiting for app to commit QMutex mResizeLock; bool mWaitingToApplyConfigure = false; diff --git a/src/compositor/compositor_api/qwaylandsurface.cpp b/src/compositor/compositor_api/qwaylandsurface.cpp index a82c93f7b..8c866351f 100644 --- a/src/compositor/compositor_api/qwaylandsurface.cpp +++ b/src/compositor/compositor_api/qwaylandsurface.cpp @@ -391,7 +391,8 @@ QWaylandSurface::QWaylandSurface(QWaylandSurfacePrivate &dptr) QWaylandSurface::~QWaylandSurface() { Q_D(QWaylandSurface); - QWaylandCompositorPrivate::get(d->compositor)->unregisterSurface(this); + if (d->compositor) + QWaylandCompositorPrivate::get(d->compositor)->unregisterSurface(this); d->notifyViewsAboutDestruction(); } diff --git a/src/compositor/extensions/qwaylandwlshell.cpp b/src/compositor/extensions/qwaylandwlshell.cpp index 66aeb64ba..924234887 100644 --- a/src/compositor/extensions/qwaylandwlshell.cpp +++ b/src/compositor/extensions/qwaylandwlshell.cpp @@ -466,7 +466,8 @@ QWaylandWlShellSurface::QWaylandWlShellSurface(QWaylandWlShell *shell, QWaylandS QWaylandWlShellSurface::~QWaylandWlShellSurface() { Q_D(QWaylandWlShellSurface); - QWaylandWlShellPrivate::get(d->m_shell)->unregisterShellSurface(this); + if (d->m_shell) + QWaylandWlShellPrivate::get(d->m_shell)->unregisterShellSurface(this); } /*! diff --git a/src/imports/compositor/WaylandCursorItem.qml b/src/imports/compositor/WaylandCursorItem.qml index 1fa099676..e50c82d56 100644 --- a/src/imports/compositor/WaylandCursorItem.qml +++ b/src/imports/compositor/WaylandCursorItem.qml @@ -73,7 +73,7 @@ WaylandQuickItem { x: cursorItem.hotspotX + offset.x y: cursorItem.hotspotY + offset.y z: -1 - surface: cursorItem.seat.drag.icon + surface: cursorItem.seat ? cursorItem.seat.drag.icon : null Connections { target: dragIcon.surface diff --git a/tests/auto/client/fullscreenshellv1/tst_fullscreenshellv1.cpp b/tests/auto/client/fullscreenshellv1/tst_fullscreenshellv1.cpp index f93d9fbc5..55158474c 100644 --- a/tests/auto/client/fullscreenshellv1/tst_fullscreenshellv1.cpp +++ b/tests/auto/client/fullscreenshellv1/tst_fullscreenshellv1.cpp @@ -93,7 +93,8 @@ void tst_WaylandClientFullScreenShellV1::createDestroyWindow() int main(int argc, char **argv) { - setenv("XDG_RUNTIME_DIR", ".", 1); + QTemporaryDir tmpRuntimeDir; + setenv("XDG_RUNTIME_DIR", tmpRuntimeDir.path().toLocal8Bit(), 1); setenv("QT_QPA_PLATFORM", "wayland", 1); // force QGuiApplication to use wayland plugin setenv("QT_WAYLAND_SHELL_INTEGRATION", "fullscreen-shell-v1", 1); setenv("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1", 1); // window decorations don't make much sense here diff --git a/tests/auto/client/iviapplication/tst_iviapplication.cpp b/tests/auto/client/iviapplication/tst_iviapplication.cpp index 59ff6f555..8d6ea6484 100644 --- a/tests/auto/client/iviapplication/tst_iviapplication.cpp +++ b/tests/auto/client/iviapplication/tst_iviapplication.cpp @@ -124,7 +124,8 @@ void tst_WaylandClientIviApplication::uniqueIviIds() int main(int argc, char **argv) { - setenv("XDG_RUNTIME_DIR", ".", 1); + QTemporaryDir tmpRuntimeDir; + setenv("XDG_RUNTIME_DIR", tmpRuntimeDir.path().toLocal8Bit(), 1); setenv("QT_QPA_PLATFORM", "wayland", 1); // force QGuiApplication to use wayland plugin setenv("QT_WAYLAND_SHELL_INTEGRATION", "ivi-shell", 1); setenv("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1", 1); // window decorations don't make much sense on ivi-application diff --git a/tests/auto/client/shared/corecompositor.cpp b/tests/auto/client/shared/corecompositor.cpp index 7edb1c2d4..5c6c83baa 100644 --- a/tests/auto/client/shared/corecompositor.cpp +++ b/tests/auto/client/shared/corecompositor.cpp @@ -43,6 +43,7 @@ CoreCompositor::CoreCompositor() } }) { + qputenv("WAYLAND_DISPLAY", m_socketName); m_timer.start(); Q_ASSERT(isClean()); } diff --git a/tests/auto/client/shared/coreprotocol.h b/tests/auto/client/shared/coreprotocol.h index 5cef476c8..f92842e02 100644 --- a/tests/auto/client/shared/coreprotocol.h +++ b/tests/auto/client/shared/coreprotocol.h @@ -163,6 +163,16 @@ protected: } }; +class Subsurface : public QObject, public QtWaylandServer::wl_subsurface +{ + Q_OBJECT +public: + explicit Subsurface(wl_client *client, int id, int version) + : QtWaylandServer::wl_subsurface(client, id, version) + { + } +}; + class SubCompositor : public Global, public QtWaylandServer::wl_subcompositor { Q_OBJECT @@ -170,7 +180,20 @@ public: explicit SubCompositor(CoreCompositor *compositor, int version = 1) : QtWaylandServer::wl_subcompositor(compositor->m_display, version) {} - // TODO + QVector<Subsurface *> m_subsurfaces; + +signals: + void subsurfaceCreated(Subsurface *subsurface); + +protected: + void subcompositor_get_subsurface(Resource *resource, uint32_t id, ::wl_resource *surface, ::wl_resource *parent) override + { + QTRY_VERIFY(parent); + QTRY_VERIFY(surface); + auto *subsurface = new Subsurface(resource->client(), id, resource->version()); + m_subsurfaces.append(subsurface); // TODO: clean up? + emit subsurfaceCreated(subsurface); + } }; struct OutputMode { diff --git a/tests/auto/client/shared/mockcompositor.cpp b/tests/auto/client/shared/mockcompositor.cpp index 6b9af4295..0711c5d8e 100644 --- a/tests/auto/client/shared/mockcompositor.cpp +++ b/tests/auto/client/shared/mockcompositor.cpp @@ -58,13 +58,10 @@ DefaultCompositor::DefaultCompositor() }); }); - QObject::connect(get<XdgWmBase>(), &XdgWmBase::toplevelCreated, [&] (XdgToplevel *toplevel) { - // Needed because lambdas don't support Qt::DirectConnection - exec([&]{ - if (m_config.autoConfigure) - toplevel->sendCompleteConfigure(); - }); - }); + QObject::connect(get<XdgWmBase>(), &XdgWmBase::toplevelCreated, get<XdgWmBase>(), [&] (XdgToplevel *toplevel) { + if (m_config.autoConfigure) + toplevel->sendCompleteConfigure(); + }, Qt::DirectConnection); } Q_ASSERT(isClean()); } diff --git a/tests/auto/client/shared/mockcompositor.h b/tests/auto/client/shared/mockcompositor.h index f5264ccf6..f17c93426 100644 --- a/tests/auto/client/shared/mockcompositor.h +++ b/tests/auto/client/shared/mockcompositor.h @@ -50,6 +50,7 @@ public: // Convenience functions Output *output(int i = 0) { return getAll<Output>().value(i, nullptr); } Surface *surface(int i = 0) { return get<WlCompositor>()->m_surfaces.value(i, nullptr); } + Subsurface *subSurface(int i = 0) { return get<SubCompositor>()->m_subsurfaces.value(i, nullptr); } XdgSurface *xdgSurface(int i = 0) { return get<XdgWmBase>()->m_xdgSurfaces.value(i, nullptr); } XdgToplevel *xdgToplevel(int i = 0) { return get<XdgWmBase>()->toplevel(i); } XdgPopup *xdgPopup(int i = 0) { return get<XdgWmBase>()->popup(i); } diff --git a/tests/auto/client/shared/xdgshell.cpp b/tests/auto/client/shared/xdgshell.cpp index 13acc01e2..72582f48d 100644 --- a/tests/auto/client/shared/xdgshell.cpp +++ b/tests/auto/client/shared/xdgshell.cpp @@ -83,7 +83,7 @@ XdgSurface::XdgSurface(XdgWmBase *xdgWmBase, Surface *surface, wl_client *client { QVERIFY(!surface->m_pending.buffer); QVERIFY(!surface->m_committed.buffer); - connect(this, &XdgSurface::toplevelCreated, xdgWmBase, &XdgWmBase::toplevelCreated); + connect(this, &XdgSurface::toplevelCreated, xdgWmBase, &XdgWmBase::toplevelCreated, Qt::DirectConnection); connect(surface, &Surface::attach, this, &XdgSurface::verifyConfigured); connect(surface, &Surface::commit, this, [this] { m_committed = m_pending; diff --git a/tests/auto/client/shared_old/mockcompositor.cpp b/tests/auto/client/shared_old/mockcompositor.cpp index 0dfaef5ea..96dc059e7 100644 --- a/tests/auto/client/shared_old/mockcompositor.cpp +++ b/tests/auto/client/shared_old/mockcompositor.cpp @@ -312,9 +312,9 @@ void *MockCompositor::run(void *data) Impl::Compositor compositor(controller); controller->m_compositor = &compositor; - controller->m_waitCondition.wakeOne(); while (!controller->m_ready) { + controller->m_waitCondition.wakeOne(); controller->dispatchCommands(); compositor.dispatchEvents(20); } diff --git a/tests/auto/client/surface/tst_surface.cpp b/tests/auto/client/surface/tst_surface.cpp index dddff0866..f9dcec581 100644 --- a/tests/auto/client/surface/tst_surface.cpp +++ b/tests/auto/client/surface/tst_surface.cpp @@ -41,6 +41,10 @@ private slots: void waitForFrameCallbackRaster(); void waitForFrameCallbackGl(); void negotiateShmFormat(); + + // Subsurfaces + void createSubsurface(); + void createSubsurfaceForHiddenParent(); }; void tst_surface::createDestroySurface() @@ -154,5 +158,42 @@ void tst_surface::negotiateShmFormat() }); } +void tst_surface::createSubsurface() +{ + QRasterWindow window; + window.resize(64, 64); + window.show(); + QCOMPOSITOR_TRY_VERIFY(xdgToplevel()); + exec([=] { xdgToplevel()->sendCompleteConfigure(); }); + QCOMPOSITOR_TRY_VERIFY(xdgSurface()->m_committedConfigureSerial); + + QRasterWindow subWindow; + subWindow.setParent(&window); + subWindow.resize(64, 64); + subWindow.show(); + QCOMPOSITOR_TRY_VERIFY(subSurface()); +} + +// Used to cause a crash in libwayland (QTBUG-79674) +void tst_surface::createSubsurfaceForHiddenParent() +{ + QRasterWindow window; + window.resize(64, 64); + window.show(); + QCOMPOSITOR_TRY_VERIFY(xdgToplevel()); + exec([=] { xdgToplevel()->sendCompleteConfigure(); }); + QCOMPOSITOR_TRY_VERIFY(xdgSurface()->m_committedConfigureSerial); + + window.hide(); + + QRasterWindow subWindow; + subWindow.setParent(&window); + subWindow.resize(64, 64); + subWindow.show(); + + // Make sure the client doesn't quit before it has a chance to crash + xdgPingAndWaitForPong(); +} + QCOMPOSITOR_TEST_MAIN(tst_surface) #include "tst_surface.moc" diff --git a/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp b/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp index a397f60eb..9885ee2bc 100644 --- a/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp +++ b/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp @@ -422,7 +422,8 @@ void tst_WaylandClientXdgShellV6::dontSpamExposeEvents() int main(int argc, char **argv) { - setenv("XDG_RUNTIME_DIR", ".", 1); + QTemporaryDir tmpRuntimeDir; + setenv("XDG_RUNTIME_DIR", tmpRuntimeDir.path().toLocal8Bit(), 1); setenv("QT_QPA_PLATFORM", "wayland", 1); // force QGuiApplication to use wayland plugin setenv("QT_WAYLAND_SHELL_INTEGRATION", "xdg-shell-v6", 1); |