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(-) (limited to 'src') 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 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(-) (limited to 'src') 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(-) (limited to 'src') 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(-) (limited to 'src') 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 9de5e8fc4bd5db73531d1590978006d3bcaa4cc4 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Tue, 3 Sep 2019 07:50:26 +0200 Subject: Client: Adjust for window border when setting text-input cursor rect set_cursor_rectangle takes wl_surface coordinates, but we sent window coordinates. Fixes: QTBUG-77987 Change-Id: Ia0bf98f9749723128bec27c3c607d1ccde2d5fd3 Reviewed-by: Gatis Paeglis --- src/client/qwaylandinputcontext.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/qwaylandinputcontext.cpp b/src/client/qwaylandinputcontext.cpp index c6f287dda..0f27f551d 100644 --- a/src/client/qwaylandinputcontext.cpp +++ b/src/client/qwaylandinputcontext.cpp @@ -119,7 +119,8 @@ void QWaylandTextInput::updateState(Qt::InputMethodQueries queries, uint32_t fla if (!QGuiApplication::focusWindow() || !QGuiApplication::focusWindow()->handle()) return; - struct ::wl_surface *surface = static_cast(QGuiApplication::focusWindow()->handle())->object(); + auto *window = static_cast(QGuiApplication::focusWindow()->handle()); + auto *surface = window->object(); if (!surface || (surface != m_surface)) return; @@ -157,8 +158,10 @@ void QWaylandTextInput::updateState(Qt::InputMethodQueries queries, uint32_t fla if (queries & Qt::ImCursorRectangle) { const QRect &cRect = event.value(Qt::ImCursorRectangle).toRect(); - const QRect &tRect = QGuiApplication::inputMethod()->inputItemTransform().mapRect(cRect); - set_cursor_rectangle(tRect.x(), tRect.y(), tRect.width(), tRect.height()); + const QRect &windowRect = QGuiApplication::inputMethod()->inputItemTransform().mapRect(cRect); + const QMargins margins = window->frameMargins(); + const QRect &surfaceRect = windowRect.translated(margins.left(), margins.top()); + set_cursor_rectangle(surfaceRect.x(), surfaceRect.y(), surfaceRect.width(), surfaceRect.height()); } if (queries & Qt::ImPreferredLanguage) { -- cgit v1.2.3 From 2950ab906db92ad0e00a1113fb0027b76e6c8ac0 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Tue, 3 Sep 2019 08:22:44 +0200 Subject: Client: Don't spam stderr about ignored window states Since it is not supported by the protocol, neither we, nor the application developer can do anything about it. Change it from warning to debug so it only shows up when enabled. Task-number: QTBUG-76061 Change-Id: I81420e0c72a9e9652f6592d65c70c7df1e5725b9 Reviewed-by: Paul Olav Tvete Reviewed-by: Pier Luigi Fiorini --- src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp | 2 +- src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp index 980e4a601..99b478d98 100644 --- a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp +++ b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp @@ -342,7 +342,7 @@ void QWaylandXdgSurfaceV6::requestWindowStates(Qt::WindowStates states) if (m_toplevel) m_toplevel->requestWindowStates(states); else - qCWarning(lcQpaWayland) << "Non-toplevel surfaces can't request window states"; + qCDebug(lcQpaWayland) << "Ignoring window states requested by non-toplevel."; } void QWaylandXdgSurfaceV6::setToplevel() diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp index f55298134..026bb56a0 100644 --- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp +++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp @@ -377,7 +377,7 @@ void QWaylandXdgSurface::requestWindowStates(Qt::WindowStates states) if (m_toplevel) m_toplevel->requestWindowStates(states); else - qCWarning(lcQpaWayland) << "Non-toplevel surfaces can't request window states"; + qCDebug(lcQpaWayland) << "Ignoring window states requested by non-toplevel zxdg_surface_v6."; } void QWaylandXdgSurface::setToplevel() -- 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(-) (limited to 'src') 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 7f189ec10a9b3e9825dda30d3a8f86ee2e07b97f 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 --- .../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(-) (limited to 'src') diff --git a/src/compositor/compositor_api/qwaylandquickitem.cpp b/src/compositor/compositor_api/qwaylandquickitem.cpp index 62a89057a..648993fc4 100644 --- a/src/compositor/compositor_api/qwaylandquickitem.cpp +++ b/src/compositor/compositor_api/qwaylandquickitem.cpp @@ -470,7 +470,7 @@ void QWaylandQuickItem::mousePressEvent(QMouseEvent *event) return; } - if (!inputRegionContains(event->pos())) { + if (!inputRegionContains(event->localPos())) { event->ignore(); return; } @@ -482,7 +482,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(); } /*! @@ -508,7 +508,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()); @@ -545,14 +545,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(); } @@ -565,16 +565,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(); @@ -603,7 +603,7 @@ void QWaylandQuickItem::wheelEvent(QWheelEvent *event) { Q_D(QWaylandQuickItem); if (d->shouldSendInputEvents()) { - if (!inputRegionContains(event->pos())) { + if (!inputRegionContains(event->posF())) { event->ignore(); return; } @@ -656,10 +656,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(); @@ -1052,7 +1052,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 c79787e6e..a82c93f7b 100644 --- a/src/compositor/compositor_api/qwaylandsurface.cpp +++ b/src/compositor/compositor_api/qwaylandsurface.cpp @@ -67,6 +67,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -706,6 +707,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 667f911c3..48b69fe21 100644 --- a/src/compositor/compositor_api/qwaylandsurface.h +++ b/src/compositor/compositor_api/qwaylandsurface.h @@ -130,6 +130,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 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(-) (limited to 'src') 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 From 195c8c22d6111150f2135c68a6d5d62adccfd844 Mon Sep 17 00:00:00 2001 From: David Edmundson Date: Sat, 7 Sep 2019 11:41:49 +0200 Subject: Client: Disable key repeating when rate is set to 0 From the docs of repeat_info: "A rate of zero will disable any repeating (regardless of the value of delay)." Avoiding starting the initial timer effectively disables everything Change-Id: I7489f61b2bc0e000efddb4255f1968072eeff2b8 Reviewed-by: Johan Helsing --- src/client/qwaylandinputdevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp index b5c18a074..9ceb222d9 100644 --- a/src/client/qwaylandinputdevice.cpp +++ b/src/client/qwaylandinputdevice.cpp @@ -896,7 +896,7 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time, QEvent::Type type = isDown ? QEvent::KeyPress : QEvent::KeyRelease; handleKey(time, type, qtkey, modifiers, code, sym, mNativeModifiers, text); - if (state == WL_KEYBOARD_KEY_STATE_PRESSED && xkb_keymap_key_repeats(mXkbKeymap.get(), code)) { + if (state == WL_KEYBOARD_KEY_STATE_PRESSED && xkb_keymap_key_repeats(mXkbKeymap.get(), code) && mRepeatRate > 0) { mRepeatKey.key = qtkey; mRepeatKey.code = code; mRepeatKey.time = time; -- cgit v1.2.3 From b1a534a536892035fdf1e826a066bda6ab34b93a Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Wed, 4 Sep 2019 11:47:13 +0200 Subject: Client: Fix touch rounding errors Touch now accounts for fractional input in the same way as for pointer input. Task-number: QTBUG-77457 Change-Id: I18e633bf7c7033187a641f757b8b24f52479971a Reviewed-by: Paul Olav Tvete --- src/client/qwaylandinputdevice.cpp | 18 ++++++++++++------ src/client/qwaylandinputdevice_p.h | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp index 731285eab..8f3df8e4d 100644 --- a/src/client/qwaylandinputdevice.cpp +++ b/src/client/qwaylandinputdevice.cpp @@ -987,14 +987,15 @@ void QWaylandInputDevice::Touch::touch_down(uint32_t serial, mParent->mSerial = serial; mFocus = window; mParent->mQDisplay->setLastInputDevice(mParent, serial, mFocus); - mParent->handleTouchPoint(id, wl_fixed_to_double(x), wl_fixed_to_double(y), Qt::TouchPointPressed); + QPointF position(wl_fixed_to_double(x), wl_fixed_to_double(y)); + mParent->handleTouchPoint(id, Qt::TouchPointPressed, position); } void QWaylandInputDevice::Touch::touch_up(uint32_t serial, uint32_t time, int32_t id) { Q_UNUSED(serial); Q_UNUSED(time); - mParent->handleTouchPoint(id, 0, 0, Qt::TouchPointReleased); + mParent->handleTouchPoint(id, Qt::TouchPointReleased); if (allTouchPointsReleased()) { mFocus = nullptr; @@ -1013,7 +1014,8 @@ void QWaylandInputDevice::Touch::touch_up(uint32_t serial, uint32_t time, int32_ void QWaylandInputDevice::Touch::touch_motion(uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y) { Q_UNUSED(time); - mParent->handleTouchPoint(id, wl_fixed_to_double(x), wl_fixed_to_double(y), Qt::TouchPointMoved); + QPointF position(wl_fixed_to_double(x), wl_fixed_to_double(y)); + mParent->handleTouchPoint(id, Qt::TouchPointMoved, position); } void QWaylandInputDevice::Touch::touch_cancel() @@ -1027,7 +1029,7 @@ void QWaylandInputDevice::Touch::touch_cancel() QWindowSystemInterface::handleTouchCancelEvent(nullptr, mParent->mTouchDevice); } -void QWaylandInputDevice::handleTouchPoint(int id, double x, double y, Qt::TouchPointState state) +void QWaylandInputDevice::handleTouchPoint(int id, Qt::TouchPointState state, const QPointF &surfacePosition) { auto end = mTouch->mPendingTouchPoints.end(); auto it = std::find_if(mTouch->mPendingTouchPoints.begin(), end, [id](auto tp){ return tp.id == id; }); @@ -1039,7 +1041,6 @@ void QWaylandInputDevice::handleTouchPoint(int id, double x, double y, Qt::Touch // 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; @@ -1053,7 +1054,12 @@ void QWaylandInputDevice::handleTouchPoint(int id, double x, double y, Qt::Touch tp.area = QRectF(0, 0, 8, 8); QMargins margins = win->frameMargins(); - tp.area.moveCenter(win->window()->mapToGlobal(QPoint(x - margins.left(), y - margins.top()))); + QPointF localPosition = surfacePosition - QPointF(margins.left(), margins.top()); + // TODO: This doesn't account for high dpi scaling for the delta, but at least it matches + // what we have for mouse input. + QPointF delta = localPosition - localPosition.toPoint(); + QPointF globalPosition = win->window()->mapToGlobal(localPosition.toPoint()) + delta; + tp.area.moveCenter(globalPosition); } tp.state = state; diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h index b0b022161..143e11220 100644 --- a/src/client/qwaylandinputdevice_p.h +++ b/src/client/qwaylandinputdevice_p.h @@ -167,7 +167,7 @@ private: uint32_t mSerial = 0; void seat_capabilities(uint32_t caps) override; - void handleTouchPoint(int id, double x, double y, Qt::TouchPointState state); + void handleTouchPoint(int id, Qt::TouchPointState state, const QPointF &surfacePosition = QPoint()); QTouchDevice *mTouchDevice = nullptr; -- cgit v1.2.3 From 7f336791cea0fa7a039703e9d8a884afc69c6070 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Wed, 11 Sep 2019 13:49:09 +0200 Subject: If egl_x11 is not available then don't turn on xcomposite-egl Since xcomposite-egl depends on the egl_x11 feature in qtbase, then this should be explicit. Change-Id: Ic1dce9526fb50f6f56e18abd58b69bcaed6d204e Reviewed-by: Paul Olav Tvete --- src/client/configure.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/configure.json b/src/client/configure.json index 7feeee4bf..91024c9d3 100644 --- a/src/client/configure.json +++ b/src/client/configure.json @@ -135,7 +135,7 @@ }, "xcomposite-egl": { "label": "XComposite EGL", - "condition": "features.wayland-client && features.opengl && features.egl && features.xlib && libs.xcomposite", + "condition": "features.wayland-client && features.opengl && features.egl && features.xlib && libs.xcomposite && features.egl_x11", "output": [ "privateFeature" ] }, "xcomposite-glx": { -- cgit v1.2.3 From 382e3292aa0eb6addac84ddefeedc98c7f3b41b2 Mon Sep 17 00:00:00 2001 From: Yuya Nishihara Date: Thu, 4 Jul 2019 15:43:23 +0900 Subject: Fix detection of wayland-kms support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We get around the "private" symbol found in wayland-kms.h by substituting it with "priv", but doing that breaks the "private:" keyword in type_traits.h. So this patch forcibly includes math.h prior to s/private/priv/. main.cpp:3:17: error: ‘priv’ does not name a type #define private priv ^ In file included from /opt/poky-agl/5.0.3/sysroots/aarch64-agl-linux/usr/include/c++/6.3.0/cmath:43:0, from /opt/poky-agl/5.0.3/sysroots/aarch64-agl-linux/usr/include/c++/6.3.0/math.h:36, from /opt/poky-agl/5.0.3/sysroots/aarch64-agl-linux/usr/include/wayland-util.h:34, from /opt/poky-agl/5.0.3/sysroots/aarch64-agl-linux/usr/include/wayland-server-core.h:32, from /opt/poky-agl/5.0.3/sysroots/aarch64-agl-linux/usr/include/wayland-kms.h:38, from main.cpp:4: /opt/poky-agl/5.0.3/sysroots/aarch64-agl-linux/usr/include/c++/6.3.0/ext/type_traits.h:71:24: error: ‘__if_type’ has not been declared typedef typename __if_type::__type __type; ^~~~~~~~~ main.cpp:3:17: error: ‘priv’ does not name a type #define private priv ^ In file included from /opt/poky-agl/5.0.3/sysroots/aarch64-agl-linux/usr/include/c++/6.3.0/cmath:43:0, from /opt/poky-agl/5.0.3/sysroots/aarch64-agl-linux/usr/include/c++/6.3.0/math.h:36, from /opt/poky-agl/5.0.3/sysroots/aarch64-agl-linux/usr/include/wayland-util.h:34, from /opt/poky-agl/5.0.3/sysroots/aarch64-agl-linux/usr/include/wayland-server-core.h:32, from /opt/poky-agl/5.0.3/sysroots/aarch64-agl-linux/usr/include/wayland-kms.h:38, from main.cpp:4: /opt/poky-agl/5.0.3/sysroots/aarch64-agl-linux/usr/include/c++/6.3.0/ext/type_traits.h:114:24: error: ‘__if_type’ has not been declared typedef typename __if_type::__type __type; ^~~~~~~~~ Change-Id: I2b42f37d5565833adcc065725119ab4912da82b0 Reviewed-by: Johan Helsing --- src/compositor/configure.json | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/compositor/configure.json b/src/compositor/configure.json index 85dc91cdb..5d8fe8dda 100644 --- a/src/compositor/configure.json +++ b/src/compositor/configure.json @@ -28,6 +28,7 @@ "test": { "tail": [ "extern \"C\" {", + "#include /* may fail because of 'private:' in c++ type_traits.h */", "#define private priv", "#include ", "#undef private", -- cgit v1.2.3