diff options
Diffstat (limited to 'tests/auto/quick/qquickwindow/tst_qquickwindow.cpp')
-rw-r--r-- | tests/auto/quick/qquickwindow/tst_qquickwindow.cpp | 685 |
1 files changed, 478 insertions, 207 deletions
diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index 05fda64654..1e2553c107 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -1,33 +1,9 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <qtest.h> #include <QDebug> +#include <QEvent> #include <QMimeData> #include <QTouchEvent> #include <QtQuick/QQuickItem> @@ -38,9 +14,9 @@ #include <QtQuick/private/qquickrectangle_p.h> #include <QtQuick/private/qquickloader_p.h> #include <QtQuick/private/qquickmousearea_p.h> -#include "../../shared/util.h" -#include "../shared/visualtestutil.h" -#include "../shared/viewtestutil.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> +#include <QtQuickTestUtils/private/visualtestutils_p.h> +#include <QtQuickTestUtils/private/viewtestutils_p.h> #include <QSignalSpy> #include <private/qquickwindow_p.h> #include <private/qguiapplication_p.h> @@ -50,7 +26,8 @@ #include <QQuickRenderControl> #include <QOperatingSystemVersion> #include <functional> -#include <QtGui/private/qrhi_p.h> +#include <QtGui/private/qeventpoint_p.h> +#include <rhi/qrhi.h> #if QT_CONFIG(opengl) #include <QOpenGLContext> #endif @@ -68,16 +45,16 @@ struct TouchEventData { QList<QEventPoint> touchPoints; }; -static QMutableEventPoint makeTouchPoint(QQuickItem *item, const QPointF &p, const QPointF &lastPoint = QPointF()) +static QEventPoint makeTouchPoint(QQuickItem *item, const QPointF &p, const QPointF &lastPoint = QPointF()) { QPointF last = lastPoint.isNull() ? p : lastPoint; - QMutableEventPoint tp; + QEventPoint tp; - tp.setPosition(p); - tp.setScenePosition(item->mapToScene(p)); - tp.setGlobalPosition(item->mapToGlobal(p)); - tp.setGlobalLastPosition(item->mapToGlobal(last)); + QMutableEventPoint::setPosition(tp, p); + QMutableEventPoint::setScenePosition(tp, item->mapToScene(p)); + QMutableEventPoint::setGlobalPosition(tp, item->mapToGlobal(p)); + QMutableEventPoint::setGlobalLastPosition(tp, item->mapToGlobal(last)); return tp; } @@ -86,7 +63,7 @@ static TouchEventData makeTouchData(QEvent::Type type, QWindow *w, QEventPoint:: { TouchEventData d = { type, nullptr, w, states, touchPoints }; for (auto &pt : d.touchPoints) - QMutableEventPoint::from(pt).detach(); + QMutableEventPoint::detach(pt); return d; } static TouchEventData makeTouchData(QEvent::Type type, QWindow *w, QEventPoint::States states, @@ -211,7 +188,8 @@ public: QPointF lastMousePos; QInputDevice::Capabilities lastMouseCapabilityFlags; - void touchEvent(QTouchEvent *event) { + void touchEvent(QTouchEvent *event) override + { if (!acceptTouchEvents) { event->ignore(); return; @@ -229,7 +207,8 @@ public: } } - void mousePressEvent(QMouseEvent *e) { + void mousePressEvent(QMouseEvent *e) override + { if (!acceptMouseEvents) { e->ignore(); return; @@ -239,7 +218,8 @@ public: lastMouseCapabilityFlags = e->device()->capabilities(); } - void mouseMoveEvent(QMouseEvent *e) { + void mouseMoveEvent(QMouseEvent *e) override + { if (!acceptMouseEvents) { e->ignore(); return; @@ -250,7 +230,8 @@ public: lastMousePos = e->position().toPoint(); } - void mouseReleaseEvent(QMouseEvent *e) { + void mouseReleaseEvent(QMouseEvent *e) override + { if (!acceptMouseEvents) { e->ignore(); return; @@ -260,12 +241,14 @@ public: lastMouseCapabilityFlags = e->device()->capabilities(); } - void mouseUngrabEvent() { + void mouseUngrabEvent() override + { qCDebug(lcTests) << objectName(); ++mouseUngrabEventCount; } - bool childMouseEventFilter(QQuickItem *item, QEvent *e) { + bool childMouseEventFilter(QQuickItem *item, QEvent *e) override + { qCDebug(lcTests) << objectName() << "filtering" << e << "ahead of delivery to" << item->metaObject()->className() << item->objectName(); switch (e->type()) { case QEvent::MouseButtonPress: @@ -295,7 +278,8 @@ int TestTouchItem::mouseReleaseNum = 0; class EventFilter : public QObject { public: - bool eventFilter(QObject *watched, QEvent *event) { + bool eventFilter(QObject *watched, QEvent *event) override + { Q_UNUSED(watched); events.append(event->type()); return false; @@ -312,37 +296,76 @@ public: int iterations; protected: - QSGNode* updatePaintNode(QSGNode *, UpdatePaintNodeData *){ + QSGNode* updatePaintNode(QSGNode *, UpdatePaintNodeData *) override + { iterations++; update(); return nullptr; } }; -class MouseRecordingWindow : public QQuickWindow +class PointerRecordingWindow : public QQuickWindow { public: - explicit MouseRecordingWindow(QWindow *parent = nullptr) : QQuickWindow(parent) { } + explicit PointerRecordingWindow(QWindow *parent = nullptr) : QQuickWindow(parent) { } protected: + bool event(QEvent *event) override { + if (event->isPointerEvent()) { + qCDebug(lcTests) << event; + m_events << PointerEvent { event->type(), static_cast<QPointerEvent *>(event)->pointingDevice() }; + } + return QQuickWindow::event(event); + } + void mousePressEvent(QMouseEvent *event) override { qCDebug(lcTests) << event; - m_mouseEvents << event->source(); + m_mouseEvents << PointerEvent { event->type(), event->pointingDevice() }; QQuickWindow::mousePressEvent(event); } void mouseMoveEvent(QMouseEvent *event) override { qCDebug(lcTests) << event; - m_mouseEvents << event->source(); + m_mouseEvents << PointerEvent { event->type(), event->pointingDevice() }; QQuickWindow::mouseMoveEvent(event); } void mouseReleaseEvent(QMouseEvent *event) override { qCDebug(lcTests) << event; - m_mouseEvents << event->source(); + m_mouseEvents << PointerEvent { event->type(), event->pointingDevice() }; QQuickWindow::mouseReleaseEvent(event); } + void touchEvent(QTouchEvent * event) override { + qCDebug(lcTests) << event; + m_touchEvents << PointerEvent { event->type(), event->pointingDevice() }; + QQuickWindow::touchEvent(event); + } + +#if QT_CONFIG(tabletevent) + void tabletEvent(QTabletEvent * event) override { + qCDebug(lcTests) << event; + m_tabletEvents << PointerEvent { event->type(), event->pointingDevice() }; + QQuickWindow::tabletEvent(event); + } +#endif + +#if QT_CONFIG(wheelevent) + void wheelEvent(QWheelEvent * event) override { + qCDebug(lcTests) << event; + m_tabletEvents << PointerEvent { event->type(), event->pointingDevice() }; + QQuickWindow::wheelEvent(event); + } +#endif + public: - QList<Qt::MouseEventSource> m_mouseEvents; + struct PointerEvent + { + QEvent::Type type; + const QPointingDevice *device; + }; + QList<PointerEvent> m_events; + QList<PointerEvent> m_mouseEvents; + QList<PointerEvent> m_touchEvents; + QList<PointerEvent> m_tabletEvents; }; class MouseRecordingItem : public QQuickItem @@ -394,14 +417,19 @@ class tst_qquickwindow : public QQmlDataTest Q_OBJECT public: tst_qquickwindow() - : touchDevice(QTest::createTouchDevice()) + : QQmlDataTest(QT_QMLTEST_DATADIR) + , touchDevice(QTest::createTouchDevice()) , touchDeviceWithVelocity(QTest::createTouchDevice(QInputDevice::DeviceType::TouchScreen, QInputDevice::Capability::Position | QPointingDevice::Capability::Velocity)) + , tabletStylusDevice(QPointingDevicePrivate::tabletDevice(QInputDevice::DeviceType::Stylus, + QPointingDevice::PointerType::Pen, + QPointingDeviceUniqueId::fromNumericId(1234567890))) { QQuickWindow::setDefaultAlphaBuffer(true); } private slots: + void initTestCase() override; void cleanup(); void aboutToStopSignal(); @@ -438,6 +466,7 @@ private slots: void grab_data(); void grab(); + void earlyGrab(); void multipleWindows(); void animationsWhileHidden(); @@ -501,8 +530,13 @@ private slots: void testChildMouseEventFilter_data(); void cleanupGrabsOnRelease(); + void subclassWithPointerEventVirtualOverrides_data(); + void subclassWithPointerEventVirtualOverrides(); + #if QT_CONFIG(shortcut) void testShortCut(); + void shortcutOverride_data(); + void shortcutOverride(); #endif void rendererInterface(); @@ -510,15 +544,38 @@ private slots: void rendererInterfaceWithRenderControl_data(); void rendererInterfaceWithRenderControl(); + void graphicsConfiguration(); + + void visibleVsVisibility_data(); + void visibleVsVisibility(); + + void eventTypes(); + private: - QPointingDevice *touchDevice; - QPointingDevice *touchDeviceWithVelocity; + QPointingDevice *touchDevice; // TODO make const after fixing QTBUG-107864 + const QPointingDevice *touchDeviceWithVelocity; + const QPointingDevice *tabletStylusDevice; }; #if QT_CONFIG(opengl) Q_DECLARE_METATYPE(QOpenGLContext *); #endif +void tst_qquickwindow::initTestCase() +{ + // for the graphicsConfiguration test + qunsetenv("QSG_NO_DEPTH_BUFFER"); + qunsetenv("QSG_RHI_DEBUG_LAYER"); + qunsetenv("QSG_RHI_PROFILE"); + qunsetenv("QSG_RHI_PREFER_SOFTWARE_RENDERER"); + qunsetenv("QT_DISABLE_SHADER_DISK_CACHE"); + qunsetenv("QSG_RHI_DISABLE_DISK_CACHE"); + qunsetenv("QSG_RHI_PIPELINE_CACHE_SAVE"); + qunsetenv("QSG_RHI_PIPELINE_CACHE_LOAD"); + + QQmlDataTest::initTestCase(); +} + void tst_qquickwindow::cleanup() { QVERIFY(QGuiApplication::topLevelWindows().isEmpty()); @@ -535,7 +592,7 @@ void tst_qquickwindow::aboutToStopSignal() window.hide(); - QTRY_VERIFY(spy.count() > 0); + QTRY_VERIFY(spy.size() > 0); } //If the item calls update inside updatePaintNode, it should schedule another sync pass @@ -551,8 +608,8 @@ void tst_qquickwindow::constantUpdates() QSignalSpy afterSpy(&window, SIGNAL(afterSynchronizing())); QTRY_VERIFY(item.iterations > 10); - QTRY_VERIFY(beforeSpy.count() > 10); - QTRY_VERIFY(afterSpy.count() > 10); + QTRY_VERIFY(beforeSpy.size() > 10); + QTRY_VERIFY(afterSpy.size() > 10); } void tst_qquickwindow::constantUpdatesOnWindow_data() @@ -653,7 +710,7 @@ void tst_qquickwindow::touchEvent_basic() // press single point touchSeq.press(0, topItem->mapToScene(pos).toPoint(),window).commit(); QQuickTouchUtils::flush(window); - QTRY_COMPARE(topItem->lastEvent.touchPoints.count(), 1); + QTRY_COMPARE(topItem->lastEvent.touchPoints.size(), 1); QVERIFY(middleItem->lastEvent.touchPoints.isEmpty()); QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty()); @@ -667,9 +724,9 @@ void tst_qquickwindow::touchEvent_basic() touchSeq.press(0, topItem->mapToScene(pos).toPoint(), window) .press(1, bottomItem->mapToScene(pos).toPoint(), window).commit(); QQuickTouchUtils::flush(window); - QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); + QCOMPARE(topItem->lastEvent.touchPoints.size(), 1); QVERIFY(middleItem->lastEvent.touchPoints.isEmpty()); - QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1); + QCOMPARE(bottomItem->lastEvent.touchPoints.size(), 1); COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, QEventPoint::State::Pressed, makeTouchPoint(topItem, pos))); COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, QEventPoint::State::Pressed, makeTouchPoint(bottomItem, pos))); topItem->reset(); @@ -681,7 +738,7 @@ void tst_qquickwindow::touchEvent_basic() QQuickTouchUtils::flush(window); touchSeq.move(0, bottomItem->mapToScene(pos).toPoint(), window).commit(); QQuickTouchUtils::flush(window); - QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); + QCOMPARE(topItem->lastEvent.touchPoints.size(), 1); COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchUpdate, window, QEventPoint::State::Updated, makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos))); topItem->reset(); @@ -692,7 +749,7 @@ void tst_qquickwindow::touchEvent_basic() QQuickTouchUtils::flush(window); touchSeq.move(0, topItem->mapToScene(pos).toPoint(), window).commit(); QQuickTouchUtils::flush(window); - QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1); + QCOMPARE(bottomItem->lastEvent.touchPoints.size(), 1); COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchUpdate, window, QEventPoint::State::Updated, makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos), pos))); bottomItem->reset(); @@ -704,9 +761,9 @@ void tst_qquickwindow::touchEvent_basic() touchSeq.stationary(0) .press(1, bottomItem->mapToScene(pos).toPoint(), window).commit(); QQuickTouchUtils::flush(window); - QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); // received press and then stationary + QCOMPARE(topItem->lastEvent.touchPoints.size(), 1); // received press and then stationary QVERIFY(middleItem->lastEvent.touchPoints.isEmpty()); - QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1); + QCOMPARE(bottomItem->lastEvent.touchPoints.size(), 1); COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchUpdate, window, QEventPoint::State::Stationary, makeTouchPoint(topItem, pos))); COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, QEventPoint::State::Pressed, makeTouchPoint(bottomItem, pos))); topItem->reset(); @@ -722,7 +779,7 @@ void tst_qquickwindow::touchEvent_basic() QQuickTouchUtils::flush(window); touchSeq.release(0, bottomItem->mapToScene(pos).toPoint(),window).commit(); QQuickTouchUtils::flush(window); - QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); + QCOMPARE(topItem->lastEvent.touchPoints.size(), 1); COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchEnd, window, QEventPoint::State::Released, makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos))); topItem->reset(); @@ -736,9 +793,9 @@ void tst_qquickwindow::touchEvent_basic() touchSeq.release(0, bottomItem->mapToScene(pos).toPoint(), window) .stationary(1).commit(); QQuickTouchUtils::flush(window); - QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); + QCOMPARE(topItem->lastEvent.touchPoints.size(), 1); QVERIFY(middleItem->lastEvent.touchPoints.isEmpty()); - QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1); + QCOMPARE(bottomItem->lastEvent.touchPoints.size(), 1); // Since qtbase 2692237bb1b0c0f50b7cc5d920eb8ab065063d47, if the point didn't have a different position on release, // then lastPosition is not changed. So in this case, it still holds the press position. I.e. on release, // it's the last position that was actually different. @@ -799,7 +856,7 @@ void tst_qquickwindow::touchEvent_propagation() // single touch to top item, should be received by middle item QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window); - QTRY_COMPARE(middleItem->lastEvent.touchPoints.count(), 1); + QTRY_COMPARE(middleItem->lastEvent.touchPoints.size(), 1); QVERIFY(topItem->lastEvent.touchPoints.isEmpty()); QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty()); COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, QEventPoint::State::Pressed, @@ -809,7 +866,7 @@ void tst_qquickwindow::touchEvent_propagation() // touch top and middle items, middle item should get both events QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window) .press(1, pointInMiddleItem, window); - QTRY_COMPARE(middleItem->lastEvent.touchPoints.count(), 2); + QTRY_COMPARE(middleItem->lastEvent.touchPoints.size(), 2); QVERIFY(topItem->lastEvent.touchPoints.isEmpty()); QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty()); COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, QEventPoint::State::Pressed, @@ -828,7 +885,7 @@ void tst_qquickwindow::touchEvent_propagation() // touch top and middle items, bottom item should get all events QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window) .press(1, pointInMiddleItem, window); - QTRY_COMPARE(bottomItem->lastEvent.touchPoints.count(), 2); + QTRY_COMPARE(bottomItem->lastEvent.touchPoints.size(), 2); QVERIFY(topItem->lastEvent.touchPoints.isEmpty()); QVERIFY(middleItem->lastEvent.touchPoints.isEmpty()); COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, QEventPoint::State::Pressed, @@ -868,12 +925,12 @@ void tst_qquickwindow::touchEvent_propagation() // middle item is disabled or has 0 opacity, bottom item receives the event QVERIFY(topItem->lastEvent.touchPoints.isEmpty()); QVERIFY(middleItem->lastEvent.touchPoints.isEmpty()); - QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1); + QCOMPARE(bottomItem->lastEvent.touchPoints.size(), 1); COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, QEventPoint::State::Pressed, makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos)))); } else { // middle item ignores event, sends it to the top item (top-most child) - QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); + QCOMPARE(topItem->lastEvent.touchPoints.size(), 1); QVERIFY(middleItem->lastEvent.touchPoints.isEmpty()); QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty()); COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, QEventPoint::State::Pressed, @@ -919,7 +976,7 @@ void tst_qquickwindow::touchEvent_cancel() QTest::touchEvent(window, touchDevice).press(0, item->mapToScene(pos).toPoint(), window); QCoreApplication::processEvents(); - QTRY_COMPARE(item->lastEvent.touchPoints.count(), 1); + QTRY_COMPARE(item->lastEvent.touchPoints.size(), 1); TouchEventData d = makeTouchData(QEvent::TouchBegin, window, QEventPoint::State::Pressed, makeTouchPoint(item, pos)); COMPARE_TOUCH_DATA(item->lastEvent, d); item->reset(); @@ -1020,13 +1077,13 @@ void tst_qquickwindow::touchEvent_velocity() item->setPosition(QPointF(50, 50)); item->setSize(QSizeF(150, 150)); - QList<QMutableEventPoint> points; - QMutableEventPoint tp(1, QEventPoint::State::Pressed); + QList<QEventPoint> points; + QEventPoint tp(1, QEventPoint::State::Pressed, {}, {}); const QPointF localPos = item->mapToScene(QPointF(10, 10)); const QPointF screenPos = window->mapToGlobal(localPos.toPoint()); - tp.setPosition(localPos); - tp.setGlobalPosition(screenPos); - tp.setEllipseDiameters(QSizeF(4, 4)); + QMutableEventPoint::setPosition(tp, localPos); + QMutableEventPoint::setGlobalPosition(tp, screenPos); + QMutableEventPoint::setEllipseDiameters(tp, QSizeF(4, 4)); points << tp; QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window)); @@ -1034,17 +1091,17 @@ void tst_qquickwindow::touchEvent_velocity() QQuickTouchUtils::flush(window); QCOMPARE(item->touchEventCount, 1); - points[0].setState(QEventPoint::State::Updated); - points[0].setPosition(localPos + QPointF(5, 5)); - points[0].setGlobalPosition(screenPos + QPointF(5, 5)); + QMutableEventPoint::setState(points[0], QEventPoint::State::Updated); + QMutableEventPoint::setPosition(points[0], localPos + QPointF(5, 5)); + QMutableEventPoint::setGlobalPosition(points[0], screenPos + QPointF(5, 5)); QVector2D velocity(1.5, 2.5); - points[0].setVelocity(velocity); + QMutableEventPoint::setVelocity(points[0], velocity); QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window)); QGuiApplication::processEvents(); QQuickTouchUtils::flush(window); QCOMPARE(item->touchEventCount, 2); - QCOMPARE(item->lastEvent.touchPoints.count(), 1); + QCOMPARE(item->lastEvent.touchPoints.size(), 1); QCOMPARE(item->lastVelocity, velocity); // Now have a transformation on the item and check if position is transformed accordingly. @@ -1052,8 +1109,8 @@ void tst_qquickwindow::touchEvent_velocity() // during delivery. If we want it to be transformed, we should add QEventPoint::sceneVelocity // so that we can keep transforming it repeatedly during Item-localization.) item->setRotation(90); // clockwise - points[0].setPosition(points[0].position() + QPointF(5, 5)); - points[0].setGlobalPosition(points[0].globalPosition() + QPointF(5, 5)); + QMutableEventPoint::setPosition(points[0], points[0].position() + QPointF(5, 5)); + QMutableEventPoint::setGlobalPosition(points[0], points[0].globalPosition() + QPointF(5, 5)); QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window)); QGuiApplication::processEvents(); @@ -1063,7 +1120,7 @@ void tst_qquickwindow::touchEvent_velocity() QPoint itemLocalPosFromEvent = item->lastEvent.touchPoints[0].position().toPoint(); QCOMPARE(itemLocalPos, itemLocalPosFromEvent); - points[0].setState(QEventPoint::State::Released); + QMutableEventPoint::setState(points[0], QEventPoint::State::Released); QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window)); QGuiApplication::processEvents(); @@ -1160,28 +1217,28 @@ void tst_qquickwindow::mouseFromTouch_basic() // the first point in each touch event should generate a synth-mouse event. item->setAcceptTouchEvents(false); - QList<QMutableEventPoint> points; - QMutableEventPoint tp(1, QEventPoint::State::Pressed); + QList<QEventPoint> points; + QEventPoint tp(1, QEventPoint::State::Pressed, {}, {}); const QPointF localPos = item->mapToScene(QPointF(10, 10)); const QPointF screenPos = window->mapToGlobal(localPos.toPoint()); - tp.setPosition(localPos); - tp.setGlobalPosition(screenPos); - tp.setEllipseDiameters(QSizeF(4, 4)); + QMutableEventPoint::setPosition(tp, localPos); + QMutableEventPoint::setGlobalPosition(tp, screenPos); + QMutableEventPoint::setEllipseDiameters(tp, QSizeF(4, 4)); points << tp; QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window)); QGuiApplication::processEvents(); QQuickTouchUtils::flush(window); - points[0].setState(QEventPoint::State::Updated); - points[0].setPosition(localPos + QPointF(5, 5)); - points[0].setGlobalPosition(screenPos + QPointF(5, 5)); + QMutableEventPoint::setState(points[0], QEventPoint::State::Updated); + QMutableEventPoint::setPosition(points[0], localPos + QPointF(5, 5)); + QMutableEventPoint::setGlobalPosition(points[0], screenPos + QPointF(5, 5)); QVector2D velocity(1.5, 2.5); - points[0].setVelocity(velocity); + QMutableEventPoint::setVelocity(points[0], velocity); QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window)); QGuiApplication::processEvents(); QQuickTouchUtils::flush(window); - points[0].setState(QEventPoint::State::Released); + QMutableEventPoint::setState(points[0], QEventPoint::State::Released); QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window)); QGuiApplication::processEvents(); @@ -1195,19 +1252,20 @@ void tst_qquickwindow::mouseFromTouch_basic() QCOMPARE(item->lastVelocityFromMouseMove, velocity); // QVERIFY(item->lastMouseCapabilityFlags.testFlag(QInputDevice::Capability::Velocity)); // TODO + QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); // avoid generating a double-click // Now the same with a transformation. item->setRotation(90); // clockwise - points[0].setState(QEventPoint::State::Pressed); - points[0].setVelocity(velocity); - tp.setPosition(localPos); - tp.setGlobalPosition(screenPos); + QMutableEventPoint::setState(points[0], QEventPoint::State::Pressed); + QMutableEventPoint::setVelocity(points[0], velocity); + QMutableEventPoint::setPosition(tp, localPos); + QMutableEventPoint::setGlobalPosition(tp, screenPos); QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window)); QGuiApplication::processEvents(); QQuickTouchUtils::flush(window); - points[0].setState(QEventPoint::State::Updated); - points[0].setPosition(localPos + QPointF(5, 5)); - points[0].setGlobalPosition(screenPos + QPointF(5, 5)); + QMutableEventPoint::setState(points[0], QEventPoint::State::Updated); + QMutableEventPoint::setPosition(points[0], localPos + QPointF(5, 5)); + QMutableEventPoint::setGlobalPosition(points[0], screenPos + QPointF(5, 5)); QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window)); QGuiApplication::processEvents(); @@ -1215,7 +1273,7 @@ void tst_qquickwindow::mouseFromTouch_basic() QCOMPARE(item->lastMousePos.toPoint(), item->mapFromScene(points[0].position()).toPoint()); QCOMPARE(item->lastVelocityFromMouseMove, velocity); // Velocity is always in scene coords - points[0].setState(QEventPoint::State::Released); + QMutableEventPoint::setState(points[0], QEventPoint::State::Released); QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window)); QCoreApplication::processEvents(); @@ -1240,7 +1298,7 @@ void tst_qquickwindow::synthMouseFromTouch() QFETCH(bool, acceptTouch); QCoreApplication::setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, synthMouse); - QScopedPointer<MouseRecordingWindow> window(new MouseRecordingWindow); + QScopedPointer<PointerRecordingWindow> window(new PointerRecordingWindow); QScopedPointer<MouseRecordingItem> item(new MouseRecordingItem(acceptTouch, nullptr)); item->setParentItem(window->contentItem()); window->resize(250, 250); @@ -1258,9 +1316,9 @@ void tst_qquickwindow::synthMouseFromTouch() QTest::touchEvent(window.data(), touchDevice).release(0, p2, window.data()); QQuickTouchUtils::flush(window.data()); - QCOMPARE(item->m_touchEvents.count(), acceptTouch ? 3 : 0); - QCOMPARE(item->m_mouseEvents.count(), (acceptTouch || !synthMouse) ? 0 : 3); - QCOMPARE(window->m_mouseEvents.count(), 0); + QCOMPARE(item->m_touchEvents.size(), acceptTouch ? 3 : 0); + QCOMPARE(item->m_mouseEvents.size(), (acceptTouch || !synthMouse) ? 0 : 3); + QCOMPARE(window->m_mouseEvents.size(), 0); for (const auto &ev : item->m_mouseEvents) QCOMPARE(ev.source, Qt::MouseEventSynthesizedByQt); } @@ -1285,7 +1343,7 @@ void tst_qquickwindow::synthMouseDoubleClickFromTouch() QFETCH(bool, expectedSynthesizedDoubleClickEvent); QCoreApplication::setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true); - QScopedPointer<MouseRecordingWindow> window(new MouseRecordingWindow); + QScopedPointer<PointerRecordingWindow> window(new PointerRecordingWindow); QScopedPointer<MouseRecordingItem> item(new MouseRecordingItem(false, nullptr)); item->setParentItem(window->contentItem()); window->resize(250, 250); @@ -1305,7 +1363,7 @@ void tst_qquickwindow::synthMouseDoubleClickFromTouch() QTest::touchEvent(window.data(), touchDevice).move(1, p2 + movement, window.data()); QTest::touchEvent(window.data(), touchDevice).release(1, p2 + movement, window.data()); - const int eventCount = item->m_mouseEvents.count(); + const int eventCount = item->m_mouseEvents.size(); QVERIFY(eventCount >= 2); const int nDoubleClicks = std::count_if(item->m_mouseEvents.constBegin(), item->m_mouseEvents.constEnd(), @@ -1518,8 +1576,7 @@ void tst_qquickwindow::grab() } QImage content = window.grabWindow(); - QCOMPARE(content.width(), int(window.width() * window.devicePixelRatio())); - QCOMPARE(content.height(), int(window.height() * window.devicePixelRatio())); + QCOMPARE(content.size(), window.size() * window.devicePixelRatio()); if (alpha) { QCOMPARE((uint) content.convertToFormat(QImage::Format_ARGB32_Premultiplied).pixel(0, 0), (uint) 0x00000000); @@ -1534,8 +1591,7 @@ void tst_qquickwindow::grab() // never was renderable before grabbing. window.hide(); QImage content = window.grabWindow(); - QCOMPARE(content.width(), int(window.width() * window.devicePixelRatio())); - QCOMPARE(content.height(), int(window.height() * window.devicePixelRatio())); + QCOMPARE(content.size(), window.size() * window.devicePixelRatio()); if (alpha) { QCOMPARE((uint) content.convertToFormat(QImage::Format_ARGB32_Premultiplied).pixel(0, 0), (uint) 0x00000000); } else { @@ -1546,8 +1602,7 @@ void tst_qquickwindow::grab() window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); content = window.grabWindow(); - QCOMPARE(content.width(), int(window.width() * window.devicePixelRatio())); - QCOMPARE(content.height(), int(window.height() * window.devicePixelRatio())); + QCOMPARE(content.size(), window.size() * window.devicePixelRatio()); if (alpha) { QCOMPARE((uint) content.convertToFormat(QImage::Format_ARGB32_Premultiplied).pixel(0, 0), (uint) 0x00000000); } else { @@ -1556,6 +1611,39 @@ void tst_qquickwindow::grab() } } +class Grabber : public QObject +{ + Q_OBJECT +public: + Q_INVOKABLE void grab(QObject *obj) { + QQuickWindow *window = qobject_cast<QQuickWindow *>(obj); + images.append(window->grabWindow()); + } + QVector<QImage> images; +}; + +void tst_qquickwindow::earlyGrab() +{ + if (QGuiApplication::platformName() == QLatin1String("minimal")) + QSKIP("Skipping due to grabWindow not functional on minimal platforms"); + + qmlRegisterType<Grabber>("Test", 1, 0, "Grabber"); + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("earlyGrab.qml")); + QScopedPointer<QQuickWindow> window(qobject_cast<QQuickWindow *>(component.create())); + QVERIFY(!window.isNull()); + window->setTitle(QTest::currentTestFunction()); + + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + Grabber *grabber = qobject_cast<Grabber *>(window->findChild<QObject *>("grabber")); + QVERIFY(grabber); + QCOMPARE(grabber->images.size(), 1); + QVERIFY(!grabber->images[0].isNull()); + QCOMPARE(grabber->images[0].convertToFormat(QImage::Format_RGBX8888).pixel(10, 20), QColor(Qt::red).rgb()); +} + void tst_qquickwindow::multipleWindows() { QList<QQuickWindow *> windows; @@ -1658,7 +1746,7 @@ void tst_qquickwindow::headless() // Verify that the visual output is the same QImage newContent = window->grabWindow(); QString errorMessage; - QVERIFY2(QQuickVisualTestUtil::compareImages(newContent, originalContent, &errorMessage), + QVERIFY2(QQuickVisualTestUtils::compareImages(newContent, originalContent, &errorMessage), qPrintable(errorMessage)); } @@ -1693,7 +1781,7 @@ void tst_qquickwindow::destroyShowWithoutHide() QImage newContent = window->grabWindow(); QString errorMessage; - QVERIFY2(QQuickVisualTestUtil::compareImages(newContent, originalContent, &errorMessage), + QVERIFY2(QQuickVisualTestUtils::compareImages(newContent, originalContent, &errorMessage), qPrintable(errorMessage)); } @@ -1719,19 +1807,19 @@ void tst_qquickwindow::focusObject() QVERIFY(QTest::qWaitForWindowActive(window)); QCOMPARE(window->contentItem(), window->focusObject()); - QCOMPARE(focusObjectSpy.count(), 1); + QCOMPARE(focusObjectSpy.size(), 1); QQuickItem *item1 = window->findChild<QQuickItem*>("item1"); QVERIFY(item1); item1->setFocus(true); QCOMPARE(item1, window->focusObject()); - QCOMPARE(focusObjectSpy.count(), 2); + QCOMPARE(focusObjectSpy.size(), 2); QQuickItem *item2 = window->findChild<QQuickItem*>("item2"); QVERIFY(item2); item2->setFocus(true); QCOMPARE(item2, window->focusObject()); - QCOMPARE(focusObjectSpy.count(), 3); + QCOMPARE(focusObjectSpy.size(), 3); // set focus for item in non-focused focus scope and // ensure focusObject does not change and signal is not emitted @@ -1739,7 +1827,7 @@ void tst_qquickwindow::focusObject() QVERIFY(item3); item3->setFocus(true); QCOMPARE(item2, window->focusObject()); - QCOMPARE(focusObjectSpy.count(), 3); + QCOMPARE(focusObjectSpy.size(), 3); } void tst_qquickwindow::focusReason() @@ -1784,24 +1872,24 @@ void tst_qquickwindow::ignoreUnhandledMouseEvents() item->setParentItem(window->contentItem()); { - QMouseEvent me(QEvent::MouseButtonPress, QPointF(50, 50), Qt::LeftButton, Qt::LeftButton, - Qt::NoModifier); + QMouseEvent me(QEvent::MouseButtonPress, QPointF(50, 50), window->mapToGlobal(QPointF(50, 50)), + Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); me.setAccepted(true); QVERIFY(QCoreApplication::sendEvent(window, &me)); QVERIFY(!me.isAccepted()); } { - QMouseEvent me(QEvent::MouseMove, QPointF(51, 51), Qt::LeftButton, Qt::LeftButton, - Qt::NoModifier); + QMouseEvent me(QEvent::MouseMove, QPointF(51, 51), window->mapToGlobal(QPointF(51, 51)), + Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); me.setAccepted(true); QVERIFY(QCoreApplication::sendEvent(window, &me)); QVERIFY(!me.isAccepted()); } { - QMouseEvent me(QEvent::MouseButtonRelease, QPointF(51, 51), Qt::LeftButton, Qt::LeftButton, - Qt::NoModifier); + QMouseEvent me(QEvent::MouseButtonRelease, QPointF(51, 51), window->mapToGlobal(QPointF(51, 51)), + Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); me.setAccepted(true); QVERIFY(QCoreApplication::sendEvent(window, &me)); QVERIFY(!me.isAccepted()); @@ -2080,6 +2168,10 @@ void tst_qquickwindow::testExpose() void tst_qquickwindow::requestActivate() { +#ifdef Q_OS_ANDROID + QSKIP("tst_qquickwindow::requestActivate crashes on Android, see QTBUG-103078."); +#endif + QQmlEngine engine; QQmlComponent component(&engine); component.loadUrl(testFileUrl("active.qml")); @@ -2106,7 +2198,7 @@ void tst_qquickwindow::requestActivate() QTRY_COMPARE(QGuiApplication::focusWindow(), window1.data()); QVERIFY(window1->isActive()); - QQuickItem *item = QQuickVisualTestUtil::findItem<QQuickItem>(window1->contentItem(), "item1"); + QQuickItem *item = QQuickVisualTestUtils::findItem<QQuickItem>(window1->contentItem(), "item1"); QVERIFY(item); //copied from src/qmltest/quicktestevent.cpp @@ -2115,18 +2207,14 @@ void tst_qquickwindow::requestActivate() { QMouseEvent me(QEvent::MouseButtonPress, pos, window1->mapToGlobal(pos), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); QSpontaneKeyEvent::setSpontaneous(&me); - if (!qApp->notify(window1.data(), &me)) { - QString warning = QString::fromLatin1("Mouse event MousePress not accepted by receiving window"); - QWARN(warning.toLatin1().data()); - } + if (!qApp->notify(window1.data(), &me)) + qWarning("Mouse event MousePress not accepted by receiving window"); } { QMouseEvent me = QMouseEvent(QEvent::MouseButtonPress, pos, window1->mapToGlobal(pos), Qt::LeftButton, {}, Qt::NoModifier); QSpontaneKeyEvent::setSpontaneous(&me); - if (!qApp->notify(window1.data(), &me)) { - QString warning = QString::fromLatin1("Mouse event MouseRelease not accepted by receiving window"); - QWARN(warning.toLatin1().data()); - } + if (!qApp->notify(window1.data(), &me)) + qWarning("Mouse event MouseRelease not accepted by receiving window"); } QTRY_COMPARE(QGuiApplication::focusWindow(), windows.at(0)); @@ -2135,6 +2223,10 @@ void tst_qquickwindow::requestActivate() void tst_qquickwindow::testWindowVisibilityOrder() { +#ifdef Q_OS_ANDROID + QSKIP("tst_qquickwindow::testWindowVisibilityOrder crashes on Android, see QTBUG-103078."); +#endif + QQmlEngine engine; QQmlComponent component(&engine); component.loadUrl(testFileUrl("windoworder.qml")); @@ -2252,6 +2344,10 @@ void tst_qquickwindow::unloadSubWindow() // QTBUG-52573 void tst_qquickwindow::changeVisibilityInCompleted() { +#ifdef Q_OS_ANDROID + QSKIP("tst_qquickwindow::changeVisibilityInCompleted crashes on Android, see QTBUG-103078."); +#endif + QQmlEngine engine; QQmlComponent component(&engine); component.loadUrl(testFileUrl("changeVisibilityInCompleted.qml")); @@ -2293,7 +2389,7 @@ void tst_qquickwindow::qobjectEventFilter_touch() // press single point QTest::touchEvent(&window, touchDevice).press(0, item->mapToScene(pos).toPoint(), &window); - QCOMPARE(eventFilter.events.count(), 1); + QCOMPARE(eventFilter.events.size(), 1); QCOMPARE(eventFilter.events.first(), (int)QEvent::TouchBegin); } @@ -2364,7 +2460,7 @@ void tst_qquickwindow::animatingSignal() window.show(); QTRY_VERIFY(window.isExposed()); - QTRY_VERIFY(spy.count() > 1); + QTRY_VERIFY(spy.size() > 1); } void tst_qquickwindow::frameSignals() @@ -2381,9 +2477,9 @@ void tst_qquickwindow::frameSignals() QSGRendererInterface *rif = window.rendererInterface(); QVERIFY(rif); - QTRY_VERIFY(beforeSpy.count() > 1); - QTRY_VERIFY(afterSpy.count() > 1); - QTRY_COMPARE(beforeSpy.count(), afterSpy.count()); + QTRY_VERIFY(beforeSpy.size() > 1); + QTRY_VERIFY(afterSpy.size() > 1); + QTRY_COMPARE(beforeSpy.size(), afterSpy.size()); } // QTBUG-36938 @@ -2513,7 +2609,8 @@ public: ~RenderJob() { ++deleted; } QQuickWindow::RenderStage stage; QList<QQuickWindow::RenderStage> *list; - void run() { + void run() override + { list->append(stage); } static int deleted; @@ -2697,9 +2794,12 @@ public: setAcceptHoverEvents(true); } - void hoverEnterEvent(QHoverEvent *event) { hoverTimestamps << event->timestamp(); } - void hoverLeaveEvent(QHoverEvent *event) { hoverTimestamps << event->timestamp(); } - void hoverMoveEvent(QHoverEvent *event) { hoverTimestamps << event->timestamp(); } + void hoverEnterEvent(QHoverEvent *event) override + { hoverTimestamps << event->timestamp(); } + void hoverLeaveEvent(QHoverEvent *event) override + { hoverTimestamps << event->timestamp(); } + void hoverMoveEvent(QHoverEvent *event) override + { hoverTimestamps << event->timestamp(); } QList<ulong> hoverTimestamps; }; @@ -2828,8 +2928,8 @@ void tst_qquickwindow::test_circleMapItem() mat->setObjectName("Top Item/MouseArea"); mat->setSize(QSizeF(40, 40)); - QSignalSpy bottomSpy(mab, SIGNAL(clicked(QQuickMouseEvent *))); - QSignalSpy topSpy(mat, SIGNAL(clicked(QQuickMouseEvent *))); + QSignalSpy bottomSpy(mab, SIGNAL(clicked(QQuickMouseEvent*))); + QSignalSpy topSpy(mat, SIGNAL(clicked(QQuickMouseEvent*))); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); @@ -2838,15 +2938,15 @@ void tst_qquickwindow::test_circleMapItem() QPoint pos(50, 50); QTest::mouseClick(&window, Qt::LeftButton, Qt::KeyboardModifiers(), pos); - QCOMPARE(topSpy.count(), 1); - QCOMPARE(bottomSpy.count(), 0); + QCOMPARE(topSpy.size(), 1); + QCOMPARE(bottomSpy.size(), 0); // Outside the "Circles" "input area", but on top of the bottomItem rectangle pos = QPoint(66, 66); QTest::mouseClick(&window, Qt::LeftButton, Qt::KeyboardModifiers(), pos); - QCOMPARE(bottomSpy.count(), 1); - QCOMPARE(topSpy.count(), 1); + QCOMPARE(bottomSpy.size(), 1); + QCOMPARE(topSpy.size(), 1); } void tst_qquickwindow::grabContentItemToImage() @@ -2892,19 +2992,19 @@ public: dropAccept = true; } - void dragEnterEvent(QDragEnterEvent *event) + void dragEnterEvent(QDragEnterEvent *event) override { event->setAccepted(enterAccept); event->setDropAction(enterDropAction); } - void dragMoveEvent(QDragMoveEvent *event) + void dragMoveEvent(QDragMoveEvent *event) override { event->setAccepted(moveAccept); event->setDropAction(moveDropAction); } - void dropEvent(QDropEvent *event) + void dropEvent(QDropEvent *event) override { event->setAccepted(dropAccept); event->setDropAction(dropDropAction); @@ -3199,57 +3299,48 @@ public: */ bool testFilterPreConditions() const { return !m_filterNotPreAccepted; } static QVector<DeliveryRecord> &deliveryList() { return m_deliveryList; } - static QSet<QEvent::Type> &includedEventTypes() + static void setExpectedDeliveryList(const QVector<DeliveryRecord> &v) { m_expectedDeliveryList = v; } + + bool isRelevant(QQuickItem *receiver, QEvent *e) { - if (m_includedEventTypes.isEmpty()) - m_includedEventTypes << QEvent::MouseButtonPress; - return m_includedEventTypes; + if (receiver->acceptTouchEvents()) + return e->type() == QEvent::TouchBegin; + return e->type() == QEvent::MouseButtonPress; } - static void setExpectedDeliveryList(const QVector<DeliveryRecord> &v) { m_expectedDeliveryList = v; } protected: bool childMouseEventFilter(QQuickItem *i, QEvent *e) override { + if (!isRelevant(i, e)) + return QQuickRectangle::childMouseEventFilter(i, e); + appendEvent(this, i, e); - switch (e->type()) { - case QEvent::MouseButtonPress: - if (!e->isAccepted()) - m_filterNotPreAccepted = true; - e->setAccepted(m_filterAccepts); - // qCDebug(lcTests) << objectName() << i->objectName(); - return m_filterReturns; - default: - break; - } - return QQuickRectangle::childMouseEventFilter(i, e); + if (!e->isAccepted()) + m_filterNotPreAccepted = true; + e->setAccepted(m_filterAccepts); + return m_filterReturns; } bool event(QEvent *e) override { + if (!isRelevant(this, e)) + QQuickRectangle::event(e); + appendEvent(nullptr, this, e); - switch (e->type()) { - case QEvent::MouseButtonPress: - // qCDebug(lcTests) << objectName(); - e->setAccepted(m_eventAccepts); - return true; - default: - break; - } - return QQuickRectangle::event(e); + e->setAccepted(m_eventAccepts); + return true; } private: static void appendEvent(QQuickItem *filter, QQuickItem *receiver, QEvent *event) { - if (includedEventTypes().contains(event->type())) { - auto record = DeliveryRecord(filter ? filter->objectName() : QString(), receiver ? receiver->objectName() : QString()); - int i = m_deliveryList.count(); - if (m_expectedDeliveryList.count() > i && m_expectedDeliveryList[i] == record) - qCDebug(lcTests).noquote().nospace() << i << ": " << record; - else - qCDebug(lcTests).noquote().nospace() << i << ": " << record - << ", expected " << (m_expectedDeliveryList.count() > i ? m_expectedDeliveryList[i].toString() : QLatin1String("nothing")) << " <---"; - m_deliveryList << record; - } + auto record = DeliveryRecord(filter ? filter->objectName() : QString(), receiver ? receiver->objectName() : QString()); + int i = m_deliveryList.size(); + if (m_expectedDeliveryList.size() > i && m_expectedDeliveryList[i] == record) + qCDebug(lcTests).noquote().nospace() << i << ": " << record; + else + qCDebug(lcTests).noquote().nospace() << i << ": " << record + << ", expected " << (m_expectedDeliveryList.size() > i ? m_expectedDeliveryList[i].toString() : QLatin1String("nothing")) << " <---"; + m_deliveryList << record; } bool m_eventAccepts; bool m_filterReturns; @@ -3259,12 +3350,10 @@ private: // list of (filtering-parent . receiver) pairs static DeliveryRecordVector m_expectedDeliveryList; static DeliveryRecordVector m_deliveryList; - static QSet<QEvent::Type> m_includedEventTypes; }; DeliveryRecordVector EventItem::m_expectedDeliveryList; DeliveryRecordVector EventItem::m_deliveryList; -QSet<QEvent::Type> EventItem::m_includedEventTypes; typedef QVector<const char*> CharStarVector; @@ -3289,11 +3378,17 @@ void tst_qquickwindow::testChildMouseEventFilter_data() // r0->r1->r2->r3 // QTest::addColumn<QPoint>("mousePos"); + QTest::addColumn<QString>("eventMode"); QTest::addColumn<InputState>("inputState"); QTest::addColumn<DeliveryRecordVector>("expectedDeliveryOrder"); - QTest::newRow("if filtered and rejected, do not deliver it to the item that filtered it") + for (const QString &eventMode : {"mouse", "touch", "touchToMouse"}) { + + #define desc(txt) qPrintable(QString("%1 events, ").arg(eventMode) + txt) + + QTest::newRow(desc("if filtered and rejected, do not deliver it to the item that filtered it")) << QPoint(100, 100) + << eventMode << InputState({ // | event() | child mouse filter // +---------+---------+---------+--------- @@ -3311,8 +3406,9 @@ void tst_qquickwindow::testChildMouseEventFilter_data() << DeliveryRecord("r1") ); - QTest::newRow("no filtering, no accepting") + QTest::newRow(desc("no filtering, no accepting")) << QPoint(100, 100) + << eventMode << InputState({ // | event() | child mouse filter // +---------+---------+---------+--------- @@ -3331,8 +3427,9 @@ void tst_qquickwindow::testChildMouseEventFilter_data() << DeliveryRecord("root") ); - QTest::newRow("all filtering, no accepting") + QTest::newRow(desc("all filtering, no accepting")) << QPoint(100, 100) + << eventMode << InputState({ // | event() | child mouse filter // +---------+---------+---------+--------- @@ -3358,8 +3455,9 @@ void tst_qquickwindow::testChildMouseEventFilter_data() ); - QTest::newRow("some filtering, no accepting") + QTest::newRow(desc("some filtering, no accepting")) << QPoint(100, 100) + << eventMode << InputState({ // | event() | child mouse filter // +---------+---------+---------+--------- @@ -3383,8 +3481,9 @@ void tst_qquickwindow::testChildMouseEventFilter_data() << DeliveryRecord("root") ); - QTest::newRow("r1 accepts") + QTest::newRow(desc("r1 accepts")) << QPoint(100, 100) + << eventMode << InputState({ // | event() | child mouse filter // +---------+---------+---------+--------- @@ -3406,8 +3505,9 @@ void tst_qquickwindow::testChildMouseEventFilter_data() << DeliveryRecord("r1") ); - QTest::newRow("r1 rejects and filters") + QTest::newRow(desc("r1 rejects and filters")) << QPoint(100, 100) + << eventMode << InputState({ // | event() | child mouse filter // +---------+---------+---------+--------- @@ -3430,12 +3530,13 @@ void tst_qquickwindow::testChildMouseEventFilter_data() << DeliveryRecord("r0") << DeliveryRecord("root") ); - + } } void tst_qquickwindow::testChildMouseEventFilter() { QFETCH(QPoint, mousePos); + QFETCH(QString, eventMode); QFETCH(InputState, inputState); QFETCH(DeliveryRecordVector, expectedDeliveryOrder); @@ -3450,21 +3551,28 @@ void tst_qquickwindow::testChildMouseEventFilter() QScopedPointer<EventFilter> rootFilter(new EventFilter); root->installEventFilter(rootFilter.data()); + const bool useMouseEvents = eventMode == "mouse"; + const bool acceptTouchEvents = eventMode == "touch"; + // Create 4 items; each item a child of the previous item. EventItem *r[4]; r[0] = new EventItem(root); r[0]->setColor(QColor(0x404040)); r[0]->setWidth(200); r[0]->setHeight(200); + r[0]->setAcceptTouchEvents(acceptTouchEvents); r[1] = new EventItem(r[0]); r[1]->setColor(QColor(0x606060)); + r[1]->setAcceptTouchEvents(acceptTouchEvents); r[2] = new EventItem(r[1]); r[2]->setColor(Qt::red); + r[2]->setAcceptTouchEvents(acceptTouchEvents); r[3] = new EventItem(r[2]); r[3]->setColor(Qt::green); + r[3]->setAcceptTouchEvents(acceptTouchEvents); for (uint i = 0; i < sizeof(r)/sizeof(EventItem*); ++i) { r[i]->setEventAccepts(inputState.r[i].eventAccepts); @@ -3481,13 +3589,17 @@ void tst_qquickwindow::testChildMouseEventFilter() DeliveryRecordVector &actualDeliveryOrder = EventItem::deliveryList(); actualDeliveryOrder.clear(); - QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, mousePos); + + if (useMouseEvents) + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, mousePos); + else + QTest::touchEvent(&window, touchDevice).press(0, mousePos, &window); // Check if event got delivered to the root item. If so, append it to the list of items the event got delivered to if (rootFilter->events.contains(QEvent::MouseButtonPress)) actualDeliveryOrder.append(DeliveryRecord("root")); - for (int i = 0; i < qMax(actualDeliveryOrder.count(), expectedDeliveryOrder.count()); ++i) { + for (int i = 0; i < qMax(actualDeliveryOrder.size(), expectedDeliveryOrder.size()); ++i) { const DeliveryRecord expectedNames = expectedDeliveryOrder.value(i); const DeliveryRecord actualNames = actualDeliveryOrder.value(i); QCOMPARE(actualNames.toString(), expectedNames.toString()); @@ -3497,8 +3609,11 @@ void tst_qquickwindow::testChildMouseEventFilter() QVERIFY(item->testFilterPreConditions()); } - // "restore" mouse state - QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, mousePos); + // "restore" mouse/touch state + if (useMouseEvents) + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, mousePos); + else + QTest::touchEvent(&window, touchDevice).release(0, mousePos, &window); } void tst_qquickwindow::cleanupGrabsOnRelease() @@ -3537,6 +3652,48 @@ void tst_qquickwindow::cleanupGrabsOnRelease() QCOMPARE(parent->mouseUngrabEventCount, 1); } +void tst_qquickwindow::subclassWithPointerEventVirtualOverrides_data() +{ + QTest::addColumn<const QPointingDevice *>("device"); + + QTest::newRow("mouse click") << QPointingDevice::primaryPointingDevice(); + QTest::newRow("touch tap") << static_cast<const QPointingDevice*>(touchDevice); // TODO QTBUG-107864 + QTest::newRow("stylus tap") << tabletStylusDevice; +} + +void tst_qquickwindow::subclassWithPointerEventVirtualOverrides() // QTBUG-97859 +{ + QFETCH(const QPointingDevice *, device); + + PointerRecordingWindow window; + window.resize(250, 250); + window.setPosition(100, 100); + window.setTitle(QTest::currentTestFunction()); + window.show(); + QVERIFY(QTest::qWaitForWindowActive(&window)); + const QPoint pos(120, 120); + + QQuickTest::pointerPress(device, &window, 0, pos); + QQuickTest::pointerRelease(device, &window, 0, pos); + + switch (device->type()) { + case QPointingDevice::DeviceType::Mouse: + QTRY_COMPARE(window.m_mouseEvents.size(), 3); // separate move before press + QCOMPARE(window.m_events.size(), 3); + break; + case QPointingDevice::DeviceType::TouchScreen: + QTRY_COMPARE(window.m_touchEvents.size(), 2); + QCOMPARE(window.m_events.size(), 2); + break; + case QPointingDevice::DeviceType::Stylus: + QTRY_COMPARE(window.m_tabletEvents.size(), 2); + QVERIFY(window.m_events.size() >= window.m_tabletEvents.size()); // tablet + synth-mouse events + break; + default: + break; + } +} + #if QT_CONFIG(shortcut) void tst_qquickwindow::testShortCut() { @@ -3559,6 +3716,39 @@ void tst_qquickwindow::testShortCut() QVERIFY(eventFilter.events.contains(int(QEvent::ShortcutOverride))); QVERIFY(window->property("received").value<bool>()); } + +void tst_qquickwindow::shortcutOverride_data() +{ + QTest::addColumn<Qt::Key>("key"); + QTest::addColumn<bool>("overridden"); + QTest::addColumn<bool>("receivedA"); + QTest::addColumn<bool>("receivedB"); + + QTest::addRow("Space") << Qt::Key_Space << false << false << false; + QTest::addRow("A") << Qt::Key_A << true << false << false; + QTest::addRow("B") << Qt::Key_B << false << false << true; +} + +void tst_qquickwindow::shortcutOverride() +{ + QFETCH(Qt::Key, key); + QFETCH(bool, overridden); + QFETCH(bool, receivedA); + QFETCH(bool, receivedB); + + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("shortcutOverride.qml")); + + QScopedPointer<QWindow> window(qobject_cast<QQuickWindow *>(component.create())); + QVERIFY(window); + QVERIFY(QTest::qWaitForWindowActive(window.get())); + + QTest::keyPress(window.get(), key); + QCOMPARE(window->property("overridden").value<bool>(), overridden); + QCOMPARE(window->property("receivedA").value<bool>(), receivedA); + QCOMPARE(window->property("receivedB").value<bool>(), receivedB); +} #endif void tst_qquickwindow::rendererInterface() @@ -3676,10 +3866,9 @@ void tst_qquickwindow::rendererInterfaceWithRenderControl_data() QTest::newRow("Vulkan") << QSGRendererInterface::VulkanRhi; #endif #ifdef Q_OS_WIN - if (QOperatingSystemVersion::current() > QOperatingSystemVersion::Windows7) - QTest::newRow("D3D11") << QSGRendererInterface::Direct3D11Rhi; + QTest::newRow("D3D11") << QSGRendererInterface::Direct3D11Rhi; #endif -#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) +#if QT_CONFIG(metal) QTest::newRow("Metal") << QSGRendererInterface::MetalRhi; #endif } @@ -3878,6 +4067,88 @@ void tst_qquickwindow::rendererInterfaceWithRenderControl() QQuickWindow::setGraphicsApi(QSGRendererInterface::Unknown); } +void tst_qquickwindow::graphicsConfiguration() +{ + QQuickGraphicsConfiguration config; + qDebug() << config; + QVERIFY(config.isDepthBufferEnabledFor2D()); + QVERIFY(!config.isDebugLayerEnabled()); + QVERIFY(!config.isDebugMarkersEnabled()); + QVERIFY(!config.prefersSoftwareDevice()); + QVERIFY(config.isAutomaticPipelineCacheEnabled()); + QVERIFY(config.pipelineCacheSaveFile().isEmpty()); + QVERIFY(config.pipelineCacheLoadFile().isEmpty()); + + QQuickGraphicsConfiguration config2 = config; + config.setDebugLayer(true); + config.setDepthBufferFor2D(false); + QVERIFY(config.isDebugLayerEnabled()); + QVERIFY(!config2.isDebugLayerEnabled()); + + config2 = config; + QVERIFY(config2.isDebugLayerEnabled()); + QVERIFY(!config2.isDepthBufferEnabledFor2D()); + + config.setAutomaticPipelineCache(false); + config.setPipelineCacheSaveFile(QLatin1String("save")); + config.setPipelineCacheLoadFile(QLatin1String("load")); + config2 = config; + QVERIFY(!config2.isAutomaticPipelineCacheEnabled()); + QCOMPARE(config2.pipelineCacheSaveFile(), QLatin1String("save")); + QCOMPARE(config2.pipelineCacheLoadFile(), QLatin1String("load")); + +#if QT_CONFIG(vulkan) + QCOMPARE(QQuickGraphicsConfiguration::preferredInstanceExtensions(), QRhiVulkanInitParams::preferredInstanceExtensions()); +#endif +} + +void tst_qquickwindow::visibleVsVisibility_data() +{ + QTest::addColumn<QUrl>("qmlfile"); + QTest::addColumn<bool>("expectVisible"); + QTest::addColumn<bool>("expectConflictingPropertyWarning"); + + QTest::newRow("default invisible") << testFileUrl("window.qml") << false << false; + QTest::newRow("just visibility") << testFileUrl("maximized.qml") << true << false; + // In these conflicting cases, the 'visibility' property "wins" (see QQuickWindowQmlImpl::setWindowVisibility()) + QTest::newRow("conflicting invisible") << testFileUrl("conflictingVisibleFalse.qml") << true << true; + QTest::newRow("conflicting visible") << testFileUrl("conflictingVisibleTrue.qml") << false << true; +} + +void tst_qquickwindow::visibleVsVisibility() +{ + QFETCH(QUrl, qmlfile); + QFETCH(bool, expectVisible); + QFETCH(bool, expectConflictingPropertyWarning); + + const QString warningMsg = qmlfile.toString() + ":3:1: QML Window: Conflicting properties 'visible' and 'visibility'"; + + QTest::failOnWarning(QRegularExpression(".*")); + if (expectConflictingPropertyWarning) + QTest::ignoreMessage(QtWarningMsg, warningMsg.toUtf8().data()); + + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(qmlfile); + QObject *created = component.create(); + QScopedPointer<QObject> cleanup(created); + QVERIFY(created); + + QQuickWindow *window = qobject_cast<QQuickWindow*>(created); + QVERIFY(window); + QCOMPARE(window->isVisible(), expectVisible); +} + +void tst_qquickwindow::eventTypes() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("eventTypes.qml")); + QObject *created = component.create(); + QScopedPointer<QObject> cleanup(created); + QVERIFY(created); +} + QTEST_MAIN(tst_qquickwindow) #include "tst_qquickwindow.moc" |