diff options
21 files changed, 308 insertions, 58 deletions
diff --git a/src/3rdparty/masm/assembler/MacroAssembler.h b/src/3rdparty/masm/assembler/MacroAssembler.h index 7d9f156c8c..f37861eb66 100644 --- a/src/3rdparty/masm/assembler/MacroAssembler.h +++ b/src/3rdparty/masm/assembler/MacroAssembler.h @@ -94,6 +94,7 @@ public: using DataLabelCompact = typename MacroAssemblerBase::DataLabelCompact; using Jump = typename MacroAssemblerBase::Jump; using PatchableJump = typename MacroAssemblerBase::PatchableJump; + using MacroAssemblerBase::PointerSize; using MacroAssemblerBase::pop; using MacroAssemblerBase::jump; @@ -200,19 +201,19 @@ public: // described in terms of other macro assembly methods. void pop() { - addPtr(TrustedImm32(sizeof(void*)), MacroAssemblerBase::stackPointerRegister); + addPtr(TrustedImm32(PointerSize), MacroAssemblerBase::stackPointerRegister); } void peek(RegisterID dest, int index = 0) { - loadPtr(Address(MacroAssemblerBase::stackPointerRegister, (index * sizeof(void*))), dest); + loadPtr(Address(MacroAssemblerBase::stackPointerRegister, (index * PointerSize)), dest); } Address addressForPoke(int index) { - return Address(MacroAssemblerBase::stackPointerRegister, (index * sizeof(void*))); + return Address(MacroAssemblerBase::stackPointerRegister, (index * PointerSize)); } - + void poke(RegisterID src, int index = 0) { storePtr(src, addressForPoke(index)); @@ -223,10 +224,12 @@ public: store32(value, addressForPoke(index)); } +#if !defined(V4_BOOTSTRAP) void poke(TrustedImmPtr imm, int index = 0) { storePtr(imm, addressForPoke(index)); } +#endif #if (CPU(X86_64) || CPU(ARM64)) && !defined(V4_BOOTSTRAP) void peek64(RegisterID dest, int index = 0) diff --git a/src/3rdparty/masm/assembler/MacroAssemblerARM64.h b/src/3rdparty/masm/assembler/MacroAssemblerARM64.h index a11637f7ca..11f1672e15 100644 --- a/src/3rdparty/masm/assembler/MacroAssemblerARM64.h +++ b/src/3rdparty/masm/assembler/MacroAssemblerARM64.h @@ -127,6 +127,8 @@ private: static const ptrdiff_t REPATCH_OFFSET_CALL_TO_POINTER = -16; public: + static const int PointerSize = 8; + MacroAssemblerARM64() : m_dataMemoryTempRegister(this, dataTempRegister) , m_cachedMemoryTempRegister(this, memoryTempRegister) diff --git a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h index 806f2e13b6..fe8170d098 100644 --- a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h +++ b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h @@ -46,6 +46,8 @@ protected: // the YarrJIT needs know about addressTempRegister in order to push inline ARMRegisters::FPSingleRegisterID fpTempRegisterAsSingle() { return ARMRegisters::asSingle(fpTempRegister); } public: + static const int PointerSize = 4; + MacroAssemblerARMv7() : m_makeJumpPatchable(false) { @@ -1242,7 +1244,7 @@ public: void pop(RegisterID dest) { // store postindexed with writeback - m_assembler.ldr(dest, ARMRegisters::sp, sizeof(void*), false, true); + m_assembler.ldr(dest, ARMRegisters::sp, 4 /*sizeof(void*)*/, false, true); } void push(RegisterID src) diff --git a/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h b/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h index 68584527fc..f2ad6a4470 100644 --- a/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h +++ b/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h @@ -37,6 +37,7 @@ namespace JSC { class MacroAssemblerMIPS : public AbstractMacroAssembler<MIPSAssembler> { public: typedef MIPSRegisters::FPRegisterID FPRegisterID; + static const int PointerSize = 4; MacroAssemblerMIPS() : m_fixedWidth(false) diff --git a/src/3rdparty/masm/assembler/MacroAssemblerX86.h b/src/3rdparty/masm/assembler/MacroAssemblerX86.h index 742a4b48f7..280cf427fc 100644 --- a/src/3rdparty/masm/assembler/MacroAssemblerX86.h +++ b/src/3rdparty/masm/assembler/MacroAssemblerX86.h @@ -35,6 +35,7 @@ namespace JSC { class MacroAssemblerX86 : public MacroAssemblerX86Common { public: static const Scale ScalePtr = TimesFour; + static const int PointerSize = 4; using MacroAssemblerX86Common::add32; using MacroAssemblerX86Common::and32; diff --git a/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h b/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h index 14757f4ea2..c7c6aae637 100644 --- a/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h +++ b/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h @@ -37,6 +37,7 @@ namespace JSC { class MacroAssemblerX86_64 : public MacroAssemblerX86Common { public: static const Scale ScalePtr = TimesEight; + static const int PointerSize = 8; using MacroAssemblerX86Common::add32; using MacroAssemblerX86Common::and32; diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index 81d34701a9..583719a3c7 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -95,6 +95,12 @@ bool CompilationUnit::memoryMapCode(QString *errorString) JSC::MacroAssemblerCodeRef codeRef = JSC::MacroAssemblerCodeRef::createSelfManagedCodeRef(JSC::MacroAssemblerCodePtr(codePtr)); JSC::ExecutableAllocator::makeExecutable(codePtr, compiledFunction->codeSize); codeRefs[i] = codeRef; + + static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_ASM"); + if (showCode) { + WTF::dataLogF("Mapped JIT code for %s\n", qPrintable(stringAt(compiledFunction->nameIndex))); + disassemble(codeRef.code(), compiledFunction->codeSize, " ", WTF::dataFile()); + } } return true; @@ -535,9 +541,7 @@ void Assembler<TargetConfiguration>::returnFromFunction(IR::Ret *s, RegisterInfo const int locals = stackLayout().calculateJSStackFrameSize(); subPtr(TrustedImm32(sizeof(QV4::Value)*locals), JITTargetPlatform::LocalsRegister); - loadPtr(Address(JITTargetPlatform::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), JITTargetPlatform::ScratchRegister); - loadPtr(Address(JITTargetPlatform::ScratchRegister, targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, engine))), JITTargetPlatform::ScratchRegister); - storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::ScratchRegister, targetStructureOffset(offsetof(EngineBase, jsStackTop)))); + storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::EngineRegister, targetStructureOffset(offsetof(EngineBase, jsStackTop)))); leaveStandardStackFrame(regularRegistersToSave, fpRegistersToSave); ret(); diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index addbfc12a3..d4a18ae886 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -1387,13 +1387,6 @@ public: RegisterSizeDependentOps::emitWriteBarrier(this, dest); } - void storeValue(QV4::Primitive value, RegisterID destination) - { - Q_UNUSED(value); - Q_UNUSED(destination); - Q_UNREACHABLE(); - } - void storeValue(QV4::Primitive value, Address destination, WriteBarrier::Type barrier) { RegisterSizeDependentOps::storeValue(this, value, destination, barrier); @@ -1463,7 +1456,7 @@ public: template <int ArgumentIndex, typename Parameter> struct SizeOnStack { - enum { Size = Select<ArgumentIndex >= RegisterArgumentCount, sizeof(void*), 0>::Chosen }; + enum { Size = Select<ArgumentIndex >= RegisterArgumentCount, RegisterSize, 0>::Chosen }; }; template <int ArgumentIndex> diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h index d9f8034b1f..ce6156802d 100644 --- a/src/qml/jit/qv4targetplatform_p.h +++ b/src/qml/jit/qv4targetplatform_p.h @@ -370,7 +370,7 @@ public: // There are two designated frame-pointer registers on ARM, depending on which instruction set // is used for the subroutine: r7 for Thumb or Thumb2, and r11 for ARM. We assign the constants // accordingly, and assign the locals-register to the "other" register. -#if CPU(ARM_THUMB2) +#if CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP) static const RegisterID FramePointerRegister = JSC::ARMRegisters::r7; static const RegisterID LocalsRegister = JSC::ARMRegisters::r11; #else // Thumbs down @@ -397,7 +397,7 @@ public: << RI(JSC::ARMRegisters::r4, QStringLiteral("r4"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) << RI(JSC::ARMRegisters::r5, QStringLiteral("r5"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) << RI(JSC::ARMRegisters::r6, QStringLiteral("r6"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) -#if !CPU(ARM_THUMB2) +#if !CPU(ARM_THUMB2) && !defined(V4_BOOTSTRAP) << RI(JSC::ARMRegisters::r7, QStringLiteral("r7"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) #endif << RI(JSC::ARMRegisters::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) @@ -405,7 +405,7 @@ public: << RI(JSC::ARMRegisters::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) #endif << RI(JSC::ARMRegisters::r10, QStringLiteral("r10"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) -#if CPU(ARM_THUMB2) +#if CPU(ARM_THUMB2) && !defined(V4_BOOTSTRAP) << RI(JSC::ARMRegisters::r11, QStringLiteral("r11"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) #endif << RI(JSC::ARMRegisters::d2, QStringLiteral("d2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index f115d4227c..40bd2e5020 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -64,6 +64,7 @@ #include <QtCore/qwaitcondition.h> #include <QtCore/qloggingcategory.h> #include <QtQml/qqmlextensioninterface.h> +#include <QtCore/qcryptographichash.h> #include <functional> diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 6a2946bdcc..27d7072f03 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -2301,7 +2301,8 @@ bool QQuickFlickable::filterMouseEvent(QQuickItem *receiver, QMouseEvent *event) bool receiverDisabled = receiver && !receiver->isEnabled(); bool stealThisEvent = d->stealMouse; - if ((stealThisEvent || contains(localPos)) && (!receiver || !receiver->keepMouseGrab() || receiverDisabled)) { + bool receiverKeepsGrab = receiver && (receiver->keepMouseGrab() || receiver->keepTouchGrab()); + if ((stealThisEvent || contains(localPos)) && (!receiver || !receiverKeepsGrab || receiverDisabled)) { QScopedPointer<QMouseEvent> mouseEvent(QQuickWindowPrivate::cloneMouseEvent(event, &localPos)); mouseEvent->setAccepted(false); @@ -2321,7 +2322,7 @@ bool QQuickFlickable::filterMouseEvent(QQuickItem *receiver, QMouseEvent *event) default: break; } - if ((receiver && stealThisEvent && !receiver->keepMouseGrab() && receiver != this) || receiverDisabled) { + if ((receiver && stealThisEvent && !receiverKeepsGrab && receiver != this) || receiverDisabled) { d->clearDelayedPress(); grabMouse(); } else if (d->delayedPressEvent) { @@ -2337,7 +2338,7 @@ bool QQuickFlickable::filterMouseEvent(QQuickItem *receiver, QMouseEvent *event) d->lastPosTime = -1; returnToBounds(); } - if (event->type() == QEvent::MouseButtonRelease || (receiver && receiver->keepMouseGrab() && !receiverDisabled)) { + if (event->type() == QEvent::MouseButtonRelease || (receiverKeepsGrab && !receiverDisabled)) { // mouse released, or another item has claimed the grab d->lastPosTime = -1; d->clearDelayedPress(); diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 80abf82e58..bd68f39e48 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -746,6 +746,7 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber) qCDebug(DBG_MOUSE_TARGET) << "grabber" << q->mouseGrabberItem() << "->" << grabber; QQuickItem *oldGrabber = q->mouseGrabberItem(); + bool fromTouch = false; if (grabber && touchMouseId != -1 && touchMouseDevice) { // update the touch item for mouse touch id to the new grabber @@ -753,6 +754,7 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber) auto point = touchMouseDevice->pointerEvent()->pointById(touchMouseId); if (point) point->setGrabber(grabber); + fromTouch = true; } else { QQuickPointerEvent *event = QQuickPointerDevice::genericMouseDevice()->pointerEvent(); Q_ASSERT(event->pointCount() == 1); @@ -762,8 +764,11 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber) if (oldGrabber) { QEvent e(QEvent::UngrabMouse); QSet<QQuickItem *> hasFiltered; - if (!sendFilteredMouseEvent(oldGrabber->parentItem(), oldGrabber, &e, &hasFiltered)) + if (!sendFilteredMouseEvent(oldGrabber->parentItem(), oldGrabber, &e, &hasFiltered)) { oldGrabber->mouseUngrabEvent(); + if (fromTouch) + oldGrabber->touchUngrabEvent(); + } } } @@ -2585,28 +2590,39 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem break; } + bool touchMouseUnset = (touchMouseId == -1); // Only deliver mouse event if it is the touchMouseId or it could become the touchMouseId - if (touchMouseId == -1 || touchMouseId == tp.id()) { + if (touchMouseUnset || touchMouseId == tp.id()) { // targetEvent is already transformed wrt local position, velocity, etc. // FIXME: remove asTouchEvent!!! QScopedPointer<QMouseEvent> mouseEvent(touchToMouseEvent(t, tp, event->asTouchEvent(), item, false)); + // If a filtering item calls QQuickWindow::mouseGrabberItem(), it should + // report the touchpoint's grabber. Whenever we send a synthetic mouse event, + // touchMouseId and touchMouseDevice must be set, even if it's only temporarily and isn't grabbed. + touchMouseId = tp.id(); + touchMouseDevice = event->device(); if (target->childMouseEventFilter(item, mouseEvent.data())) { qCDebug(DBG_TOUCH) << " - second chance intercepted on childMouseEventFilter by " << target; if (t != QEvent::MouseButtonRelease) { qCDebug(DBG_TOUCH_TARGET) << "TP" << tp.id() << "->" << target; - touchMouseDevice = event->device(); - if (touchMouseId == -1) { + if (touchMouseUnset) { // the point was grabbed as a pure touch point before, now it will be treated as mouse // but the old receiver still needs to be informed if (auto oldGrabber = touchMouseDevice->pointerEvent()->pointById(tp.id())->grabber()) oldGrabber->touchUngrabEvent(); } - touchMouseId = tp.id(); + touchMouseUnset = false; // We want to leave touchMouseId and touchMouseDevice set target->grabMouse(); } filtered = true; } + if (touchMouseUnset) { + // Now that we're done sending a synth mouse event, and it wasn't grabbed, + // the touchpoint is no longer acting as a synthetic mouse. Restore previous state. + touchMouseId = -1; + touchMouseDevice = nullptr; + } // Only one event can be filtered as a mouse event. break; } diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index ea02723db8..5d7fb04b9f 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -353,10 +353,9 @@ QImage QQuickWidgetPrivate::grabFramebuffer() return renderControl->grab(); } -QObject *QQuickWidgetPrivate::focusObject() -{ - return offscreenWindow ? offscreenWindow->focusObject() : 0; -} +// Intentionally not overriding the QQuickWindow's focusObject. +// Key events should go to our key event handlers, and then to the +// QQuickWindow, not any in-scene item. /*! \module QtQuickWidgets diff --git a/src/quickwidgets/qquickwidget_p.h b/src/quickwidgets/qquickwidget_p.h index 559321cd51..6892e6e0b4 100644 --- a/src/quickwidgets/qquickwidget_p.h +++ b/src/quickwidgets/qquickwidget_p.h @@ -99,8 +99,6 @@ public: void destroyContext(); void handleContextCreationFailure(const QSurfaceFormat &format, bool isEs); - QObject *focusObject() Q_DECL_OVERRIDE; - #if QT_CONFIG(opengl) GLuint textureId() const Q_DECL_OVERRIDE; QImage grabFramebuffer() Q_DECL_OVERRIDE; diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 1e80f1bf65..f9c1fcce91 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -18,4 +18,7 @@ qtHaveModule(gui):qtConfig(opengl(es1|es2)?) { # console applications not supported uikit: SUBDIRS -= qmltest +# Restricted sub-set for now +boot2qt: SUBDIRS = qml + installed_cmake.depends = cmake diff --git a/tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp b/tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp index 2ce0cfe210..5d7009e7c8 100644 --- a/tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp +++ b/tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp @@ -71,7 +71,7 @@ void tst_EcmaScriptTests::runTests() #endif } -QTEST_MAIN(tst_EcmaScriptTests) +QTEST_GUILESS_MAIN(tst_EcmaScriptTests) #include "tst_ecmascripttests.moc" diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro index a9b18e9f32..007eb0dc83 100644 --- a/tests/auto/qml/qml.pro +++ b/tests/auto/qml/qml.pro @@ -7,6 +7,9 @@ PUBLICTESTS += \ parserstress \ qjsvalueiterator \ qjsonbinding \ + +!boot2qt { +PUBLICTESTS += \ qmlmin \ qqmlcomponent \ qqmlconsole \ @@ -25,15 +28,21 @@ PUBLICTESTS += \ qquickfolderlistmodel \ qqmlapplicationengine \ qqmlsettings \ - qqmlstatemachine + qqmlstatemachine \ + qmldiskcache +} PRIVATETESTS += \ - animation \ qqmlcpputils \ + qqmldirparser \ + v4misc \ + +!boot2qt { +PRIVATETESTS += \ + animation \ qqmlecmascript \ qqmlcontext \ qqmlexpression \ - qqmldirparser \ qqmlglobal \ qqmllanguage \ qqmlopenmetaobject \ @@ -57,13 +66,12 @@ PRIVATETESTS += \ qqmltimer \ qqmlinstantiator \ qqmlenginecleanup \ - v4misc \ qqmltranslation \ qqmlimport \ qqmlobjectmodel \ - qmldiskcache \ qv4mm \ ecmascripttests +} qtHaveModule(widgets) { PUBLICTESTS += \ @@ -73,7 +81,7 @@ qtHaveModule(widgets) { SUBDIRS += $$PUBLICTESTS SUBDIRS += $$METATYPETESTS -qtConfig(process) { +qtConfig(process):!boot2qt { !contains(QT_CONFIG, no-qml-debug): SUBDIRS += debugger SUBDIRS += qmllint qmlplugindump } diff --git a/tests/auto/quick/qquickflickable/data/nestedSlider.qml b/tests/auto/quick/qquickflickable/data/nestedSlider.qml new file mode 100644 index 0000000000..2fd0cbfcc8 --- /dev/null +++ b/tests/auto/quick/qquickflickable/data/nestedSlider.qml @@ -0,0 +1,36 @@ +import QtQuick 2.0 +import Test 1.0 + +Flickable { + width: 240 + height: 320 + contentWidth: width * 1.5 + contentHeight: height * 1.5 + contentY: height * 0.25 + + Rectangle { + id: slider + width: 50 + height: 200 + color: "lightgray" + border.color: drag.active ? "green" : "black" + anchors.centerIn: parent + radius: 4 + + TouchDragArea { + id: drag + objectName: "drag" + anchors.fill: parent + } + + Rectangle { + width: parent.width - 2 + height: 20 + radius: 5 + color: "darkgray" + border.color: "black" + x: 1 + y: Math.min(slider.height - height, Math.max(0, drag.pos.y - height / 2)) + } + } +} diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index 9ead271bfe..3ecebfb48f 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -46,12 +46,109 @@ using namespace QQuickViewTestUtil; using namespace QQuickVisualTestUtil; +// an abstract Slider which only handles touch events +class TouchDragArea : public QQuickItem +{ + Q_OBJECT + Q_PROPERTY(QPointF pos READ pos NOTIFY posChanged) + Q_PROPERTY(bool active READ active NOTIFY activeChanged) + Q_PROPERTY(bool keepMouseGrab READ keepMouseGrab WRITE setKeepMouseGrab NOTIFY keepMouseGrabChanged) + Q_PROPERTY(bool keepTouchGrab READ keepTouchGrab WRITE setKeepTouchGrab NOTIFY keepTouchGrabChanged) + +public: + TouchDragArea(QQuickItem *parent = 0) + : QQuickItem(parent) + , touchEvents(0) + , touchUpdates(0) + , touchReleases(0) + , ungrabs(0) + , m_active(false) + { + setFlags(ItemAcceptsDrops); + } + + QPointF pos() const { return m_pos; } + + bool active() const { return m_active; } + + void setKeepMouseGrab(bool keepMouseGrab) + { + QQuickItem::setKeepMouseGrab(keepMouseGrab); + emit keepMouseGrabChanged(); + } + + void setKeepTouchGrab(bool keepTouchGrab) + { + QQuickItem::setKeepTouchGrab(keepTouchGrab); + emit keepTouchGrabChanged(); + } + + int touchEvents; + int touchUpdates; + int touchReleases; + int ungrabs; + QVector<Qt::TouchPointState> touchPointStates; + +protected: + void touchEvent(QTouchEvent *ev) override + { + QCOMPARE(ev->touchPoints().count(), 1); + auto touchpoint = ev->touchPoints().first(); + switch (touchpoint.state()) { + case Qt::TouchPointPressed: + QVERIFY(!m_active); + m_active = true; + emit activeChanged(); + grabTouchPoints(QVector<int>() << touchpoint.id()); + break; + case Qt::TouchPointMoved: + ++touchUpdates; + break; + case Qt::TouchPointReleased: + QVERIFY(m_active); + m_active = false; + ++touchReleases; + emit activeChanged(); + case Qt::TouchPointStationary: + break; + } + touchPointStates << touchpoint.state(); + ++touchEvents; + m_pos = touchpoint.pos(); + emit posChanged(); + } + + void touchUngrabEvent() override + { + ++ungrabs; + QVERIFY(m_active); + emit ungrabbed(); + m_active = false; + emit activeChanged(); + } + +signals: + void ungrabbed(); + void posChanged(); + void keepMouseGrabChanged(); + void keepTouchGrabChanged(); + void activeChanged(); + +private: + QPointF m_pos; + bool m_active; +}; + class tst_qquickflickable : public QQmlDataTest { Q_OBJECT public: + tst_qquickflickable() + : touchDevice(QTest::createTouchDevice()) + {} private slots: + void initTestCase() override; void create(); void horizontalViewportSize(); void verticalViewportSize(); @@ -89,6 +186,8 @@ private slots: void stopAtBounds(); void stopAtBounds_data(); void nestedMouseAreaUsingTouch(); + void nestedSliderUsingTouch(); + void nestedSliderUsingTouch_data(); void pressDelayWithLoader(); void movementFromProgrammaticFlick(); void cleanup(); @@ -101,9 +200,16 @@ private slots: void overshoot_reentrant(); private: - void flickWithTouch(QQuickWindow *window, QTouchDevice *touchDevice, const QPoint &from, const QPoint &to); + void flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to); + QTouchDevice *touchDevice; }; +void tst_qquickflickable::initTestCase() +{ + QQmlDataTest::initTestCase(); + qmlRegisterType<TouchDragArea>("Test",1,0,"TouchDragArea"); +} + void tst_qquickflickable::cleanup() { QVERIFY(QGuiApplication::topLevelWindows().isEmpty()); @@ -1530,12 +1636,6 @@ void tst_qquickflickable::clickAndDragWhenTransformed() void tst_qquickflickable::flickTwiceUsingTouches() { - QTouchDevice *touchDevice = new QTouchDevice; - touchDevice->setName("Fake Touchscreen"); - touchDevice->setType(QTouchDevice::TouchScreen); - touchDevice->setCapabilities(QTouchDevice::Position); - QWindowSystemInterface::registerTouchDevice(touchDevice); - QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("longList.qml")); QTRY_COMPARE(window->status(), QQuickView::Ready); @@ -1548,7 +1648,7 @@ void tst_qquickflickable::flickTwiceUsingTouches() QVERIFY(flickable != 0); QCOMPARE(flickable->contentY(), 0.0f); - flickWithTouch(window.data(), touchDevice, QPoint(100, 400), QPoint(100, 240)); + flickWithTouch(window.data(), QPoint(100, 400), QPoint(100, 240)); qreal contentYAfterFirstFlick = flickable->contentY(); qDebug() << "contentYAfterFirstFlick " << contentYAfterFirstFlick; @@ -1556,7 +1656,7 @@ void tst_qquickflickable::flickTwiceUsingTouches() // Wait until view stops moving QTRY_VERIFY(!flickable->isMoving()); - flickWithTouch(window.data(), touchDevice, QPoint(100, 400), QPoint(100, 240)); + flickWithTouch(window.data(), QPoint(100, 400), QPoint(100, 240)); // In the original bug, that second flick would cause Flickable to halt immediately qreal contentYAfterSecondFlick = flickable->contentY(); @@ -1564,7 +1664,7 @@ void tst_qquickflickable::flickTwiceUsingTouches() QTRY_VERIFY(contentYAfterSecondFlick > (contentYAfterFirstFlick + 80.0f)); } -void tst_qquickflickable::flickWithTouch(QQuickWindow *window, QTouchDevice *touchDevice, const QPoint &from, const QPoint &to) +void tst_qquickflickable::flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to) { QTest::touchEvent(window, touchDevice).press(0, from, window); QQuickTouchUtils::flush(window); @@ -1869,12 +1969,6 @@ void tst_qquickflickable::stopAtBounds() void tst_qquickflickable::nestedMouseAreaUsingTouch() { - QTouchDevice *touchDevice = new QTouchDevice; - touchDevice->setName("Fake Touchscreen"); - touchDevice->setType(QTouchDevice::TouchScreen); - touchDevice->setCapabilities(QTouchDevice::Position); - QWindowSystemInterface::registerTouchDevice(touchDevice); - QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("nestedmousearea.qml")); QTRY_COMPARE(window->status(), QQuickView::Ready); @@ -1887,7 +1981,7 @@ void tst_qquickflickable::nestedMouseAreaUsingTouch() QVERIFY(flickable != 0); QCOMPARE(flickable->contentY(), 50.0f); - flickWithTouch(window.data(), touchDevice, QPoint(100, 300), QPoint(100, 200)); + flickWithTouch(window.data(), QPoint(100, 300), QPoint(100, 200)); // flickable should not have moved QCOMPARE(flickable->contentY(), 50.0); @@ -1897,6 +1991,65 @@ void tst_qquickflickable::nestedMouseAreaUsingTouch() QVERIFY(nested->y() < 100.0); } +void tst_qquickflickable::nestedSliderUsingTouch_data() +{ + QTest::addColumn<bool>("keepMouseGrab"); + QTest::addColumn<bool>("keepTouchGrab"); + QTest::addColumn<int>("updates"); + QTest::addColumn<int>("releases"); + QTest::addColumn<int>("ungrabs"); + + QTest::newRow("keepBoth") << true << true << 8 << 1 << 0; + QTest::newRow("keepMouse") << true << false << 8 << 1 << 0; + QTest::newRow("keepTouch") << false << true << 8 << 1 << 0; + QTest::newRow("keepNeither") << false << false << 6 << 0 << 1; +} + +void tst_qquickflickable::nestedSliderUsingTouch() +{ + QFETCH(bool, keepMouseGrab); + QFETCH(bool, keepTouchGrab); + QFETCH(int, updates); + QFETCH(int, releases); + QFETCH(int, ungrabs); + + QQuickView *window = new QQuickView; + QScopedPointer<QQuickView> windowPtr(window); + windowPtr->setSource(testFileUrl("nestedSlider.qml")); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window); + QQuickViewTestUtil::moveMouseAway(window); + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + QVERIFY(window->rootObject() != 0); + + QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); + QVERIFY(flickable); + + TouchDragArea *tda = flickable->findChild<TouchDragArea*>("drag"); + QVERIFY(tda); + + // Drag down and a little to the right: flickable will steal the grab only if tda allows it + const int dragThreshold = qApp->styleHints()->startDragDistance(); + tda->setKeepMouseGrab(keepMouseGrab); + tda->setKeepTouchGrab(keepTouchGrab); + QPoint p0 = tda->mapToScene(QPoint(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(0, p0, window); + QQuickTouchUtils::flush(window); + for (int i = 0; i < 8; ++i) { + p0 += QPoint(dragThreshold / 6, dragThreshold / 4); + QTest::touchEvent(window, touchDevice).move(0, p0, window); + QQuickTouchUtils::flush(window); + } + QCOMPARE(tda->active(), !ungrabs); + QTest::touchEvent(window, touchDevice).release(0, p0, window); + QQuickTouchUtils::flush(window); + QCOMPARE(tda->touchPointStates.first(), Qt::TouchPointPressed); + QCOMPARE(tda->touchUpdates, updates); + QCOMPARE(tda->touchReleases, releases); + QCOMPARE(tda->ungrabs, ungrabs); +} + // QTBUG-31328 void tst_qquickflickable::pressDelayWithLoader() { diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp index 2681f1a966..36d99ad48d 100644 --- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp +++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp @@ -375,7 +375,7 @@ void tst_qquickimage::mirror() } QImage img = expected.toImage(); - QCOMPARE(screenshots[fillMode], img); + QCOMPARE(screenshots[fillMode].convertToFormat(img.format()), img); } } diff --git a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp index 5e8f762e23..bd051ec990 100644 --- a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp +++ b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp @@ -58,6 +58,7 @@ private slots: void grabBeforeShow(); void reparentToNewWindow(); void nullEngine(); + void keyEvents(); }; @@ -337,6 +338,33 @@ void tst_qquickwidget::nullEngine() QVERIFY(widget.engine()); } +class KeyHandlingWidget : public QQuickWidget +{ +public: + void keyPressEvent(QKeyEvent *e) override { + if (e->key() == Qt::Key_A) + ok = true; + } + + bool ok = false; +}; + +void tst_qquickwidget::keyEvents() +{ + // A QQuickWidget should behave like a normal widget when it comes to event handling. + // Verify that key events actually reach the widget. (QTBUG-45757) + KeyHandlingWidget widget; + widget.setSource(testFileUrl("rectangle.qml")); + widget.show(); + QVERIFY(QTest::qWaitForWindowExposed(widget.window(), 5000)); + + // Note: send the event to the QWindow, not the QWidget, in order + // to simulate the full event processing chain. + QTest::keyClick(widget.window()->windowHandle(), Qt::Key_A); + + QTRY_VERIFY(widget.ok); +} + QTEST_MAIN(tst_qquickwidget) #include "tst_qquickwidget.moc" |