From 5d43a686fc3d5f13087a61e8ef216ecbbae0d15e Mon Sep 17 00:00:00 2001 From: David Edmundson Date: Sun, 23 Jun 2019 14:48:30 +0200 Subject: Client: Make handleUpdate aware of exposure changes The wl_surface can be destroyed whilst a render is happening. Calling wl_surface::frame after the window is reset can crash as wl_surface is null. Fixes: QTBUG-77747 Change-Id: I139a9b234cb6acba81d6c1d5fa58629904a25053 Reviewed-by: Paul Olav Tvete --- src/client/qwaylandwindow.cpp | 9 ++++++++- src/client/qwaylandwindow_p.h | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp index 76d7715a8..1d4315a39 100644 --- a/src/client/qwaylandwindow.cpp +++ b/src/client/qwaylandwindow.cpp @@ -210,6 +210,8 @@ void QWaylandWindow::initWindow() void QWaylandWindow::initializeWlSurface() { + Q_ASSERT(!isInitialized()); + QWriteLocker lock(&mSurfaceLock); init(mDisplay->createSurface(static_cast(this))); } @@ -245,8 +247,10 @@ void QWaylandWindow::reset(bool sendDestroyEvent) mShellSurface = nullptr; delete mSubSurfaceWindow; mSubSurfaceWindow = nullptr; - if (isInitialized()) + if (isInitialized()) { + QWriteLocker lock(&mSurfaceLock); destroy(); + } mScreens.clear(); if (mFrameCallback) { @@ -1147,6 +1151,9 @@ void QWaylandWindow::requestUpdate() void QWaylandWindow::handleUpdate() { // TODO: Should sync subsurfaces avoid requesting frame callbacks? + QReadLocker lock(&mSurfaceLock); + if (!isInitialized()) + return; if (mFrameCallback) { wl_callback_destroy(mFrameCallback); diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h index 23432e398..ed4061f0e 100644 --- a/src/client/qwaylandwindow_p.h +++ b/src/client/qwaylandwindow_p.h @@ -53,6 +53,8 @@ #include #include +#include + #include #include #include @@ -272,6 +274,8 @@ private: static QMutex mFrameSyncMutex; static QWaylandWindow *mMouseGrab; + QReadWriteLock mSurfaceLock; + friend class QWaylandSubSurface; }; -- cgit v1.2.3 From 2c9396b063ca03b36e03fbdb85853a410787313d Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Tue, 20 Aug 2019 15:32:32 +0200 Subject: Add changes file for Qt 5.12.5 + e008c69e231169425e2ae602deabc0eb749376ab Fix compile error with -no-opengl + cde2fe3fba31b9b8d258f0663bc34009fd769efd Compositor: Map touch ids to contiguous ids + af9ec8a76d7e62444fadb518256fc58723fe5186 Client: Don't add all windows to activePopups + af00b80178138e55be7ea892a118e6357798e0f2 Don't crash if we start a drag without dragFocus + ec9057081f1094fbfeb11449bc533997731e4079 Client: Fix stuttering when the GUI thread is busy + a4e6f88f50d1a1dd56df77ce8b07b98aceb20ddc Client: Reset frame callback timer when hiding a window + acba020f1b6725e2d431636b1a2cfb075672ddcb Bump version + 5ca9f28f4b272d3265b97c16029071a0070195a6 Fix compilation with C++20 + 25a46893782979c74f57ab725b1ce55fbfc4fa2f Fix the build when libs didn't get built + 3d5cec736ce17c6b40c52bb8966f8fc40b742664 Fix expose event compression + 43d8a3091894ceb4ab934167b2f3eda27564eb6d Backport texture sharing for NVIDIA + 86b0d64b6c44fd8c3c3dd133bf52239f5520e524 Client: Add safer fromObject function to scanner + 2838c7f33a0b2f40b026d00b3e00139f94c358e7 Fix incorrect conversion to straight alpha pixel formats + 3e96fa1df8d2bc0ec8ab66abae1f20439b786b40 Client: Fix large clipboard pasting Change-Id: Ie61a19a3adb04e1280b2f70839778cf2c708a85b Reviewed-by: Johan Helsing --- dist/changes-5.12.5 | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 dist/changes-5.12.5 diff --git a/dist/changes-5.12.5 b/dist/changes-5.12.5 new file mode 100644 index 000000000..cecbdafa7 --- /dev/null +++ b/dist/changes-5.12.5 @@ -0,0 +1,36 @@ +Qt 5.12.5 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.12.0 through 5.12.4. + +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.12 series is binary compatible with the 5.11.x series. +Applications compiled for 5.11 will continue to run with 5.12. + +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 * +**************************************************************************** + + - [QTBUG-76104] Fixed a build error when configured with -no-opengl. + +**************************************************************************** +* QPA plugin * +**************************************************************************** + + - [QTBUG-76124] Fixed a crash when closing multiple popups at once. + - [QTBUG-76368] Fixed a crash that sometimes happened when starting + a drag-and-drop operation. + - [QTBUG-74085] Fixed crash when using custom Wayland surface. + - [QTBUG-76397] Fixed stuttering when the GUI thread is busy. + - [QTBUG-76657] Fixed occasional update problem when re-showing a hidden window. + - Fixed bug that could truncate large clipboard pastings. -- cgit v1.2.3 From 5400af8850a7a73a19443839fbd0c8f3d45b091b Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 28 Aug 2019 13:45:41 +0200 Subject: Make QT_WAYLAND_COMPOSITOR_QUICK a feature The define was only set when building Qt, not when including public headers in application code. Therefore, the sizes of objects did not match between the client code that calls new and the constructor inside Qt. Unfortunately, adding the additional members breaks binary compatibility. This has already happened between 5.11 and 5.12. It just wasn't apparent from the headers. If we removed the members again now, we would break binary compatibility again. Therefore, the best course of action seems to be acknowledging the break and adding the members also in the headers. [ChangeLog][Compositor][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. Fixes: QTBUG-75677 Change-Id: I3c1ee309ad8e0cd0b6389a76fd1d91e6e2be495c Reviewed-by: Johan Helsing Reviewed-by: Paul Olav Tvete --- src/compositor/compositor_api/compositor_api.pri | 4 +--- src/compositor/compositor_api/qwaylandquickchildren.h | 7 +++---- src/compositor/configure.json | 6 ++++++ src/compositor/extensions/qwaylandivisurface.cpp | 4 ++-- src/compositor/extensions/qwaylandivisurface.h | 2 +- src/compositor/extensions/qwaylandshellsurface.cpp | 2 +- src/compositor/extensions/qwaylandshellsurface.h | 2 +- src/compositor/extensions/qwaylandwlshell.cpp | 4 ++-- src/compositor/extensions/qwaylandwlshell.h | 2 +- src/compositor/extensions/qwaylandxdgshell.cpp | 4 ++-- src/compositor/extensions/qwaylandxdgshell.h | 2 +- src/compositor/extensions/qwaylandxdgshellv5.cpp | 6 +++--- src/compositor/extensions/qwaylandxdgshellv5.h | 4 ++-- src/compositor/extensions/qwaylandxdgshellv6.cpp | 4 ++-- src/compositor/extensions/qwaylandxdgshellv6.h | 2 +- src/imports/compositor/compositor.pro | 2 -- 16 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/compositor/compositor_api/compositor_api.pri b/src/compositor/compositor_api/compositor_api.pri index 8dbe12ac1..c8f1c98b7 100644 --- a/src/compositor/compositor_api/compositor_api.pri +++ b/src/compositor/compositor_api/compositor_api.pri @@ -64,9 +64,7 @@ qtConfig(draganddrop) { compositor_api/qwaylanddrag.cpp } -qtHaveModule(quick):qtConfig(opengl) { - DEFINES += QT_WAYLAND_COMPOSITOR_QUICK - +qtConfig(wayland-compositor-quick) { SOURCES += \ compositor_api/qwaylandquickcompositor.cpp \ compositor_api/qwaylandquicksurface.cpp \ diff --git a/src/compositor/compositor_api/qwaylandquickchildren.h b/src/compositor/compositor_api/qwaylandquickchildren.h index 7d821ab50..cee7a67ec 100644 --- a/src/compositor/compositor_api/qwaylandquickchildren.h +++ b/src/compositor/compositor_api/qwaylandquickchildren.h @@ -51,16 +51,15 @@ // We mean it. // -#ifdef QT_WAYLAND_COMPOSITOR_QUICK +#include +#if QT_CONFIG(wayland_compositor_quick) #include #include #endif -#include - QT_BEGIN_NAMESPACE -#ifdef QT_WAYLAND_COMPOSITOR_QUICK +#if QT_CONFIG(wayland_compositor_quick) #define Q_WAYLAND_COMPOSITOR_DECLARE_QUICK_CHILDREN(className) \ Q_PROPERTY(QQmlListProperty data READ data DESIGNABLE false) \ Q_CLASSINFO("DefaultProperty", "data") \ diff --git a/src/compositor/configure.json b/src/compositor/configure.json index 0412d5e3b..985f36ddc 100644 --- a/src/compositor/configure.json +++ b/src/compositor/configure.json @@ -152,6 +152,12 @@ "label": "VSP2 hardware layer integration", "condition": "features.wayland-server && features.eglfs_vsp2 && libs.wayland-kms", "output": [ "privateFeature" ] + }, + "wayland-compositor-quick": { + "label": "QtQuick integration for wayland compositor", + "purpose": "Allows QtWayland compositor types to be used with QtQuick", + "condition": "features.wayland-server && module.quick && features.opengl", + "output": [ "publicFeature" ] } }, diff --git a/src/compositor/extensions/qwaylandivisurface.cpp b/src/compositor/extensions/qwaylandivisurface.cpp index b6398f060..7cf6464e9 100644 --- a/src/compositor/extensions/qwaylandivisurface.cpp +++ b/src/compositor/extensions/qwaylandivisurface.cpp @@ -40,7 +40,7 @@ #include "qwaylandivisurface.h" #include "qwaylandivisurface_p.h" #include "qwaylandiviapplication_p.h" -#ifdef QT_WAYLAND_COMPOSITOR_QUICK +#if QT_CONFIG(wayland_compositor_quick) #include "qwaylandivisurfaceintegration_p.h" #endif @@ -207,7 +207,7 @@ void QWaylandIviSurface::sendConfigure(const QSize &size) d->send_configure(size.width(), size.height()); } -#ifdef QT_WAYLAND_COMPOSITOR_QUICK +#if QT_CONFIG(wayland_compositor_quick) QWaylandQuickShellIntegration *QWaylandIviSurface::createIntegration(QWaylandQuickShellSurfaceItem *item) { return new QtWayland::IviSurfaceIntegration(item); diff --git a/src/compositor/extensions/qwaylandivisurface.h b/src/compositor/extensions/qwaylandivisurface.h index 65d5bbc86..525ad9571 100644 --- a/src/compositor/extensions/qwaylandivisurface.h +++ b/src/compositor/extensions/qwaylandivisurface.h @@ -78,7 +78,7 @@ public: Q_INVOKABLE void sendConfigure(const QSize &size); -#ifdef QT_WAYLAND_COMPOSITOR_QUICK +#if QT_CONFIG(wayland_compositor_quick) QWaylandQuickShellIntegration *createIntegration(QWaylandQuickShellSurfaceItem *item) override; #endif diff --git a/src/compositor/extensions/qwaylandshellsurface.cpp b/src/compositor/extensions/qwaylandshellsurface.cpp index 3cfe44895..f29e4e553 100644 --- a/src/compositor/extensions/qwaylandshellsurface.cpp +++ b/src/compositor/extensions/qwaylandshellsurface.cpp @@ -69,7 +69,7 @@ * \sa QWaylandSurface, QWaylandWlShellSurface, QWaylandXdgSurfaceV5, QWaylandIviSurface */ -#ifdef QT_WAYLAND_COMPOSITOR_QUICK +#if QT_CONFIG(wayland_compositor_quick) /*! * \fn QWaylandQuickShellIntegration *QWaylandShellSurface::createIntegration(QWaylandQuickShellSurfaceItem *item) * diff --git a/src/compositor/extensions/qwaylandshellsurface.h b/src/compositor/extensions/qwaylandshellsurface.h index aca02e2fa..6b943f368 100644 --- a/src/compositor/extensions/qwaylandshellsurface.h +++ b/src/compositor/extensions/qwaylandshellsurface.h @@ -54,7 +54,7 @@ class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandShellSurface : public QWaylandComposit Q_OBJECT Q_PROPERTY(Qt::WindowType windowType READ windowType NOTIFY windowTypeChanged) public: -#ifdef QT_WAYLAND_COMPOSITOR_QUICK +#if QT_CONFIG(wayland_compositor_quick) virtual QWaylandQuickShellIntegration *createIntegration(QWaylandQuickShellSurfaceItem *item) = 0; #endif QWaylandShellSurface(QWaylandObject *waylandObject) : QWaylandCompositorExtension(waylandObject) {} diff --git a/src/compositor/extensions/qwaylandwlshell.cpp b/src/compositor/extensions/qwaylandwlshell.cpp index d932a06c9..5e4ec6e6a 100644 --- a/src/compositor/extensions/qwaylandwlshell.cpp +++ b/src/compositor/extensions/qwaylandwlshell.cpp @@ -41,7 +41,7 @@ #include "qwaylandwlshell.h" #include "qwaylandwlshell_p.h" -#ifdef QT_WAYLAND_COMPOSITOR_QUICK +#if QT_CONFIG(wayland_compositor_quick) #include "qwaylandwlshellintegration_p.h" #endif @@ -584,7 +584,7 @@ void QWaylandWlShellSurface::sendPopupDone() d->send_popup_done(); } -#ifdef QT_WAYLAND_COMPOSITOR_QUICK +#if QT_CONFIG(wayland_compositor_quick) QWaylandQuickShellIntegration *QWaylandWlShellSurface::createIntegration(QWaylandQuickShellSurfaceItem *item) { return new QtWayland::WlShellIntegration(item); diff --git a/src/compositor/extensions/qwaylandwlshell.h b/src/compositor/extensions/qwaylandwlshell.h index 421888000..b37773e28 100644 --- a/src/compositor/extensions/qwaylandwlshell.h +++ b/src/compositor/extensions/qwaylandwlshell.h @@ -140,7 +140,7 @@ public: Q_INVOKABLE void sendConfigure(const QSize &size, ResizeEdge edges); Q_INVOKABLE void sendPopupDone(); -#ifdef QT_WAYLAND_COMPOSITOR_QUICK +#if QT_CONFIG(wayland_compositor_quick) QWaylandQuickShellIntegration *createIntegration(QWaylandQuickShellSurfaceItem *item) override; #endif diff --git a/src/compositor/extensions/qwaylandxdgshell.cpp b/src/compositor/extensions/qwaylandxdgshell.cpp index bd332287e..69e35632b 100644 --- a/src/compositor/extensions/qwaylandxdgshell.cpp +++ b/src/compositor/extensions/qwaylandxdgshell.cpp @@ -37,7 +37,7 @@ #include "qwaylandxdgshell.h" #include "qwaylandxdgshell_p.h" -#ifdef QT_WAYLAND_COMPOSITOR_QUICK +#if QT_CONFIG(wayland_compositor_quick) #include "qwaylandxdgshellintegration_p.h" #endif @@ -680,7 +680,7 @@ QWaylandXdgSurface *QWaylandXdgSurface::fromResource(wl_resource *resource) return static_cast(xsResource->xdg_surface_object)->q_func(); } -#ifdef QT_WAYLAND_COMPOSITOR_QUICK +#if QT_CONFIG(wayland_compositor_quick) QWaylandQuickShellIntegration *QWaylandXdgSurface::createIntegration(QWaylandQuickShellSurfaceItem *item) { Q_D(const QWaylandXdgSurface); diff --git a/src/compositor/extensions/qwaylandxdgshell.h b/src/compositor/extensions/qwaylandxdgshell.h index 774dd2282..c7834ab91 100644 --- a/src/compositor/extensions/qwaylandxdgshell.h +++ b/src/compositor/extensions/qwaylandxdgshell.h @@ -119,7 +119,7 @@ public: static QByteArray interfaceName(); static QWaylandXdgSurface *fromResource(::wl_resource *resource); -#ifdef QT_WAYLAND_COMPOSITOR_QUICK +#if QT_CONFIG(wayland_compositor_quick) QWaylandQuickShellIntegration *createIntegration(QWaylandQuickShellSurfaceItem *item) override; #endif diff --git a/src/compositor/extensions/qwaylandxdgshellv5.cpp b/src/compositor/extensions/qwaylandxdgshellv5.cpp index a6e88aabb..51516e556 100644 --- a/src/compositor/extensions/qwaylandxdgshellv5.cpp +++ b/src/compositor/extensions/qwaylandxdgshellv5.cpp @@ -40,7 +40,7 @@ #include "qwaylandxdgshellv5.h" #include "qwaylandxdgshellv5_p.h" -#ifdef QT_WAYLAND_COMPOSITOR_QUICK +#if QT_CONFIG(wayland_compositor_quick) #include "qwaylandxdgshellv5integration_p.h" #endif @@ -1308,7 +1308,7 @@ uint QWaylandXdgSurfaceV5::sendResizing(const QSize &maxSize) return sendConfigure(maxSize, conf.states); } -#ifdef QT_WAYLAND_COMPOSITOR_QUICK +#if QT_CONFIG(wayland_compositor_quick) QWaylandQuickShellIntegration *QWaylandXdgSurfaceV5::createIntegration(QWaylandQuickShellSurfaceItem *item) { return new QtWayland::XdgShellV5Integration(item); @@ -1509,7 +1509,7 @@ void QWaylandXdgPopupV5::sendPopupDone() d->send_popup_done(); } -#ifdef QT_WAYLAND_COMPOSITOR_QUICK +#if QT_CONFIG(wayland_compositor_quick) QWaylandQuickShellIntegration *QWaylandXdgPopupV5::createIntegration(QWaylandQuickShellSurfaceItem *item) { return new QtWayland::XdgPopupV5Integration(item); diff --git a/src/compositor/extensions/qwaylandxdgshellv5.h b/src/compositor/extensions/qwaylandxdgshellv5.h index f989d04c7..66e9ceb05 100644 --- a/src/compositor/extensions/qwaylandxdgshellv5.h +++ b/src/compositor/extensions/qwaylandxdgshellv5.h @@ -171,7 +171,7 @@ public: Q_INVOKABLE uint sendFullscreen(const QSize &size); Q_INVOKABLE uint sendResizing(const QSize &maxSize); -#ifdef QT_WAYLAND_COMPOSITOR_QUICK +#if QT_CONFIG(wayland_compositor_quick) QWaylandQuickShellIntegration *createIntegration(QWaylandQuickShellSurfaceItem *item) override; #endif @@ -243,7 +243,7 @@ public: Q_INVOKABLE void sendPopupDone(); -#ifdef QT_WAYLAND_COMPOSITOR_QUICK +#if QT_CONFIG(wayland_compositor_quick) QWaylandQuickShellIntegration *createIntegration(QWaylandQuickShellSurfaceItem *item) override; #endif diff --git a/src/compositor/extensions/qwaylandxdgshellv6.cpp b/src/compositor/extensions/qwaylandxdgshellv6.cpp index 8338fe6e2..e4cb1dc26 100644 --- a/src/compositor/extensions/qwaylandxdgshellv6.cpp +++ b/src/compositor/extensions/qwaylandxdgshellv6.cpp @@ -37,7 +37,7 @@ #include "qwaylandxdgshellv6.h" #include "qwaylandxdgshellv6_p.h" -#ifdef QT_WAYLAND_COMPOSITOR_QUICK +#if QT_CONFIG(wayland_compositor_quick) #include "qwaylandxdgshellv6integration_p.h" #endif @@ -685,7 +685,7 @@ QWaylandXdgSurfaceV6 *QWaylandXdgSurfaceV6::fromResource(wl_resource *resource) return static_cast(xsResource->zxdg_surface_v6_object)->q_func(); } -#ifdef QT_WAYLAND_COMPOSITOR_QUICK +#if QT_CONFIG(wayland_compositor_quick) QWaylandQuickShellIntegration *QWaylandXdgSurfaceV6::createIntegration(QWaylandQuickShellSurfaceItem *item) { Q_D(const QWaylandXdgSurfaceV6); diff --git a/src/compositor/extensions/qwaylandxdgshellv6.h b/src/compositor/extensions/qwaylandxdgshellv6.h index b9c47c578..710482ac3 100644 --- a/src/compositor/extensions/qwaylandxdgshellv6.h +++ b/src/compositor/extensions/qwaylandxdgshellv6.h @@ -119,7 +119,7 @@ public: static QByteArray interfaceName(); static QWaylandXdgSurfaceV6 *fromResource(::wl_resource *resource); -#ifdef QT_WAYLAND_COMPOSITOR_QUICK +#if QT_CONFIG(wayland_compositor_quick) QWaylandQuickShellIntegration *createIntegration(QWaylandQuickShellSurfaceItem *item) override; #endif diff --git a/src/imports/compositor/compositor.pro b/src/imports/compositor/compositor.pro index 50b26d4d0..cc8a5306b 100644 --- a/src/imports/compositor/compositor.pro +++ b/src/imports/compositor/compositor.pro @@ -14,8 +14,6 @@ COMPOSITOR_QML_FILES += \ WaylandOutputWindow.qml \ WaylandCursorItem.qml -DEFINES += QT_WAYLAND_COMPOSITOR_QUICK - # Create the resource file GENERATED_RESOURCE_FILE = $$OUT_PWD/compositor.qrc -- cgit v1.2.3 From 1cce394099bd83261a0fe3bb73acd5c4bd8a749a Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Wed, 21 Aug 2019 13:44:05 +0200 Subject: Client: Don't freeze in QDrag::exec if there was no drag focus af00b801 fixed a crash when starting a drag without a valid focus, but there is still a problem, because QDrag::exec will never return because it's waiting indefinitely in an event loop. - QWaylandDataDevice::startDrag can now fail by returning false. - When starting a drag fails, we cancel the drag through QWaylandDrag::cancelDrag wrapped in invokeMethod. - Also, don't unnecessarily create a data_source if we cannot start a drag. [ChangeLog][QPA plugin] Fixed a freeze that happened when starting a drag-and-drop operation without a valid source surface. Change-Id: Iea19b0c92c196a44d1274a966bee4ff519632d34 Reviewed-by: Paul Olav Tvete --- src/client/qwaylanddatadevice.cpp | 17 ++++++++++------- src/client/qwaylanddatadevice_p.h | 2 +- src/client/qwaylanddnd.cpp | 9 +++++++-- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/client/qwaylanddatadevice.cpp b/src/client/qwaylanddatadevice.cpp index 6b2a408eb..990f92ba9 100644 --- a/src/client/qwaylanddatadevice.cpp +++ b/src/client/qwaylanddatadevice.cpp @@ -102,19 +102,22 @@ QWaylandDataOffer *QWaylandDataDevice::dragOffer() const return m_dragOffer.data(); } -void QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon) +bool QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon) { - m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData)); - connect(m_dragSource.data(), &QWaylandDataSource::cancelled, this, &QWaylandDataDevice::dragSourceCancelled); - QWaylandWindow *origin = m_display->currentInputDevice()->pointerFocus(); if (!origin) origin = m_display->currentInputDevice()->touchFocus(); - if (origin) - start_drag(m_dragSource->object(), origin->object(), icon->object(), m_display->currentInputDevice()->serial()); - else + if (!origin) { qCDebug(lcQpaWayland) << "Couldn't start a drag because the origin window could not be found."; + return false; + } + + m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData)); + connect(m_dragSource.data(), &QWaylandDataSource::cancelled, this, &QWaylandDataDevice::dragSourceCancelled); + + start_drag(m_dragSource->object(), origin->object(), icon->object(), m_display->currentInputDevice()->serial()); + return true; } void QWaylandDataDevice::cancelDrag() diff --git a/src/client/qwaylanddatadevice_p.h b/src/client/qwaylanddatadevice_p.h index 0a7f42538..16c3ad28e 100644 --- a/src/client/qwaylanddatadevice_p.h +++ b/src/client/qwaylanddatadevice_p.h @@ -89,7 +89,7 @@ public: #if QT_CONFIG(draganddrop) QWaylandDataOffer *dragOffer() const; - void startDrag(QMimeData *mimeData, QWaylandWindow *icon); + bool startDrag(QMimeData *mimeData, QWaylandWindow *icon); void cancelDrag(); #endif diff --git a/src/client/qwaylanddnd.cpp b/src/client/qwaylanddnd.cpp index b01a9db36..6535aa16b 100644 --- a/src/client/qwaylanddnd.cpp +++ b/src/client/qwaylanddnd.cpp @@ -66,8 +66,13 @@ void QWaylandDrag::startDrag() { QBasicDrag::startDrag(); QWaylandWindow *icon = static_cast(shapedPixmapWindow()->handle()); - m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), icon); - icon->addAttachOffset(-drag()->hotSpot()); + if (m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), icon)) { + icon->addAttachOffset(-drag()->hotSpot()); + } else { + // Cancelling immediately does not work, since the event loop for QDrag::exec is started + // after this function returns. + QMetaObject::invokeMethod(this, [this](){ cancelDrag(); }, Qt::QueuedConnection); + } } void QWaylandDrag::cancel() -- cgit v1.2.3 From 2e9c90aaefdfe5f1e9b90159c5e6981230627055 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Mon, 19 Aug 2019 13:46:08 +0200 Subject: Client: Refactor touch handling and fix various bugs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename mTouchPoints to mPendingTouchPoints, to clarify that they're the accumulated state so far, which will be applied with the wl_touch.frame event. QWaylandInputDevice::Touch::mPrevTouchPoints is no longer needed and has been removed. Fixes the following issues with the old approach: - touchPointsReleased() only checked mTouchPoints, which was cleared on touch_frame and populated again on touch_motion and touch_down, which meant that it could return true even though there were still touch points left. Leading to the workaround for missing wl_touch.frame events on Weston being triggered to often. - Touch focus was cleared on any wl_touch.up event, not just the last one. - The order of the touch events was not stable and relied on the order of the events (QTBUG-77014). Fixes: QTBUG-77014 Change-Id: Ic3ecdc87e77b0e0276afefd127ad2b965142cbd4 Reviewed-by: Jan Arve Sæther Reviewed-by: Shawn Rutledge --- src/client/qwaylandinputdevice.cpp | 102 ++++++++++++++++--------------------- src/client/qwaylandinputdevice_p.h | 3 +- 2 files changed, 45 insertions(+), 60 deletions(-) diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp index 495f258de..6016589a6 100644 --- a/src/client/qwaylandinputdevice.cpp +++ b/src/client/qwaylandinputdevice.cpp @@ -874,15 +874,20 @@ void QWaylandInputDevice::Touch::touch_up(uint32_t serial, uint32_t time, int32_ { Q_UNUSED(serial); Q_UNUSED(time); - mFocus = nullptr; mParent->handleTouchPoint(id, 0, 0, Qt::TouchPointReleased); - // As of Weston 1.5.90 there is no touch_frame after the last touch_up - // (i.e. when the last finger is released). To accommodate for this, issue a - // touch_frame. This cannot hurt since it is safe to call the touch_frame - // handler multiple times when there are no points left. - if (allTouchPointsReleased()) + if (allTouchPointsReleased()) { + mFocus = nullptr; + + // As of Weston 7.0.0 there is no touch_frame after the last touch_up + // (i.e. when the last finger is released). To accommodate for this, issue a + // touch_frame. This cannot hurt since it is safe to call the touch_frame + // handler multiple times when there are no points left. + // See: https://gitlab.freedesktop.org/wayland/weston/issues/44 + // TODO: change logging category to lcQpaWaylandInput in newer versions. + qCDebug(lcQpaWayland, "Generating fake frame event to work around Weston bug"); touch_frame(); + } } void QWaylandInputDevice::Touch::touch_motion(uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y) @@ -893,8 +898,7 @@ void QWaylandInputDevice::Touch::touch_motion(uint32_t time, int32_t id, wl_fixe void QWaylandInputDevice::Touch::touch_cancel() { - mPrevTouchPoints.clear(); - mTouchPoints.clear(); + mPendingTouchPoints.clear(); QWaylandTouchExtension *touchExt = mParent->mQDisplay->touchExtension(); if (touchExt) @@ -905,19 +909,16 @@ void QWaylandInputDevice::Touch::touch_cancel() void QWaylandInputDevice::handleTouchPoint(int id, double x, double y, Qt::TouchPointState state) { - QWindowSystemInterface::TouchPoint tp; - - // Find out the coordinates for Released events. - bool coordsOk = false; - if (state == Qt::TouchPointReleased) - for (int i = 0; i < mTouch->mPrevTouchPoints.count(); ++i) - if (mTouch->mPrevTouchPoints.at(i).id == id) { - tp.area = mTouch->mPrevTouchPoints.at(i).area; - coordsOk = true; - break; - } + auto end = mTouch->mPendingTouchPoints.end(); + auto it = std::find_if(mTouch->mPendingTouchPoints.begin(), end, [id](auto tp){ return tp.id == id; }); + if (it == end) { + it = mTouch->mPendingTouchPoints.insert(end, QWindowSystemInterface::TouchPoint()); + it->id = id; + } + QWindowSystemInterface::TouchPoint &tp = *it; - if (!coordsOk) { + // Only moved and pressed needs to update/set position + if (state == Qt::TouchPointMoved || state == Qt::TouchPointPressed) { // x and y are surface relative. // We need a global (screen) position. QWaylandWindow *win = mTouch->mFocus; @@ -936,59 +937,37 @@ void QWaylandInputDevice::handleTouchPoint(int id, double x, double y, Qt::Touch } tp.state = state; - tp.id = id; tp.pressure = tp.state == Qt::TouchPointReleased ? 0 : 1; - mTouch->mTouchPoints.append(tp); } bool QWaylandInputDevice::Touch::allTouchPointsReleased() { - for (int i = 0; i < mTouchPoints.count(); ++i) - if (mTouchPoints.at(i).state != Qt::TouchPointReleased) + for (const auto &tp : qAsConst(mPendingTouchPoints)) { + if (tp.state != Qt::TouchPointReleased) return false; - + } return true; } void QWaylandInputDevice::Touch::releasePoints() { - Q_FOREACH (const QWindowSystemInterface::TouchPoint &previousPoint, mPrevTouchPoints) { - QWindowSystemInterface::TouchPoint tp = previousPoint; + if (mPendingTouchPoints.empty()) + return; + + for (QWindowSystemInterface::TouchPoint &tp : mPendingTouchPoints) tp.state = Qt::TouchPointReleased; - mTouchPoints.append(tp); - } + touch_frame(); } void QWaylandInputDevice::Touch::touch_frame() { - // Copy all points, that are in the previous but not in the current list, as stationary. - for (int i = 0; i < mPrevTouchPoints.count(); ++i) { - const QWindowSystemInterface::TouchPoint &prevPoint(mPrevTouchPoints.at(i)); - if (prevPoint.state == Qt::TouchPointReleased) - continue; - bool found = false; - for (int j = 0; j < mTouchPoints.count(); ++j) - if (mTouchPoints.at(j).id == prevPoint.id) { - found = true; - break; - } - if (!found) { - QWindowSystemInterface::TouchPoint p = prevPoint; - p.state = Qt::TouchPointStationary; - mTouchPoints.append(p); - } - } - - if (mTouchPoints.isEmpty()) { - mPrevTouchPoints.clear(); - return; - } + // TODO: early return if no events? QWindow *window = mFocus ? mFocus->window() : nullptr; if (mFocus) { - const QWindowSystemInterface::TouchPoint &tp = mTouchPoints.last(); + const QWindowSystemInterface::TouchPoint &tp = mPendingTouchPoints.last(); // When the touch event is received, the global pos is calculated with the margins // in mind. Now we need to adjust again to get the correct local pos back. QMargins margins = window->frameMargins(); @@ -997,14 +976,21 @@ void QWaylandInputDevice::Touch::touch_frame() if (mFocus->touchDragDecoration(mParent, localPos, tp.area.center(), tp.state, mParent->modifiers())) return; } - QWindowSystemInterface::handleTouchEvent(window, mParent->mTouchDevice, mTouchPoints); - if (allTouchPointsReleased()) - mPrevTouchPoints.clear(); - else - mPrevTouchPoints = mTouchPoints; + QWindowSystemInterface::handleTouchEvent(window, mParent->mTouchDevice, mPendingTouchPoints); + + // Prepare state for next frame + const auto prevTouchPoints = mPendingTouchPoints; + mPendingTouchPoints.clear(); + for (const auto &prevPoint: prevTouchPoints) { + // All non-released touch points should be part of the next touch event + if (prevPoint.state != Qt::TouchPointReleased) { + QWindowSystemInterface::TouchPoint tp = prevPoint; + tp.state = Qt::TouchPointStationary; // ... as stationary (unless proven otherwise) + mPendingTouchPoints.append(tp); + } + } - mTouchPoints.clear(); } } diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h index 7aa86539b..d9bae9836 100644 --- a/src/client/qwaylandinputdevice_p.h +++ b/src/client/qwaylandinputdevice_p.h @@ -304,8 +304,7 @@ public: QWaylandInputDevice *mParent = nullptr; QPointer mFocus; - QList mTouchPoints; - QList mPrevTouchPoints; + QList mPendingTouchPoints; }; class QWaylandPointerEvent -- cgit v1.2.3 From 33d2062f8ac9419ec1c6504be47fe48119e605bb Mon Sep 17 00:00:00 2001 From: Pavel Tumakaev Date: Wed, 31 Jul 2019 13:26:51 +0300 Subject: Fix deadlock in QWaylandWindow::waitForFrameSync Calling the QOpenGLContext::swapBuffers from QGuiApplicationPrivate::processExposeEvent in some cases leads to recursive calls of QWaylandWindow::waitForFrameSync. Since the mWaitingForFrameCallback check in WaylandWindow::waitForFrameSync is performed after the mutex is locked, the QMutexLocker tries to lock the mFrameSyncMutex mutex in every recursive call, that leads to a deadlock. This patch moves the performing of the mWaitingForFrameCallback check before locking the mutex. Change-Id: Ia2d834b7dd03fcd91bbe29a3a897b4db2d155527 Reviewed-by: Johan Helsing --- src/client/qwaylandwindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp index abc54f584..953582323 100644 --- a/src/client/qwaylandwindow.cpp +++ b/src/client/qwaylandwindow.cpp @@ -657,10 +657,11 @@ QMutex QWaylandWindow::mFrameSyncMutex; bool QWaylandWindow::waitForFrameSync(int timeout) { - QMutexLocker locker(&mFrameSyncMutex); if (!mWaitingForFrameCallback) return true; + QMutexLocker locker(&mFrameSyncMutex); + wl_proxy_set_queue(reinterpret_cast(mFrameCallback), mFrameQueue); mDisplay->dispatchQueueWhile(mFrameQueue, [&]() { return mWaitingForFrameCallback; }, timeout); -- cgit v1.2.3 From 481cea71043dabf6d5ff33101a66693af86438e1 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Wed, 4 Sep 2019 10:12:32 +0200 Subject: Compositor: Fix various input-related rounding errors QPointF::toPoint (which is what the QPoint versions of the events use internally) uses qRound, which is not the right kind of rounding to use with the QRegion we use for the input region. This switches to use QPointF variants instead of QPoint wherever possible, and then the correct conversion (with qFloor) is done once in the new QPointF version of QWaylandSurface::inputRegionContains(). The compositor inputRegion test has now been updated to test the new API. [ChangeLog][Compositor] Fixed various rounding errors related to touch and mouse input. Fixes: QTBUG-77457 Change-Id: Ife2365abd56a239c34eee91310ab0e698a50d4ff Reviewed-by: Paul Olav Tvete (cherry picked from commit 7f189ec10a9b3e9825dda30d3a8f86ee2e07b97f) Reviewed-by: Pier Luigi Fiorini --- .../compositor_api/qwaylandquickitem.cpp | 28 +++++++++++----------- .../compositor_api/qwaylandquickitem_p.h | 2 +- src/compositor/compositor_api/qwaylandsurface.cpp | 18 ++++++++++++++ src/compositor/compositor_api/qwaylandsurface.h | 7 ++++++ 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/compositor/compositor_api/qwaylandquickitem.cpp b/src/compositor/compositor_api/qwaylandquickitem.cpp index 2b24c13b7..5010247f9 100644 --- a/src/compositor/compositor_api/qwaylandquickitem.cpp +++ b/src/compositor/compositor_api/qwaylandquickitem.cpp @@ -465,7 +465,7 @@ void QWaylandQuickItem::mousePressEvent(QMouseEvent *event) return; } - if (!inputRegionContains(event->pos())) { + if (!inputRegionContains(event->localPos())) { event->ignore(); return; } @@ -477,7 +477,7 @@ void QWaylandQuickItem::mousePressEvent(QMouseEvent *event) seat->sendMouseMoveEvent(d->view.data(), mapToSurface(event->localPos()), event->windowPos()); seat->sendMousePressEvent(event->button()); - d->hoverPos = event->pos(); + d->hoverPos = event->localPos(); } /*! @@ -503,7 +503,7 @@ void QWaylandQuickItem::mouseMoveEvent(QMouseEvent *event) #endif // QT_CONFIG(draganddrop) { seat->sendMouseMoveEvent(d->view.data(), mapToSurface(event->localPos()), event->windowPos()); - d->hoverPos = event->pos(); + d->hoverPos = event->localPos(); } } else { emit mouseMove(event->windowPos()); @@ -540,14 +540,14 @@ void QWaylandQuickItem::mouseReleaseEvent(QMouseEvent *event) void QWaylandQuickItem::hoverEnterEvent(QHoverEvent *event) { Q_D(QWaylandQuickItem); - if (!inputRegionContains(event->pos())) { + if (!inputRegionContains(event->posF())) { event->ignore(); return; } if (d->shouldSendInputEvents()) { QWaylandSeat *seat = compositor()->seatFor(event); - seat->sendMouseMoveEvent(d->view.data(), event->pos(), mapToScene(event->pos())); - d->hoverPos = event->pos(); + seat->sendMouseMoveEvent(d->view.data(), event->posF(), mapToScene(event->posF())); + d->hoverPos = event->posF(); } else { event->ignore(); } @@ -560,16 +560,16 @@ void QWaylandQuickItem::hoverMoveEvent(QHoverEvent *event) { Q_D(QWaylandQuickItem); if (surface()) { - if (!inputRegionContains(event->pos())) { + if (!inputRegionContains(event->posF())) { event->ignore(); return; } } if (d->shouldSendInputEvents()) { QWaylandSeat *seat = compositor()->seatFor(event); - if (event->pos() != d->hoverPos) { - seat->sendMouseMoveEvent(d->view.data(), mapToSurface(event->pos()), mapToScene(event->pos())); - d->hoverPos = event->pos(); + if (event->posF() != d->hoverPos) { + seat->sendMouseMoveEvent(d->view.data(), mapToSurface(event->posF()), mapToScene(event->posF())); + d->hoverPos = event->posF(); } } else { event->ignore(); @@ -598,7 +598,7 @@ void QWaylandQuickItem::wheelEvent(QWheelEvent *event) { Q_D(QWaylandQuickItem); if (d->shouldSendInputEvents()) { - if (!inputRegionContains(event->pos())) { + if (!inputRegionContains(event->posF())) { event->ignore(); return; } @@ -651,10 +651,10 @@ void QWaylandQuickItem::touchEvent(QTouchEvent *event) if (d->shouldSendInputEvents() && d->touchEventsEnabled) { QWaylandSeat *seat = compositor()->seatFor(event); - QPoint pointPos; + QPointF pointPos; const QList &points = event->touchPoints(); if (!points.isEmpty()) - pointPos = points.at(0).pos().toPoint(); + pointPos = points.at(0).pos(); if (event->type() == QEvent::TouchBegin && !inputRegionContains(pointPos)) { event->ignore(); @@ -1039,7 +1039,7 @@ void QWaylandQuickItem::setFocusOnClick(bool focus) bool QWaylandQuickItem::inputRegionContains(const QPointF &localPosition) const { if (QWaylandSurface *s = surface()) - return s->inputRegionContains(mapToSurface(localPosition).toPoint()); + return s->inputRegionContains(mapToSurface(localPosition)); return false; } diff --git a/src/compositor/compositor_api/qwaylandquickitem_p.h b/src/compositor/compositor_api/qwaylandquickitem_p.h index 3d710d71b..352a130dc 100644 --- a/src/compositor/compositor_api/qwaylandquickitem_p.h +++ b/src/compositor/compositor_api/qwaylandquickitem_p.h @@ -171,7 +171,7 @@ public: bool focusOnClick = true; bool sizeFollowsSurface = true; bool belowParent = false; - QPoint hoverPos; + QPointF hoverPos; QMatrix4x4 lastMatrix; QQuickWindow *connectedWindow = nullptr; diff --git a/src/compositor/compositor_api/qwaylandsurface.cpp b/src/compositor/compositor_api/qwaylandsurface.cpp index f457c372c..e7bb0d7de 100644 --- a/src/compositor/compositor_api/qwaylandsurface.cpp +++ b/src/compositor/compositor_api/qwaylandsurface.cpp @@ -66,6 +66,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -601,6 +602,23 @@ bool QWaylandSurface::inputRegionContains(const QPoint &p) const return d->inputRegion.contains(p); } +//TODO: Add appropriate \since version when this is made public. +/*! + * Returns \c true if the QWaylandSurface's input region contains the point \a position. + * Otherwise returns \c false. + */ +bool QWaylandSurface::inputRegionContains(const QPointF &position) const +{ + Q_D(const QWaylandSurface); + // QRegion::contains operates in integers. If a region has a rect (0,0,10,10), (0,0) is + // inside while (10,10) is outside. Therefore, we can't use QPoint::toPoint(), which will + // round upwards, meaning the point (-0.25,-0.25) would be rounded to (0,0) and count as + // being inside the region, and similarly, a point (9.75,9.75) inside the region would be + // rounded upwards and count as being outside the region. + const QPoint floored(qFloor(position.x()), qFloor(position.y())); + return d->inputRegion.contains(floored); +} + /*! * \qmlmethod void QtWaylandCompositor::WaylandSurface::destroy() * diff --git a/src/compositor/compositor_api/qwaylandsurface.h b/src/compositor/compositor_api/qwaylandsurface.h index a138b2af5..c4d80d2bf 100644 --- a/src/compositor/compositor_api/qwaylandsurface.h +++ b/src/compositor/compositor_api/qwaylandsurface.h @@ -120,6 +120,13 @@ public: QWaylandCompositor *compositor() const; bool inputRegionContains(const QPoint &p) const; +private: + // TODO: Making this private now since it's added in a patch release, and we want to ensure + // compatibility with older patch releases. + // This should simply be made public (and the friend removed) in the next minor release. + friend class QWaylandQuickItem; + bool inputRegionContains(const QPointF &position) const; +public: Q_INVOKABLE void destroy(); Q_INVOKABLE bool isDestroyed() const; -- cgit v1.2.3