diff options
Diffstat (limited to 'src')
86 files changed, 944 insertions, 138 deletions
diff --git a/src/particles/qquickparticlesystem.cpp b/src/particles/qquickparticlesystem.cpp index 5806d7914c..5744c61849 100644 --- a/src/particles/qquickparticlesystem.cpp +++ b/src/particles/qquickparticlesystem.cpp @@ -767,10 +767,9 @@ void QQuickParticleSystem::reset() timeInt = 0; //Clear guarded pointers which have been deleted - int cleared = 0; - cleared += m_emitters.removeAll(nullptr); - cleared += m_painters.removeAll(nullptr); - cleared += m_affectors.removeAll(nullptr); + m_emitters.removeAll(nullptr); + m_painters.removeAll(nullptr); + m_affectors.removeAll(nullptr); bySysIdx.resize(0); initGroups();//Also clears all logical particles diff --git a/src/particles/shaders_ng/imageparticle.frag b/src/particles/shaders_ng/imageparticle.frag index 90b79e6ea9..074771f4fd 100644 --- a/src/particles/shaders_ng/imageparticle.frag +++ b/src/particles/shaders_ng/imageparticle.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 #if defined(TABLE) diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp index ae50225035..9c83f8c1fd 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp @@ -224,9 +224,10 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr) QV4::ScopedValue v(scope); QV4::Heap::InternalClass *ic = ctxt->internalClass(); for (uint i = 0; i < ic->size; ++i) { - QString name = ic->keyAt(i); - names.append(name); - v = static_cast<QV4::Heap::CallContext *>(ctxt->d())->locals[i]; + QV4::ScopedValue stringOrSymbol(scope, ic->keyAt(i)); + QV4::ScopedString propName(scope, stringOrSymbol->toString(scope.engine)); + names.append(propName->toQString()); + v = ctxt->getProperty(propName); collectedRefs.append(addValueRef(v)); } diff --git a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp index 85b6bac203..ca8f3e3145 100644 --- a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp @@ -493,9 +493,10 @@ void NativeDebugger::handleVariables(QJsonObject *response, const QJsonObject &a QV4::Heap::InternalClass *ic = callContext->internalClass(); QV4::ScopedValue v(scope); for (uint i = 0; i < ic->size; ++i) { - QString name = ic->keyAt(i); - v = callContext->d()->locals[i]; - collector.collect(&output, QString(), name, v); + QV4::ScopedValue stringOrSymbol(scope, ic->keyAt(i)); + QV4::ScopedString propName(scope, stringOrSymbol->toString(scope.engine)); + v = callContext->getProperty(propName); + collector.collect(&output, QString(), propName->toQString(), v); } } diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h index 8b2d5066c6..9453120eb6 100644 --- a/src/qml/common/qv4compileddata_p.h +++ b/src/qml/common/qv4compileddata_p.h @@ -1322,6 +1322,28 @@ struct TypeReferenceMap : QHash<int, TypeReference> return *insert(nameIndex, loc); } + template <typename Iterator> + void collectFromFunctions(Iterator it, Iterator end) + { + for (; it != end; ++it) { + auto formal = it->formalsBegin(); + auto formalEnd = it->formalsEnd(); + for ( ; formal != formalEnd; ++formal) { + if (!formal->type.indexIsBuiltinType()) { + TypeReference &r + = this->add(formal->type.typeNameIndexOrBuiltinType(), it->location); + r.errorWhenNotFound = true; + } + } + + if (!it->returnType.indexIsBuiltinType()) { + TypeReference &r + = this->add(it->returnType.typeNameIndexOrBuiltinType(), it->location); + r.errorWhenNotFound = true; + } + } + } + template <typename CompiledObject> void collectFromObject(const CompiledObject *obj) { @@ -1353,13 +1375,6 @@ struct TypeReferenceMap : QHash<int, TypeReference> this->add(ic->nameIndex, ic->location); } } - - template <typename Iterator> - void collectFromObjects(Iterator it, Iterator end) - { - for (; it != end; ++it) - collectFromObject(*it); - } }; using DependentTypesHasher = std::function<QByteArray()>; diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 9739c936da..814a5e8c65 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -109,10 +109,14 @@ bool Parameter::initType(QV4::CompiledData::ParameterType *paramType, const QV4: const QString typeName = stringGenerator->stringForIndex(typeNameIndex); auto builtinType = stringToBuiltinType(typeName); if (builtinType == QV4::CompiledData::BuiltinType::InvalidBuiltin) { - if (typeName.isEmpty() || !typeName.at(0).isUpper()) { + if (typeName.isEmpty() || typeName == QLatin1String("void")) { + paramType->set(true, quint32(builtinType)); + return false; + } else if (!typeName.at(0).isUpper()) { paramType->set(false, 0); return false; } + Q_ASSERT(quint32(typeNameIndex) < (1u << 31)); paramType->set(false, typeNameIndex); } else { @@ -1805,7 +1809,6 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen nextOffset += signalTableSize; quint32_le *enumOffsetTable = reinterpret_cast<quint32_le*>(objectPtr + objectToWrite->offsetToEnums); - quint32 enumTableSize = 0; char *enumPtr = objectPtr + nextOffset; for (const Enum *e = o->firstEnum(); e; e = e->next) { *enumOffsetTable++ = enumPtr - objectPtr; @@ -1820,7 +1823,6 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen *enumValueToWrite = *enumValue; int size = QV4::CompiledData::Enum::calculateSize(e->enumValues->count); - enumTableSize += size; enumPtr += size; } diff --git a/src/qml/jsapi/qjsmanagedvalue.cpp b/src/qml/jsapi/qjsmanagedvalue.cpp index ce43b958cf..85406c21b2 100644 --- a/src/qml/jsapi/qjsmanagedvalue.cpp +++ b/src/qml/jsapi/qjsmanagedvalue.cpp @@ -1123,8 +1123,11 @@ QStringList QJSManagedValue::jsMetaMembers() const const int size = heapClass->size; QStringList result; result.reserve(size); - for (int i = 0; i < size; ++i) - result.append(heapClass->keyAt(i)); + QV4::Scope scope(c->engine()); + for (int i = 0; i < size; ++i) { + QV4::ScopedValue key(scope, heapClass->keyAt(i)); + result.append(key->toQString()); + } return result; } diff --git a/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp b/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp index a9ab2f5ccb..b66e6b9467 100644 --- a/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp +++ b/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp @@ -79,6 +79,16 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co // Data structure and qt version matched, so now we can access the rest of the file safely. length = static_cast<size_t>(lseek(fd, 0, SEEK_END)); + /* Error out early on file corruption. We assume we can read header.unitSize bytes + later (even before verifying the checksum), potentially causing out-of-bound + reads + Also, no need to wait until checksum verification if we know beforehand + that the cached unit is bogus + */ + if (length != header.unitSize) { + *errorString = QStringLiteral("Potential file corruption, file too small"); + return nullptr; + } void *ptr = mmap(nullptr, length, PROT_READ, MAP_SHARED, fd, /*offset*/0); if (ptr == MAP_FAILED) { diff --git a/src/qml/jsruntime/qv4compilationunitmapper_win.cpp b/src/qml/jsruntime/qv4compilationunitmapper_win.cpp index b4f0a6ff4d..de950ece05 100644 --- a/src/qml/jsruntime/qv4compilationunitmapper_win.cpp +++ b/src/qml/jsruntime/qv4compilationunitmapper_win.cpp @@ -86,6 +86,23 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co // Data structure and qt version matched, so now we can access the rest of the file safely. + /* Error out early on file corruption. We assume we can read header.unitSize bytes + later (even before verifying the checksum), potentially causing out-of-bound + reads + Also, no need to wait until checksum verification if we know beforehand + that the cached unit is bogus + */ + LARGE_INTEGER fileSize; + if (!GetFileSizeEx(handle, &fileSize)) { + *errorString = QStringLiteral("Could not determine file size"); + return nullptr; + } + if (header.unitSize != fileSize.QuadPart) { + *errorString = QStringLiteral("Potential file corruption, file too small"); + return nullptr; + } + + HANDLE fileMappingHandle = CreateFileMapping(handle, 0, PAGE_READONLY, 0, 0, 0); if (!fileMappingHandle) { *errorString = qt_error_string(GetLastError()); diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 282046f3fa..c3df66f67e 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -334,9 +334,14 @@ ReturnedValue ExecutionContext::getProperty(String *name) case Heap::ExecutionContext::Type_CallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx); - uint index = c->internalClass->indexOfValueOrGetter(id); - if (index < UINT_MAX) + const uint index = c->internalClass->indexOfValueOrGetter(id); + if (index < c->locals.alloc) return c->locals[index].asReturnedValue(); + + // TODO: We should look up the module imports here, but those are part of the CU: + // imports[index - c->locals.size]; + // See QTBUG-118478 + Q_FALLTHROUGH(); } case Heap::ExecutionContext::Type_WithContext: @@ -384,9 +389,14 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) case Heap::ExecutionContext::Type_CallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx); - uint index = c->internalClass->indexOfValueOrGetter(id); - if (index < UINT_MAX) + const uint index = c->internalClass->indexOfValueOrGetter(id); + if (index < c->locals.alloc) return c->locals[index].asReturnedValue(); + + // TODO: We should look up the module imports here, but those are part of the CU: + // imports[index - c->locals.size]; + // See QTBUG-118478 + Q_FALLTHROUGH(); } case Heap::ExecutionContext::Type_GlobalContext: { diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 0927687578..b303dd497a 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -2503,6 +2503,13 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi return true; } } + + if (metaType == QMetaType::fromType<QQmlListProperty<QObject>>()) { + if (const QV4::QmlListWrapper *wrapper = value.as<QV4::QmlListWrapper>()) { + *reinterpret_cast<QQmlListProperty<QObject> *>(data) = wrapper->d()->property(); + return true; + } + } } { diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp index 7fe3862172..ba10d29d51 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit.cpp +++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp @@ -517,6 +517,15 @@ int ExecutableCompilationUnit::totalObjectCount() const { return inlineComponentData[icRoot].totalObjectCount; } +ResolvedTypeReference *ExecutableCompilationUnit::resolvedType(QMetaType type) const +{ + for (ResolvedTypeReference *ref : std::as_const(resolvedTypes)) { + if (ref->type().typeId() == type) + return ref; + } + return nullptr; +} + int ExecutableCompilationUnit::totalParserStatusCount() const { if (icRoot == -1) return m_totalParserStatusCount; diff --git a/src/qml/jsruntime/qv4executablecompilationunit_p.h b/src/qml/jsruntime/qv4executablecompilationunit_p.h index 9ceec1fbf7..38d35baf3f 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit_p.h +++ b/src/qml/jsruntime/qv4executablecompilationunit_p.h @@ -175,6 +175,7 @@ public: QVector<QQmlRefPointer<QQmlScriptData>> dependentScripts; ResolvedTypeReferenceMap resolvedTypes; ResolvedTypeReference *resolvedType(int id) const { return resolvedTypes.value(id); } + ResolvedTypeReference *resolvedType(QMetaType type) const; bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const; diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index eabb220c50..fdaa8cbaa4 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -329,9 +329,15 @@ void InternalClass::destroy() Base::destroy(); } -QString InternalClass::keyAt(uint index) const -{ - return nameMap.at(index).toQString(); +ReturnedValue InternalClass::keyAt(uint index) const +{ + PropertyKey key = nameMap.at(index); + if (!key.isValid()) + return Encode::undefined(); + if (key.isArrayIndex()) + return Encode(key.asArrayIndex()); + Q_ASSERT(key.isStringOrSymbol()); + return key.asStringOrSymbol()->asReturnedValue(); } void InternalClass::changeMember(QV4::Object *object, PropertyKey id, PropertyAttributes data, InternalClassEntry *entry) diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 37dbeded6f..a80ec2e957 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -343,7 +343,7 @@ struct InternalClass : Base { void init(InternalClass *other); void destroy(); - Q_QML_PRIVATE_EXPORT QString keyAt(uint index) const; + Q_QML_PRIVATE_EXPORT ReturnedValue keyAt(uint index) const; Q_REQUIRED_RESULT InternalClass *nonExtensible(); static void addMember(QV4::Object *object, PropertyKey id, PropertyAttributes data, InternalClassEntry *entry); diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index 301dad38fd..382f6c684a 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -230,10 +230,6 @@ struct Q_QML_PRIVATE_EXPORT Lookup { markDef.h2->mark(stack); } - void clear() { - memset(&markDef, 0, sizeof(markDef)); - } - void releasePropertyCache() { if (getter == getterQObject diff --git a/src/qml/jsruntime/qv4module.cpp b/src/qml/jsruntime/qv4module.cpp index 26bef9cd37..548dd7be25 100644 --- a/src/qml/jsruntime/qv4module.cpp +++ b/src/qml/jsruntime/qv4module.cpp @@ -258,9 +258,12 @@ OwnPropertyKeyIterator *Module::virtualOwnPropertyKeys(const Object *o, Value *t if (module->d()->unit->isESModule()) { names = module->d()->unit->exportedNames(); } else { - Heap::InternalClass *scopeClass = module->d()->scope->internalClass; - for (uint i = 0; i < scopeClass->size; ++i) - names << scopeClass->keyAt(i); + QV4::Scope scope(module->engine()); + QV4::Scoped<InternalClass> scopeClass(scope, module->d()->scope->internalClass); + for (uint i = 0, end = scopeClass->d()->size; i < end; ++i) { + QV4::ScopedValue key(scope, scopeClass->d()->keyAt(i)); + names << key->toQString(); + } } return new ModuleNamespaceIterator(names); diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp index 1b737ee308..c5ec43bbb7 100644 --- a/src/qml/qml/qqml.cpp +++ b/src/qml/qml/qqml.cpp @@ -1059,7 +1059,7 @@ void AOTCompiledContext::storeNameSloppy(uint nameIndex, void *value, QMetaType // the property cache we store a value into the property. QV4::Lookup l; - l.clear(); + memset(&l, 0, sizeof(QV4::Lookup)); l.nameIndex = nameIndex; ObjectPropertyResult storeResult = ObjectPropertyResult::NeedsInit; switch (initObjectLookup(this, &l, qmlScopeObject, QMetaType())) { diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index fc629bc060..b544852953 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -901,10 +901,13 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper && !(bindingFlags & QV4::CompiledData::Binding::IsPropertyObserver) && !_valueTypeProperty; - if (_ddata->hasBindingBit(bindingProperty->coreIndex()) && allowedToRemoveBinding) { - QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(bindingProperty->coreIndex())); - } else if (bindingProperty->isBindable() && allowedToRemoveBinding) { - removePendingBinding(_bindingTarget, bindingProperty->coreIndex()); + if (allowedToRemoveBinding) { + if (bindingProperty->isBindable()) { + removePendingBinding(_bindingTarget, bindingProperty->coreIndex()); + } else { + QQmlPropertyPrivate::removeBinding( + _bindingTarget, QQmlPropertyIndex(bindingProperty->coreIndex())); + } } if (bindingType == QV4::CompiledData::Binding::Type_Script || binding->isTranslationBinding()) { @@ -950,6 +953,9 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper qmlBinding = QQmlPropertyBinding::create(bindingProperty, runtimeFunction, _scopeObject, context, currentQmlContext(), _bindingTarget, index); } sharedState.data()->allQPropertyBindings.push_back(DeferredQPropertyBinding {_bindingTarget, bindingProperty->coreIndex(), qmlBinding }); + + QQmlData *data = QQmlData::get(_bindingTarget, true); + data->setBindingBit(_bindingTarget, bindingProperty->coreIndex()); } else { // When writing bindings to grouped properties implemented as value types, // such as point.x: { someExpression; }, then the binding is installed on @@ -1467,17 +1473,27 @@ bool QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interrupt) while (!sharedState->allQPropertyBindings.isEmpty()) { auto& [target, index, qmlBinding] = sharedState->allQPropertyBindings.first(); + + QQmlData *data = QQmlData::get(target); + if (!data || !data->hasBindingBit(index)) { + // The target property has been overwritten since we stashed the binding. + sharedState->allQPropertyBindings.pop_front(); + continue; + } + QUntypedBindable bindable; void *argv[] = { &bindable }; // allow interception target->metaObject()->metacall(target, QMetaObject::BindableProperty, index, argv); const bool success = bindable.setBinding(qmlBinding); + const auto bindingPrivateRefCount = QPropertyBindingPrivate::get(qmlBinding)->ref; + // Only pop_front after setting the binding as the bindings are refcounted. sharedState->allQPropertyBindings.pop_front(); // If the binding was actually not set, it's deleted now. - if (success) { + if (success && bindingPrivateRefCount > 1) { if (auto priv = QPropertyBindingPrivate::get(qmlBinding); priv->hasCustomVTable()) { auto qmlBindingPriv = static_cast<QQmlPropertyBinding *>(priv); auto jsExpression = qmlBindingPriv->jsExpression(); diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h index c415b5f33a..3ce665c24f 100644 --- a/src/qml/qml/qqmlpropertycachecreator_p.h +++ b/src/qml/qml/qqmlpropertycachecreator_p.h @@ -932,53 +932,74 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor QQmlPropertyData *targetProperty = targetCache->property(coreIndex); Q_ASSERT(targetProperty); + const QMetaType targetPropType = targetProperty->propType(); + + const auto resolveType = [](QMetaType targetPropType) { + if (targetPropType.flags() & QMetaType::IsEnumeration) + return QMetaType::fromType<int>(); + else + return targetPropType; + }; + + const auto populateWithPropertyData = [&](const QQmlPropertyData *property) { + *type = resolveType(property->propType()); + writable = property->isWritable(); + resettable = property->isResettable(); + bindable = property->isBindable(); + + // Copy type flags + propertyFlags->copyPropertyTypeFlags(property->flags()); + if (property->isVarProperty()) + propertyFlags->type = QQmlPropertyData::Flags::QVariantType; + }; + // for deep aliases, valueTypeIndex is always set - if (!QQmlMetaType::isValueType(targetProperty->propType()) && valueTypeIndex != -1) { + if (!QQmlMetaType::isValueType(targetPropType) && valueTypeIndex != -1) { // deep alias property - *type = targetProperty->propType(); - targetCache = enginePriv->propertyCacheForType(type->id()); - Q_ASSERT(targetCache); - targetProperty = targetCache->property(valueTypeIndex); - if (targetProperty == nullptr) { - return qQmlCompileError(alias.referenceLocation, - QQmlPropertyCacheCreatorBase::tr("Invalid alias target")); + QQmlRefPointer<QQmlPropertyCache> typeCache + = enginePriv->propertyCacheForType(targetPropType.id()); + + if (!typeCache) { + // See if it's a half-resolved composite type + if (const QV4::ResolvedTypeReference *typeRef + = objectContainer->resolvedType(targetPropType)) { + typeCache = typeRef->typePropertyCache(); + } } - *type = targetProperty->propType(); - writable = targetProperty->isWritable(); - resettable = targetProperty->isResettable(); - bindable = targetProperty->isBindable(); + const QQmlPropertyData *typeProperty = typeCache + ? typeCache->property(valueTypeIndex) + : nullptr; + if (typeProperty == nullptr) { + return qQmlCompileError( + alias.referenceLocation, + QQmlPropertyCacheCreatorBase::tr("Invalid alias target")); + } + populateWithPropertyData(typeProperty); } else { // value type or primitive type or enum - *type = targetProperty->propType(); - - writable = targetProperty->isWritable(); - resettable = targetProperty->isResettable(); - bindable = targetProperty->isBindable(); + populateWithPropertyData(targetProperty); if (valueTypeIndex != -1) { - const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(*type); - if (valueTypeMetaObject->property(valueTypeIndex).isEnumType()) - *type = QMetaType::fromType<int>(); - else - *type = valueTypeMetaObject->property(valueTypeIndex).metaType(); - } else { - if (targetProperty->isEnum()) { - *type = QMetaType::fromType<int>(); - } else { - // Copy type flags - propertyFlags->copyPropertyTypeFlags(targetProperty->flags()); - - if (targetProperty->isVarProperty()) - propertyFlags->type = QQmlPropertyData::Flags::QVariantType; - } + const QMetaObject *valueTypeMetaObject + = QQmlMetaType::metaObjectForValueType(*type); + const QMetaProperty valueTypeMetaProperty + = valueTypeMetaObject->property(valueTypeIndex); + *type = resolveType(valueTypeMetaProperty.metaType()); + + // We can only write or reset the value type property if we can write + // the value type itself. + resettable = writable && valueTypeMetaProperty.isResettable(); + writable = writable && valueTypeMetaProperty.isWritable(); + + bindable = valueTypeMetaProperty.isBindable(); } } } - propertyFlags->setIsWritable(!(alias.hasFlag(QV4::CompiledData::Alias::IsReadOnly)) - && writable); + propertyFlags->setIsWritable( + writable && !alias.hasFlag(QV4::CompiledData::Alias::IsReadOnly)); propertyFlags->setIsResettable(resettable); propertyFlags->setIsBindable(bindable); return QQmlError(); diff --git a/src/qml/qml/qqmltypecompiler_p.h b/src/qml/qml/qqmltypecompiler_p.h index 1a100828f8..5b92b8de4a 100644 --- a/src/qml/qml/qqmltypecompiler_p.h +++ b/src/qml/qml/qqmltypecompiler_p.h @@ -132,6 +132,15 @@ public: return resolvedTypes->value(id); } + QV4::ResolvedTypeReference *resolvedType(QMetaType type) const + { + for (QV4::ResolvedTypeReference *ref : std::as_const(*resolvedTypes)) { + if (ref->type().typeId() == type) + return ref; + } + return nullptr; + } + CompositeMetaTypeIds typeIdsForComponent(int objectId = 0) const; private: diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp index fe9729cf75..a244bdd0ba 100644 --- a/src/qml/qml/qqmltypedata.cpp +++ b/src/qml/qml/qqmltypedata.cpp @@ -160,6 +160,9 @@ bool QQmlTypeData::tryLoadFromDiskCache() for (int i = 0, count = m_compiledData->objectCount(); i < count; ++i) { auto object = m_compiledData->objectAt(i); m_typeReferences.collectFromObject(object); + m_typeReferences.collectFromFunctions( + m_compiledData->objectFunctionsBegin(object), + m_compiledData->objectFunctionsEnd(object)); const auto inlineComponentTable = object->inlineComponentTable(); for (auto i = 0; i != object->nInlineComponents; ++i) { ics.push_back(inlineComponentTable[i]); @@ -660,7 +663,13 @@ void QQmlTypeData::continueLoadFromIR() } } - m_typeReferences.collectFromObjects(m_document->objects.constBegin(), m_document->objects.constEnd()); + for (auto it = m_document->objects.constBegin(), end = m_document->objects.constEnd(); + it != end; ++it) { + const QmlIR::Object *object = *it; + m_typeReferences.collectFromObject(object); + m_typeReferences.collectFromFunctions(object->functionsBegin(), object->functionsEnd()); + } + m_importCache.setBaseUrl(finalUrl(), finalUrlString()); // For remote URLs, we don't delay the loading of the implicit import diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 93736b0002..ce245ea6ce 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -91,8 +91,25 @@ const QMetaObject *QQmlTypeWrapper::metaObject() const if (!type.isValid()) return nullptr; - if (type.isSingleton()) - return type.metaObject(); + if (type.isSingleton()) { + auto metaObjectCandidate = type.metaObject(); + // if the candidate is the same as te baseMetaObject, we know that + // we don't have an extended singleton; in that case the + // actual instance might be subclass of type instead of type itself + // so we need to query the actual object for it's meta-object + if (metaObjectCandidate == type.baseMetaObject()) { + QQmlEnginePrivate *qmlEngine = QQmlEnginePrivate::get(engine()->qmlEngine()); + auto object = qmlEngine->singletonInstance<QObject *>(type); + if (object) + return object->metaObject(); + } + /* if we instead have an extended singleton, the dynamic proxy + meta-object must alreday be set up correctly + ### TODO: it isn't, as QQmlTypePrivate::init has no way to + query the object + */ + return metaObjectCandidate; + } return type.attachedPropertiesType(QQmlEnginePrivate::get(engine()->qmlEngine())); } diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index b6f68536ca..053058341a 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -925,15 +925,20 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * int coreIndex = encodedIndex.coreIndex(); const int valueTypePropertyIndex = encodedIndex.valueTypeIndex(); - // Remove binding (if any) on write - if(c == QMetaObject::WriteProperty) { - int flags = *reinterpret_cast<int*>(a[3]); - if (flags & QQmlPropertyData::RemoveBindingOnAliasWrite) { - QQmlData *targetData = QQmlData::get(target); - if (targetData && targetData->hasBindingBit(coreIndex)) - QQmlPropertyPrivate::removeBinding(target, encodedIndex); + const auto removePendingBinding + = [c, a](QObject *target, int coreIndex, QQmlPropertyIndex encodedIndex) { + // Remove binding (if any) on write + if (c == QMetaObject::WriteProperty) { + int flags = *reinterpret_cast<int*>(a[3]); + if (flags & QQmlPropertyData::RemoveBindingOnAliasWrite) { + QQmlData *targetData = QQmlData::get(target); + if (targetData && targetData->hasBindingBit(coreIndex)) { + QQmlPropertyPrivate::removeBinding(target, encodedIndex); + targetData->clearBindingBit(coreIndex); + } + } } - } + }; if (valueTypePropertyIndex != -1) { if (!targetDData->propertyCache) @@ -943,6 +948,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * QQmlGadgetPtrWrapper *valueType = QQmlGadgetPtrWrapper::instance( ctxt->engine(), pd->propType()); if (valueType) { + removePendingBinding(target, coreIndex, encodedIndex); valueType->read(target, coreIndex); int rv = QMetaObject::metacall(valueType, c, valueTypePropertyIndex, a); @@ -954,10 +960,14 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * // deep alias void *argv[1] = { &target }; QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex, argv); + removePendingBinding( + target, valueTypePropertyIndex, + QQmlPropertyIndex(valueTypePropertyIndex)); return QMetaObject::metacall(target, c, valueTypePropertyIndex, a); } } else { + removePendingBinding(target, coreIndex, encodedIndex); return QMetaObject::metacall(target, c, coreIndex, a); } diff --git a/src/qmltest/SignalSpy.qml b/src/qmltest/SignalSpy.qml index 7257e4f3f3..641f8642c6 100644 --- a/src/qmltest/SignalSpy.qml +++ b/src/qmltest/SignalSpy.qml @@ -81,6 +81,16 @@ Item { id: spy visible: false + Component.onDestruction: { + // We are potentially destroyed before the target object, + // and since only the sender (target) being destroyed destroys a connection + // in QML, and not the receiver (us/"spy"), we need to manually disconnect. + // When QTBUG-118166 is implemented, we can remove this. + let signalFunc = target ? target[signalName] : null + if (signalFunc) + signalFunc.disconnect(spy.qtest_activated) + } + TestUtil { id: util } diff --git a/src/qmltest/TestCase.qml b/src/qmltest/TestCase.qml index 5a2cd1d5c4..2b817ad7dd 100644 --- a/src/qmltest/TestCase.qml +++ b/src/qmltest/TestCase.qml @@ -260,6 +260,105 @@ import "testlogger.js" as TestLogger of \l Component, the \l createTemporaryObject() function can be used. \sa {QtTest::SignalSpy}{SignalSpy}, {Qt Quick Test} + + \section1 Separating tests from application logic + + In most cases, you would want to separate your tests from the application + logic by splitting them into different projects and linking them. + + For example, you could have the following project structure: + + \badcode + . + | — CMakeLists.txt + | — src + | | — main.cpp + | — qml + | | — main.qml + | — modules + | | — MyModule + | | — MyButton.qml + | | — CMakeLists.txt + | — tests + | — UnitQMLTests + | — tst_testqml.qml + | — tests_main.cpp + | — tests_setup.cpp + | — tests_setup.h + \endcode + + Now, to test \c modules/MyModule/MyButton.qml, create a library for + \c MyModule in \c modules/MyModule/CMakeLists.txt and link it to your + test project, \c tests/UnitQMLTests/CMakeLists.txt: + + \if defined(onlinedocs) + \tab {build-qt-app}{tab-cmake-add-library}{modules/MyModule/CMakeLists.txt}{checked} + \tab {build-qt-app}{tab-cmake-link-against-library}{tests/UnitQMLTests/CMakeLists.txt}{} + \tab {build-qt-app}{tab-tests_main}{tests/UnitQMLTests/tests_main.cpp}{} + \tab {build-qt-app}{tab-tests-setup-cpp}{tests/UnitQMLTests/tests_setup.cpp}{} + \tab {build-qt-app}{tab-tests-setup-h}{tests/UnitQMLTests/tests_setup.h}{} + \tabcontent {tab-cmake-add-library} + \else + \section1 Add library + \endif + \dots + \snippet modules_MyModule_CMakeLists.txt add library + \dots + \if defined(onlinedocs) + \endtabcontent + \tabcontent {tab-cmake-link-against-library} + \else + \section1 Link against library + \endif + \dots + \snippet tests_UnitQMLTests_CMakeLists.txt link against library + \dots + \if defined(onlinedocs) + \endtabcontent + \tabcontent {tab-tests_main} + \else + \section1 main.cpp + \endif + \snippet tests_main.cpp main + \if defined(onlinedocs) + \endtabcontent + \tabcontent {tab-tests-setup-cpp} + \else + \section1 setup c++ + \endif + \snippet tests_setup.cpp setup + \if defined(onlinedocs) + \endtabcontent + \tabcontent {tab-tests-setup-h} + \else + \section1 setup header + \endif + \snippet tests_setup.h setup + \if defined(onlinedocs) + \endtabcontent + \endif + + Then, in \c tests/UnitQMLTests/tst_testqml.qml, you can import + \c modules/MyModule/MyButton.qml: + + \if defined(onlinedocs) + \tab {test-qml}{tab-qml-import}{tests/UnitQMLTests/tst_testqml.qml}{checked} + \tab {test-qml}{tab-qml-my-button}{modules/MyModule/MyButton.qml}{} + \tabcontent {tab-qml-import} + \else + \section1 Import QML + \endif + \snippet tests_UnitQMLTests_tst_testqml.qml import + \if defined(onlinedocs) + \endtabcontent + \tabcontent {tab-qml-my-button} + \else + \section1 Define QML button + \endif + \snippet modules_MyModule_MyButton.qml define + \if defined(onlinedocs) + \endtabcontent + \endif */ diff --git a/src/qmltest/doc/snippets/modules_MyModule_CMakeLists.txt b/src/qmltest/doc/snippets/modules_MyModule_CMakeLists.txt new file mode 100644 index 0000000000..37ac70aaa2 --- /dev/null +++ b/src/qmltest/doc/snippets/modules_MyModule_CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 3.20) + +set(MODULE_NAME "MyModule") +project(${MODULE_NAME} LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) +set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + +find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick) + +file(GLOB QML_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml) +source_group("Qml Files" FILES ${QML_SOURCES}) + +//! [add library] +qt_add_library(MyModule STATIC) + +qt6_add_qml_module(MyModule + URI MyModule + VERSION 1.0 + QML_FILES ${QML_SOURCES} +) +//! [add library] + +set_target_properties(MyModule PROPERTIES + MACOSX_BUNDLE TRUE + WIN32_EXECUTABLE FALSE +) + +target_link_libraries(MyModule PRIVATE + Qt::Core + Qt::Gui + Qt::Qml + Qt::Quick +) + +target_include_directories(MyModule PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/src/qmltest/doc/snippets/modules_MyModule_MyButton.qml b/src/qmltest/doc/snippets/modules_MyModule_MyButton.qml new file mode 100644 index 0000000000..5d7dd9c7dd --- /dev/null +++ b/src/qmltest/doc/snippets/modules_MyModule_MyButton.qml @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2023 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [define] +import QtQuick +import QtQuick.Controls + +Button { + width: 50 + height: 50 + onClicked: width = 100 +} +//! [define] diff --git a/src/qmltest/doc/snippets/tests_UnitQMLTests_CMakeLists.txt b/src/qmltest/doc/snippets/tests_UnitQMLTests_CMakeLists.txt new file mode 100644 index 0000000000..ba444c2cd6 --- /dev/null +++ b/src/qmltest/doc/snippets/tests_UnitQMLTests_CMakeLists.txt @@ -0,0 +1,30 @@ +cmake_minimum_required(VERSION 3.2) + +project(TestQML LANGUAGES CXX) + +enable_testing() + +find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS QuickTest Qml) +find_package(Qt6 REQUIRED COMPONENTS QuickTest Qml) + +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +# no need to copy around qml test files for shadow builds - just set the respective define +add_definitions(-DQUICK_TEST_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}") + +//! [link against library] +add_executable(TestQML tests_main.cpp + tests_setup.cpp tests_setup.h) + +add_test(NAME TestQML COMMAND TestQML) + +target_link_libraries( + TestQML + PRIVATE Qt6::QuickTest + PRIVATE Qt6::Qml + PRIVATE MyModule + PRIVATE MyModuleplugin +) +//! [link against library] diff --git a/src/qmltest/doc/snippets/tests_UnitQMLTests_tst_testqml.qml b/src/qmltest/doc/snippets/tests_UnitQMLTests_tst_testqml.qml new file mode 100644 index 0000000000..432d20d762 --- /dev/null +++ b/src/qmltest/doc/snippets/tests_UnitQMLTests_tst_testqml.qml @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2023 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [import] +import QtQuick +import QtQuick.Controls + +import QtTest +import MyModule + +Item { + width: 800 + height: 600 + + MyButton { + id: myButton + anchors.centerIn: parent + } + + TestCase { + name: "MyButton" + when: windowShown + + function test_clickToExpand() { + const widthBeforeClick = myButton.width; + mouseClick(myButton); + const widthAfterClick = myButton.width; + verify(widthBeforeClick < widthAfterClick); + } + } +} +//! [import] diff --git a/src/qmltest/doc/snippets/tests_main.cpp b/src/qmltest/doc/snippets/tests_main.cpp new file mode 100644 index 0000000000..983f932acd --- /dev/null +++ b/src/qmltest/doc/snippets/tests_main.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2023 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [main] +#include <QtQuickTest/quicktest.h> +#include "tests_setup.h" + +QUICK_TEST_MAIN_WITH_SETUP(TestQML, Setup) +//! [main] diff --git a/src/qmltest/doc/snippets/tests_setup.cpp b/src/qmltest/doc/snippets/tests_setup.cpp new file mode 100644 index 0000000000..f7914dda87 --- /dev/null +++ b/src/qmltest/doc/snippets/tests_setup.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2023 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [setup] +#include "tests_setup.h" + +void Setup::applicationAvailable() +{ + // custom code that doesn't require QQmlEngine +} + +void Setup::qmlEngineAvailable(QQmlEngine *engine) +{ + // add import paths + engine->addImportPath("../../"); +} + +void Setup::cleanupTestCase() +{ + // custom code to clean up before destruction starts +} +//! [setup] diff --git a/src/qmltest/doc/snippets/tests_setup.h b/src/qmltest/doc/snippets/tests_setup.h new file mode 100644 index 0000000000..f5baa04eeb --- /dev/null +++ b/src/qmltest/doc/snippets/tests_setup.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2023 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [setup] +#ifndef SETUP_H +#define SETUP_H + +#include <QObject> +#include <QQmlEngine> + +class Setup : public QObject +{ + Q_OBJECT +public: + Setup() = default; + +public slots: + void applicationAvailable(); + void qmlEngineAvailable(QQmlEngine *engine); + void cleanupTestCase(); +}; + +#endif // SETUP_H +//! [setup] diff --git a/src/quick/doc/snippets/qml/pathview/pathview.qml b/src/quick/doc/snippets/qml/pathview/pathview.qml index 58d19b1a0c..0c3b96bb26 100644 --- a/src/quick/doc/snippets/qml/pathview/pathview.qml +++ b/src/quick/doc/snippets/qml/pathview/pathview.qml @@ -59,15 +59,20 @@ Rectangle { id: delegate Column { id: wrapper + + required property url icon + required property string name + opacity: PathView.isCurrentItem ? 1 : 0.5 + Image { anchors.horizontalCenter: nameText.horizontalCenter width: 64; height: 64 - source: icon + source: wrapper.icon } Text { id: nameText - text: name + text: wrapper.name font.pointSize: 16 } } diff --git a/src/quick/handlers/qquickpointerdevicehandler.cpp b/src/quick/handlers/qquickpointerdevicehandler.cpp index 69080b2027..a016ba5f12 100644 --- a/src/quick/handlers/qquickpointerdevicehandler.cpp +++ b/src/quick/handlers/qquickpointerdevicehandler.cpp @@ -306,7 +306,7 @@ bool QQuickPointerDeviceHandler::wantsPointerEvent(QPointerEvent *event) if (d->acceptedModifiers != Qt::KeyboardModifierMask && event->modifiers() != d->acceptedModifiers) return false; // Some handlers (HoverHandler, PinchHandler) set acceptedButtons to Qt::NoButton to indicate that button state is irrelevant. - if (event->pointingDevice()->pointerType() != QPointingDevice::PointerType::Finger && + if (event->pointingDevice()->type() != QPointingDevice::DeviceType::TouchScreen && acceptedButtons() != Qt::NoButton && event->type() != QEvent::Wheel && (static_cast<QSinglePointEvent *>(event)->buttons() & acceptedButtons()) == 0 && (static_cast<QSinglePointEvent *>(event)->button() & acceptedButtons()) == 0) diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp index 3abb366676..2b907d3805 100644 --- a/src/quick/handlers/qquicktaphandler.cpp +++ b/src/quick/handlers/qquicktaphandler.cpp @@ -121,15 +121,16 @@ bool QQuickTapHandler::wantsEventPoint(const QPointerEvent *event, const QEventP ret = parentContains(point); break; case QEventPoint::Updated: + ret = point.id() == this->point().id(); switch (m_gesturePolicy) { case DragThreshold: - ret = !overThreshold && parentContains(point); + ret = ret && !overThreshold && parentContains(point); break; case WithinBounds: - ret = parentContains(point); + ret = ret && parentContains(point); break; case ReleaseWithinBounds: - ret = point.id() == this->point().id(); + // no change to ret: depends only whether it's the already-tracking point ID break; } break; diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp index 1f5c55cffe..b1733b1791 100644 --- a/src/quick/items/qquickloader.cpp +++ b/src/quick/items/qquickloader.cpp @@ -197,9 +197,7 @@ qreal QQuickLoaderPrivate::getImplicitHeight() const \section2 Loader Sizing Behavior - If the source component is not an Item type, Loader does not - apply any special sizing rules. When used to load visual types, - Loader applies the following sizing rules: + When used to load visual types, Loader applies the following sizing rules: \list \li If an explicit size is not specified for the Loader, the Loader @@ -226,6 +224,8 @@ qreal QQuickLoaderPrivate::getImplicitHeight() const \li The red rectangle will be 50x50, centered in the root item. \endtable + If the source component is not an Item type, Loader does not apply any + special sizing rules. \section2 Receiving Signals from Loaded Objects diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp index 8687de8f43..d4b6e4c963 100644 --- a/src/quick/items/qquickmultipointtoucharea.cpp +++ b/src/quick/items/qquickmultipointtoucharea.cpp @@ -687,7 +687,7 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event, RemapEventPoints emit released(_releasedTouchPoints); if (moved) emit updated(_movedTouchPoints); - if (started) + if (started && !_pressedTouchPoints.isEmpty()) emit pressed(_pressedTouchPoints); if (ended || moved || started) emit touchUpdated(_touchPoints.values()); } @@ -732,12 +732,15 @@ void QQuickMultiPointTouchArea::addTouchPoint(const QEventPoint *p) void QQuickMultiPointTouchArea::addTouchPoint(const QMouseEvent *e) { QQuickTouchPoint *dtp = nullptr; - for (QQuickTouchPoint *tp : qAsConst(_touchPrototypes)) + for (QQuickTouchPoint *tp : qAsConst(_touchPrototypes)) { if (!tp->inUse()) { tp->setInUse(true); dtp = tp; break; + } else if (_mouseTouchPoint == tp) { + return; // do not allow more than one touchpoint to react to the mouse (QTBUG-83662) } + } if (dtp == nullptr) dtp = new QQuickTouchPoint(false); diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp index 9f259166df..f8f56557ae 100644 --- a/src/quick/items/qquicktableview.cpp +++ b/src/quick/items/qquicktableview.cpp @@ -1593,21 +1593,22 @@ void QQuickTableViewPrivate::forceLayout() const QSize actualTableSize = calculateTableSize(); if (tableSize != actualTableSize) { - // This can happen if the app is calling forceLayout while - // the model is updated, but before we're notified about it. - rebuildOptions = RebuildOption::All; - } else { - // Resizing a column (or row) can result in the table going from being - // e.g completely inside the viewport to go outside. And in the latter - // case, the user needs to be able to scroll the viewport, also if - // flags such as Flickable.StopAtBounds is in use. So we need to - // update contentWidth/Height to support that case. - rebuildOptions = RebuildOption::LayoutOnly - | RebuildOption::CalculateNewContentWidth - | RebuildOption::CalculateNewContentHeight - | checkForVisibilityChanges(); + // The table size will have changed if forceLayout is called after + // the row count in the model has changed, but before we received + // a rowsInsertedCallback about it (and vice versa for columns). + rebuildOptions |= RebuildOption::ViewportOnly; } + // Resizing a column (or row) can result in the table going from being + // e.g completely inside the viewport to go outside. And in the latter + // case, the user needs to be able to scroll the viewport, also if + // flags such as Flickable.StopAtBounds is in use. So we need to + // update contentWidth/Height to support that case. + rebuildOptions |= RebuildOption::LayoutOnly + | RebuildOption::CalculateNewContentWidth + | RebuildOption::CalculateNewContentHeight + | checkForVisibilityChanges(); + scheduleRebuildTable(rebuildOptions); auto rootView = rootSyncView(); @@ -3232,9 +3233,6 @@ QVariant QQuickTableViewPrivate::modelImpl() const void QQuickTableViewPrivate::setModelImpl(const QVariant &newModel) { - if (newModel == assignedModel) - return; - assignedModel = newModel; scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All); emit q_func()->modelChanged(); @@ -3242,7 +3240,7 @@ void QQuickTableViewPrivate::setModelImpl(const QVariant &newModel) void QQuickTableViewPrivate::syncModel() { - if (modelVariant == assignedModel) + if (compareModel(modelVariant, assignedModel)) return; if (model) { @@ -3498,6 +3496,13 @@ void QQuickTableViewPrivate::modelResetCallback() scheduleRebuildTable(RebuildOption::All); } +bool QQuickTableViewPrivate::compareModel(const QVariant& model1, const QVariant& model2) const +{ + return (model1 == model2 || + (model1.userType() == qMetaTypeId<QJSValue>() && model2.userType() == qMetaTypeId<QJSValue>() && + model1.value<QJSValue>().strictlyEquals(model2.value<QJSValue>()))); +} + void QQuickTableViewPrivate::scheduleRebuildIfFastFlick() { Q_Q(QQuickTableView); @@ -3727,6 +3732,9 @@ QVariant QQuickTableView::model() const void QQuickTableView::setModel(const QVariant &newModel) { + if (d_func()->compareModel(newModel, d_func()->assignedModel)) + return; + return d_func()->setModelImpl(newModel); } diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h index 9893cd97e7..3f969ab195 100644 --- a/src/quick/items/qquicktableview_p_p.h +++ b/src/quick/items/qquicktableview_p_p.h @@ -249,7 +249,7 @@ public: // When the applications assignes a new model or delegate to the view, we keep them // around until we're ready to take them into use (syncWithPendingChanges). QVariant assignedModel = QVariant(int(0)); - QQmlComponent *assignedDelegate = nullptr; + QQmlGuard<QQmlComponent> assignedDelegate; // loadedRows/Columns describes the rows and columns that are currently loaded (from top left // row/column to bottom right row/column). loadedTableOuterRect describes the actual @@ -477,6 +477,7 @@ public: void columnsRemovedCallback(const QModelIndex &parent, int begin, int end); void layoutChangedCallback(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint); void modelResetCallback(); + bool compareModel(const QVariant& model1, const QVariant& model2) const; void scheduleRebuildIfFastFlick(); void setLocalViewportX(qreal contentX); diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 597cd300df..a08f46a1b4 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -3305,6 +3305,11 @@ void QQuickWindow::endExternalCommands() The (x,y) position is relative to the \l Screen if there is only one, or to the virtual desktop (arrangement of multiple screens). + \note Not all windowing systems support setting or querying top level + window positions. On such a system, programmatically moving windows + may not have any effect, and artificial values may be returned for + the current positions, such as \c QPoint(0, 0). + \qml Window { x: 100; y: 100; width: 100; height: 100 } \endqml diff --git a/src/quick/scenegraph/shaders_ng/24bittextmask.frag b/src/quick/scenegraph/shaders_ng/24bittextmask.frag index ed8da4cd30..49023666ce 100644 --- a/src/quick/scenegraph/shaders_ng/24bittextmask.frag +++ b/src/quick/scenegraph/shaders_ng/24bittextmask.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/32bitcolortext.frag b/src/quick/scenegraph/shaders_ng/32bitcolortext.frag index 4198a4d339..000adb619e 100644 --- a/src/quick/scenegraph/shaders_ng/32bitcolortext.frag +++ b/src/quick/scenegraph/shaders_ng/32bitcolortext.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/8bittextmask.frag b/src/quick/scenegraph/shaders_ng/8bittextmask.frag index a06743876d..9507728803 100644 --- a/src/quick/scenegraph/shaders_ng/8bittextmask.frag +++ b/src/quick/scenegraph/shaders_ng/8bittextmask.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag b/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag index f725cbc5e7..9c0f36b81f 100644 --- a/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag +++ b/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.frag b/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.frag index b1551d8ef4..9e89d17219 100644 --- a/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.frag +++ b/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_a.frag b/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_a.frag index 7c6bd9a493..4fe30b69ee 100644 --- a/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_a.frag +++ b/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_a.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_a_fwidth.frag b/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_a_fwidth.frag index 30ec465791..4dc7432e44 100644 --- a/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_a_fwidth.frag +++ b/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_a_fwidth.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_fwidth.frag b/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_fwidth.frag index 511bffb09a..44aea6b979 100644 --- a/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_fwidth.frag +++ b/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_fwidth.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.frag b/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.frag index aa3390094b..320c19973b 100644 --- a/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.frag +++ b/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_a.frag b/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_a.frag index ab3a5f63ff..0ddd1b40d1 100644 --- a/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_a.frag +++ b/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_a.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_a_fwidth.frag b/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_a_fwidth.frag index 8f528fea1e..8b124213a4 100644 --- a/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_a_fwidth.frag +++ b/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_a_fwidth.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_fwidth.frag b/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_fwidth.frag index a71cc1d9b0..40f519636e 100644 --- a/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_fwidth.frag +++ b/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_fwidth.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/distancefieldtext.frag b/src/quick/scenegraph/shaders_ng/distancefieldtext.frag index d594207567..a86f68c8cb 100644 --- a/src/quick/scenegraph/shaders_ng/distancefieldtext.frag +++ b/src/quick/scenegraph/shaders_ng/distancefieldtext.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/distancefieldtext_a.frag b/src/quick/scenegraph/shaders_ng/distancefieldtext_a.frag index bb807d86d8..449647561f 100644 --- a/src/quick/scenegraph/shaders_ng/distancefieldtext_a.frag +++ b/src/quick/scenegraph/shaders_ng/distancefieldtext_a.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/distancefieldtext_a_fwidth.frag b/src/quick/scenegraph/shaders_ng/distancefieldtext_a_fwidth.frag index 1aa1175b57..534ec9208c 100644 --- a/src/quick/scenegraph/shaders_ng/distancefieldtext_a_fwidth.frag +++ b/src/quick/scenegraph/shaders_ng/distancefieldtext_a_fwidth.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/distancefieldtext_fwidth.frag b/src/quick/scenegraph/shaders_ng/distancefieldtext_fwidth.frag index a698c19550..04886d6b12 100644 --- a/src/quick/scenegraph/shaders_ng/distancefieldtext_fwidth.frag +++ b/src/quick/scenegraph/shaders_ng/distancefieldtext_fwidth.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/flatcolor.frag b/src/quick/scenegraph/shaders_ng/flatcolor.frag index 3a677b7c93..cac8f1fb17 100644 --- a/src/quick/scenegraph/shaders_ng/flatcolor.frag +++ b/src/quick/scenegraph/shaders_ng/flatcolor.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) out vec4 fragColor; diff --git a/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.frag b/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.frag index 723227a04d..19dce21aa4 100644 --- a/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.frag +++ b/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext_a.frag b/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext_a.frag index a9d56f6380..0cfe63edbf 100644 --- a/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext_a.frag +++ b/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext_a.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.frag b/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.frag index 08b2ce5187..343e93f54f 100644 --- a/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.frag +++ b/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec3 sampleNearLeft; diff --git a/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext_a.frag b/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext_a.frag index ef9407491b..e5aef90fda 100644 --- a/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext_a.frag +++ b/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext_a.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec3 sampleNearLeft; diff --git a/src/quick/scenegraph/shaders_ng/opaquetexture.frag b/src/quick/scenegraph/shaders_ng/opaquetexture.frag index 2cd2175f87..18dd7e0fcb 100644 --- a/src/quick/scenegraph/shaders_ng/opaquetexture.frag +++ b/src/quick/scenegraph/shaders_ng/opaquetexture.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 qt_TexCoord; diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext.frag b/src/quick/scenegraph/shaders_ng/outlinedtext.frag index e2f82d3845..6a5e1aa28b 100644 --- a/src/quick/scenegraph/shaders_ng/outlinedtext.frag +++ b/src/quick/scenegraph/shaders_ng/outlinedtext.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag b/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag index 274d891a3c..853f08e8ee 100644 --- a/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag +++ b/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/shadereffect.frag b/src/quick/scenegraph/shaders_ng/shadereffect.frag index bde493f6ce..ef4bbe78f3 100644 --- a/src/quick/scenegraph/shaders_ng/shadereffect.frag +++ b/src/quick/scenegraph/shaders_ng/shadereffect.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 qt_TexCoord0; diff --git a/src/quick/scenegraph/shaders_ng/smoothcolor.frag b/src/quick/scenegraph/shaders_ng/smoothcolor.frag index ede283be0c..314a387922 100644 --- a/src/quick/scenegraph/shaders_ng/smoothcolor.frag +++ b/src/quick/scenegraph/shaders_ng/smoothcolor.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec4 color; diff --git a/src/quick/scenegraph/shaders_ng/smoothtexture.frag b/src/quick/scenegraph/shaders_ng/smoothtexture.frag index b06764ad95..a7ddc57535 100644 --- a/src/quick/scenegraph/shaders_ng/smoothtexture.frag +++ b/src/quick/scenegraph/shaders_ng/smoothtexture.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 texCoord; diff --git a/src/quick/scenegraph/shaders_ng/sprite.frag b/src/quick/scenegraph/shaders_ng/sprite.frag index 338f5e957e..846958c71c 100644 --- a/src/quick/scenegraph/shaders_ng/sprite.frag +++ b/src/quick/scenegraph/shaders_ng/sprite.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec4 fTexS; diff --git a/src/quick/scenegraph/shaders_ng/stencilclip.frag b/src/quick/scenegraph/shaders_ng/stencilclip.frag index 3f6222389d..ec4d3a05b1 100644 --- a/src/quick/scenegraph/shaders_ng/stencilclip.frag +++ b/src/quick/scenegraph/shaders_ng/stencilclip.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) out vec4 fragColor; diff --git a/src/quick/scenegraph/shaders_ng/styledtext.frag b/src/quick/scenegraph/shaders_ng/styledtext.frag index 2e380dfeae..df14c09aed 100644 --- a/src/quick/scenegraph/shaders_ng/styledtext.frag +++ b/src/quick/scenegraph/shaders_ng/styledtext.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/styledtext_a.frag b/src/quick/scenegraph/shaders_ng/styledtext_a.frag index 62e162c851..eda1062f2d 100644 --- a/src/quick/scenegraph/shaders_ng/styledtext_a.frag +++ b/src/quick/scenegraph/shaders_ng/styledtext_a.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/textmask.frag b/src/quick/scenegraph/shaders_ng/textmask.frag index ed8da4cd30..49023666ce 100644 --- a/src/quick/scenegraph/shaders_ng/textmask.frag +++ b/src/quick/scenegraph/shaders_ng/textmask.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 sampleCoord; diff --git a/src/quick/scenegraph/shaders_ng/texture.frag b/src/quick/scenegraph/shaders_ng/texture.frag index bd22f817e0..d4be87ec29 100644 --- a/src/quick/scenegraph/shaders_ng/texture.frag +++ b/src/quick/scenegraph/shaders_ng/texture.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 qt_TexCoord; diff --git a/src/quick/scenegraph/shaders_ng/vertexcolor.frag b/src/quick/scenegraph/shaders_ng/vertexcolor.frag index ede283be0c..314a387922 100644 --- a/src/quick/scenegraph/shaders_ng/vertexcolor.frag +++ b/src/quick/scenegraph/shaders_ng/vertexcolor.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec4 color; diff --git a/src/quick/scenegraph/shaders_ng/visualization.frag b/src/quick/scenegraph/shaders_ng/visualization.frag index 29f718fe5d..378afc2088 100644 --- a/src/quick/scenegraph/shaders_ng/visualization.frag +++ b/src/quick/scenegraph/shaders_ng/visualization.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 pos; diff --git a/src/quick/util/qquickdeliveryagent.cpp b/src/quick/util/qquickdeliveryagent.cpp index a1f3fc64fd..7a6905b5de 100644 --- a/src/quick/util/qquickdeliveryagent.cpp +++ b/src/quick/util/qquickdeliveryagent.cpp @@ -1712,17 +1712,19 @@ void QQuickDeliveryAgentPrivate::onGrabChanged(QObject *grabber, QPointingDevice } if (currentEventDeliveryAgent == q && event && event->device()) { - auto epd = QPointingDevicePrivate::get(const_cast<QPointingDevice*>(event->pointingDevice()))->queryPointById(point.id()); - Q_ASSERT(epd); switch (transition) { case QPointingDevice::GrabPassive: { + auto epd = QPointingDevicePrivate::get(const_cast<QPointingDevice*>(event->pointingDevice()))->queryPointById(point.id()); + Q_ASSERT(epd); QPointingDevicePrivate::setPassiveGrabberContext(epd, grabber, q); qCDebug(lcPtr) << "remembering that" << q << "handles point" << point.id() << "after" << transition; } break; - case QPointingDevice::GrabExclusive: + case QPointingDevice::GrabExclusive: { + auto epd = QPointingDevicePrivate::get(const_cast<QPointingDevice*>(event->pointingDevice()))->queryPointById(point.id()); + Q_ASSERT(epd); epd->exclusiveGrabberContext = q; qCDebug(lcPtr) << "remembering that" << q << "handles point" << point.id() << "after" << transition; - break; + } break; case QPointingDevice::CancelGrabExclusive: case QPointingDevice::UngrabExclusive: // taken care of in QPointingDevicePrivate::setExclusiveGrabber(,,nullptr), removeExclusiveGrabber() diff --git a/src/quickcontrols2/basic/Menu.qml b/src/quickcontrols2/basic/Menu.qml index 475e58ccb8..bee89f94bb 100644 --- a/src/quickcontrols2/basic/Menu.qml +++ b/src/quickcontrols2/basic/Menu.qml @@ -54,9 +54,7 @@ T.Menu { contentItem: ListView { implicitHeight: contentHeight model: control.contentModel - interactive: Window.window - ? contentHeight + control.topPadding + control.bottomPadding > Window.window.height - : false + interactive: contentHeight + control.topPadding + control.bottomPadding > control.height clip: true currentIndex: control.currentIndex diff --git a/src/quickcontrols2/fusion/Menu.qml b/src/quickcontrols2/fusion/Menu.qml index 7808850ce4..d56860d43e 100644 --- a/src/quickcontrols2/fusion/Menu.qml +++ b/src/quickcontrols2/fusion/Menu.qml @@ -58,9 +58,7 @@ T.Menu { contentItem: ListView { implicitHeight: contentHeight model: control.contentModel - interactive: Window.window - ? contentHeight + control.topPadding + control.bottomPadding > Window.window.height - : false + interactive: contentHeight + control.topPadding + control.bottomPadding > control.height clip: true currentIndex: control.currentIndex diff --git a/src/quickcontrols2/imagine/Menu.qml b/src/quickcontrols2/imagine/Menu.qml index 346c649021..ec73df6afd 100644 --- a/src/quickcontrols2/imagine/Menu.qml +++ b/src/quickcontrols2/imagine/Menu.qml @@ -68,9 +68,7 @@ T.Menu { contentItem: ListView { implicitHeight: contentHeight model: control.contentModel - interactive: Window.window - ? contentHeight + control.topPadding + control.bottomPadding > Window.window.height - : false + interactive: contentHeight + control.topPadding + control.bottomPadding > control.height clip: true currentIndex: control.currentIndex diff --git a/src/quickcontrols2/material/Menu.qml b/src/quickcontrols2/material/Menu.qml index b7e80c92ef..df11e0ebf0 100644 --- a/src/quickcontrols2/material/Menu.qml +++ b/src/quickcontrols2/material/Menu.qml @@ -73,9 +73,7 @@ T.Menu { implicitHeight: contentHeight model: control.contentModel - interactive: Window.window - ? contentHeight + control.topPadding + control.bottomPadding > Window.window.height - : false + interactive: contentHeight + control.topPadding + control.bottomPadding > control.height clip: true currentIndex: control.currentIndex diff --git a/src/quickcontrols2/universal/Menu.qml b/src/quickcontrols2/universal/Menu.qml index c4723f32aa..5d5a1a5650 100644 --- a/src/quickcontrols2/universal/Menu.qml +++ b/src/quickcontrols2/universal/Menu.qml @@ -55,9 +55,7 @@ T.Menu { contentItem: ListView { implicitHeight: contentHeight model: control.contentModel - interactive: Window.window - ? contentHeight + control.topPadding + control.bottomPadding > Window.window.height - : false + interactive: contentHeight + control.topPadding + control.bottomPadding > control.height clip: true currentIndex: control.currentIndex diff --git a/src/quickshapes/shaders_ng/conicalgradient.frag b/src/quickshapes/shaders_ng/conicalgradient.frag index 0b1e01bae2..99592e14e4 100644 --- a/src/quickshapes/shaders_ng/conicalgradient.frag +++ b/src/quickshapes/shaders_ng/conicalgradient.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 coord; diff --git a/src/quickshapes/shaders_ng/lineargradient.frag b/src/quickshapes/shaders_ng/lineargradient.frag index 16894fc764..26fa540154 100644 --- a/src/quickshapes/shaders_ng/lineargradient.frag +++ b/src/quickshapes/shaders_ng/lineargradient.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in float gradTabIndex; diff --git a/src/quickshapes/shaders_ng/radialgradient.frag b/src/quickshapes/shaders_ng/radialgradient.frag index 411e589295..743cc2a8cb 100644 --- a/src/quickshapes/shaders_ng/radialgradient.frag +++ b/src/quickshapes/shaders_ng/radialgradient.frag @@ -1,3 +1,6 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #version 440 layout(location = 0) in vec2 coord; diff --git a/src/quicktemplates2/qquickstackview.cpp b/src/quicktemplates2/qquickstackview.cpp index 5b859adba1..77b674a22a 100644 --- a/src/quicktemplates2/qquickstackview.cpp +++ b/src/quicktemplates2/qquickstackview.cpp @@ -550,7 +550,8 @@ QQuickItem *QQuickStackView::find(const QJSValue &callback, LoadBehavior behavio \value StackView.ReplaceTransition An operation with replace transitions (since QtQuick.Controls 2.1). \value StackView.PopTransition An operation with pop transitions (since QtQuick.Controls 2.1). - If no operation is provided, \c PushTransition will be used. + If no operation is provided, \c Immediate will be used if the stack is + empty, and \c PushTransition otherwise. \note Items that already exist in the stack are not pushed. @@ -792,7 +793,8 @@ void QQuickStackView::pop(QQmlV4Function *args) \value StackView.ReplaceTransition An operation with replace transitions (since QtQuick.Controls 2.1). \value StackView.PopTransition An operation with pop transitions (since QtQuick.Controls 2.1). - If no operation is provided, \c ReplaceTransition will be used. + If no operation is provided, \c Immediate will be used if the stack is + empty, and \c ReplaceTransition otherwise. The following example illustrates the use of push and pop transitions with replace(). |