From 453a3806a31b29e8d57664359395ff1a59fdd49e Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 9 Oct 2018 08:57:20 +0200 Subject: Document that aliases cannot point to attached properties Change-Id: I0acef28542e5322cf3de23ec7fcb571513ccb673 Reviewed-by: Simon Hausmann --- src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc index 31650db7c0..2bb1fcac61 100644 --- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc +++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc @@ -462,6 +462,8 @@ Unlike an ordinary property, an alias has the following restrictions: \li The \e {alias reference} is not optional, unlike the optional default value for an ordinary property; the alias reference must be provided when the alias is first declared. +\li It cannot refer to \l {Attached Properties and Attached Signal Handlers} + {attached properties}. \li It cannot refer to grouped properties; the following code will not work: \code property alias color: rectangle.border.color -- cgit v1.2.3 From 7ca32bc41c2b5a5f6ea360391ba7e398ad7f961b Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Thu, 11 Oct 2018 09:14:51 +0200 Subject: qmlplugindump: Remove sigsegv handler It's not safe to use printf and memory allocations in a signal handler. Task-number: QTBUG-70460 Change-Id: I2a4caf302e17992471575bd89faa505a8db4a7e3 Reviewed-by: Marco Benelli Reviewed-by: Simon Hausmann --- tools/qmlplugindump/main.cpp | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp index 5c5a6a8eb1..08fc0168dd 100644 --- a/tools/qmlplugindump/main.cpp +++ b/tools/qmlplugindump/main.cpp @@ -66,9 +66,6 @@ #include #endif -#ifdef Q_OS_UNIX -#include -#endif #ifdef Q_OS_WIN # if !defined(Q_CC_MINGW) # include @@ -731,17 +728,6 @@ enum ExitCode { EXIT_IMPORTERROR = 3 }; -#ifdef Q_OS_UNIX -void sigSegvHandler(int) { - fprintf(stderr, "Error: SEGV\n"); - if (!currentProperty.isEmpty()) - fprintf(stderr, "While processing the property '%s', which probably has uninitialized data.\n", currentProperty.toLatin1().constData()); - if (!inObjectInstantiation.isEmpty()) - fprintf(stderr, "While instantiating the object '%s'.\n", inObjectInstantiation.toLatin1().constData()); - exit(EXIT_SEGV); -} -#endif - void printUsage(const QString &appName) { std::cerr << qPrintable(QString( @@ -964,17 +950,6 @@ int main(int argc, char *argv[]) #endif // Q_OS_WIN && !Q_CC_MINGW // The default message handler might not print to console on some systems. Enforce this. qInstallMessageHandler(printDebugMessage); -#ifdef Q_OS_UNIX - // qmldump may crash, but we don't want any crash handlers to pop up - // therefore we intercept the segfault and just exit() ourselves - struct sigaction sigAction; - - sigemptyset(&sigAction.sa_mask); - sigAction.sa_handler = &sigSegvHandler; - sigAction.sa_flags = 0; - - sigaction(SIGSEGV, &sigAction, nullptr); -#endif #ifdef QT_SIMULATOR // Running this application would bring up the Qt Simulator (since it links Qt GUI), avoid that! -- cgit v1.2.3 From 1ce94fc0f5311c8d9d7dc50de239a827279edcd9 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 11 Sep 2018 10:41:57 +0200 Subject: Qt Labs Settings: warn if failed to initialize internal QSettings instance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First, warn the user that the QSettings instance failed to initialize if there was an error. Then, if the error was QSettings::AccessError, print the specific application identifiers that weren't set so they know what they have to do. For example: QML Settings: Failed to initialize QSettings instance. Status code is: 1 QML Settings: The following application identifiers have not been set: QVector("organizationName", "organizationDomain") In my case, the QSettings instance wasn't created on Windows because organizationName wasn't set. Change-Id: I7970209e09b78f785730422c45978775311b96ac Reviewed-by: Jan Arve Sæther --- src/imports/settings/qqmlsettings.cpp | 22 +++++++++++++++ tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp | 34 +++++++++++++++++++++--- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/imports/settings/qqmlsettings.cpp b/src/imports/settings/qqmlsettings.cpp index 2271774643..54ff64a3a9 100644 --- a/src/imports/settings/qqmlsettings.cpp +++ b/src/imports/settings/qqmlsettings.cpp @@ -39,10 +39,12 @@ #include "qqmlsettings_p.h" #include +#include #include #include #include #include +#include #include #include @@ -269,6 +271,26 @@ QSettings *QQmlSettingsPrivate::instance() const if (!settings) { QQmlSettings *q = const_cast(q_func()); settings = new QSettings(q); + if (settings->status() != QSettings::NoError) { + // TODO: can't print out the enum due to the following error: + // error: C2666: 'QQmlInfo::operator <<': 15 overloads have similar conversions + qmlWarning(q) << "Failed to initialize QSettings instance. Status code is: " << int(settings->status()); + + if (settings->status() == QSettings::AccessError) { + QVector missingIdentifiers; + if (QCoreApplication::organizationName().isEmpty()) + missingIdentifiers.append(QLatin1String("organizationName")); + if (QCoreApplication::organizationDomain().isEmpty()) + missingIdentifiers.append(QLatin1String("organizationDomain")); + if (QCoreApplication::applicationName().isEmpty()) + missingIdentifiers.append(QLatin1String("applicationName")); + + if (!missingIdentifiers.isEmpty()) + qmlWarning(q) << "The following application identifiers have not been set: " << missingIdentifiers; + } + return settings; + } + if (!category.isEmpty()) settings->beginGroup(category); if (initialized) diff --git a/tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp b/tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp index b353d23539..b0be799bd5 100644 --- a/tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp +++ b/tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp @@ -53,6 +53,7 @@ private slots: void categories(); void siblings(); void initial(); + void noApplicationIdentifiersSet(); }; // ### Replace keyValueMap("foo", "bar") with QVariantMap({{"foo", "bar"}}) @@ -147,10 +148,6 @@ void tst_QQmlSettings::initTestCase() { QQmlDataTest::initTestCase(); - QCoreApplication::setApplicationName("tst_QQmlSettings"); - QCoreApplication::setOrganizationName("QtProject"); - QCoreApplication::setOrganizationDomain("qt-project.org"); - qmlRegisterType("Qt.test", 1, 0, "CppObject"); } @@ -158,6 +155,10 @@ void tst_QQmlSettings::init() { QSettings settings; settings.clear(); + + QCoreApplication::setApplicationName("tst_QQmlSettings"); + QCoreApplication::setOrganizationName("QtProject"); + QCoreApplication::setOrganizationDomain("qt-project.org"); } void tst_QQmlSettings::cleanup() @@ -481,6 +482,31 @@ void tst_QQmlSettings::initial() QCOMPARE(settings->property("value").toString(), QStringLiteral("initial")); } +void tst_QQmlSettings::noApplicationIdentifiersSet() +{ +#ifdef Q_OS_MACOS + QSKIP("macOS doesn't complain about empty application identifiers"); +#endif + + QCoreApplication::setApplicationName(QString()); + QCoreApplication::setOrganizationName(QString()); + QCoreApplication::setOrganizationDomain(QString()); + + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*QML Settings: Failed to initialize QSettings instance. Status code is: 1")); + // Can't set an empty applicationName because QCoreApplication won't allow it, which is why it's not listed here. + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*QML Settings: The following application identifiers have not been set: QVector\\(\"organizationName\", \"organizationDomain\"\\)")); + + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("basic.qml")); + QScopedPointer root(component.create()); + QVERIFY(root.data()); + // The value of the QML property will be true because it defaults to it... + QVERIFY(root->property("success").toBool()); + QSettings settings; + // ... but the settings' value should be false because it was never loaded. + QVERIFY(!settings.value("success").toBool()); +} + QTEST_MAIN(tst_QQmlSettings) #include "tst_qqmlsettings.moc" -- cgit v1.2.3 From 7f57472e24a45a9cb56c7742f4c031405262ef98 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 3 Oct 2018 17:09:40 +0200 Subject: Warn, don't crash during nested delivery of mouse or touch presses If during delivery of a mouse press, user code calls qApp->sendEvent() with another mouse press, then when delivery of the nested event is finished, we call QQuickPointerMouseEvent::reset(nullptr). Then when delivery of the original mouse press resumes, crashes are possible because most of the code assumes that QQuickPointerEvent::m_event is not null during delivery. Change-Id: Id65b1f2f64351e40d03bcd4f4d16693d616729da Fixes: QTBUG-70898 Reviewed-by: Shawn Rutledge --- src/quick/items/qquickevents_p_p.h | 2 + src/quick/items/qquickwindow.cpp | 8 ++++ .../quick/qquickmousearea/data/nestedSendEvent.qml | 49 ++++++++++++++++++++++ .../quick/qquickmousearea/tst_qquickmousearea.cpp | 33 +++++++++++++++ 4 files changed, 92 insertions(+) create mode 100644 tests/auto/quick/qquickmousearea/data/nestedSendEvent.qml diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h index 4097845ec9..b2642735f2 100644 --- a/src/quick/items/qquickevents_p_p.h +++ b/src/quick/items/qquickevents_p_p.h @@ -447,6 +447,8 @@ protected: Qt::MouseButton m_button = Qt::NoButton; Qt::MouseButtons m_pressedButtons; + friend class QQuickWindowPrivate; + Q_DISABLE_COPY(QQuickPointerEvent) }; diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 1c44afc594..53c0231f87 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -2508,6 +2508,10 @@ bool QQuickWindowPrivate::deliverPressOrReleaseEvent(QQuickPointerEvent *event, } for (QQuickItem *item : targetItems) { + if (!event->m_event) { + qWarning("event went missing during delivery! (nested sendEvent() is not allowed)"); + break; + } if (!handlersOnly && sendFilteredPointerEvent(event, item)) { if (event->isAccepted()) { for (int i = 0; i < event->pointCount(); ++i) @@ -2521,6 +2525,10 @@ bool QQuickWindowPrivate::deliverPressOrReleaseEvent(QQuickPointerEvent *event, // nor to any item which already had a chance to filter. if (skipDelivery.contains(item)) continue; + if (!event->m_event) { + qWarning("event went missing during delivery! (nested sendEvent() is not allowed)"); + break; + } deliverMatchingPointsToItem(item, event, handlersOnly); if (event->allPointsAccepted()) handlersOnly = true; diff --git a/tests/auto/quick/qquickmousearea/data/nestedSendEvent.qml b/tests/auto/quick/qquickmousearea/data/nestedSendEvent.qml new file mode 100644 index 0000000000..908a43b04e --- /dev/null +++ b/tests/auto/quick/qquickmousearea/data/nestedSendEvent.qml @@ -0,0 +1,49 @@ +import QtQuick 2.11 +import QtQuick.Window 2.11 +import Test 1.0 + +Window { + id: window + visible: true + width: 200 + height: 200 + + property EventSender sender: EventSender { } + + Item { + width: 200 + height: 200 + + MouseArea { + anchors.fill: parent + } + + Item { + width: 200 + height: 200 + + Rectangle { + width: 200 + height: 100 + color: "red" + + MouseArea { + anchors.fill: parent + onPressed: sender.sendMouseClick(window, 50, 50) + } + } + + Rectangle { + y: 100 + width: 200 + height: 100 + color: "yellow" + + MouseArea { + anchors.fill: parent + onPressed: sender.sendMouseClick(window, 50, 50) + } + } + } + } +} diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp index aa379e834e..558ca2e759 100644 --- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp +++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp @@ -98,6 +98,22 @@ private: qreal m_radius; }; +class EventSender : public QObject { + Q_OBJECT + +public: + Q_INVOKABLE void sendMouseClick(QObject* obj ,qreal x , qreal y) { + { + QMouseEvent event(QEvent::MouseButtonPress, QPointF(x , y), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); + qApp->sendEvent(obj, &event); + } + { + QMouseEvent event(QEvent::MouseButtonRelease, QPointF(x , y), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); + qApp->sendEvent(obj, &event); + } + } +}; + class tst_QQuickMouseArea: public QQmlDataTest { Q_OBJECT @@ -106,6 +122,7 @@ public: : device(nullptr) { qmlRegisterType("Test", 1, 0, "CircleMask"); + qmlRegisterType("Test", 1, 0, "EventSender"); } private slots: @@ -165,6 +182,7 @@ private slots: void pressOneAndTapAnother_data(); void pressOneAndTapAnother(); void mask(); + void nestedEventDelivery(); private: int startDragDistance() const { @@ -2298,6 +2316,21 @@ void tst_QQuickMouseArea::mask() QCOMPARE(window.rootObject()->property("clicked").toInt(), 1); } +void tst_QQuickMouseArea::nestedEventDelivery() // QTBUG-70898 +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("nestedSendEvent.qml")); + QScopedPointer window(qmlobject_cast(c.create())); + QVERIFY(window.data()); + + // Click each MouseArea and verify that it doesn't crash + QByteArray message = "event went missing during delivery! (nested sendEvent() is not allowed)"; + QTest::ignoreMessage(QtWarningMsg, message); + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50,50)); + QTest::ignoreMessage(QtWarningMsg, message); // twice though, actually + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50,150)); +} + QTEST_MAIN(tst_QQuickMouseArea) #include "tst_qquickmousearea.moc" -- cgit v1.2.3 From 614d16d6f0e5e125b5572c4cd2bfe447f939a9b2 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Thu, 11 Oct 2018 10:02:59 +0200 Subject: Doc: place more importance on not binding to x/y/width/height It's common for users to bind to these properties and think that it's a bug that it doesn't work, so we should make the note in the docs more strongly worded and elaborate a bit. Change-Id: I82c8d5644ed81cc616a3035f489344a491ea5a66 Reviewed-by: Andy Shaw Reviewed-by: Venugopal Shivashankar --- src/imports/layouts/qquicklayout.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/imports/layouts/qquicklayout.cpp b/src/imports/layouts/qquicklayout.cpp index cc206bcb95..d90eae5f80 100644 --- a/src/imports/layouts/qquicklayout.cpp +++ b/src/imports/layouts/qquicklayout.cpp @@ -74,10 +74,14 @@ false, the item's size will be fixed to its preferred size. Otherwise, it will grow or shrink between its minimum and maximum size as the layout is resized. - \note It is not recommended to have bindings to the x, y, width, or height properties of items - in a layout, since this would conflict with the goals of Layout, and can also cause binding - loops. - + \note Do not bind to the x, y, width, or height properties of items in a layout, + as this would conflict with the goals of Layout, and can also cause binding loops. + The width and height properties are used by the layout engine to store the current + size of items as calculated from the minimum/preferred/maximum attached properties, + and can be ovewritten each time the items are laid out. Use + \l {Layout::preferredWidth}{Layout.preferredWidth} and + \l {Layout::preferredHeight}{Layout.preferredHeight}, or \l {Item::}{implicitWidth} + and \l {Item::}{implicitHeight} to specify the preferred size of items. \sa GridLayout \sa RowLayout -- cgit v1.2.3 From 0f0ed2070333d61a2603cf3e9bc0cb15439e1177 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 16 Oct 2018 13:08:10 +0200 Subject: At least warn when triggering a rendering limitation We can only have up to 65536/4 tiles since we are indexing with quint16. Task-number: QTBUG-58924 Change-Id: I55b5a9f2a3fb4582e327859482dd978b61b21e4e Reviewed-by: Laszlo Agocs --- src/quick/scenegraph/qsgbasicinternalimagenode.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/quick/scenegraph/qsgbasicinternalimagenode.cpp b/src/quick/scenegraph/qsgbasicinternalimagenode.cpp index c8699218ba..4effaa154d 100644 --- a/src/quick/scenegraph/qsgbasicinternalimagenode.cpp +++ b/src/quick/scenegraph/qsgbasicinternalimagenode.cpp @@ -230,6 +230,9 @@ QSGGeometry *QSGBasicInternalImageNode::updateGeometry(const QRectF &targetRect, ++vCells; if (innerTargetRect.bottom() != targetRect.bottom()) ++vCells; + if (hCells * vCells * 4 >= 0x10000) + qWarning("QTBUG-58924 - Too many tiles in QSGInternalImageNode, rendering will be partially missing."); + QVarLengthArray xData(2 * hCells); QVarLengthArray yData(2 * vCells); X *xs = xData.data(); -- cgit v1.2.3 From 4a886753a75c7c4d66f1fa9cab5a6c5a03240df3 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Tue, 9 Oct 2018 09:12:07 +0200 Subject: Accessible: Return StaticText if there is no explicit role set Before, it would assume that StaticText was the role if the item could be cast to a QQuickText. It should only do this if the role is not explicitly set, in case it is not really StaticText in the attached property. Change-Id: I800810f1347fc9aa412c4ca5d180f78d27a89b38 Reviewed-by: Andre de la Rocha --- src/quick/accessible/qaccessiblequickitem.cpp | 10 ++-- .../qquickaccessible/tst_qquickaccessible.cpp | 70 +++++++++++++++++++++- 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp index 87e581384b..98e7663c96 100644 --- a/src/quick/accessible/qaccessiblequickitem.cpp +++ b/src/quick/accessible/qaccessiblequickitem.cpp @@ -205,14 +205,16 @@ QAccessible::Role QAccessibleQuickItem::role() const // Workaround for setAccessibleRole() not working for // Text items. Text items are special since they are defined // entirely from C++ (setting the role from QML works.) - if (qobject_cast(const_cast(item()))) - return QAccessible::StaticText; QAccessible::Role role = QAccessible::NoRole; if (item()) role = QQuickItemPrivate::get(item())->accessibleRole(); - if (role == QAccessible::NoRole) - role = QAccessible::Client; + if (role == QAccessible::NoRole) { + if (qobject_cast(const_cast(item()))) + role = QAccessible::StaticText; + else + role = QAccessible::Client; + } return role; } diff --git a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp index 0ee78fae54..1bfeb94161 100644 --- a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp +++ b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp @@ -42,9 +42,11 @@ #include #include #include +#include +#include #include "../../shared/util.h" - +#include "../shared/visualtestutil.h" #define EXPECT(cond) \ do { \ @@ -224,6 +226,72 @@ void tst_QQuickAccessible::quickAttachedProperties() } delete object; } + + // Check overriding of attached role for Text + { + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\nText {\n" + "Accessible.role: Accessible.Button\n" + "Accessible.name: \"TextButton\"\n" + "Accessible.description: \"Text Button\"\n" + "}", QUrl()); + QObject *object = component.create(); + QVERIFY(object != nullptr); + + QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(object); + QVERIFY(attachedObject); + if (attachedObject) { + QVariant p = attachedObject->property("role"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toInt(), int(QAccessible::PushButton)); + p = attachedObject->property("name"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toString(), QLatin1String("TextButton")); + p = attachedObject->property("description"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toString(), QLatin1String("Text Button")); + } + delete object; + } + // Check overriding of attached role for Text + { + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\nListView {\n" + "id: list\n" + "model: 5\n" + "delegate: Text {\n" + "objectName: \"acc_text\"\n" + "Accessible.role: Accessible.Button\n" + "Accessible.name: \"TextButton\"\n" + "Accessible.description: \"Text Button\"\n" + "}\n" + "}", QUrl()); + QObject *object = component.create(); + QVERIFY(object != nullptr); + + QQuickListView *listview = qobject_cast(object); + QVERIFY(listview != nullptr); + QQuickItem *contentItem = listview->contentItem(); + QQuickText *childItem = QQuickVisualTestUtil::findItem(contentItem, "acc_text"); + QVERIFY(childItem != nullptr); + + QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(childItem); + QVERIFY(attachedObject); + if (attachedObject) { + QVariant p = attachedObject->property("role"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toInt(), int(QAccessible::PushButton)); + p = attachedObject->property("name"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toString(), QLatin1String("TextButton")); + p = attachedObject->property("description"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toString(), QLatin1String("Text Button")); + } + delete object; + } QTestAccessibility::clearEvents(); } -- cgit v1.2.3 From fb9abc8d06dcd7183cc89d74441cac8beda48e02 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Wed, 24 Oct 2018 09:12:10 +0200 Subject: Add missing "We mean it." warning Change-Id: I19ca6e366cb8b2ca069ac2f4b2c2c834bcea8f3d Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4promiseobject_p.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/qml/jsruntime/qv4promiseobject_p.h b/src/qml/jsruntime/qv4promiseobject_p.h index 80f7183074..bce59b19a7 100644 --- a/src/qml/jsruntime/qv4promiseobject_p.h +++ b/src/qml/jsruntime/qv4promiseobject_p.h @@ -39,6 +39,17 @@ #ifndef QV4PROMISEOBJECT_H #define QV4PROMISEOBJECT_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4object_p.h" #include "qv4functionobject_p.h" -- cgit v1.2.3 From a74de6921809b42970abfdc10e8a1de461685fd9 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 25 Oct 2018 14:28:31 +0200 Subject: Add test for the duplicate state name warning Change-Id: Id5524d7553ef37fbbc84157a4a4c7251e477f215 Reviewed-by: Simon Hausmann --- tests/auto/quick/qquickstates/data/duplicateStateName.qml | 13 +++++++++++++ tests/auto/quick/qquickstates/tst_qquickstates.cpp | 12 ++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 tests/auto/quick/qquickstates/data/duplicateStateName.qml diff --git a/tests/auto/quick/qquickstates/data/duplicateStateName.qml b/tests/auto/quick/qquickstates/data/duplicateStateName.qml new file mode 100644 index 0000000000..7bfafbef1b --- /dev/null +++ b/tests/auto/quick/qquickstates/data/duplicateStateName.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 + +Rectangle { + property bool condition1: false + property bool condition2: false + property bool condition3: false + + states: [ + State { name: "state1"; when: condition1 }, + State { name: "state2"; when: condition2 }, + State { name: "state1"; when: condition3 } + ] +} diff --git a/tests/auto/quick/qquickstates/tst_qquickstates.cpp b/tests/auto/quick/qquickstates/tst_qquickstates.cpp index 073fe33e20..50554f6333 100644 --- a/tests/auto/quick/qquickstates/tst_qquickstates.cpp +++ b/tests/auto/quick/qquickstates/tst_qquickstates.cpp @@ -137,6 +137,7 @@ private slots: void revertListBug(); void QTBUG_38492(); void revertListMemoryLeak(); + void duplicateStateName(); }; void tst_qquickstates::initTestCase() @@ -1654,6 +1655,17 @@ void tst_qquickstates::revertListMemoryLeak() QVERIFY(bindingPtr->ref == 1); } +void tst_qquickstates::duplicateStateName() +{ + QQmlEngine engine; + + QQmlComponent c(&engine, testFileUrl("duplicateStateName.qml")); + QTest::ignoreMessage(QtWarningMsg, fullDataPath("duplicateStateName.qml") + ":3:1: QML Rectangle: Found duplicate state name: state1"); + QScopedPointer item(qobject_cast(c.create())); + QVERIFY(!item.isNull()); +} + + QTEST_MAIN(tst_qquickstates) #include "tst_qquickstates.moc" -- cgit v1.2.3 From cff2ea73dbe802de970e80025de80d9734d0f35d Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 25 Oct 2018 15:07:11 +0200 Subject: [Micro]Optimize duplicate state name check With 9 states the benchmark showed QSet 0.00041 ms QVector 0.00016 ms QVLA 0.00015 ms Change-Id: Ie2de19bd8281b7fddd9ad4246035dcd0f3483102 Reviewed-by: Simon Hausmann Reviewed-by: Shawn Rutledge Reviewed-by: Frederik Gladhorn --- src/quick/util/qquickstategroup.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/quick/util/qquickstategroup.cpp b/src/quick/util/qquickstategroup.cpp index 3d8c5e0507..d8daec2f07 100644 --- a/src/quick/util/qquickstategroup.cpp +++ b/src/quick/util/qquickstategroup.cpp @@ -302,7 +302,8 @@ void QQuickStateGroup::componentComplete() Q_D(QQuickStateGroup); d->componentComplete = true; - QSet names; + QVarLengthArray names; + names.reserve(d->states.count()); for (int ii = 0; ii < d->states.count(); ++ii) { QQuickState *state = d->states.at(ii); if (!state->isNamed()) @@ -312,7 +313,7 @@ void QQuickStateGroup::componentComplete() if (names.contains(stateName)) { qmlWarning(state->parent()) << "Found duplicate state name: " << stateName; } else { - names << stateName; + names.append(std::move(stateName)); } } -- cgit v1.2.3 From 7f6657337f3b0b43c089efd29c914d4af26395e2 Mon Sep 17 00:00:00 2001 From: Alexander Akulich Date: Sun, 21 Oct 2018 20:33:07 +0300 Subject: Fix QML compatibility for Text.contentWidth/Height changed handlers The properties used to have a single notifier that name is different from the properties names. QML Engine always connects a handler to signal, if it exists and only if there is no such signal then it lookup for a property notifier. In commit e92f76cf9ea91e87ec2e3e68234899fd9c12142f we introduced new signals that match the names of the two property changes handlers, but the signals are not available on older import. Remove revision number from the notifiers of Text.contentWidth/contentHeight to fix backward compatibility until a better solution (such as extra engine logic like "if a signal that matches the handler is not available then check if there is a way to connect to a property notifier that matches the handler" Fixes: QTBUG-71247 Change-Id: I11fb6230d85218ef437816c60c8147b953d47241 Reviewed-by: Simon Hausmann --- src/quick/items/qquicktext_p.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h index f4e7fa7046..1af60051fb 100644 --- a/src/quick/items/qquicktext_p.h +++ b/src/quick/items/qquicktext_p.h @@ -272,8 +272,10 @@ Q_SIGNALS: void textFormatChanged(QQuickText::TextFormat textFormat); void elideModeChanged(QQuickText::TextElideMode mode); void contentSizeChanged(); - Q_REVISION(12) void contentWidthChanged(qreal contentWidth); - Q_REVISION(12) void contentHeightChanged(qreal contentHeight); + // The next two signals should be marked as Q_REVISION(12). See QTBUG-71247 + void contentWidthChanged(qreal contentWidth); + void contentHeightChanged(qreal contentHeight); + void lineHeightChanged(qreal lineHeight); void lineHeightModeChanged(LineHeightMode mode); void fontSizeModeChanged(); -- cgit v1.2.3 From 33d85e20037e83d10b8ce66f8745f00d84baccd8 Mon Sep 17 00:00:00 2001 From: Alexander Akulich Date: Thu, 18 Oct 2018 16:27:35 +0300 Subject: Fix backward QML compatibility for Flickable.isAtBoundaryChanged() QML code that imports any previous QtQuick version (e.g. 2.11) and connects to any of the four 'at boundary' properties (atXEnd, atXBeginning, atYEnd and atYBeginning) change notifier (e.g. atXEndChanged) stop working because the new signals available only with new import, but the older import has no idea that it could connect to the older notifier (isAtBoundaryChanged). Remove revision number from the notifiers of the four 'at boundary' properties to mostly fix backward compatibility until a better solution is available. Fixes: QTBUG-71243 Change-Id: I9b4c944c62e0c6c83ceed765b7cd99519e9cd109 Reviewed-by: Shawn Rutledge Reviewed-by: Simon Hausmann Reviewed-by: Frederik Gladhorn --- src/quick/items/qquickflickable_p.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/quick/items/qquickflickable_p.h b/src/quick/items/qquickflickable_p.h index 1bd8fc1020..b7c4fa5b67 100644 --- a/src/quick/items/qquickflickable_p.h +++ b/src/quick/items/qquickflickable_p.h @@ -267,10 +267,11 @@ Q_SIGNALS: Q_REVISION(9) void horizontalOvershootChanged(); Q_REVISION(9) void verticalOvershootChanged(); - Q_REVISION(12) void atXEndChanged(); - Q_REVISION(12) void atYEndChanged(); - Q_REVISION(12) void atXBeginningChanged(); - Q_REVISION(12) void atYBeginningChanged(); + // The next four signals should be marked as Q_REVISION(12). See QTBUG-71243 + void atXEndChanged(); + void atYEndChanged(); + void atXBeginningChanged(); + void atYBeginningChanged(); protected: bool childMouseEventFilter(QQuickItem *, QEvent *) override; -- cgit v1.2.3 From 475c74a9926efcd968572563e678988e53804603 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Mon, 8 Jan 2018 13:33:27 -0600 Subject: Hold internal reference to incubator object while incubating Task-number: QTBUG-53111 Change-Id: Ifaef6a855914d79155f8028b0de7ccca3c9a00f5 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlcomponent.cpp | 18 ++++++++----- .../qml/qqmlincubator/data/garbageCollection.qml | 19 ++++++++++++++ tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp | 30 ++++++++++++++++++++++ 3 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 tests/auto/qml/qqmlincubator/data/garbageCollection.qml diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index a67c5c4a2b..5ed3cc5d6a 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1132,22 +1132,23 @@ class QQmlComponentIncubator : public QQmlIncubator public: QQmlComponentIncubator(QV4::Heap::QmlIncubatorObject *inc, IncubationMode mode) : QQmlIncubator(mode) - , incubatorObject(inc) - {} + { + incubatorObject.set(inc->internalClass->engine, inc); + } void statusChanged(Status s) override { - QV4::Scope scope(incubatorObject->internalClass->engine); - QV4::Scoped i(scope, incubatorObject); + QV4::Scope scope(incubatorObject.engine()); + QV4::Scoped i(scope, incubatorObject.as()); i->statusChanged(s); } void setInitialState(QObject *o) override { - QV4::Scope scope(incubatorObject->internalClass->engine); - QV4::Scoped i(scope, incubatorObject); + QV4::Scope scope(incubatorObject.engine()); + QV4::Scoped i(scope, incubatorObject.as()); i->setInitialState(o); } - QV4::Heap::QmlIncubatorObject *incubatorObject; + QV4::PersistentValue incubatorObject; // keep a strong internal reference while incubating }; @@ -1571,6 +1572,9 @@ void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s) QQmlEnginePrivate::warning(QQmlEnginePrivate::get(scope.engine->qmlEngine()), error); } } + + if (s != QQmlIncubator::Loading) + d()->incubator->incubatorObject.clear(); } #undef INITIALPROPERTIES_SOURCE diff --git a/tests/auto/qml/qqmlincubator/data/garbageCollection.qml b/tests/auto/qml/qqmlincubator/data/garbageCollection.qml new file mode 100644 index 0000000000..6866a02a00 --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/garbageCollection.qml @@ -0,0 +1,19 @@ +import QtQuick 2.0 + +QtObject { + id: root + + property var incubator + + function getAndClearIncubator() { + var result = incubator + incubator = null + return result + } + + Component.onCompleted: { + var c = Qt.createComponent("statusChanged.qml"); // use existing simple type for convenience + var incubator = c.incubateObject(root); + incubator.onStatusChanged = function(status) { if (status === 1) root.incubator = incubator } + } +} diff --git a/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp index 8f0e04e12e..8e25079703 100644 --- a/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp +++ b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp @@ -39,6 +39,7 @@ #include #include #include "../../shared/util.h" +#include #include #include @@ -68,6 +69,7 @@ private slots: void chainedAsynchronousClear(); void selfDelete(); void contextDelete(); + void garbageCollection(); private: QQmlIncubationController controller; @@ -1144,6 +1146,34 @@ void tst_qqmlincubator::contextDelete() } } +// QTBUG-53111 +void tst_qqmlincubator::garbageCollection() +{ + QQmlComponent component(&engine, testFileUrl("garbageCollection.qml")); + QScopedPointer obj(component.create()); + + engine.collectGarbage(); + + bool b = true; + controller.incubateWhile(&b); + + // verify incubation completed (the incubator was not prematurely collected) + QVariant incubatorVariant; + QMetaObject::invokeMethod(obj.data(), "getAndClearIncubator", Q_RETURN_ARG(QVariant, incubatorVariant)); + QJSValue strongRef = incubatorVariant.value(); + QVERIFY(!strongRef.isNull() && !strongRef.isUndefined()); + + // turn the last strong reference to the incubator into a weak one and collect + QV4::WeakValue weakIncubatorRef; + weakIncubatorRef.set(QQmlEnginePrivate::getV4Engine(&engine), *QJSValuePrivate::getValue(&strongRef)); + strongRef = QJSValue(); + incubatorVariant.clear(); + + // verify incubator is correctly collected now that incubation is complete and all references are gone + engine.collectGarbage(); + QVERIFY(weakIncubatorRef.isNullOrUndefined()); +} + QTEST_MAIN(tst_qqmlincubator) #include "tst_qqmlincubator.moc" -- cgit v1.2.3