From b08a4c2f421494b515dc7ef6f50d33e37e18eb91 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Tue, 12 Jul 2016 19:29:39 +0200 Subject: Remove vsync sleep before rendering first frame The QSGRenderThread slept for up to one vsync interval before the first frame was rendered. This happened when the QSGRenderContext was not yet initialized and thus a sync could not result in changes. With LTTNG and custom trace points this latency was easily visible before the first frame swap. With perf it can also be checked, when one does: QSG_RENDER_LOOP=threaded perf trace record -m 10M \ -e syscalls:sys_enter_nanosleep,syscalls:sys_enter_ioctl \ --call-graph dwarf qml main.qml ... [ perf record: Captured and wrote 116.731 MB perf.data (14309 samples) ] Then afterwards have a look at the output of perf script --comms QSGRenderThread And you will notice the sleep directly at the start, followed by the bulk of ioctl required to setup the OpenGL contexts: QSGRenderThread 10875 [001] 13940.801449: syscalls:sys_enter_nanosleep: rqtp: 0x7f1ab954cd60, rmtp: 0x7f1ab954cd60 7f1ada3997fd __nanosleep+0x2d (/usr/lib/libpthread-2.23.so) 7f1ada9683ed qt_nanosleep+0x2d (/home/milian/projects/compiled/qt5-5.7-opt/lib/libQt5Core.so.5.7.0) 7f1ada8c73b8 QThread::msleep+0x38 (/home/milian/projects/compiled/qt5-5.7-opt/lib/libQt5Core.so.5.7.0) 7f1abb594320 QSGRenderThread::syncAndRender+0x320 (/home/milian/projects/compiled/qt5-5.7-opt/lib/libQt5Quick.so.5.7.0) 7f1abb598b0c QSGRenderThread::run+0x19c (/home/milian/projects/compiled/qt5-5.7-opt/lib/libQt5Quick.so.5.7.0) 7f1ada8c7f89 QThreadPrivate::start+0x149 (/home/milian/projects/compiled/qt5-5.7-opt/lib/libQt5Core.so.5.7.0) 7f1ada390484 start_thread+0xc4 (/usr/lib/libpthread-2.23.so) 7f1ad982e6dd __clone+0x6d (/usr/lib/libc-2.23.so) ... ioctl follow This change here checks the validity of the render context before sleeping, thereby removing the vsync latency before rendering the first frame. Note that simply skipping the calls to `syncAndRender` from `run` is not an option, as those also trigger the expose event that is required for the initialization to happen eventually. [ChangeLog][QtQuick] The threaded scene graph renderer does not sleep up to one vsync interval before the first frame anymore. Change-Id: If7474d5420e0d4a1d05ccb664c7c6932fa989127 Reviewed-by: Gunnar Sletta Reviewed-by: Ulf Hermann --- src/quick/scenegraph/qsgthreadedrenderloop.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index 8d6bea9e67..ceb3caa53f 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -593,7 +593,7 @@ void QSGRenderThread::syncAndRender() #endif Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame); - if (!syncResultedInChanges && !repaintRequested) { + if (!syncResultedInChanges && !repaintRequested && sgrc->isValid()) { qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- no changes, render aborted"; int waitTime = vsyncDelta - (int) waitTimer.elapsed(); if (waitTime > 0) -- cgit v1.2.3 From 06ed1ad17abe1ef597d4ecf86962da5ac21365e5 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 19 Jul 2016 11:28:14 +0200 Subject: JS: Check for errors before using sub-expression results Specifically: don't de-reference a result and assume that it's not-null. Task-number: QTBUG-54687 Change-Id: If07d3250a95a7815ab7a3262b88e0227965ef8e7 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4codegen.cpp | 116 ++++++++++++++++++++++++++++++++-------- 1 file changed, 95 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index c14163a2f7..6bf931c882 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -1052,6 +1052,8 @@ bool Codegen::visit(ArrayLiteral *ast) current->expr = _block->CONST(IR::MissingType, 0); } Result expr = expression(it->expression); + if (hasError) + return false; IR::ExprList *arg = _function->New(); if (!current) { @@ -1094,6 +1096,8 @@ bool Codegen::visit(ArrayMemberExpression *ast) Result base = expression(ast->base); Result index = expression(ast->expression); + if (hasError) + return false; _expr.code = subscript(*base, *index); return false; } @@ -1133,10 +1137,16 @@ bool Codegen::visit(BinaryExpression *ast) const unsigned r = _block->newTemp(); - move(_block->TEMP(r), *expression(ast->left)); + Result lhs = expression(ast->left); + if (hasError) + return false; + move(_block->TEMP(r), *lhs); setLocation(cjump(_block->TEMP(r), iftrue, endif), ast->operatorToken); _block = iftrue; - move(_block->TEMP(r), *expression(ast->right)); + Result rhs = expression(ast->right); + if (hasError) + return false; + move(_block->TEMP(r), *rhs); _block->JUMP(endif); _expr.code = _block->TEMP(r); @@ -1154,10 +1164,16 @@ bool Codegen::visit(BinaryExpression *ast) IR::BasicBlock *endif = _function->newBasicBlock(exceptionHandler()); const unsigned r = _block->newTemp(); - move(_block->TEMP(r), *expression(ast->left)); + Result lhs = expression(ast->left); + if (hasError) + return false; + move(_block->TEMP(r), *lhs); setLocation(cjump(_block->TEMP(r), endif, iffalse), ast->operatorToken); _block = iffalse; - move(_block->TEMP(r), *expression(ast->right)); + Result rhs = expression(ast->right); + if (hasError) + return false; + move(_block->TEMP(r), *rhs); _block->JUMP(endif); _block = endif; @@ -1167,6 +1183,8 @@ bool Codegen::visit(BinaryExpression *ast) } IR::Expr* left = *expression(ast->left); + if (hasError) + return false; switch (ast->op) { case QSOperator::Or: @@ -1176,17 +1194,19 @@ bool Codegen::visit(BinaryExpression *ast) case QSOperator::Assign: { if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation())) return false; - IR::Expr* right = *expression(ast->right); + Result right = expression(ast->right); + if (hasError) + return false; if (!left->isLValue()) { throwReferenceError(ast->operatorToken, QStringLiteral("left-hand side of assignment operator is not an lvalue")); return false; } if (_expr.accept(nx)) { - move(left, right); + move(left, *right); } else { const unsigned t = _block->newTemp(); - move(_block->TEMP(t), right); + move(_block->TEMP(t), *right); move(left, _block->TEMP(t)); _expr.code = _block->TEMP(t); } @@ -1206,17 +1226,19 @@ bool Codegen::visit(BinaryExpression *ast) case QSOperator::InplaceXor: { if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation())) return false; - IR::Expr* right = *expression(ast->right); + Result right = expression(ast->right); + if (hasError) + return false; if (!left->isLValue()) { throwSyntaxError(ast->operatorToken, QStringLiteral("left-hand side of inplace operator is not an lvalue")); return false; } if (_expr.accept(nx)) { - move(left, right, baseOp(ast->op)); + move(left, *right, baseOp(ast->op)); } else { const unsigned t = _block->newTemp(); - move(_block->TEMP(t), right); + move(_block->TEMP(t), *right); move(left, _block->TEMP(t), baseOp(ast->op)); _expr.code = left; } @@ -1239,12 +1261,14 @@ bool Codegen::visit(BinaryExpression *ast) left = _block->TEMP(t); } - IR::Expr* right = *expression(ast->right); + Result right = expression(ast->right); + if (hasError) + return false; if (_expr.accept(cx)) { - setLocation(cjump(binop(IR::binaryOperator(ast->op), left, right, ast->operatorToken), _expr.iftrue, _expr.iffalse), ast->operatorToken); + setLocation(cjump(binop(IR::binaryOperator(ast->op), left, *right, ast->operatorToken), _expr.iftrue, _expr.iffalse), ast->operatorToken); } else { - IR::Expr *e = binop(IR::binaryOperator(ast->op), left, right, ast->operatorToken); + IR::Expr *e = binop(IR::binaryOperator(ast->op), left, *right, ast->operatorToken); if (e->asConst() || e->asString()) _expr.code = e; else { @@ -1273,9 +1297,11 @@ bool Codegen::visit(BinaryExpression *ast) left = _block->TEMP(t); } - IR::Expr* right = *expression(ast->right); + Result right = expression(ast->right); + if (hasError) + return false; - IR::Expr *e = binop(IR::binaryOperator(ast->op), left, right, ast->operatorToken); + IR::Expr *e = binop(IR::binaryOperator(ast->op), left, *right, ast->operatorToken); if (e->asConst() || e->asString()) _expr.code = e; else { @@ -1300,11 +1326,15 @@ bool Codegen::visit(CallExpression *ast) IR::ExprList *args = 0, **args_it = &args; for (ArgumentList *it = ast->arguments; it; it = it->next) { Result arg = expression(it->expression); + if (hasError) + return false; IR::Expr *actual = argument(*arg); *args_it = _function->New(); (*args_it)->init(actual); args_it = &(*args_it)->next; } + if (hasError) + return false; _expr.code = call(*base, args); return false; } @@ -1323,11 +1353,17 @@ bool Codegen::visit(ConditionalExpression *ast) condition(ast->expression, iftrue, iffalse); _block = iftrue; - move(_block->TEMP(t), *expression(ast->ok)); + Result ok = expression(ast->ok); + if (hasError) + return false; + move(_block->TEMP(t), *ok); _block->JUMP(endif); _block = iffalse; - move(_block->TEMP(t), *expression(ast->ko)); + Result ko = expression(ast->ko); + if (hasError) + return false; + move(_block->TEMP(t), *ko); _block->JUMP(endif); _block = endif; @@ -1343,6 +1379,8 @@ bool Codegen::visit(DeleteExpression *ast) return false; IR::Expr* expr = *expression(ast->expression); + if (hasError) + return false; // Temporaries cannot be deleted IR::ArgLocal *al = expr->asArgLocal(); if (al && al->index < static_cast(_env->members.size())) { @@ -1404,7 +1442,8 @@ bool Codegen::visit(FieldMemberExpression *ast) return false; Result base = expression(ast->base); - _expr.code = member(*base, _function->newString(ast->name.toString())); + if (!hasError) + _expr.code = member(*base, _function->newString(ast->name.toString())); return false; } @@ -1495,6 +1534,8 @@ bool Codegen::visit(NewExpression *ast) return false; Result base = expression(ast->expression); + if (hasError) + return false; IR::Expr *expr = *base; if (expr && !expr->asTemp() && !expr->asArgLocal() && !expr->asName() && !expr->asMember()) { const unsigned t = _block->newTemp(); @@ -1511,6 +1552,8 @@ bool Codegen::visit(NewMemberExpression *ast) return false; Result base = expression(ast->base); + if (hasError) + return false; IR::Expr *expr = *base; if (expr && !expr->asTemp() && !expr->asArgLocal() && !expr->asName() && !expr->asMember()) { const unsigned t = _block->newTemp(); @@ -1521,6 +1564,8 @@ bool Codegen::visit(NewMemberExpression *ast) IR::ExprList *args = 0, **args_it = &args; for (ArgumentList *it = ast->arguments; it; it = it->next) { Result arg = expression(it->expression); + if (hasError) + return false; IR::Expr *actual = argument(*arg); *args_it = _function->New(); (*args_it)->init(actual); @@ -1538,6 +1583,8 @@ bool Codegen::visit(NotExpression *ast) return false; Result expr = expression(ast->expression); + if (hasError) + return false; const unsigned r = _block->newTemp(); setLocation(move(_block->TEMP(r), unop(IR::OpNot, *expr, ast->notToken)), ast->notToken); _expr.code = _block->TEMP(r); @@ -1595,6 +1642,8 @@ bool Codegen::visit(ObjectLiteral *ast) QString name = it->assignment->name->asString(); if (PropertyNameAndValue *nv = AST::cast(it->assignment)) { Result value = expression(nv->value); + if (hasError) + return false; ObjectPropertyValue &v = valueMap[name]; if (v.hasGetter() || v.hasSetter() || (_function->isStrict && v.value)) { throwSyntaxError(nv->lastSourceLocation(), @@ -1725,6 +1774,8 @@ bool Codegen::visit(PostDecrementExpression *ast) return false; Result expr = expression(ast->base); + if (hasError) + return false; if (!expr->isLValue()) { throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral("Invalid left-hand side expression in postfix operation")); return false; @@ -1751,6 +1802,8 @@ bool Codegen::visit(PostIncrementExpression *ast) return false; Result expr = expression(ast->base); + if (hasError) + return false; if (!expr->isLValue()) { throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral("Invalid left-hand side expression in postfix operation")); return false; @@ -1777,6 +1830,8 @@ bool Codegen::visit(PreDecrementExpression *ast) return false; Result expr = expression(ast->expression); + if (hasError) + return false; if (!expr->isLValue()) { throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral("Prefix ++ operator applied to value that is not a reference.")); return false; @@ -1802,6 +1857,8 @@ bool Codegen::visit(PreIncrementExpression *ast) return false; Result expr = expression(ast->expression); + if (hasError) + return false; if (!expr->isLValue()) { throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral("Prefix ++ operator applied to value that is not a reference.")); return false; @@ -1854,6 +1911,8 @@ bool Codegen::visit(TildeExpression *ast) return false; Result expr = expression(ast->expression); + if (hasError) + return false; const unsigned t = _block->newTemp(); setLocation(move(_block->TEMP(t), unop(IR::OpCompl, *expr, ast->tildeToken)), ast->tildeToken); _expr.code = _block->TEMP(t); @@ -1879,6 +1938,8 @@ bool Codegen::visit(TypeOfExpression *ast) return false; Result expr = expression(ast->expression); + if (hasError) + return false; IR::ExprList *args = _function->New(); args->init(reference(*expr)); _expr.code = call(_block->NAME(IR::Name::builtin_typeof, ast->typeofToken.startLine, ast->typeofToken.startColumn), args); @@ -1891,6 +1952,8 @@ bool Codegen::visit(UnaryMinusExpression *ast) return false; Result expr = expression(ast->expression); + if (hasError) + return false; const unsigned t = _block->newTemp(); setLocation(move(_block->TEMP(t), unop(IR::OpUMinus, *expr, ast->minusToken)), ast->minusToken); _expr.code = _block->TEMP(t); @@ -1903,6 +1966,8 @@ bool Codegen::visit(UnaryPlusExpression *ast) return false; Result expr = expression(ast->expression); + if (hasError) + return false; const unsigned t = _block->newTemp(); setLocation(move(_block->TEMP(t), unop(IR::OpUPlus, *expr, ast->plusToken)), ast->plusToken); _expr.code = _block->TEMP(t); @@ -2217,7 +2282,10 @@ bool Codegen::visit(ForEachStatement *ast) IR::BasicBlock *foreachend = _function->newBasicBlock(exceptionHandler()); int objectToIterateOn = _block->newTemp(); - move(_block->TEMP(objectToIterateOn), *expression(ast->expression)); + Result expr = expression(ast->expression); + if (hasError) + return false; + move(_block->TEMP(objectToIterateOn), *expr); IR::ExprList *args = _function->New(); args->init(_block->TEMP(objectToIterateOn)); @@ -2229,7 +2297,10 @@ bool Codegen::visit(ForEachStatement *ast) _block = foreachbody; int temp = _block->newTemp(); - move(*expression(ast->initialiser), _block->TEMP(temp)); + Result init = expression(ast->initialiser); + if (hasError) + return false; + move(*init, _block->TEMP(temp)); statement(ast->statement); _block->JUMP(foreachin); @@ -2719,7 +2790,10 @@ bool Codegen::visit(WithStatement *ast) _function->hasWith = true; const int withObject = _block->newTemp(); - _block->MOVE(_block->TEMP(withObject), *expression(ast->expression)); + Result src = expression(ast->expression); + if (hasError) + return false; + _block->MOVE(_block->TEMP(withObject), *src); // need an exception handler for with to cleanup the with scope IR::BasicBlock *withExceptionHandler = _function->newBasicBlock(exceptionHandler()); -- cgit v1.2.3 From d6ac86f59250e05eb5e7db5bb8a45a85db1f0f25 Mon Sep 17 00:00:00 2001 From: Maximiliano Curia Date: Tue, 19 Jul 2016 15:49:48 +0200 Subject: Fix QQmlEngine crash on big endian 64 bit architectures (s390x) This change disables the BIG_ENDIAN 32 bits words mangling in 64 bits machines (where the words are 64 bits long); this would otherwise result in a segfault. Task-number: QTBUG-54717 Change-Id: I6b5ab6f213880b030795185c05e609d290168901 Reviewed-by: Simon Hausmann Reviewed-by: Timo Jyrinki Reviewed-by: Erik Verbruggen --- src/qml/jsruntime/qv4value_p.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 7c2bb31a00..5abf5ad9e8 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -96,13 +96,13 @@ public: Q_ALWAYS_INLINE quint64 rawValue() const { return _val; } Q_ALWAYS_INLINE void setRawValue(quint64 raw) { _val = raw; } -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN || defined(QV4_USE_64_BIT_VALUE_ENCODING) static inline int valueOffset() { return 0; } static inline int tagOffset() { return 4; } Q_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; } Q_ALWAYS_INLINE quint32 value() const { return _val & quint64(~quint32(0)); } Q_ALWAYS_INLINE quint32 tag() const { return _val >> 32; } -#else // !Q_LITTLE_ENDIAN +#else // !Q_LITTLE_ENDIAN && !defined(QV4_USE_64_BIT_VALUE_ENCODING) static inline int valueOffset() { return 4; } static inline int tagOffset() { return 0; } Q_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(value) << 32 | tag; } -- cgit v1.2.3 From c016634478a4c9f480f7d9d5c85dded307a80d13 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 20 Jul 2016 09:25:46 +0200 Subject: Fix string property assignments to 2d vectors and quaternions Just like it's possible to assign "1,2,3" to a QVector3D, the same should be possible for a QVector2D and a QQuaternion. Task-number: QTBUG-54858 Change-Id: I8f394279dcdf5c057876efaa316b4bad51a4c126 Reviewed-by: Robin Burchell --- src/qml/compiler/qqmltypecompiler.cpp | 24 ++++++++++++++++++++++++ src/qml/qml/qqmlobjectcreator.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) (limited to 'src') diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index fcc0ca8d14..7e4ee344ff 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -2244,6 +2244,17 @@ bool QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCa } } break; + case QVariant::Vector2D: { + struct { + float xp; + float yp; + } vec; + if (!QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) { + recordError(binding->valueLocation, tr("Invalid property assignment: 2D vector expected")); + return false; + } + } + break; case QVariant::Vector3D: { struct { float xp; @@ -2269,6 +2280,19 @@ bool QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCa } } break; + case QVariant::Quaternion: { + struct { + float wp; + float xp; + float yp; + float zp; + } vec; + if (!QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) { + recordError(binding->valueLocation, tr("Invalid property assignment: quaternion expected")); + return false; + } + } + break; case QVariant::RegExp: recordError(binding->valueLocation, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax")); return false; diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 15c38c1d5b..0c13a7a017 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -507,6 +507,18 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } break; + case QVariant::Vector2D: { + struct { + float xp; + float yp; + } vec; + bool ok = QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(qmlUnit), &vec, sizeof(vec)); + Q_ASSERT(ok); + Q_UNUSED(ok); + argv[0] = reinterpret_cast(&vec); + QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + } + break; case QVariant::Vector3D: { struct { float xp; @@ -534,6 +546,20 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } break; + case QVariant::Quaternion: { + struct { + float wp; + float xp; + float yp; + float zp; + } vec; + bool ok = QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(qmlUnit), &vec, sizeof(vec)); + Q_ASSERT(ok); + Q_UNUSED(ok); + argv[0] = reinterpret_cast(&vec); + QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + } + break; case QVariant::RegExp: Q_ASSERT(!"not possible"); break; -- cgit v1.2.3 From 0a87552e8122cdda58160da2dd549da411d9093c Mon Sep 17 00:00:00 2001 From: Dan Cape Date: Wed, 7 Oct 2015 15:46:14 -0400 Subject: Fix QQuickItem's setAcceptedMouseButtons function When using setAcceptedMouseButtons to only allow the LeftButton, the user can click the LeftButton and while still holding it press the RightButton. There would be a press event sent for both. To resolve this, a check needed to be added to ensure the acceptedMouseButtons are checked when a second press comes in. [ChangeLog][QtQuick][QQuickItem] Fixed issue with mouse button events being sent even when they were disabled by setAcceptedMouseButtons. Change-Id: I064f3ff56ede12b1572e172be326eb337e280750 Task-number: QTBUG-31861 Reviewed-by: Frederik Gladhorn Reviewed-by: Robin Burchell Reviewed-by: Shawn Rutledge --- src/quick/items/qquickwindow.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index de1b5f236e..8a2471b34f 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -1584,6 +1584,12 @@ bool QQuickWindowPrivate::deliverMouseEvent(QMouseEvent *event) } if (mouseGrabberItem) { + if (event->button() != Qt::NoButton + && mouseGrabberItem->acceptedMouseButtons() + && !(mouseGrabberItem->acceptedMouseButtons() & event->button())) { + event->ignore(); + return false; + } QPointF localPos = mouseGrabberItem->mapFromScene(event->windowPos()); QScopedPointer me(cloneMouseEvent(event, &localPos)); me->accept(); -- cgit v1.2.3 From 1943ef3b06d3f95a4e6c4d24f771cee8db02d342 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 22 Jul 2016 19:38:10 -0700 Subject: Work around ICC bug about C++11 noexcept inheritance qquickitemanimation.cpp(213): error #809: exception specification for virtual function "QQuickParentAnimationData::~QQuickParentAnimationData" is incompatible with that of overridden function "QAbstractAnimationAction::~QAbstractAnimationAction" Change-Id: I149e0540c00745fe8119fffd1463cb59e590b6b8 Reviewed-by: Simon Hausmann --- src/quick/items/qquickitemanimation.cpp | 42 ++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickitemanimation.cpp b/src/quick/items/qquickitemanimation.cpp index 9d140b3156..6b48ca5bf9 100644 --- a/src/quick/items/qquickitemanimation.cpp +++ b/src/quick/items/qquickitemanimation.cpp @@ -194,6 +194,27 @@ QPointF QQuickParentAnimationPrivate::computeTransformOrigin(QQuickItem::Transfo } } +struct QQuickParentAnimationData : public QAbstractAnimationAction +{ + QQuickParentAnimationData() : reverse(false) {} + ~QQuickParentAnimationData() { qDeleteAll(pc); } + + QQuickStateActions actions; + //### reverse should probably apply on a per-action basis + bool reverse; + QList pc; + void doAction() Q_DECL_OVERRIDE + { + for (int ii = 0; ii < actions.count(); ++ii) { + const QQuickStateAction &action = actions.at(ii); + if (reverse) + action.event->reverse(); + else + action.event->execute(); + } + } +}; + QAbstractAnimationJob* QQuickParentAnimation::transition(QQuickStateActions &actions, QQmlProperties &modified, TransitionDirection direction, @@ -201,27 +222,6 @@ QAbstractAnimationJob* QQuickParentAnimation::transition(QQuickStateActions &act { Q_D(QQuickParentAnimation); - struct QQuickParentAnimationData : public QAbstractAnimationAction - { - QQuickParentAnimationData() : reverse(false) {} - ~QQuickParentAnimationData() { qDeleteAll(pc); } - - QQuickStateActions actions; - //### reverse should probably apply on a per-action basis - bool reverse; - QList pc; - void doAction() Q_DECL_OVERRIDE - { - for (int ii = 0; ii < actions.count(); ++ii) { - const QQuickStateAction &action = actions.at(ii); - if (reverse) - action.event->reverse(); - else - action.event->execute(); - } - } - }; - QQuickParentAnimationData *data = new QQuickParentAnimationData; QQuickParentAnimationData *viaData = new QQuickParentAnimationData; -- cgit v1.2.3 From 16b680b734101db0cb4fa3f313ac563a509ddff4 Mon Sep 17 00:00:00 2001 From: Thomas McGuire Date: Mon, 25 Jul 2016 13:23:34 +0200 Subject: QQmlPropertyMap: Don't spuriously emit valueChanged() signal The valueChanged() signal was emitted when the property was written with the same value. This increased the potential for binding loops in user code. Change-Id: Ifeb8f6f23e2022aa35cb6cac7cf1a3dbc0e8ca2f Task-number: QTBUG-48136 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlopenmetaobject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp index 9188ba6174..0e60cae92f 100644 --- a/src/qml/qml/qqmlopenmetaobject.cpp +++ b/src/qml/qml/qqmlopenmetaobject.cpp @@ -272,7 +272,7 @@ int QQmlOpenMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void * propertyRead(propId); *reinterpret_cast(a[0]) = d->getData(propId); } else if (c == QMetaObject::WriteProperty) { - if (propId <= d->data.count() || d->data[propId].first != *reinterpret_cast(a[0])) { + if (propId >= d->data.count() || d->data[propId].first != *reinterpret_cast(a[0])) { propertyWrite(propId); QPair &prop = d->getDataRef(propId); prop.first = propertyWriteValue(propId, *reinterpret_cast(a[0])); -- cgit v1.2.3 From 1c5737d3cb0502f551f7108feda517b153572954 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 26 Jul 2016 09:43:49 +0200 Subject: Mention Q_FLAG in C++ <=> QML type conversion documentation For a user visiting doc.qt.io/qt-5/qtqml-cppintegration-data.html, it's very difficult to know how to use an enum as flags in QML, because it's not mentioned anywhere on this page. Change-Id: I35065bff825b8aebab1477ec883d17cbab92b3ba Reviewed-by: Frederik Gladhorn --- src/qml/doc/src/cppintegration/data.qdoc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc index e153ca3d8b..ff30bffa83 100644 --- a/src/qml/doc/src/cppintegration/data.qdoc +++ b/src/qml/doc/src/cppintegration/data.qdoc @@ -375,6 +375,8 @@ Message { } \endqml +To use an enum as a \l {QFlags}{flags} type in QML, see \l Q_FLAG(). + \note The names of enum values must begin with a capital letter in order to be accessible from QML. -- cgit v1.2.3 From a05f59388e004160899d5d311884cfabe10c3b8c Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Fri, 1 Jul 2016 16:32:20 +0200 Subject: Fix documentation of Component.createObject The parent argument should really be any QObject, not just Items. Change-Id: I4d105722b9d76585dd353eddf464a1ec39fea75e Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlcomponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 24abf52e38..9d56ea50de 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1145,7 +1145,7 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent) } /*! - \qmlmethod object Component::createObject(Item parent, object properties) + \qmlmethod object Component::createObject(QtObject parent, object properties) Creates and returns an object instance of this component that will have the given \a parent and \a properties. The \a properties argument is optional. -- cgit v1.2.3 From 75d6392d6c5efa6fdd1f63cac6a2438fedb2f2a9 Mon Sep 17 00:00:00 2001 From: Venugopal Shivashankar Date: Tue, 1 Mar 2016 15:31:52 +0100 Subject: Doc: Describe how to implement custom SQL models for QML Change-Id: I31781f32c2f9699f386a326f18cb5cc705582a89 Reviewed-by: Leena Miettinen Reviewed-by: Mitch Curtis --- .../doc/src/concepts/modelviewsdata/cppmodels.qdoc | 105 +++++++++++++++++++++ 1 file changed, 105 insertions(+) (limited to 'src') diff --git a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc index cb281a2d4a..a764402c2f 100644 --- a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc +++ b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc @@ -156,6 +156,111 @@ with list models of QAbstractItemModel type: \li \l DelegateModel::parentModelIndex() returns a QModelIndex which can be assigned to DelegateModel::rootIndex \endlist +\section2 SQL Models + +Qt provides C++ classes that support SQL data models. These classes work +transparently on the underlying SQL data, reducing the need to run SQL +queries for basic SQL operations such as create, insert, or update. +For more details about these classes, see \l{Using the SQL Model Classes}. + +Although the C++ classes provide complete feature sets to operate on SQL +data, they do not provide data access to QML. So you must implement a +C++ custom data model as a subclass of one of these classes, and expose it +to QML either as a type or context property. + +\section3 Read-only Data Model + +The custom model must reimplement the following methods to enable read-only +access to the data from QML: + +\list +\li \l{QAbstractItemModel::}{roleNames}() to expose the role names to the + QML frontend. For example, the following version returns the selected + table's field names as role names: + \code + QHash SqlQueryModel::roleNames() const + { + QHash roles; + // record() returns an empty QSqlRecord + for (int i = 0; i < this->record().count(); i ++) { + roles.insert(Qt::UserRole + i + 1, record().fieldName(i).toUtf8()); + } + return roles; + } + \endcode +\li \l{QSqlQueryModel::}{data}() to expose SQL data to the QML frontend. + For example, the following implementation returns data for the given + model index: + \code + QVariant SqlQueryModel::data(const QModelIndex &index, int role) const + { + QVariant value; + + if (index.isValid()) { + if (role < Qt::UserRole) { + value = QSqlQueryModel::data(index, role); + } else { + int columnIdx = role - Qt::UserRole - 1; + QModelIndex modelIndex = this->index(index.row(), columnIdx); + value = QSqlQueryModel::data(modelIndex, Qt::DisplayRole); + } + } + return value; + } + \endcode +\endlist + +The QSqlQueryModel class is good enough to implement a custom read-only +model that represents data in an SQL database. The +\l{Qt Quick Controls 2 - Chat Tutorial}{chat tutorial} example +demonstrates this very well by implementing a custom model to fetch the +contact details from an SQLite database. + +\section3 Editable Data Model + +Besides the \c roleNames() and \c data(), the editable models must reimplement +the \l{QSqlTableModel::}{setData} method to save changes to existing SQL data. +The following version of the method checks if the given model index is valid +and the \c role is equal to \l Qt::EditRole, before calling the parent class +version: + +\code +bool SqlEditableModel::setData(const QModelIndex &item, const QVariant &value, int role) +{ + if (item.isValid() && role == Qt::EditRole) { + QSqlTableModel::setData(item, value,role); + emit dataChanged(item, item); + return true; + } + return false; + +} +\endcode + +\note It is important to emit the \l{QAbstractItemModel::}{dataChanged}() +signal after saving the changes. + +Unlike the C++ item views such as QListView or QTableView, the \c setData() +method must be explicitly invoked from QML whenever appropriate. For example, +on the \l[QML]{TextField::}{editingFinished}() or \l[QML]{TextField::}{accepted}() +signal of \l[QtQuickControls]{TextField}. Depending on the +\l{QSqlTableModel::}{EditStrategy} used by the model, the changes are either +queued for submission later or submitted immediately. + +You can also insert new data into the model by calling +\l {QSqlTableModel::insertRecord}(). In the following example snippet, +a QSqlRecord is populated with book details and appended to the +model: + +\code + ... + QSqlRecord newRecord = record(); + newRecord.setValue("author", "John Grisham"); + newRecord.setValue("booktitle", "The Litigators"); + insertRecord(rowCount(), newRecord); + ... +\endcode + \section2 Exposing C++ Data Models to QML The above examples use QQmlContext::setContextProperty() to set -- cgit v1.2.3 From fe92db0a0eeed502ef851930b3404b38c4a03f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Martins?= Date: Fri, 29 Jul 2016 13:32:22 +0100 Subject: Revert "macOS: Use sRGB when doing native font rendering into FBO" This reverts commit 1e18a4f985f6ec4a0191a2e0cc087b13d29b1719. It breaks a QtCanvas3D unit-test and I can't look at it now. Will have another take at this soon. Change-Id: I22acd55443783934596d25cc4c8774bd34609f6b Reviewed-by: Liang Qi --- src/quick/scenegraph/qsgdefaultlayer.cpp | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/quick/scenegraph/qsgdefaultlayer.cpp b/src/quick/scenegraph/qsgdefaultlayer.cpp index 99735564ef..fa69f911dd 100644 --- a/src/quick/scenegraph/qsgdefaultlayer.cpp +++ b/src/quick/scenegraph/qsgdefaultlayer.cpp @@ -42,29 +42,6 @@ DEFINE_BOOL_CONFIG_OPTION(qmlFboOverlay, QML_FBO_OVERLAY) #endif DEFINE_BOOL_CONFIG_OPTION(qmlFboFlushBeforeDetach, QML_FBO_FLUSH_BEFORE_DETACH) - - -static QOpenGLFramebufferObject *createFramebuffer(const QSize &size, - QOpenGLFramebufferObjectFormat format) -{ -#ifdef Q_OS_MACOS - QOpenGLContext *context = QOpenGLContext::currentContext(); - if (context->hasExtension("GL_ARB_framebuffer_sRGB") - && context->hasExtension("GL_EXT_texture_sRGB") - && context->hasExtension("GL_EXT_texture_sRGB_decode")) - format.setInternalTextureFormat(GL_SRGB8_ALPHA8_EXT); -#endif - QOpenGLFramebufferObject *fbo = new QOpenGLFramebufferObject(size, format); -#ifdef Q_OS_MACOS - if (format.internalTextureFormat() == GL_SRGB8_ALPHA8_EXT) { - QOpenGLFunctions *funcs = context->functions(); - funcs->glBindTexture(GL_TEXTURE_2D, fbo->texture()); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT); - } -#endif - return fbo; -} - namespace { class BindableFbo : public QSGBindable @@ -347,7 +324,7 @@ void QSGDefaultLayer::grab() format.setInternalTextureFormat(m_format); format.setSamples(m_context->openglContext()->format().samples()); - m_secondaryFbo = createFramebuffer(m_size, format); + m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format); m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo); } else { QOpenGLFramebufferObjectFormat format; @@ -356,14 +333,14 @@ void QSGDefaultLayer::grab() if (m_recursive) { deleteFboLater = true; delete m_secondaryFbo; - m_secondaryFbo = createFramebuffer(m_size, format); + m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format); funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture()); updateBindOptions(true); m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo); } else { delete m_fbo; delete m_secondaryFbo; - m_fbo = createFramebuffer(m_size, format); + m_fbo = new QOpenGLFramebufferObject(m_size, format); m_secondaryFbo = 0; funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); updateBindOptions(true); @@ -377,7 +354,7 @@ void QSGDefaultLayer::grab() Q_ASSERT(m_fbo); Q_ASSERT(!m_multisampling); - m_secondaryFbo = createFramebuffer(m_size, m_fbo->format()); + m_secondaryFbo = new QOpenGLFramebufferObject(m_size, m_fbo->format()); funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture()); updateBindOptions(true); } -- cgit v1.2.3