From d76efbe8efab30eddbdf48b77fbbec712e2e7652 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 28 Feb 2022 15:28:34 +0100 Subject: QQuickLoader: Check for QQmlEngine before using it The loader's context may have been removed from the context hierarchy or it may not have a context in the first place. We should not crash then. Fixes: QTBUG-67950 Change-Id: I1058d5b1f978aa040f8b2f018c4357dd7a3ef333 Reviewed-by: Fabian Kosmale (cherry picked from commit 79e885537f8546a18d7d9d902d6efe40b1915c96) --- src/quick/items/qquickloader.cpp | 26 +++++++++++++----- src/quick/items/qquickloader_p_p.h | 1 + tests/auto/quick/qquickloader/data/noEngine.qml | 32 ++++++++++++++++++++++ tests/auto/quick/qquickloader/tst_qquickloader.cpp | 15 ++++++++++ 4 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 tests/auto/quick/qquickloader/data/noEngine.qml diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp index 93cff95b7b..7b08ec5a66 100644 --- a/src/quick/items/qquickloader.cpp +++ b/src/quick/items/qquickloader.cpp @@ -439,9 +439,8 @@ void QQuickLoader::loadFromSource() } if (isComponentComplete()) { - QQmlComponent::CompilationMode mode = d->asynchronous ? QQmlComponent::Asynchronous : QQmlComponent::PreferSynchronous; if (!d->component) - d->component.setObject(new QQmlComponent(qmlEngine(this), d->source, mode, this), this); + d->createComponent(); d->load(); } } @@ -806,11 +805,8 @@ void QQuickLoader::componentComplete() Q_D(QQuickLoader); QQuickItem::componentComplete(); if (active()) { - if (d->loadingFromSource) { - QQmlComponent::CompilationMode mode = d->asynchronous ? QQmlComponent::Asynchronous : QQmlComponent::PreferSynchronous; - if (!d->component) - d->component.setObject(new QQmlComponent(qmlEngine(this), d->source, mode, this), this); - } + if (d->loadingFromSource && !d->component) + d->createComponent(); d->load(); } } @@ -1044,6 +1040,22 @@ void QQuickLoaderPrivate::updateStatus() } } +void QQuickLoaderPrivate::createComponent() +{ + Q_Q(QQuickLoader); + const QQmlComponent::CompilationMode mode = asynchronous + ? QQmlComponent::Asynchronous + : QQmlComponent::PreferSynchronous; + if (QQmlContext *context = qmlContext(q)) { + if (QQmlEngine *engine = context->engine()) { + component.setObject(new QQmlComponent(engine, source, mode, q), q); + return; + } + } + + qmlWarning(q) << "createComponent: Cannot find a QML engine."; +} + #include QT_END_NAMESPACE diff --git a/src/quick/items/qquickloader_p_p.h b/src/quick/items/qquickloader_p_p.h index 5fc231a8e6..4c63b82b6a 100644 --- a/src/quick/items/qquickloader_p_p.h +++ b/src/quick/items/qquickloader_p_p.h @@ -98,6 +98,7 @@ public: QV4::ReturnedValue extractInitialPropertyValues(QQmlV4Function *args, QObject *loader, bool *error); QQuickLoader::Status computeStatus() const; void updateStatus(); + void createComponent(); qreal getImplicitWidth() const override; qreal getImplicitHeight() const override; diff --git a/tests/auto/quick/qquickloader/data/noEngine.qml b/tests/auto/quick/qquickloader/data/noEngine.qml new file mode 100644 index 0000000000..19e619f32e --- /dev/null +++ b/tests/auto/quick/qquickloader/data/noEngine.qml @@ -0,0 +1,32 @@ +import QtQuick 2 + +Item { + id: root + property bool a: false + property int changes: 0 + onAChanged: { + m.model = 0 + m.model = 1 + ++changes; + } + + Repeater { + id: m + model: 1 + + Item { + Timer { + onTriggered: { + root.a = true + l.source = "loaded.qml" + } + interval: 0 + running: true + } + + Loader { + id: l + } + } + } +} diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp index dddacbaa0b..db678ae5a1 100644 --- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp +++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp @@ -133,6 +133,7 @@ private slots: void setSourceAndCheckStatus(); void asyncLoaderRace(); + void noEngine(); }; Q_DECLARE_METATYPE(QList) @@ -1515,6 +1516,20 @@ void tst_QQuickLoader::asyncLoaderRace() QCOMPARE(loader->item(), nullptr); } +void tst_QQuickLoader::noEngine() +{ + QQmlEngine engine; + const QUrl url = testFileUrl("noEngine.qml"); + QQmlComponent component(&engine, url); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); + QScopedPointer o(component.create()); + + const QString message = url.toString() + + QStringLiteral(":27:13: QML Loader: createComponent: Cannot find a QML engine."); + QTest::ignoreMessage(QtWarningMsg, qPrintable(message)); + QTRY_COMPARE(o->property("changes").toInt(), 1); +} + QTEST_MAIN(tst_QQuickLoader) #include "tst_qquickloader.moc" -- cgit v1.2.3 From f4a55f7633d5ee2534363fc45129c86a5fae5d6b Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 25 Feb 2022 14:07:54 +0100 Subject: QML: Protect against EAGAIN when calling madvise on linux Apparently it can fail with EAGAIN. We rely on madvise to zero out the memory. Therefore loop until it succeeds like we do on other OS. Fixes: QTBUG-100431 Change-Id: I9819f8d82a251e222b0b500991584d40e641b672 Reviewed-by: Andrei Golubev Reviewed-by: Fabian Kosmale (cherry picked from commit 6aef29a7316d50800fb9cec388139bd3870f682e) Reviewed-by: Qt Cherry-pick Bot --- src/3rdparty/masm/wtf/OSAllocatorPosix.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp b/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp index d59fdcd675..d54b7e9492 100644 --- a/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp +++ b/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp @@ -111,7 +111,11 @@ void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, (fd == -1 ? MAP_ANON : 0), fd, 0); if (result == MAP_FAILED) CRASH(); - madvise(result, bytes, MADV_DONTNEED); + + while (madvise(result, bytes, MADV_DONTNEED)) { + if (errno != EAGAIN) + CRASH(); + } if (fd != -1) close(fd); @@ -218,7 +222,12 @@ void OSAllocator::commit(void* address, size_t bytes, bool writable, bool execut protection |= PROT_EXEC; if (mprotect(address, bytes, protection)) CRASH(); - madvise(address, bytes, MADV_WILLNEED); + + while (madvise(address, bytes, MADV_WILLNEED)) { + if (errno != EAGAIN) + CRASH(); + } + #elif HAVE(MADV_FREE_REUSE) UNUSED_PARAM(writable); UNUSED_PARAM(executable); @@ -238,7 +247,10 @@ void OSAllocator::decommit(void* address, size_t bytes) // Use PROT_NONE and MAP_LAZY to decommit the pages. mmap(address, bytes, PROT_NONE, MAP_FIXED | MAP_LAZY | MAP_PRIVATE | MAP_ANON, -1, 0); #elif OS(LINUX) - madvise(address, bytes, MADV_DONTNEED); + while (madvise(address, bytes, MADV_DONTNEED)) { + if (errno != EAGAIN) + CRASH(); + } if (mprotect(address, bytes, PROT_NONE)) CRASH(); #elif HAVE(MADV_FREE_REUSE) -- cgit v1.2.3 From 8d81b24ffe3ddeea33a8611bdf666a0a44fd9cda Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 23 Mar 2022 11:36:59 +0100 Subject: V4 ArrayIterator: Protect retrieved value from GC When constructing the iterator return object, the garbage collector may run, and drop the element value we want to return. Fixes: QTBUG-101700 Change-Id: I60c9b0b9fbb9e784fa089a8b5bb274d02ef7fc1f Reviewed-by: Maximilian Goldstein Reviewed-by: Andrei Golubev (cherry picked from commit 185760fa44f5b62f1ed3f10a458f4bc38072768f) Reviewed-by: Fabian Kosmale --- src/qml/jsruntime/qv4arrayiterator.cpp | 6 +-- tests/auto/qml/qjsengine/tst_qjsengine.cpp | 72 ++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/src/qml/jsruntime/qv4arrayiterator.cpp b/src/qml/jsruntime/qv4arrayiterator.cpp index a484a8ffa2..dc82000c25 100644 --- a/src/qml/jsruntime/qv4arrayiterator.cpp +++ b/src/qml/jsruntime/qv4arrayiterator.cpp @@ -86,18 +86,18 @@ ReturnedValue ArrayIteratorPrototype::method_next(const FunctionObject *b, const return IteratorPrototype::createIterResultObject(scope.engine, Value::fromInt32(index), false); } - ReturnedValue elementValue = a->get(index); + QV4::ScopedValue elementValue(scope, a->get(index)); CHECK_EXCEPTION(); if (itemKind == ValueIteratorKind) { - return IteratorPrototype::createIterResultObject(scope.engine, Value::fromReturnedValue(elementValue), false); + return IteratorPrototype::createIterResultObject(scope.engine, elementValue, false); } else { Q_ASSERT(itemKind == KeyValueIteratorKind); ScopedArrayObject resultArray(scope, scope.engine->newArrayObject()); resultArray->arrayReserve(2); resultArray->arrayPut(0, Value::fromInt32(index)); - resultArray->arrayPut(1, Value::fromReturnedValue(elementValue)); + resultArray->arrayPut(1, elementValue); resultArray->setArrayLengthUnchecked(2); return IteratorPrototype::createIterResultObject(scope.engine, resultArray, false); diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index b75bf820d5..c66e2dccf3 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -268,6 +268,7 @@ private slots: void dataViewCtor(); void uiLanguage(); + void forOfAndGc(); public: Q_INVOKABLE QJSValue throwingCppMethod1(); @@ -5250,6 +5251,77 @@ void tst_QJSEngine::uiLanguage() } } +void tst_QJSEngine::forOfAndGc() +{ + // We want to guard against the iterator of a for..of loop leaving the result unprotected from + // garbage collection. It should be possible to construct a pure JS test case, but due to the + // vaguaries of garbage collection it's hard to reliably trigger the crash. This test is the + // best I could come up with. + + QQmlEngine engine; + QQmlComponent c(&engine); + c.setData(R"( + import QtQml 2.15 + import QtQml.Models 2.15 + + QtObject { + id: counter + property int count: 0 + + property DelegateModel model: DelegateModel { + id: filesModel + + model: ListModel { + Component.onCompleted: { + for (let idx = 0; idx < 50; idx++) + append({"i" : idx}) + } + } + + groups: [ + DelegateModelGroup { + name: "selected" + } + ] + + function getSelected() { + for (let i = 0; i < items.count; ++i) { + var item = items.get(i) + for (let el of item.groups) { + if (el === "selected") + ++counter.count + } + } + } + + property bool bSelect: true + function selectAll() { + for (let i = 0; i < items.count; ++i) { + if (bSelect && !items.get(i).inSelected) + items.addGroups(i, 1, ["selected"]) + else + items.removeGroups(i, 1, ["selected"]) + getSelected() + } + bSelect = !bSelect + } + } + + property Timer timer: Timer { + running: true + interval: 1 + repeat: true + onTriggered: filesModel.selectAll() + } + } + )", QUrl()); + + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer o(c.create()); + + QTRY_VERIFY(o->property("count").toInt() > 32768); +} + QTEST_MAIN(tst_QJSEngine) #include "tst_qjsengine.moc" -- cgit v1.2.3 From 4f26db43b719222d0659422f44ac62abb5a5677a Mon Sep 17 00:00:00 2001 From: Heikki Halmet Date: Tue, 29 Mar 2022 10:58:10 +0300 Subject: Fix blacklisting string for Ubuntu 20.04 in qquickmultipointtoucharea Task-number: QTBUG-101499 Change-Id: If94315c5be1594538fee6af9f5c5a3353e6307ed Reviewed-by: Ville Voutilainen --- tests/auto/quick/qquickmultipointtoucharea/BLACKLIST | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST index cfbd47d3dc..db8595544b 100644 --- a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST +++ b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST @@ -1,6 +1,6 @@ [nonOverlapping] # QTBUG-101499 -ubuntu-20 +ubuntu-20.04 ubuntu-16.04 ubuntu-18.04 opensuse-42.3 @@ -8,7 +8,7 @@ opensuse-leap sles [nested] # QTBUG-101499 -ubuntu-20 +ubuntu-20.04 ubuntu-16.04 ubuntu-18.04 opensuse-42.3 -- cgit v1.2.3 From 253922cc74ebb4c62c224e70fccee02a72016d35 Mon Sep 17 00:00:00 2001 From: Jaishree Vyas Date: Mon, 28 Mar 2022 15:24:55 +0200 Subject: Doc: Improve cursorPosition description in TextInput and TextEdit docs Fixes: QTBUG-97169 Change-Id: I060be767dd980c489d8e5426d67f2e8b6d21e96c Reviewed-by: Leena Miettinen Reviewed-by: Shawn Rutledge Reviewed-by: Ivan Tkachenko Reviewed-by: Eskil Abrahamsen Blomfeldt (cherry picked from commit 79807f37b5e9e9744fdaf7af380fd7bfb7ed85f4) Reviewed-by: Qt Cherry-pick Bot --- src/quick/items/qquicktextedit.cpp | 10 +++++++++- src/quick/items/qquicktextinput.cpp | 15 ++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index 2d0402a9c2..c21844f1d6 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -1204,7 +1204,15 @@ void QQuickTextEdit::setCursorVisible(bool on) /*! \qmlproperty int QtQuick::TextEdit::cursorPosition - The position of the cursor in the TextEdit. + The position of the cursor in the TextEdit. The cursor is positioned between + characters. + + \note The \e characters in this case refer to the string of \l QChar objects, + therefore 16-bit Unicode characters, and the position is considered an index + into this string. This does not necessarily correspond to individual graphemes + in the writing system, as a single grapheme may be represented by multiple + Unicode characters, such as in the case of surrogate pairs, linguistic + ligatures or diacritics. */ int QQuickTextEdit::cursorPosition() const { diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 4c76352171..631c687ee7 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -831,7 +831,20 @@ void QQuickTextInput::setCursorVisible(bool on) /*! \qmlproperty int QtQuick::TextInput::cursorPosition - The position of the cursor in the TextInput. + The position of the cursor in the TextInput. The cursor is positioned between + characters. + + \note The \e characters in this case refer to the string of \l QChar objects, + therefore 16-bit Unicode characters, and the position is considered an index + into this string. This does not necessarily correspond to individual graphemes + in the writing system, as a single grapheme may be represented by multiple + Unicode characters, such as in the case of surrogate pairs, linguistic + ligatures or diacritics. + + \l displayText is different if echoMode is set to \l TextInput.Password: then + each passwordMaskCharacter is a "narrow" character + (the cursorPosition always moves by 1), even if the text in the TextInput is not. + */ int QQuickTextInput::cursorPosition() const { -- cgit v1.2.3 From 8b71b4b5705a1a39cc1484c58084f8cdc131827e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Tue, 29 Mar 2022 15:18:16 +0300 Subject: Set depth mask correctly for clear Fixes Quick3D Offscreen render mode. The depth mask must also be set for the clear when depth buffer is used. Fixes: QTBUG-102128 Change-Id: Ic98133e20007449056ecca14c0fdcfa2f6f81377 Reviewed-by: Laszlo Agocs --- src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index a6c07d5964..f8f3639f36 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -4024,6 +4024,7 @@ void Renderer::renderBatches() if (m_useDepthBuffer) { glClearDepthf(1); // calls glClearDepth() under the hood for desktop OpenGL + glDepthMask(true); } glColorMask(true, true, true, true); glDisable(GL_SCISSOR_TEST); -- cgit v1.2.3 From 7dbdd872488a6b4cb15a5d19b33ab5954b4f9f4c Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 5 Apr 2022 18:02:43 +0200 Subject: tst_qqmllistcompositor: fix -Wdeprecated-enum-enum-conversion Instead of an unnamed enum, make these extra flags of the correct type, C::Flag. This is the same technique used a few lines up for extra C::Group flags. Change-Id: I2dd5221f95bfa49c93e9cbf9d8583ac38c24de95 Reviewed-by: Ulf Hermann (cherry picked from commit 7f349aeb3183c1945854a66180164c3f50a51895) Reviewed-by: Qt Cherry-pick Bot --- tests/auto/qml/qqmllistcompositor/tst_qqmllistcompositor.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/auto/qml/qqmllistcompositor/tst_qqmllistcompositor.cpp b/tests/auto/qml/qqmllistcompositor/tst_qqmllistcompositor.cpp index b49832499e..9315b2d24d 100644 --- a/tests/auto/qml/qqmllistcompositor/tst_qqmllistcompositor.cpp +++ b/tests/auto/qml/qqmllistcompositor/tst_qqmllistcompositor.cpp @@ -89,15 +89,13 @@ QT_END_NAMESPACE static const C::Group Visible = C::Group(2); static const C::Group Selection = C::Group(3); +constexpr auto VisibleFlag = C::Flag(0x04); +constexpr auto SelectionFlag = C::Flag(0x08); + class tst_qqmllistcompositor : public QObject { Q_OBJECT - enum { - VisibleFlag = 0x04, - SelectionFlag = 0x08 - }; - void populateChange( C::Change &change, int sIndex, int vIndex, int dIndex, int cIndex, int count, int flags, int moveId) { -- cgit v1.2.3 From ed0f2d29ee1d218b7db306e853762d4c14b129e5 Mon Sep 17 00:00:00 2001 From: Tarja Sundqvist Date: Wed, 6 Apr 2022 17:57:28 +0300 Subject: Bump version --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index a9549f1eb1..0d692629d3 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -4,4 +4,4 @@ CONFIG += warning_clean DEFINES += QT_NO_LINKED_LIST DEFINES += QT_NO_JAVA_STYLE_ITERATORS -MODULE_VERSION = 5.15.9 +MODULE_VERSION = 5.15.10 -- cgit v1.2.3 From 4de68f1cfefe21871a223df1e94b8e6db87b343d Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 21 Mar 2022 11:21:09 +0100 Subject: doc: Fix inherited property docs in HoverHandler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some base class snippets use TapHandler, but it's better to show snippets specifically with HoverHandler. These snippets are also runnable and thus testable. Fixes: QTBUG-95395 Task-number: QTBUG-101932 Change-Id: Ibcdc30ff8a785a3651177c79522332cf09c3013c Reviewed-by: Topi Reiniö (cherry picked from commit a76ad7ef6a87af074612897ea6df30167ebe698e) Reviewed-by: Qt Cherry-pick Bot --- .../snippets/pointerHandlers/hoverModifiers.qml | 69 ++++++++++++++++ .../pointerHandlers/hoverMouseOrStylus.qml | 69 ++++++++++++++++ .../pointerHandlers/hoverStylusOrEraser.qml | 76 +++++++++++++++++ .../pointerHandlers/images/cursor-eraser.png | Bin 0 -> 1454 bytes src/quick/handlers/qquickhoverhandler.cpp | 92 +++++++++++++++++++++ 5 files changed, 306 insertions(+) create mode 100644 src/quick/doc/snippets/pointerHandlers/hoverModifiers.qml create mode 100644 src/quick/doc/snippets/pointerHandlers/hoverMouseOrStylus.qml create mode 100644 src/quick/doc/snippets/pointerHandlers/hoverStylusOrEraser.qml create mode 100644 src/quick/doc/snippets/pointerHandlers/images/cursor-eraser.png diff --git a/src/quick/doc/snippets/pointerHandlers/hoverModifiers.qml b/src/quick/doc/snippets/pointerHandlers/hoverModifiers.qml new file mode 100644 index 0000000000..b8a378ddcf --- /dev/null +++ b/src/quick/doc/snippets/pointerHandlers/hoverModifiers.qml @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2022 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$ +** +****************************************************************************/ +//![0] +import QtQuick + +Rectangle { + width: 150; height: 50; radius: 3 + color: control.hovered ? "goldenrod" : shift.hovered ? "wheat" : "beige" + + HoverHandler { + id: control + acceptedModifiers: Qt.ControlModifier + cursorShape: Qt.PointingHandCursor + } + + HoverHandler { + id: shift + acceptedModifiers: Qt.ShiftModifier + cursorShape: Qt.CrossCursor + } +} +//![0] diff --git a/src/quick/doc/snippets/pointerHandlers/hoverMouseOrStylus.qml b/src/quick/doc/snippets/pointerHandlers/hoverMouseOrStylus.qml new file mode 100644 index 0000000000..6bd6a40b1a --- /dev/null +++ b/src/quick/doc/snippets/pointerHandlers/hoverMouseOrStylus.qml @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2022 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$ +** +****************************************************************************/ +//![0] +import QtQuick + +Rectangle { + width: 150; height: 50; radius: 3 + color: mouse.hovered ? "goldenrod" : stylus.hovered ? "tomato" : "wheat" + + HoverHandler { + id: stylus + acceptedDevices: PointerDevice.Stylus + cursorShape: Qt.CrossCursor + } + + HoverHandler { + id: mouse + acceptedDevices: PointerDevice.Mouse + cursorShape: Qt.PointingHandCursor + } +} +//![0] diff --git a/src/quick/doc/snippets/pointerHandlers/hoverStylusOrEraser.qml b/src/quick/doc/snippets/pointerHandlers/hoverStylusOrEraser.qml new file mode 100644 index 0000000000..5d82158baf --- /dev/null +++ b/src/quick/doc/snippets/pointerHandlers/hoverStylusOrEraser.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2022 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$ +** +****************************************************************************/ +//![0] +import QtQuick + +Rectangle { + id: rect + width: 150; height: 150 + + HoverHandler { + id: stylus + acceptedPointerTypes: PointerDevice.Pen + cursorShape: Qt.CrossCursor + } + + HoverHandler { + id: eraser + acceptedPointerTypes: PointerDevice.Eraser + cursorShape: Qt.BlankCursor + target: Image { + parent: rect + source: "images/cursor-eraser.png" + visible: eraser.hovered + x: eraser.point.position.x + y: eraser.point.position.y - 32 + } + } +} +//![0] diff --git a/src/quick/doc/snippets/pointerHandlers/images/cursor-eraser.png b/src/quick/doc/snippets/pointerHandlers/images/cursor-eraser.png new file mode 100644 index 0000000000..e5488a89f2 Binary files /dev/null and b/src/quick/doc/snippets/pointerHandlers/images/cursor-eraser.png differ diff --git a/src/quick/handlers/qquickhoverhandler.cpp b/src/quick/handlers/qquickhoverhandler.cpp index 9034f20c8e..38ee521270 100644 --- a/src/quick/handlers/qquickhoverhandler.cpp +++ b/src/quick/handlers/qquickhoverhandler.cpp @@ -153,6 +153,98 @@ void QQuickHoverHandler::setHovered(bool hovered) } } +/*! + \internal + \qmlproperty flags QtQuick::HoverHandler::acceptedButtons + + This property is not used in HoverHandler. +*/ + +/*! + \qmlproperty flags QtQuick::HoverHandler::acceptedDevices + + The types of pointing devices that can activate the pointer handler. + + By default, this property is set to + \l{QInputDevice::DeviceType}{PointerDevice.AllDevices}. + If you set it to an OR combination of device types, it will ignore pointer + events from the non-matching devices. + + For example, an item could be made to respond to mouse hover in one way, + and stylus hover in another way, with two handlers: + + \snippet pointerHandlers/hoverMouseOrStylus.qml 0 + + The available device types are as follows: + + \value PointerDevice.Mouse A mouse. + \value PointerDevice.TouchScreen A touchscreen. + \value PointerDevice.TouchPad A touchpad or trackpad. + \value PointerDevice.Stylus A stylus on a graphics tablet. + \value PointerDevice.Airbrush An airbrush on a graphics tablet. + \value PointerDevice.Puck A digitizer with crosshairs, on a graphics tablet. + \value PointerDevice.AllDevices Any type of pointing device. + + \sa QInputDevice::DeviceType +*/ + +/*! + \qmlproperty flags QtQuick::HoverHandler::acceptedPointerTypes + + The types of pointing instruments (generic, stylus, eraser, and so on) + that can activate the pointer handler. + + By default, this property is set to + \l {QPointingDevice::PointerType} {PointerDevice.AllPointerTypes}. + If you set it to an OR combination of device types, it will ignore events + from non-matching events. + + For example, you could provide feedback by changing the cursor depending on + whether a stylus or eraser is hovering over a graphics tablet: + + \snippet pointerHandlers/hoverStylusOrEraser.qml 0 + + The available pointer types are as follows: + + \value PointerDevice.Generic A mouse or a device that emulates a mouse. + \value PointerDevice.Finger A finger on a touchscreen (hover detection is unlikely). + \value PointerDevice.Pen A stylus on a graphics tablet. + \value PointerDevice.Eraser An eraser on a graphics tablet. + \value PointerDevice.Cursor A digitizer with crosshairs, on a graphics tablet. + \value PointerDevice.AllPointerTypes Any type of pointing device. + + \sa QPointingDevice::PointerType +*/ + +/*! + \qmlproperty flags QtQuick::HoverHandler::acceptedModifiers + + If this property is set, a hover event is handled only if the given keyboard + modifiers are pressed. The event is ignored without the modifiers. + + This property is set to \c Qt.KeyboardModifierMask by default, resulting + in handling hover events regardless of any modifier keys. + + For example, an \l[QML]{Item} could have two handlers of the same type, one + of which is enabled only if the required keyboard modifiers are pressed: + + \snippet pointerHandlers/hoverModifiers.qml 0 + + The available modifiers are as follows: + + \value Qt.NoModifier No modifier key is allowed. + \value Qt.ShiftModifier A Shift key on the keyboard must be pressed. + \value Qt.ControlModifier A Ctrl key on the keyboard must be pressed. + \value Qt.AltModifier An Alt key on the keyboard must be pressed. + \value Qt.MetaModifier A Meta key on the keyboard must be pressed. + \value Qt.KeypadModifier A keypad button must be pressed. + \value Qt.GroupSwitchModifier A Mode_switch key on the keyboard must be pressed. + X11 only (unless activated on Windows by a command line argument). + \value Qt.KeyboardModifierMask The handler ignores modifier keys. + + \sa Qt::KeyboardModifier +*/ + /*! \since 5.15 \qmlproperty Qt::CursorShape QtQuick::HoverHandler::cursorShape -- cgit v1.2.3 From ca7f317e11df3ac61d90e795833c3b2a074c7caa Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Mon, 18 Jan 2021 11:19:04 +0200 Subject: Build fixes for GCC 11 Task-number: QTBUG-89977 Change-Id: I975a859d5252e2721475f86ced6c8dab06ae8c9c Reviewed-by: Lars Knoll (cherry picked from commit eb6525f126f680f99598bac79d2682e2ebbdc4ac) Reviewed-by: Marc Mutz --- src/qml/compiler/qv4bytecodegenerator_p.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qml/compiler/qv4bytecodegenerator_p.h b/src/qml/compiler/qv4bytecodegenerator_p.h index aa672e27ce..ac07889159 100644 --- a/src/qml/compiler/qv4bytecodegenerator_p.h +++ b/src/qml/compiler/qv4bytecodegenerator_p.h @@ -186,13 +186,13 @@ QT_WARNING_POP Q_REQUIRED_RESULT Jump jumpNotUndefined() { - Instruction::JumpNotUndefined data; + Instruction::JumpNotUndefined data{}; return addJumpInstruction(data); } Q_REQUIRED_RESULT Jump jumpNoException() { - Instruction::JumpNoException data; + Instruction::JumpNoException data{}; return addJumpInstruction(data); } -- cgit v1.2.3 From 1642236f7bca4ca3f303f8058ad13b21566a4a1d Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Apr 2022 16:10:12 +0200 Subject: QQuickProfilerAdapterFactoryPlugin: includemocs Including moc files directly into their classes' TU tends to improve codegen and enables extended compiler warnings, e.g. about unused private functions or fields. Task-number: QTBUG-102948 Change-Id: Ib109ea7751de96d03967c36833cf71e06cbf99b5 Reviewed-by: Fabian Kosmale (cherry picked from commit ad20a1e10da40455286037bdca99ed9eae801736) Reviewed-by: Qt Cherry-pick Bot --- src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp index 90b249dd3d..ab8c22afce 100644 --- a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp +++ b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp @@ -175,3 +175,5 @@ void QQuickProfilerAdapter::receiveData(const QVector &new_d } QT_END_NAMESPACE + +#include "moc_qquickprofileradapter.cpp" -- cgit v1.2.3 From aff2abaf1ed5b6a5681cb06725ecd1b04f5fba48 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Apr 2022 16:10:12 +0200 Subject: QDebugMessageServiceFactoryPlugin: includemocs Including moc files directly into their classes' TU tends to improve codegen and enables extended compiler warnings, e.g. about unused private functions or fields. Task-number: QTBUG-102948 Change-Id: Ib3e4bdd9b9ec2162f3c1f016b8d9e8b16e7243e2 Reviewed-by: Fabian Kosmale (cherry picked from commit 8fd0c934f235e5fb682917229bdb820d58f1859a) Reviewed-by: Qt Cherry-pick Bot --- src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.cpp b/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.cpp index be54fd2ebb..7a46110117 100644 --- a/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.cpp +++ b/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.cpp @@ -106,3 +106,5 @@ void QDebugMessageServiceImpl::synchronizeTime(const QElapsedTimer &otherTimer) } QT_END_NAMESPACE + +#include "moc_qdebugmessageservice.cpp" -- cgit v1.2.3 From 14b78bbdc258809d3882e05338e962f794e5dd11 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Apr 2022 16:10:12 +0200 Subject: QtPacketProtocolPrivate: includemocs Including moc files directly into their classes' TU tends to improve codegen and enables extended compiler warnings, e.g. about unused private functions or fields. Task-number: QTBUG-102948 Change-Id: Ie8ad0b22731981723a42091ffa4bca09a9431892 Reviewed-by: Fabian Kosmale (cherry picked from commit 20c665c20b6848fb39d97b04f1a580ecf1221b7f) Reviewed-by: Qt Cherry-pick Bot --- src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp b/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp index 784f155fce..f6863ef4f0 100644 --- a/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp +++ b/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp @@ -324,3 +324,5 @@ bool QPacketProtocolPrivate::readFromDevice(char *buffer, qint64 size) */ QT_END_NAMESPACE + +#include "moc_qpacketprotocol_p.cpp" -- cgit v1.2.3 From db367d547a483916e493fd65789217c468de53ad Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Apr 2022 16:29:37 +0200 Subject: QuickShapesPrivate: includemocs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Including moc files directly into their classes' TU tends to improve codegen and enables extended compiler warnings, e.g. about unused private functions or fields. Task-number: QTBUG-102948 Change-Id: Ifd2eff233a07bf8e5b42f46b8658caa56bf0e58c Reviewed-by: Mårten Nordheim (cherry picked from commit 74aabf43532848f92bd28be52de87d5111320c22) Reviewed-by: Qt Cherry-pick Bot --- src/quickshapes/qquickshapegenericrenderer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/quickshapes/qquickshapegenericrenderer.cpp b/src/quickshapes/qquickshapegenericrenderer.cpp index a7246da2c2..8d2097f95b 100644 --- a/src/quickshapes/qquickshapegenericrenderer.cpp +++ b/src/quickshapes/qquickshapegenericrenderer.cpp @@ -1280,3 +1280,5 @@ QSGMaterialShader *QQuickShapeConicalGradientMaterial::createShader() const } QT_END_NAMESPACE + +#include "moc_qquickshapegenericrenderer_p.cpp" -- cgit v1.2.3 From 8cdb7d040d7fc88297bb996b034b3ddba93c7c1f Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Apr 2022 16:10:12 +0200 Subject: QQmlNativeDebugServiceFactoryPlugin: includemocs Including moc files directly into their classes' TU tends to improve codegen and enables extended compiler warnings, e.g. about unused private functions or fields. Task-number: QTBUG-102948 Change-Id: I347017b915ca0c04d386dfb30b5587863f2ea638 Reviewed-by: Fabian Kosmale (cherry picked from commit 99e289f99cfd8661a30d34ac4d7c846dbacbef19) Reviewed-by: Qt Cherry-pick Bot --- .../qmltooling/qmldbg_nativedebugger/qqmlnativedebugservicefactory.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservicefactory.cpp b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservicefactory.cpp index d46d8f9dfa..1f31495a70 100644 --- a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservicefactory.cpp +++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservicefactory.cpp @@ -52,3 +52,5 @@ QQmlDebugService *QQmlNativeDebugServiceFactory::create(const QString &key) } QT_END_NAMESPACE + +#include "moc_qqmlnativedebugservicefactory.cpp" -- cgit v1.2.3 From 787f2dda9186b3a396bc161e95e0c2c084b35608 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Apr 2022 16:10:12 +0200 Subject: QQmlProfilerServiceFactoryPlugin: includemocs Including moc files directly into their classes' TU tends to improve codegen and enables extended compiler warnings, e.g. about unused private functions or fields. Task-number: QTBUG-102948 Change-Id: Idc57e5a664a62d8ed199582a1230e508e227abf7 Reviewed-by: Fabian Kosmale (cherry picked from commit aa9a29ed5f1b8d386dc21d3333891a739b46c8e3) Reviewed-by: Qt Cherry-pick Bot --- src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp index 3004c7d412..4fbb575db7 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp @@ -159,3 +159,5 @@ void QQmlProfilerAdapter::receiveData(const QVector &new_data, } QT_END_NAMESPACE + +#include "moc_qqmlprofileradapter.cpp" -- cgit v1.2.3 From 34457245cebbd34e0dc8874338be836f05669b45 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Apr 2022 16:10:12 +0200 Subject: QQmlDebuggerServiceFactoryPlugin: includemocs Including moc files directly into their classes' TU tends to improve codegen and enables extended compiler warnings, e.g. about unused private functions or fields. Task-number: QTBUG-102948 Change-Id: Ibff8a716a7fb2bc2045ebacc85c94765cbd5b531 Reviewed-by: Fabian Kosmale (cherry picked from commit 7fc017a8f555f3c8c2b5fb5cd1a2c195d00a8769) Reviewed-by: Qt Cherry-pick Bot --- src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp index 13a8cab467..5d1e894a2b 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp @@ -56,3 +56,5 @@ QQmlDebugService *QQmlDebuggerServiceFactory::create(const QString &key) } QT_END_NAMESPACE + +#include "moc_qqmldebuggerservicefactory.cpp" -- cgit v1.2.3 From dc1789ac127422148c46dd0427d98c963b0ee468 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Apr 2022 16:10:12 +0200 Subject: QQmlInspectorServiceFactoryPlugin: includemocs Including moc files directly into their classes' TU tends to improve codegen and enables extended compiler warnings, e.g. about unused private functions or fields. Task-number: QTBUG-102948 Change-Id: I51062af584ada3dae3e8435df7ed7accf1935450 Reviewed-by: Fabian Kosmale (cherry picked from commit 217cb9a111d94071b0d43bd0d2d2cd1e2d6a2ca5) Reviewed-by: Qt Cherry-pick Bot --- src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp b/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp index fe71422d8f..8a38922cc0 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp +++ b/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp @@ -407,4 +407,6 @@ GlobalInspector::~GlobalInspector() QT_END_NAMESPACE +#include "moc_globalinspector.cpp" + #include -- cgit v1.2.3 From 5ee7e7069c32bc335cebb2b21ed664fe67996597 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Apr 2022 16:29:35 +0200 Subject: QmlModels: includemocs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Including moc files directly into their classes' TU tends to improve codegen and enables extended compiler warnings, e.g. about unused private functions or fields. Task-number: QTBUG-102948 Change-Id: I7927a2ce6140c9379f152b2932c3a45b8fc16a7a Reviewed-by: Mårten Nordheim (cherry picked from commit fa049c2f84c5db14f54df36f7d5705476e323cff) Reviewed-by: Qt Cherry-pick Bot --- src/qmlmodels/qqmlabstractdelegatecomponent.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qmlmodels/qqmlabstractdelegatecomponent.cpp b/src/qmlmodels/qqmlabstractdelegatecomponent.cpp index 298eb7260f..b6e7abe074 100644 --- a/src/qmlmodels/qqmlabstractdelegatecomponent.cpp +++ b/src/qmlmodels/qqmlabstractdelegatecomponent.cpp @@ -59,3 +59,5 @@ QVariant QQmlAbstractDelegateComponent::value(QQmlAdaptorModel *adaptorModel, in } QT_END_NAMESPACE + +#include "moc_qqmlabstractdelegatecomponent_p.cpp" -- cgit v1.2.3 From 99e8880e540f236ce85801f117475384e36b19cb Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Apr 2022 16:10:10 +0200 Subject: QmlDebugPrivate: includemocs Including moc files directly into their classes' TU tends to improve codegen and enables extended compiler warnings, e.g. about unused private functions or fields. Task-number: QTBUG-102948 Change-Id: Ifc06bc5b7a0cbe27188677e869a133dfcd1217ce Reviewed-by: Fabian Kosmale (cherry picked from commit ef2b433c00508f784fb82a515174a459ae4ed5e6) Reviewed-by: Qt Cherry-pick Bot --- src/qmldebug/qqmldebugclient.cpp | 2 ++ src/qmldebug/qqmldebugmessageclient.cpp | 2 ++ src/qmldebug/qqmldebugtranslationclient.cpp | 2 ++ src/qmldebug/qqmlenginedebugclient.cpp | 2 ++ src/qmldebug/qqmlinspectorclient.cpp | 2 ++ src/qmldebug/qqmlpreviewclient.cpp | 2 ++ src/qmldebug/qv4debugclient.cpp | 2 ++ 7 files changed, 14 insertions(+) diff --git a/src/qmldebug/qqmldebugclient.cpp b/src/qmldebug/qqmldebugclient.cpp index 994cfe0c55..cce111efe5 100644 --- a/src/qmldebug/qqmldebugclient.cpp +++ b/src/qmldebug/qqmldebugclient.cpp @@ -123,3 +123,5 @@ void QQmlDebugClient::messageReceived(const QByteArray &message) } QT_END_NAMESPACE + +#include "moc_qqmldebugclient_p.cpp" diff --git a/src/qmldebug/qqmldebugmessageclient.cpp b/src/qmldebug/qqmldebugmessageclient.cpp index 6d49420c63..5370edebbe 100644 --- a/src/qmldebug/qqmldebugmessageclient.cpp +++ b/src/qmldebug/qqmldebugmessageclient.cpp @@ -88,3 +88,5 @@ void QQmlDebugMessageClient::messageReceived(const QByteArray &data) } QT_END_NAMESPACE + +#include "moc_qqmldebugmessageclient_p.cpp" diff --git a/src/qmldebug/qqmldebugtranslationclient.cpp b/src/qmldebug/qqmldebugtranslationclient.cpp index a4a2d1cec4..500318c8c6 100644 --- a/src/qmldebug/qqmldebugtranslationclient.cpp +++ b/src/qmldebug/qqmldebugtranslationclient.cpp @@ -74,3 +74,5 @@ void QQmlDebugTranslationClient::triggerLanguage(const QUrl &url, const QString } QT_END_NAMESPACE + +#include "moc_qqmldebugtranslationclient_p.cpp" diff --git a/src/qmldebug/qqmlenginedebugclient.cpp b/src/qmldebug/qqmlenginedebugclient.cpp index 108e8d5da9..ce68ce42de 100644 --- a/src/qmldebug/qqmlenginedebugclient.cpp +++ b/src/qmldebug/qqmlenginedebugclient.cpp @@ -566,3 +566,5 @@ qint32 QQmlEngineDebugClient::getId() } QT_END_NAMESPACE + +#include "moc_qqmlenginedebugclient_p.cpp" diff --git a/src/qmldebug/qqmlinspectorclient.cpp b/src/qmldebug/qqmlinspectorclient.cpp index f2a3734d2d..0ded2f0ad6 100644 --- a/src/qmldebug/qqmlinspectorclient.cpp +++ b/src/qmldebug/qqmlinspectorclient.cpp @@ -148,3 +148,5 @@ void QQmlInspectorClient::messageReceived(const QByteArray &message) } QT_END_NAMESPACE + +#include "moc_qqmlinspectorclient_p.cpp" diff --git a/src/qmldebug/qqmlpreviewclient.cpp b/src/qmldebug/qqmlpreviewclient.cpp index 65e0e43ca3..e9affcab2b 100644 --- a/src/qmldebug/qqmlpreviewclient.cpp +++ b/src/qmldebug/qqmlpreviewclient.cpp @@ -137,3 +137,5 @@ void QQmlPreviewClient::triggerLanguage(const QUrl &url, const QString &locale) } QT_END_NAMESPACE + +#include "moc_qqmlpreviewclient_p.cpp" diff --git a/src/qmldebug/qv4debugclient.cpp b/src/qmldebug/qv4debugclient.cpp index e6ac035afe..9984f5ebba 100644 --- a/src/qmldebug/qv4debugclient.cpp +++ b/src/qmldebug/qv4debugclient.cpp @@ -576,3 +576,5 @@ QByteArray QV4DebugClientPrivate::packMessage(const QByteArray &type, const QJso } QT_END_NAMESPACE + +#include "moc_qv4debugclient_p.cpp" -- cgit v1.2.3 From 68eabf398aa5acd683f3b0ca860fed73218aaf1b Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Tue, 28 Jul 2020 09:19:32 +0200 Subject: Avoid -Wclass-memaccess warning Change-Id: Ia5e6ed13528fac68fe9f5f5b13471b6806d53b21 Reviewed-by: Laszlo Agocs (cherry picked from commit 4225411b7fceffa87e2e5bbba5dc725cbaba20e5) Reviewed-by: Marc Mutz --- src/quick/scenegraph/coreapi/qsgmaterialrhishader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quick/scenegraph/coreapi/qsgmaterialrhishader.cpp b/src/quick/scenegraph/coreapi/qsgmaterialrhishader.cpp index 6aece47aea..045215fc0f 100644 --- a/src/quick/scenegraph/coreapi/qsgmaterialrhishader.cpp +++ b/src/quick/scenegraph/coreapi/qsgmaterialrhishader.cpp @@ -105,7 +105,7 @@ void QSGMaterialRhiShaderPrivate::prepare(QShader::Variant vertexShaderVariant) ubufBinding = -1; ubufSize = 0; ubufStages = { }; - memset(combinedImageSamplerBindings, 0, sizeof(combinedImageSamplerBindings)); + memset(static_cast(combinedImageSamplerBindings), 0, sizeof(combinedImageSamplerBindings)); vertexShader = fragmentShader = nullptr; masterUniformData.clear(); -- cgit v1.2.3 From d4021a8d62287219a4be9fbd555b9ba91130737a Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 29 Apr 2022 15:18:08 +0200 Subject: MouseArea: don't get stuck in doubleClick if handler caused ungrab The bug scenario went like this: 1) QQuickMouseArea::mouseDoubleClickEvent() emits doubleClicked 2) onDoubleClicked in QML hid the MouseArea somehow 3) QQuickMouseArea::ungrabMouse() is called; it sets d->pressed = Qt::NoButton and d->doubleClick = false (and others) 4) eventually we get back to the continuation of mouseDoubleClickEvent() which sets d->doubleClick back to true 5) mouse release: this MouseArea is not involved (no grab anymore) 6) next mouse press: QQuickMouseArea::setPressed() has if (!d->doubleClick) emit pressed(&me); pressed() is not emitted because of leftover state So either we need to avoid setting d->doubleClick to true if d->pressed has been set to Qt::NoButton in QQuickMouseArea::ungrabMouse(); or else we should reorder the statements in mouseDoubleClickEvent() to set d->doubleClick before emitting doubleClicked, so that it will not be overridden after the QML handler is called. This patch takes the first approach. Fixes: QTBUG-35995 Fixes: QTBUG-102158 Change-Id: Ibe5c9bfbc9c7a70772dd5ebfbc9ce401c6c226d3 Reviewed-by: Fabian Kosmale (cherry picked from commit 089c3b15b95fc0ddbf2385378f96702a999771c8) --- src/quick/items/qquickmousearea.cpp | 3 ++- .../qquickmousearea/data/doubleClickToHide.qml | 19 +++++++++++++++ .../quick/qquickmousearea/tst_qquickmousearea.cpp | 28 ++++++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 tests/auto/quick/qquickmousearea/data/doubleClickToHide.qml diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp index 39e0652605..7f5272a142 100644 --- a/src/quick/items/qquickmousearea.cpp +++ b/src/quick/items/qquickmousearea.cpp @@ -825,7 +825,8 @@ void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event) emit this->doubleClicked(&me); if (!me.isAccepted()) d->propagate(&me, QQuickMouseAreaPrivate::DoubleClick); - d->doubleClick = d->isDoubleClickConnected() || me.isAccepted(); + if (d->pressed) + d->doubleClick = d->isDoubleClickConnected() || me.isAccepted(); } QQuickItem::mouseDoubleClickEvent(event); } diff --git a/tests/auto/quick/qquickmousearea/data/doubleClickToHide.qml b/tests/auto/quick/qquickmousearea/data/doubleClickToHide.qml new file mode 100644 index 0000000000..01f6eaabed --- /dev/null +++ b/tests/auto/quick/qquickmousearea/data/doubleClickToHide.qml @@ -0,0 +1,19 @@ +import QtQuick 2.0 + +Item { + id: root + property int clicked: 0 + property int doubleClicked: 0 + property int released: 0 + + MouseArea { + width: 200; height: 200 + onClicked: { root.clicked++ } + onDoubleClicked: { + root.doubleClicked++ + visible = false + } + onReleased: { root.released++ } + } +} + diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp index 1c99357ab7..27fee2aab3 100644 --- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp +++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp @@ -161,6 +161,7 @@ private slots: void nestedEventDelivery(); void settingHiddenInPressUngrabs(); void containsMouseAndVisibility(); + void doubleClickToHide(); private: int startDragDistance() const { @@ -2500,6 +2501,33 @@ void tst_QQuickMouseArea::containsMouseAndVisibility() QVERIFY(!mouseArea->hovered()); } +// QTBUG-35995 and QTBUG-102158 +void tst_QQuickMouseArea::doubleClickToHide() +{ + QQuickView window; + QByteArray errorMessage; + QVERIFY2(QQuickTest::initView(window, testFileUrl("doubleClickToHide.qml"), true, &errorMessage), errorMessage.constData()); + window.show(); + window.requestActivate(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + + QQuickMouseArea *mouseArea = window.rootObject()->findChild(); + QVERIFY(mouseArea); + + QTest::mouseDClick(&window, Qt::LeftButton, Qt::NoModifier, {10, 10}); + + QCOMPARE(window.rootObject()->property("clicked").toInt(), 1); + QCOMPARE(window.rootObject()->property("doubleClicked").toInt(), 1); + QCOMPARE(mouseArea->isVisible(), false); + QCOMPARE(mouseArea->pressed(), false); + QCOMPARE(mouseArea->pressedButtons(), Qt::NoButton); + + mouseArea->setVisible(true); + + QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, {10, 10}); + QCOMPARE(window.rootObject()->property("clicked").toInt(), 2); +} + QTEST_MAIN(tst_QQuickMouseArea) #include "tst_qquickmousearea.moc" -- cgit v1.2.3 From 91050c663724a8f1927504c2a9a6b2817d0414c0 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Apr 2022 17:13:19 +0200 Subject: QQmlTableModelColumn: remove unused field mIndex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found by Clang after includemocs: qqmltablemodelcolumn_p.h:220:9: error: private field 'mIndex' is not used [-Werror,-Wunused-private-field] int mIndex = -1; ^ Change-Id: I408d93c2f4d84d2223f971af472eabc80c31aaa3 Reviewed-by: Mårten Nordheim (cherry picked from commit 910052db8aa3da1ffdced1b17609443dc1cca566) --- src/imports/labsmodels/qqmltablemodelcolumn_p.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/imports/labsmodels/qqmltablemodelcolumn_p.h b/src/imports/labsmodels/qqmltablemodelcolumn_p.h index b7d94a1790..6f1f34435b 100644 --- a/src/imports/labsmodels/qqmltablemodelcolumn_p.h +++ b/src/imports/labsmodels/qqmltablemodelcolumn_p.h @@ -213,8 +213,6 @@ Q_SIGNALS: void setSizeHintChanged(); private: - int mIndex = -1; - // We store these in hashes because QQuickTableModel needs string-based lookup in certain situations. QHash mGetters; QHash mSetters; -- cgit v1.2.3 From 4afd45162c1c63a24f6cd1e73c4ad3e368c5a11a Mon Sep 17 00:00:00 2001 From: Nicholas Bennett Date: Wed, 4 May 2022 13:57:59 +0300 Subject: Docs: Document textInput.acceptableInput as read only Added \readonly to the qml property comment. Fixes: QTBUG-103224 Change-Id: I42ddad6501700c586fe4154cd675d881a4686f8d Reviewed-by: Shawn Rutledge (cherry picked from commit c00e9fbbf397bb155da43b2b0c18ca5e8e2697cd) Reviewed-by: Qt Cherry-pick Bot --- src/quick/items/qquicktextinput.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 631c687ee7..8ceb8827f5 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -1165,6 +1165,7 @@ void QQuickTextInput::setInputMask(const QString &im) /*! \qmlproperty bool QtQuick::TextInput::acceptableInput + \readonly This property is always true unless a validator or input mask has been set. If a validator or input mask has been set, this property will only be true -- cgit v1.2.3 From 9a18deda600d22e564a3b723b7d8a0021cfcb8bf Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 2 May 2022 15:51:45 +0200 Subject: PinchArea: ignore ZoomNativeGesture and RotateNativeGesture if told to MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As with most event-handling Items, the user can reject the first event by setting accepted to false in QML. It was implemented for touch events, but not for native gesture events. Amends d896d76b0f2ff0387cd09a04107ea5df087268e1 Fixes: QTBUG-101628 Change-Id: I05a15cb71e6c97c35d6e56a58d9d59028fe33462 Reviewed-by: Jan Arve Sæther (cherry picked from commit 175681bbbc5f69426330aa3061abd280264670b6) Reviewed-by: Qt Cherry-pick Bot --- src/quick/items/qquickpincharea.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp index 994bdc54a9..93b68b061a 100644 --- a/src/quick/items/qquickpincharea.cpp +++ b/src/quick/items/qquickpincharea.cpp @@ -710,6 +710,8 @@ bool QQuickPinchArea::event(QEvent *event) clearPinch(); break; case Qt::ZoomNativeGesture: { + if (d->pinchRejected) + break; qreal scale = d->pinchLastScale * (1.0 + gesture->value()); QQuickPinchEvent pe(d->pinchStartCenter, scale, d->pinchLastAngle, 0.0); pe.setStartCenter(d->pinchStartCenter); @@ -727,7 +729,10 @@ bool QQuickPinchArea::event(QEvent *event) else emit pinchStarted(&pe); d->inPinch = true; - updatePinchTarget(); + if (pe.accepted()) + updatePinchTarget(); + else + d->pinchRejected = true; } break; case Qt::SmartZoomNativeGesture: { if (gesture->value() > 0.0 && d->pinch && d->pinch->target()) { @@ -751,6 +756,8 @@ bool QQuickPinchArea::event(QEvent *event) emit smartZoom(&pe); } break; case Qt::RotateNativeGesture: { + if (d->pinchRejected) + break; qreal angle = d->pinchLastAngle + gesture->value(); QQuickPinchEvent pe(d->pinchStartCenter, d->pinchLastScale, angle, 0.0); pe.setStartCenter(d->pinchStartCenter); @@ -769,7 +776,10 @@ bool QQuickPinchArea::event(QEvent *event) emit pinchStarted(&pe); d->inPinch = true; d->pinchRotation = angle; - updatePinchTarget(); + if (pe.accepted()) + updatePinchTarget(); + else + d->pinchRejected = true; } break; default: return QQuickItem::event(event); -- cgit v1.2.3 From 0a82cb4709c24bd8b8b559ac255780f014b13545 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Apr 2022 16:29:36 +0200 Subject: QuickTest: includemocs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Including moc files directly into their classes' TU tends to improve codegen and enables extended compiler warnings, e.g. about unused private functions or fields. Manual conflict resolutions: - dropped all inclusions into non-existing files Task-number: QTBUG-102948 Change-Id: Ic8d138526724734169ff7f0686ad19d30c729307 Reviewed-by: Mårten Nordheim (cherry picked from commit cdca7e8c1090a48b0df29a45ddbb462920475a05) Reviewed-by: Qt CI Bot Reviewed-by: Ulf Hermann --- src/qmltest/quicktest.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp index ccf676b36c..b2725b6846 100644 --- a/src/qmltest/quicktest.cpp +++ b/src/qmltest/quicktest.cpp @@ -650,3 +650,5 @@ int quick_test_main_with_setup(int argc, char **argv, const char *name, const ch } QT_END_NAMESPACE + +#include "moc_quicktest_p.cpp" -- cgit v1.2.3 From 0eff75134155021c8f506b52d1258cf257ffc529 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Apr 2022 17:43:38 +0200 Subject: Qml: includemocs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Including moc files directly into their classes' TU tends to improve codegen and enables extended compiler warnings, e.g. about unused private functions or fields. Manual conflict resolutions: - dropped all inclusions into non-existing files - qv4sequenceobject_p.h doesn't have Q_GADGETs in 5.15 - QQmlProperty and QQmlScriptString are not Q_GADGETs in 5.15 Task-number: QTBUG-102948 Change-Id: Ie39c60a19ba562affe6bd52ba68b38db95298cf3 Reviewed-by: Qt CI Bot Reviewed-by: Mårten Nordheim (cherry picked from commit 26992a29c6ec1697fe6cec3379b37d1c9b203947) Reviewed-by: Fabian Kosmale --- src/qml/jsruntime/qv4promiseobject.cpp | 2 ++ src/qml/qml/qqmlengine.cpp | 2 ++ src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp | 2 ++ src/qml/util/qqmlpropertymap.cpp | 2 ++ 4 files changed, 8 insertions(+) diff --git a/src/qml/jsruntime/qv4promiseobject.cpp b/src/qml/jsruntime/qv4promiseobject.cpp index 11a0f3901c..e9e8d6f5eb 100644 --- a/src/qml/jsruntime/qv4promiseobject.cpp +++ b/src/qml/jsruntime/qv4promiseobject.cpp @@ -116,6 +116,8 @@ struct ResolveThenableEvent : public QEvent } // namespace QV4 QT_END_NAMESPACE +#include "moc_qv4promiseobject_p.cpp" + ReactionHandler::ReactionHandler(QObject *parent) : QObject(parent) {} diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 25f1e37fad..ba87c9810f 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -2671,4 +2671,6 @@ bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */) QT_END_NAMESPACE +#include "moc_qqmlengine_p.cpp" + #include "moc_qqmlengine.cpp" diff --git a/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp b/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp index 644c10e88d..7a754e1c7d 100644 --- a/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp +++ b/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp @@ -72,3 +72,5 @@ void QQmlTypeLoaderNetworkReplyProxy::manualFinished(QNetworkReply *reply) } QT_END_NAMESPACE + +#include "moc_qqmltypeloadernetworkreplyproxy_p.cpp" diff --git a/src/qml/util/qqmlpropertymap.cpp b/src/qml/util/qqmlpropertymap.cpp index 3b481c5384..db257711c8 100644 --- a/src/qml/util/qqmlpropertymap.cpp +++ b/src/qml/util/qqmlpropertymap.cpp @@ -370,3 +370,5 @@ QQmlPropertyMap::QQmlPropertyMap(const QMetaObject *staticMetaObject, QObject *p */ QT_END_NAMESPACE + +#include "moc_qqmlpropertymap.cpp" -- cgit v1.2.3 From 7712ce869dea7ef2a93d240dee61b4ef420a2270 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Apr 2022 16:10:12 +0200 Subject: QQmlPreviewServiceFactoryPlugin: includemocs Including moc files directly into their classes' TU tends to improve codegen and enables extended compiler warnings, e.g. about unused private functions or fields. Manual conflict resolutions: - dropped all inclusions into non-existing files Task-number: QTBUG-102948 Change-Id: I329951a5063d7fa7d2124354f751b8744fbae486 Reviewed-by: Fabian Kosmale (cherry picked from commit a79bdbd19f4a4f8fbc9551da8821517e977cb77b) Reviewed-by: Qt CI Bot Reviewed-by: Ulf Hermann --- src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp | 2 ++ src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp | 2 ++ src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp | 2 ++ src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp | 2 ++ src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp | 2 ++ 5 files changed, 10 insertions(+) diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp index 63aa03e025..e5e5407dbb 100644 --- a/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp +++ b/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp @@ -66,3 +66,5 @@ void QQmlDebugTranslationServiceImpl::foundTranslationBinding(QQmlTranslationBin } QT_END_NAMESPACE + +#include "moc_qqmldebugtranslationservice.cpp" diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp index f97dcfc767..5fa1e064cd 100644 --- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp +++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp @@ -197,3 +197,5 @@ void QQmlPreviewFileLoader::clearCache() } QT_END_NAMESPACE + +#include "moc_qqmlpreviewfileloader.cpp" diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp index 5015055fac..b0b7630a05 100644 --- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp +++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp @@ -456,3 +456,5 @@ void QQmlPreviewHandler::tryCreateObject() } QT_END_NAMESPACE + +#include "moc_qqmlpreviewhandler.cpp" diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp index 4623f37483..6268dbde8a 100644 --- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp +++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp @@ -197,3 +197,5 @@ void QQmlPreviewServiceImpl::forwardFps(const QQmlPreviewHandler::FpsInfo &frame } QT_END_NAMESPACE + +#include "moc_qqmlpreviewservice.cpp" diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp index ca14170c5f..02e307ed32 100644 --- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp +++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp @@ -54,3 +54,5 @@ QQmlDebugService *QQmlPreviewServiceFactory::create(const QString &key) } QT_END_NAMESPACE + +#include "moc_qqmlpreviewservicefactory.cpp" -- cgit v1.2.3 From bc9b1ac980a81d88dd82f4215964daaf446ae171 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Apr 2022 17:48:19 +0200 Subject: QSGRhiShaderEffectNode: remove unused m_rc member MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found by Clang after includemocs: qsgrhishadereffectnode_p.h:145:30: error: private field 'm_rc' is not used [-Werror,-Wunused-private-field] QSGDefaultRenderContext *m_rc; ^ Change-Id: I915751abb01d9ff5d57c364be333ca2c171eaa97 Reviewed-by: Mårten Nordheim (cherry picked from commit 8a963700499a4264edaf462d906128f662a090fc) Reviewed-by: Qt CI Bot Reviewed-by: Ulf Hermann --- src/quick/scenegraph/qsgrhishadereffectnode.cpp | 2 +- src/quick/scenegraph/qsgrhishadereffectnode_p.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/quick/scenegraph/qsgrhishadereffectnode.cpp b/src/quick/scenegraph/qsgrhishadereffectnode.cpp index ce915a3fd0..75e1c2beb0 100644 --- a/src/quick/scenegraph/qsgrhishadereffectnode.cpp +++ b/src/quick/scenegraph/qsgrhishadereffectnode.cpp @@ -572,10 +572,10 @@ void QSGRhiShaderEffectMaterial::updateTextureProviders(bool layoutChange) QSGRhiShaderEffectNode::QSGRhiShaderEffectNode(QSGDefaultRenderContext *rc, QSGRhiGuiThreadShaderEffectManager *mgr) : QSGShaderEffectNode(mgr), - m_rc(rc), m_mgr(mgr), m_material(this) { + Q_UNUSED(rc); setFlag(UsePreprocess, true); setMaterial(&m_material); } diff --git a/src/quick/scenegraph/qsgrhishadereffectnode_p.h b/src/quick/scenegraph/qsgrhishadereffectnode_p.h index 2d89926820..9be7917c55 100644 --- a/src/quick/scenegraph/qsgrhishadereffectnode_p.h +++ b/src/quick/scenegraph/qsgrhishadereffectnode_p.h @@ -139,7 +139,6 @@ private Q_SLOTS: void handleTextureProviderDestroyed(QObject *object); private: - QSGDefaultRenderContext *m_rc; QSGRhiGuiThreadShaderEffectManager *m_mgr; QSGRhiShaderEffectMaterial m_material; }; -- cgit v1.2.3 From 6269589ae2804d0c5d5a7b9bd4e78acdac799de0 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Apr 2022 17:43:38 +0200 Subject: Quick: includemocs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Including moc files directly into their classes' TU tends to improve codegen and enables extended compiler warnings, e.g. about unused private functions or fields. Manual conflict resolutions: - dropped all inclusions into non-existing files - qsgabstractrenderer_p.h doesn't contain a Q_OBJECT in 5.15 - QQuickAnchorLine isn't a Q_GADGET in 5.15 Task-number: QTBUG-102948 Change-Id: I695daa12613de3bada67eb69a26a8dce07c4b85e Reviewed-by: Mårten Nordheim (cherry picked from commit 6a23f186138dff2a7007288a02702bce23d7ca70) Reviewed-by: Qt CI Bot Reviewed-by: Ulf Hermann --- src/quick/handlers/qquickdragaxis.cpp | 2 ++ src/quick/handlers/qquickdraghandler.cpp | 2 ++ src/quick/handlers/qquickhandlerpoint.cpp | 2 ++ src/quick/handlers/qquickhoverhandler.cpp | 2 ++ src/quick/handlers/qquickmultipointhandler.cpp | 2 ++ src/quick/handlers/qquickpinchhandler.cpp | 2 ++ src/quick/handlers/qquickpointerdevicehandler.cpp | 2 ++ src/quick/handlers/qquickpointerhandler.cpp | 2 ++ src/quick/handlers/qquickpointhandler.cpp | 2 ++ src/quick/handlers/qquicksinglepointhandler.cpp | 2 ++ src/quick/handlers/qquicktaphandler.cpp | 2 ++ src/quick/handlers/qquickwheelhandler.cpp | 2 ++ src/quick/items/qquickevents.cpp | 2 ++ src/quick/items/qquickflickable.cpp | 2 ++ src/quick/items/qquickimage.cpp | 4 ++++ src/quick/items/qquickitemsmodule.cpp | 2 ++ src/quick/items/qquickscalegrid.cpp | 2 ++ src/quick/items/qquicktableview.cpp | 2 ++ src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp | 2 ++ src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp | 2 ++ src/quick/scenegraph/qsgrhishadereffectnode.cpp | 2 ++ src/quick/scenegraph/util/qsgplaintexture.cpp | 2 ++ src/quick/util/qquicksmoothedanimation.cpp | 2 ++ src/quick/util/qquicktimeline.cpp | 2 ++ 24 files changed, 50 insertions(+) diff --git a/src/quick/handlers/qquickdragaxis.cpp b/src/quick/handlers/qquickdragaxis.cpp index 823c58d12e..6d29317b43 100644 --- a/src/quick/handlers/qquickdragaxis.cpp +++ b/src/quick/handlers/qquickdragaxis.cpp @@ -76,3 +76,5 @@ void QQuickDragAxis::setEnabled(bool enabled) } QT_END_NAMESPACE + +#include "moc_qquickdragaxis_p.cpp" diff --git a/src/quick/handlers/qquickdraghandler.cpp b/src/quick/handlers/qquickdraghandler.cpp index 4e4e7c9f33..1c4c4e85d6 100644 --- a/src/quick/handlers/qquickdraghandler.cpp +++ b/src/quick/handlers/qquickdraghandler.cpp @@ -343,3 +343,5 @@ void QQuickDragHandler::setTranslation(const QVector2D &trans) */ QT_END_NAMESPACE + +#include "moc_qquickdraghandler_p.cpp" diff --git a/src/quick/handlers/qquickhandlerpoint.cpp b/src/quick/handlers/qquickhandlerpoint.cpp index 9ef0f676e1..56a3f09fa5 100644 --- a/src/quick/handlers/qquickhandlerpoint.cpp +++ b/src/quick/handlers/qquickhandlerpoint.cpp @@ -348,3 +348,5 @@ void QQuickHandlerPoint::reset(const QVector &points) */ QT_END_NAMESPACE + +#include "moc_qquickhandlerpoint_p.cpp" diff --git a/src/quick/handlers/qquickhoverhandler.cpp b/src/quick/handlers/qquickhoverhandler.cpp index 38ee521270..4c14176014 100644 --- a/src/quick/handlers/qquickhoverhandler.cpp +++ b/src/quick/handlers/qquickhoverhandler.cpp @@ -294,3 +294,5 @@ void QQuickHoverHandler::setHovered(bool hovered) */ QT_END_NAMESPACE + +#include "moc_qquickhoverhandler_p.cpp" diff --git a/src/quick/handlers/qquickmultipointhandler.cpp b/src/quick/handlers/qquickmultipointhandler.cpp index 4f050b70b0..a33804e421 100644 --- a/src/quick/handlers/qquickmultipointhandler.cpp +++ b/src/quick/handlers/qquickmultipointhandler.cpp @@ -436,3 +436,5 @@ QMetaProperty &QQuickMultiPointHandlerPrivate::yMetaProperty() const } QT_END_NAMESPACE + +#include "moc_qquickmultipointhandler_p.cpp" diff --git a/src/quick/handlers/qquickpinchhandler.cpp b/src/quick/handlers/qquickpinchhandler.cpp index aebf9fc63e..9985c85878 100644 --- a/src/quick/handlers/qquickpinchhandler.cpp +++ b/src/quick/handlers/qquickpinchhandler.cpp @@ -546,3 +546,5 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event) */ QT_END_NAMESPACE + +#include "moc_qquickpinchhandler_p.cpp" diff --git a/src/quick/handlers/qquickpointerdevicehandler.cpp b/src/quick/handlers/qquickpointerdevicehandler.cpp index 0238bfb7b0..96ad0eff10 100644 --- a/src/quick/handlers/qquickpointerdevicehandler.cpp +++ b/src/quick/handlers/qquickpointerdevicehandler.cpp @@ -314,3 +314,5 @@ bool QQuickPointerDeviceHandler::wantsPointerEvent(QQuickPointerEvent *event) } QT_END_NAMESPACE + +#include "moc_qquickpointerdevicehandler_p.cpp" diff --git a/src/quick/handlers/qquickpointerhandler.cpp b/src/quick/handlers/qquickpointerhandler.cpp index 428a71e2c0..9e9c2e8d6f 100644 --- a/src/quick/handlers/qquickpointerhandler.cpp +++ b/src/quick/handlers/qquickpointerhandler.cpp @@ -742,3 +742,5 @@ bool QQuickPointerHandlerPrivate::dragOverThreshold(const QQuickEventPoint *poin } QT_END_NAMESPACE + +#include "moc_qquickpointerhandler_p.cpp" diff --git a/src/quick/handlers/qquickpointhandler.cpp b/src/quick/handlers/qquickpointhandler.cpp index 3ebd13a754..b8f6e9b8a9 100644 --- a/src/quick/handlers/qquickpointhandler.cpp +++ b/src/quick/handlers/qquickpointhandler.cpp @@ -163,3 +163,5 @@ QVector2D QQuickPointHandler::translation() const } QT_END_NAMESPACE + +#include "moc_qquickpointhandler_p.cpp" diff --git a/src/quick/handlers/qquicksinglepointhandler.cpp b/src/quick/handlers/qquicksinglepointhandler.cpp index 5d42eb0668..1cf09025cf 100644 --- a/src/quick/handlers/qquicksinglepointhandler.cpp +++ b/src/quick/handlers/qquicksinglepointhandler.cpp @@ -218,3 +218,5 @@ void QQuickSinglePointHandlerPrivate::reset() } QT_END_NAMESPACE + +#include "moc_qquicksinglepointhandler_p.cpp" diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp index 04c9558e0a..06e45643bf 100644 --- a/src/quick/handlers/qquicktaphandler.cpp +++ b/src/quick/handlers/qquicktaphandler.cpp @@ -431,3 +431,5 @@ void QQuickTapHandler::updateTimeHeld() from the previous \c tapCount. */ QT_END_NAMESPACE + +#include "moc_qquicktaphandler_p.cpp" diff --git a/src/quick/handlers/qquickwheelhandler.cpp b/src/quick/handlers/qquickwheelhandler.cpp index d727505020..407978627a 100644 --- a/src/quick/handlers/qquickwheelhandler.cpp +++ b/src/quick/handlers/qquickwheelhandler.cpp @@ -527,3 +527,5 @@ QMetaProperty &QQuickWheelHandlerPrivate::targetMetaProperty() const } QT_END_NAMESPACE + +#include "moc_qquickwheelhandler_p.cpp" diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp index d433b194a5..0e63c17e98 100644 --- a/src/quick/items/qquickevents.cpp +++ b/src/quick/items/qquickevents.cpp @@ -2274,3 +2274,5 @@ Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickEventPoint *eve #endif QT_END_NAMESPACE + +#include "moc_qquickevents_p_p.cpp" diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 3a36a0082b..c64825166a 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -2937,4 +2937,6 @@ void QQuickFlickable::setBoundsMovement(BoundsMovement movement) QT_END_NAMESPACE +#include "moc_qquickflickable_p_p.cpp" + #include "moc_qquickflickable_p.cpp" diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp index ab00eccd5e..0b1cd55396 100644 --- a/src/quick/items/qquickimage.cpp +++ b/src/quick/items/qquickimage.cpp @@ -945,3 +945,7 @@ void QQuickImage::setMipmap(bool use) */ QT_END_NAMESPACE + +#include "moc_qquickimage_p_p.cpp" + +#include "moc_qquickimage_p.cpp" diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index 922a7fec96..e996d4b553 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -128,6 +128,8 @@ QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(lcTransient) QT_END_NAMESPACE +#include "moc_qquickitemsmodule_p.cpp" + static QQmlPrivate::AutoParentResult qquickitem_autoParent(QObject *obj, QObject *parent) { // When setting a parent (especially during dynamic object creation) in QML, diff --git a/src/quick/items/qquickscalegrid.cpp b/src/quick/items/qquickscalegrid.cpp index 8ae09de535..aa32d3e96a 100644 --- a/src/quick/items/qquickscalegrid.cpp +++ b/src/quick/items/qquickscalegrid.cpp @@ -217,3 +217,5 @@ QString QQuickGridScaledImage::pixmapUrl() const } QT_END_NAMESPACE + +#include "moc_qquickscalegrid_p_p.cpp" diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp index 7fc6b6572d..2a8a8ccae0 100644 --- a/src/quick/items/qquicktableview.cpp +++ b/src/quick/items/qquicktableview.cpp @@ -3096,3 +3096,5 @@ QQuickTableSectionSizeProviderPrivate::~QQuickTableSectionSizeProviderPrivate() #include "moc_qquicktableview_p.cpp" QT_END_NAMESPACE + +#include "moc_qquicktableview_p_p.cpp" diff --git a/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp b/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp index 62025970ef..23bfbe38c6 100644 --- a/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp +++ b/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp @@ -180,3 +180,5 @@ QSGTexture *Texture::removedFromAtlas() const } QT_END_NAMESPACE + +#include "moc_qsgcompressedatlastexture_p.cpp" diff --git a/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp b/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp index d502f55eb0..bee529657e 100644 --- a/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp +++ b/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp @@ -382,3 +382,5 @@ QSize QSGCompressedTextureFactory::textureSize() const } QT_END_NAMESPACE + +#include "moc_qsgcompressedtexture_p.cpp" diff --git a/src/quick/scenegraph/qsgrhishadereffectnode.cpp b/src/quick/scenegraph/qsgrhishadereffectnode.cpp index 75e1c2beb0..4b1bea4ff1 100644 --- a/src/quick/scenegraph/qsgrhishadereffectnode.cpp +++ b/src/quick/scenegraph/qsgrhishadereffectnode.cpp @@ -884,3 +884,5 @@ bool QSGRhiGuiThreadShaderEffectManager::reflect(ShaderInfo *result) } QT_END_NAMESPACE + +#include "moc_qsgrhishadereffectnode_p.cpp" diff --git a/src/quick/scenegraph/util/qsgplaintexture.cpp b/src/quick/scenegraph/util/qsgplaintexture.cpp index 72d44a5baa..bd4c538756 100644 --- a/src/quick/scenegraph/util/qsgplaintexture.cpp +++ b/src/quick/scenegraph/util/qsgplaintexture.cpp @@ -466,3 +466,5 @@ void QSGPlainTexturePrivate::updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch } QT_END_NAMESPACE + +#include "moc_qsgplaintexture_p.cpp" diff --git a/src/quick/util/qquicksmoothedanimation.cpp b/src/quick/util/qquicksmoothedanimation.cpp index 31101459a0..f1fbcefc91 100644 --- a/src/quick/util/qquicksmoothedanimation.cpp +++ b/src/quick/util/qquicksmoothedanimation.cpp @@ -569,4 +569,6 @@ void QQuickSmoothedAnimation::setMaximumEasingTime(int v) QT_END_NAMESPACE +#include "moc_qquicksmoothedanimation_p_p.cpp" + #include "moc_qquicksmoothedanimation_p.cpp" diff --git a/src/quick/util/qquicktimeline.cpp b/src/quick/util/qquicktimeline.cpp index f22c26d964..6287ce2974 100644 --- a/src/quick/util/qquicktimeline.cpp +++ b/src/quick/util/qquicktimeline.cpp @@ -957,3 +957,5 @@ QQuickTimeLineObject *QQuickTimeLineCallback::callbackObject() const } QT_END_NAMESPACE + +#include "moc_qquicktimeline_p_p.cpp" -- cgit v1.2.3 From 02ff6f2950dd6b2a26e8cc93fcaefe1cfeecae80 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Apr 2022 23:30:02 +0200 Subject: Add a TU for QQmlProfilerEventReceiver This allows includemoc'ing, as well as de-inlining the destructor of this polymorphic class. Make the ctor explicit as a drive-by. Manual conflict resolutions: - port from cmake to qmake Task-number: QTBUG-45582 Task-number: QTBUG-102948 Pick-to: 6.3 6.2 5.15 Change-Id: I8b3bae7d5ae539d10d4bba119734bde5f20be9fe Reviewed-by: Ulf Hermann Reviewed-by: Qt CI Bot (cherry picked from commit 4ba43434bd1fe643c704d7367aff8b7cedf6af03) --- src/qmldebug/qmldebug.pro | 1 + src/qmldebug/qqmlprofilereventreceiver.cpp | 49 ++++++++++++++++++++++++++++++ src/qmldebug/qqmlprofilereventreceiver_p.h | 3 +- 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 src/qmldebug/qqmlprofilereventreceiver.cpp diff --git a/src/qmldebug/qmldebug.pro b/src/qmldebug/qmldebug.pro index ac3f3bf3bf..fd15c9054a 100644 --- a/src/qmldebug/qmldebug.pro +++ b/src/qmldebug/qmldebug.pro @@ -16,6 +16,7 @@ SOURCES += \ qqmlprofilerclient.cpp \ qqmlprofilerevent.cpp \ qqmlprofilereventlocation.cpp \ + qqmlprofilereventreceiver.cpp \ qqmlprofilereventtype.cpp \ qqmlprofilertypedevent.cpp \ qv4debugclient.cpp diff --git a/src/qmldebug/qqmlprofilereventreceiver.cpp b/src/qmldebug/qqmlprofilereventreceiver.cpp new file mode 100644 index 0000000000..cb88f821f8 --- /dev/null +++ b/src/qmldebug/qqmlprofilereventreceiver.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlprofilereventreceiver_p.h" + +QT_BEGIN_NAMESPACE + +QQmlProfilerEventReceiver::~QQmlProfilerEventReceiver() + = default; + +QT_END_NAMESPACE + +#include "moc_qqmlprofilereventreceiver_p.cpp" diff --git a/src/qmldebug/qqmlprofilereventreceiver_p.h b/src/qmldebug/qqmlprofilereventreceiver_p.h index 654d710135..8e7d3d1758 100644 --- a/src/qmldebug/qqmlprofilereventreceiver_p.h +++ b/src/qmldebug/qqmlprofilereventreceiver_p.h @@ -62,7 +62,8 @@ class QQmlProfilerEventReceiver : public QObject { Q_OBJECT public: - QQmlProfilerEventReceiver(QObject *parent = nullptr) : QObject(parent) {} + explicit QQmlProfilerEventReceiver(QObject *parent = nullptr) : QObject(parent) {} + ~QQmlProfilerEventReceiver() override; virtual int numLoadedEventTypes() const = 0; virtual void addEventType(const QQmlProfilerEventType &type) = 0; -- cgit v1.2.3 From 51780c5b96c506bf2aeb62bb2ddfcd901f6ca669 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Apr 2022 17:43:37 +0200 Subject: QmlModels: includemocs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Including moc files directly into their classes' TU tends to improve codegen and enables extended compiler warnings, e.g. about unused private functions or fields. Manual conflict resolutions: - dropped all inclusions into non-existing files Task-number: QTBUG-102948 Change-Id: I080e266e1a23f03efd4acdf48fa51a555429ceac Reviewed-by: Mårten Nordheim (cherry picked from commit 69f7039ada381591f751d1e213c94d48307657a1) Reviewed-by: Qt CI Bot Reviewed-by: Ulf Hermann --- src/qmlmodels/qqmldelegatemodel.cpp | 2 ++ src/qmlmodels/qqmllistmodel.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp index 8e9ca0ce55..ba636df45d 100644 --- a/src/qmlmodels/qqmldelegatemodel.cpp +++ b/src/qmlmodels/qqmldelegatemodel.cpp @@ -3923,4 +3923,6 @@ QV4::ReturnedValue QQmlDelegateModelEngineData::array(QV4::ExecutionEngine *v4, QT_END_NAMESPACE +#include "moc_qqmldelegatemodel_p_p.cpp" + #include "moc_qqmldelegatemodel_p.cpp" diff --git a/src/qmlmodels/qqmllistmodel.cpp b/src/qmlmodels/qqmllistmodel.cpp index 590f918538..33668a39ec 100644 --- a/src/qmlmodels/qqmllistmodel.cpp +++ b/src/qmlmodels/qqmllistmodel.cpp @@ -2942,4 +2942,6 @@ bool QQmlListModelParser::definesEmptyList(const QString &s) QT_END_NAMESPACE +#include "moc_qqmllistmodel_p_p.cpp" + #include "moc_qqmllistmodel_p.cpp" -- cgit v1.2.3 From be08107ce9cb45b92ec2b9e6a727b6415a7f6b20 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Apr 2022 23:30:02 +0200 Subject: Add a TU for QQmlDebugServer This allows includemoc'ing, as well as de-inlining the destructor of this polymorphic class. Requires to rename the original qdebugserver.cpp, which turned out to be the implementation file for QQmlDebugServer_Factory_. I chose, surprise, qqmldebugserverfactory.cpp. The whole plugin could even be implemented in a single .cpp file, I guess. Manual conflict resolutions: - ported from cmake to qmake Task-number: QTBUG-45582 Task-number: QTBUG-102948 Change-Id: I81aa4c60fa30ba5ced546afc72c5a4a3ba0e619f Reviewed-by: Fabian Kosmale (cherry picked from commit 30e2ae00a934a6dec7cd438e9c8d4493769507e7) Reviewed-by: Qt CI Bot Reviewed-by: Ulf Hermann --- .../qmltooling/qmldbg_server/qmldbg_server.pro | 2 +- .../qmltooling/qmldbg_server/qqmldebugserver.cpp | 767 --------------------- .../qmldbg_server/qqmldebugserverfactory.cpp | 767 +++++++++++++++++++++ src/qml/debugger/debugger.pri | 1 + src/qml/debugger/qqmldebugconnector_p.h | 1 + src/qml/debugger/qqmldebugserver.cpp | 49 ++ src/qml/debugger/qqmldebugserver_p.h | 1 + 7 files changed, 820 insertions(+), 768 deletions(-) delete mode 100644 src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp create mode 100644 src/plugins/qmltooling/qmldbg_server/qqmldebugserverfactory.cpp create mode 100644 src/qml/debugger/qqmldebugserver.cpp diff --git a/src/plugins/qmltooling/qmldbg_server/qmldbg_server.pro b/src/plugins/qmltooling/qmldbg_server/qmldbg_server.pro index d7d24a4d39..4233388a11 100644 --- a/src/plugins/qmltooling/qmldbg_server/qmldbg_server.pro +++ b/src/plugins/qmltooling/qmldbg_server/qmldbg_server.pro @@ -2,7 +2,7 @@ TARGET = qmldbg_server QT = qml-private packetprotocol-private SOURCES += \ - $$PWD/qqmldebugserver.cpp + $$PWD/qqmldebugserverfactory.cpp HEADERS += \ $$PWD/qqmldebugserverfactory.h diff --git a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp deleted file mode 100644 index 6f4d373ddd..0000000000 --- a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp +++ /dev/null @@ -1,767 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:COMM$ -** -** 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. -** -** $QT_END_LICENSE$ -** -** -** -** -** -** -** -** -** -** -** -** -** -** -** -** -** -** -** -****************************************************************************/ - -#include "qqmldebugserverfactory.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -/* - QQmlDebug Protocol (Version 1): - - handshake: - 1. Client sends - "QDeclarativeDebugServer" 0 version pluginNames [QDataStream version] - version: an int representing the highest protocol version the client knows - pluginNames: plugins available on client side - 2. Server sends - "QDeclarativeDebugClient" 0 version pluginNames pluginVersions [QDataStream version] - version: an int representing the highest protocol version the client & server know - pluginNames: plugins available on server side. plugins both in the client and server message are enabled. - client plugin advertisement - 1. Client sends - "QDeclarativeDebugServer" 1 pluginNames - server plugin advertisement (not implemented: all services are required to register before open()) - 1. Server sends - "QDeclarativeDebugClient" 1 pluginNames pluginVersions - plugin communication: - Everything send with a header different to "QDeclarativeDebugServer" is sent to the appropriate plugin. - */ - -Q_QML_DEBUG_PLUGIN_LOADER(QQmlDebugServerConnection) - -const int protocolVersion = 1; -using QQmlDebugPacket = QVersionedPacket; - -class QQmlDebugServerImpl; -class QQmlDebugServerThread : public QThread -{ -public: - QQmlDebugServerThread() : m_server(nullptr), m_portFrom(-1), m_portTo(-1) {} - - void setServer(QQmlDebugServerImpl *server) - { - m_server = server; - } - - void setPortRange(int portFrom, int portTo, const QString &hostAddress) - { - m_pluginName = QLatin1String("QTcpServerConnection"); - m_portFrom = portFrom; - m_portTo = portTo; - m_hostAddress = hostAddress; - } - - void setFileName(const QString &fileName) - { - m_pluginName = QLatin1String("QLocalClientConnection"); - m_fileName = fileName; - } - - const QString &pluginName() const - { - return m_pluginName; - } - - void run() override; - -private: - QQmlDebugServerImpl *m_server; - QString m_pluginName; - int m_portFrom; - int m_portTo; - QString m_hostAddress; - QString m_fileName; -}; - -class QQmlDebugServerImpl : public QQmlDebugServer -{ - Q_OBJECT -public: - QQmlDebugServerImpl(); - - bool blockingMode() const override; - - QQmlDebugService *service(const QString &name) const override; - - void addEngine(QJSEngine *engine) override; - void removeEngine(QJSEngine *engine) override; - bool hasEngine(QJSEngine *engine) const override; - - bool addService(const QString &name, QQmlDebugService *service) override; - bool removeService(const QString &name) override; - - bool open(const QVariantHash &configuration) override; - void setDevice(QIODevice *socket) override; - - void parseArguments(); - - static void cleanup(); - -private: - friend class QQmlDebugServerThread; - friend class QQmlDebugServerFactory; - - class EngineCondition { - public: - EngineCondition() : numServices(0), condition(new QWaitCondition) {} - - bool waitForServices(QMutex *locked, int numEngines); - bool isWaiting() const { return numServices > 0; } - - void wake(); - private: - int numServices; - - // shared pointer to allow for QHash-inflicted copying. - QSharedPointer condition; - }; - - bool canSendMessage(const QString &name); - void doSendMessage(const QString &name, const QByteArray &message); - void wakeEngine(QJSEngine *engine); - void sendMessage(const QString &name, const QByteArray &message); - void sendMessages(const QString &name, const QList &messages); - void changeServiceState(const QString &serviceName, QQmlDebugService::State state); - void removeThread(); - void receiveMessage(); - void protocolError(); - - QQmlDebugServerConnection *m_connection; - QHash m_plugins; - QStringList m_clientPlugins; - bool m_gotHello; - bool m_blockingMode; - - QHash m_engineConditions; - - mutable QMutex m_helloMutex; - QWaitCondition m_helloCondition; - QQmlDebugServerThread m_thread; - QPacketProtocol *m_protocol; - QAtomicInt m_changeServiceStateCalls; -}; - -void QQmlDebugServerImpl::cleanup() -{ - QQmlDebugServerImpl *server = static_cast( - QQmlDebugConnector::instance()); - if (!server) - return; - - { - QObject signalSource; - for (QHash::ConstIterator i = server->m_plugins.constBegin(); - i != server->m_plugins.constEnd(); ++i) { - server->m_changeServiceStateCalls.ref(); - QString key = i.key(); - // Process this in the server's thread. - connect(&signalSource, &QObject::destroyed, server, [key, server](){ - server->changeServiceState(key, QQmlDebugService::NotConnected); - }, Qt::QueuedConnection); - } - } - - // Wait for changeServiceState calls to finish - // (while running an event loop because some services - // might again defer execution of stuff in the GUI thread) - QEventLoop loop; - while (!server->m_changeServiceStateCalls.testAndSetOrdered(0, 0)) - loop.processEvents(); - - // Stop the thread while the application is still there. - server->m_thread.exit(); - server->m_thread.wait(); -} - -void QQmlDebugServerThread::run() -{ - Q_ASSERT_X(m_server != nullptr, Q_FUNC_INFO, "There should always be a debug server available here."); - QQmlDebugServerConnection *connection = loadQQmlDebugServerConnection(m_pluginName); - if (connection) { - { - QMutexLocker connectionLocker(&m_server->m_helloMutex); - m_server->m_connection = connection; - connection->setServer(m_server); - m_server->m_helloCondition.wakeAll(); - } - - if (m_fileName.isEmpty()) { - if (!connection->setPortRange(m_portFrom, m_portTo, m_server->blockingMode(), - m_hostAddress)) - return; - } else if (!connection->setFileName(m_fileName, m_server->blockingMode())) { - return; - } - - if (m_server->blockingMode()) - connection->waitForConnection(); - } else { - qWarning() << "QML Debugger: Couldn't load plugin" << m_pluginName; - return; - } - - exec(); - - // make sure events still waiting are processed - QEventLoop eventLoop; - eventLoop.processEvents(QEventLoop::AllEvents); -} - -bool QQmlDebugServerImpl::blockingMode() const -{ - return m_blockingMode; -} - -static void cleanupOnShutdown() -{ - // We cannot do this in the destructor as the connection plugin will get unloaded before the - // server plugin and we need the connection to send any remaining data. This function is - // triggered before any plugins are unloaded. - QQmlDebugServerImpl::cleanup(); -} - -QQmlDebugServerImpl::QQmlDebugServerImpl() : - m_connection(nullptr), - m_gotHello(false), - m_blockingMode(false) -{ - static bool postRoutineAdded = false; - if (!postRoutineAdded) { - qAddPostRoutine(cleanupOnShutdown); - postRoutineAdded = true; - } - - // used in sendMessages - qRegisterMetaType >("QList"); - // used in changeServiceState - qRegisterMetaType("QQmlDebugService::State"); - - m_thread.setServer(this); - moveToThread(&m_thread); - - // Remove the thread immmediately when it finishes, so that we don't have to wait for the - // event loop to signal that. - QObject::connect(&m_thread, &QThread::finished, this, &QQmlDebugServerImpl::removeThread, - Qt::DirectConnection); - m_thread.setObjectName(QStringLiteral("QQmlDebugServerThread")); - parseArguments(); -} - -bool QQmlDebugServerImpl::open(const QVariantHash &configuration = QVariantHash()) -{ - if (m_thread.isRunning()) - return false; - if (!configuration.isEmpty()) { - m_blockingMode = configuration[QLatin1String("block")].toBool(); - if (configuration.contains(QLatin1String("portFrom"))) { - int portFrom = configuration[QLatin1String("portFrom")].toInt(); - int portTo = configuration[QLatin1String("portTo")].toInt(); - m_thread.setPortRange(portFrom, portTo == -1 ? portFrom : portTo, - configuration[QLatin1String("hostAddress")].toString()); - } else if (configuration.contains(QLatin1String("fileName"))) { - m_thread.setFileName(configuration[QLatin1String("fileName")].toString()); - } else { - return false; - } - } - - if (m_thread.pluginName().isEmpty()) - return false; - - QMutexLocker locker(&m_helloMutex); - m_thread.start(); - m_helloCondition.wait(&m_helloMutex); // wait for connection - if (m_blockingMode && !m_gotHello) - m_helloCondition.wait(&m_helloMutex); // wait for hello - return true; -} - -void QQmlDebugServerImpl::parseArguments() -{ - // format: qmljsdebugger=port:[,port_to],host:][,block] - const QString args = commandLineArguments(); - if (args.isEmpty()) - return; // Manual initialization, through QQmlDebugServer::open() - - // ### remove port definition when protocol is changed - int portFrom = 0; - int portTo = 0; - bool block = false; - bool ok = false; - QString hostAddress; - QString fileName; - QStringList services; - - const auto lstjsDebugArguments = args.splitRef(QLatin1Char(','), Qt::SkipEmptyParts); - for (auto argsIt = lstjsDebugArguments.begin(), argsItEnd = lstjsDebugArguments.end(); argsIt != argsItEnd; ++argsIt) { - const QStringRef &strArgument = *argsIt; - if (strArgument.startsWith(QLatin1String("port:"))) { - portFrom = strArgument.mid(5).toInt(&ok); - portTo = portFrom; - const auto argsNext = argsIt + 1; - if (argsNext == argsItEnd) - break; - if (ok) { - portTo = argsNext->toString().toInt(&ok); - if (ok) { - ++argsIt; - } else { - portTo = portFrom; - ok = true; - } - } - } else if (strArgument.startsWith(QLatin1String("host:"))) { - hostAddress = strArgument.mid(5).toString(); - } else if (strArgument == QLatin1String("block")) { - block = true; - } else if (strArgument.startsWith(QLatin1String("file:"))) { - fileName = strArgument.mid(5).toString(); - ok = !fileName.isEmpty(); - } else if (strArgument.startsWith(QLatin1String("services:"))) { - services.append(strArgument.mid(9).toString()); - } else if (!services.isEmpty()) { - services.append(strArgument.toString()); - } else if (!strArgument.startsWith(QLatin1String("connector:"))) { - const QString message = tr("QML Debugger: Invalid argument \"%1\" detected." - " Ignoring the same.").arg(strArgument.toString()); - qWarning("%s", qPrintable(message)); - } - } - - if (ok) { - setServices(services); - m_blockingMode = block; - if (!fileName.isEmpty()) - m_thread.setFileName(fileName); - else - m_thread.setPortRange(portFrom, portTo, hostAddress); - } else { - QString usage; - QTextStream str(&usage); - str << tr("QML Debugger: Ignoring \"-qmljsdebugger=%1\".").arg(args) << '\n' - << tr("The format is \"-qmljsdebugger=[file:|port:][,]" - "[,host:][,block][,services:][,]*\"") << '\n' - << tr("\"file:\" can be used to specify the name of a file the debugger will try " - "to connect to using a QLocalSocket. If \"file:\" is given any \"host:\" and" - "\"port:\" arguments will be ignored.") << '\n' - << tr("\"host:\" and \"port:\" can be used to specify an address and a single " - "port or a range of ports the debugger will try to bind to with a " - "QTcpServer.") << '\n' - << tr("\"block\" makes the debugger and some services wait for clients to be " - "connected and ready before the first QML engine starts.") << '\n' - << tr("\"services:\" can be used to specify which debug services the debugger " - "should load. Some debug services interact badly with others. The V4 " - "debugger should not be loaded when using the QML profiler as it will force " - "any V4 engines to use the JavaScript interpreter rather than the JIT. The " - "following debug services are available by default:") << '\n' - << QQmlEngineDebugService::s_key << "\t- " << tr("The QML debugger") << '\n' - << QV4DebugService::s_key << "\t- " << tr("The V4 debugger") << '\n' - << QQmlInspectorService::s_key << "\t- " << tr("The QML inspector") << '\n' - << QQmlProfilerService::s_key << "\t- " << tr("The QML profiler") << '\n' - << QQmlEngineControlService::s_key << "\t- " - //: Please preserve the line breaks and formatting - << tr("Allows the client to delay the starting and stopping of\n" - "\t\t QML engines until other services are ready. QtCreator\n" - "\t\t uses this service with the QML profiler in order to\n" - "\t\t profile multiple QML engines at the same time.") - << '\n' << QDebugMessageService::s_key << "\t- " - //: Please preserve the line breaks and formatting - << tr("Sends qDebug() and similar messages over the QML debug\n" - "\t\t connection. QtCreator uses this for showing debug\n" - "\t\t messages in the debugger console.") << '\n' - << '\n' << QQmlDebugTranslationService::s_key << "\t- " - //: Please preserve the line breaks and formatting - << tr("helps to see if a translated text\n" - "\t\t will result in an elided text\n" - "\t\t in QML elements.") << '\n' - << tr("Other services offered by qmltooling plugins that implement " - "QQmlDebugServiceFactory and which can be found in the standard plugin " - "paths will also be available and can be specified. If no \"services\" " - "argument is given, all services found this way, including the default " - "ones, are loaded."); - qWarning("%s", qPrintable(usage)); - } -} - -void QQmlDebugServerImpl::receiveMessage() -{ - typedef QHash::const_iterator DebugServiceConstIt; - - // to be executed in debugger thread - Q_ASSERT(QThread::currentThread() == thread()); - - if (!m_protocol) - return; - - QQmlDebugPacket in(m_protocol->read()); - - QString name; - - in >> name; - if (name == QLatin1String("QDeclarativeDebugServer")) { - int op = -1; - in >> op; - if (op == 0) { - int version; - in >> version >> m_clientPlugins; - - //Get the supported QDataStream version - if (!in.atEnd()) { - in >> s_dataStreamVersion; - if (s_dataStreamVersion > QDataStream::Qt_DefaultCompiledVersion) - s_dataStreamVersion = QDataStream::Qt_DefaultCompiledVersion; - } - - bool clientSupportsMultiPackets = false; - if (!in.atEnd()) - in >> clientSupportsMultiPackets; - - // Send the hello answer immediately, since it needs to arrive before - // the plugins below start sending messages. - - QQmlDebugPacket out; - QStringList pluginNames; - QList pluginVersions; - if (clientSupportsMultiPackets) { // otherwise, disable all plugins - const int count = m_plugins.count(); - pluginNames.reserve(count); - pluginVersions.reserve(count); - for (QHash::ConstIterator i = m_plugins.constBegin(); - i != m_plugins.constEnd(); ++i) { - pluginNames << i.key(); - pluginVersions << i.value()->version(); - } - } - - out << QString(QStringLiteral("QDeclarativeDebugClient")) << 0 << protocolVersion - << pluginNames << pluginVersions << dataStreamVersion(); - - m_protocol->send(out.data()); - m_connection->flush(); - - QMutexLocker helloLock(&m_helloMutex); - m_gotHello = true; - - for (DebugServiceConstIt iter = m_plugins.constBegin(), cend = m_plugins.constEnd(); iter != cend; ++iter) { - QQmlDebugService::State newState = QQmlDebugService::Unavailable; - if (m_clientPlugins.contains(iter.key())) - newState = QQmlDebugService::Enabled; - m_changeServiceStateCalls.ref(); - changeServiceState(iter.key(), newState); - } - - m_helloCondition.wakeAll(); - - } else if (op == 1) { - // Service Discovery - QStringList oldClientPlugins = m_clientPlugins; - in >> m_clientPlugins; - - for (DebugServiceConstIt iter = m_plugins.constBegin(), cend = m_plugins.constEnd(); iter != cend; ++iter) { - const QString &pluginName = iter.key(); - QQmlDebugService::State newState = QQmlDebugService::Unavailable; - if (m_clientPlugins.contains(pluginName)) - newState = QQmlDebugService::Enabled; - - if (oldClientPlugins.contains(pluginName) - != m_clientPlugins.contains(pluginName)) { - m_changeServiceStateCalls.ref(); - changeServiceState(iter.key(), newState); - } - } - - } else { - qWarning("QML Debugger: Invalid control message %d.", op); - protocolError(); - return; - } - - } else { - if (m_gotHello) { - QHash::Iterator iter = m_plugins.find(name); - if (iter == m_plugins.end()) { - qWarning() << "QML Debugger: Message received for missing plugin" << name << '.'; - } else { - QQmlDebugService *service = *iter; - QByteArray message; - while (!in.atEnd()) { - in >> message; - service->messageReceived(message); - } - } - } else { - qWarning("QML Debugger: Invalid hello message."); - } - - } -} - -void QQmlDebugServerImpl::changeServiceState(const QString &serviceName, - QQmlDebugService::State newState) -{ - // to be executed in debugger thread - Q_ASSERT(QThread::currentThread() == thread()); - - QQmlDebugService *service = m_plugins.value(serviceName); - if (service && service->state() != newState) { - service->stateAboutToBeChanged(newState); - service->setState(newState); - service->stateChanged(newState); - } - - m_changeServiceStateCalls.deref(); -} - -void QQmlDebugServerImpl::removeThread() -{ - Q_ASSERT(m_thread.isFinished()); - Q_ASSERT(QThread::currentThread() == thread()); - - QThread *parentThread = m_thread.thread(); - - delete m_connection; - m_connection = nullptr; - - // Move it back to the parent thread so that we can potentially restart it on a new thread. - moveToThread(parentThread); -} - -QQmlDebugService *QQmlDebugServerImpl::service(const QString &name) const -{ - return m_plugins.value(name); -} - -void QQmlDebugServerImpl::addEngine(QJSEngine *engine) -{ - // to be executed outside of debugger thread - Q_ASSERT(QThread::currentThread() != &m_thread); - - QMutexLocker locker(&m_helloMutex); - Q_ASSERT(!m_engineConditions.contains(engine)); - - for (QQmlDebugService *service : qAsConst(m_plugins)) - service->engineAboutToBeAdded(engine); - - m_engineConditions[engine].waitForServices(&m_helloMutex, m_plugins.count()); - - for (QQmlDebugService *service : qAsConst(m_plugins)) - service->engineAdded(engine); -} - -void QQmlDebugServerImpl::removeEngine(QJSEngine *engine) -{ - // to be executed outside of debugger thread - Q_ASSERT(QThread::currentThread() != &m_thread); - - QMutexLocker locker(&m_helloMutex); - Q_ASSERT(m_engineConditions.contains(engine)); - - for (QQmlDebugService *service : qAsConst(m_plugins)) - service->engineAboutToBeRemoved(engine); - - m_engineConditions[engine].waitForServices(&m_helloMutex, m_plugins.count()); - - for (QQmlDebugService *service : qAsConst(m_plugins)) - service->engineRemoved(engine); - - m_engineConditions.remove(engine); -} - -bool QQmlDebugServerImpl::hasEngine(QJSEngine *engine) const -{ - QMutexLocker locker(&m_helloMutex); - QHash::ConstIterator i = m_engineConditions.constFind(engine); - // if we're still waiting the engine isn't fully "there", yet, nor fully removed. - return i != m_engineConditions.constEnd() && !i.value().isWaiting(); -} - -bool QQmlDebugServerImpl::addService(const QString &name, QQmlDebugService *service) -{ - // to be executed before thread starts - Q_ASSERT(!m_thread.isRunning()); - - if (!service || m_plugins.contains(name)) - return false; - - connect(service, &QQmlDebugService::messageToClient, - this, &QQmlDebugServerImpl::sendMessage); - connect(service, &QQmlDebugService::messagesToClient, - this, &QQmlDebugServerImpl::sendMessages); - - connect(service, &QQmlDebugService::attachedToEngine, - this, &QQmlDebugServerImpl::wakeEngine, Qt::QueuedConnection); - connect(service, &QQmlDebugService::detachedFromEngine, - this, &QQmlDebugServerImpl::wakeEngine, Qt::QueuedConnection); - - service->setState(QQmlDebugService::Unavailable); - m_plugins.insert(name, service); - - return true; -} - -bool QQmlDebugServerImpl::removeService(const QString &name) -{ - // to be executed after thread ends - Q_ASSERT(!m_thread.isRunning()); - - QQmlDebugService *service = m_plugins.value(name); - if (!service) - return false; - - m_plugins.remove(name); - service->setState(QQmlDebugService::NotConnected); - - disconnect(service, &QQmlDebugService::detachedFromEngine, - this, &QQmlDebugServerImpl::wakeEngine); - disconnect(service, &QQmlDebugService::attachedToEngine, - this, &QQmlDebugServerImpl::wakeEngine); - - disconnect(service, &QQmlDebugService::messagesToClient, - this, &QQmlDebugServerImpl::sendMessages); - disconnect(service, &QQmlDebugService::messageToClient, - this, &QQmlDebugServerImpl::sendMessage); - - return true; -} - -bool QQmlDebugServerImpl::canSendMessage(const QString &name) -{ - // to be executed in debugger thread - Q_ASSERT(QThread::currentThread() == thread()); - return m_connection && m_connection->isConnected() && m_protocol && - m_clientPlugins.contains(name); -} - -void QQmlDebugServerImpl::doSendMessage(const QString &name, const QByteArray &message) -{ - QQmlDebugPacket out; - out << name << message; - m_protocol->send(out.data()); -} - -void QQmlDebugServerImpl::sendMessage(const QString &name, const QByteArray &message) -{ - if (canSendMessage(name)) { - doSendMessage(name, message); - m_connection->flush(); - } -} - -void QQmlDebugServerImpl::sendMessages(const QString &name, const QList &messages) -{ - if (canSendMessage(name)) { - QQmlDebugPacket out; - out << name; - for (const QByteArray &message : messages) - out << message; - m_protocol->send(out.data()); - m_connection->flush(); - } -} - -void QQmlDebugServerImpl::wakeEngine(QJSEngine *engine) -{ - // to be executed in debugger thread - Q_ASSERT(QThread::currentThread() == thread()); - - QMutexLocker locker(&m_helloMutex); - m_engineConditions[engine].wake(); -} - -bool QQmlDebugServerImpl::EngineCondition::waitForServices(QMutex *locked, int num) -{ - Q_ASSERT_X(numServices == 0, Q_FUNC_INFO, "Request to wait again before previous wait finished"); - numServices = num; - return numServices > 0 ? condition->wait(locked) : true; -} - -void QQmlDebugServerImpl::EngineCondition::wake() -{ - if (--numServices == 0) - condition->wakeAll(); - Q_ASSERT_X(numServices >=0, Q_FUNC_INFO, "Woken more often than #services."); -} - -void QQmlDebugServerImpl::setDevice(QIODevice *socket) -{ - m_protocol = new QPacketProtocol(socket, this); - QObject::connect(m_protocol, &QPacketProtocol::readyRead, - this, &QQmlDebugServerImpl::receiveMessage); - QObject::connect(m_protocol, &QPacketProtocol::error, - this, &QQmlDebugServerImpl::protocolError); - - if (blockingMode()) - m_protocol->waitForReadyRead(-1); -} - -void QQmlDebugServerImpl::protocolError() -{ - qWarning("QML Debugger: A protocol error has occurred! Giving up ..."); - m_connection->disconnect(); - // protocol might still be processing packages at this point - m_protocol->deleteLater(); - m_protocol = nullptr; -} - -QQmlDebugConnector *QQmlDebugServerFactory::create(const QString &key) -{ - // Cannot parent it to this because it gets moved to another thread - return (key == QLatin1String("QQmlDebugServer") ? new QQmlDebugServerImpl : nullptr); -} - -QT_END_NAMESPACE - -#include "qqmldebugserver.moc" diff --git a/src/plugins/qmltooling/qmldbg_server/qqmldebugserverfactory.cpp b/src/plugins/qmltooling/qmldbg_server/qqmldebugserverfactory.cpp new file mode 100644 index 0000000000..8bc5b1c9e1 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_server/qqmldebugserverfactory.cpp @@ -0,0 +1,767 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:COMM$ +** +** 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. +** +** $QT_END_LICENSE$ +** +** +** +** +** +** +** +** +** +** +** +** +** +** +** +** +** +** +** +****************************************************************************/ + +#include "qqmldebugserverfactory.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/* + QQmlDebug Protocol (Version 1): + + handshake: + 1. Client sends + "QDeclarativeDebugServer" 0 version pluginNames [QDataStream version] + version: an int representing the highest protocol version the client knows + pluginNames: plugins available on client side + 2. Server sends + "QDeclarativeDebugClient" 0 version pluginNames pluginVersions [QDataStream version] + version: an int representing the highest protocol version the client & server know + pluginNames: plugins available on server side. plugins both in the client and server message are enabled. + client plugin advertisement + 1. Client sends + "QDeclarativeDebugServer" 1 pluginNames + server plugin advertisement (not implemented: all services are required to register before open()) + 1. Server sends + "QDeclarativeDebugClient" 1 pluginNames pluginVersions + plugin communication: + Everything send with a header different to "QDeclarativeDebugServer" is sent to the appropriate plugin. + */ + +Q_QML_DEBUG_PLUGIN_LOADER(QQmlDebugServerConnection) + +const int protocolVersion = 1; +using QQmlDebugPacket = QVersionedPacket; + +class QQmlDebugServerImpl; +class QQmlDebugServerThread : public QThread +{ +public: + QQmlDebugServerThread() : m_server(nullptr), m_portFrom(-1), m_portTo(-1) {} + + void setServer(QQmlDebugServerImpl *server) + { + m_server = server; + } + + void setPortRange(int portFrom, int portTo, const QString &hostAddress) + { + m_pluginName = QLatin1String("QTcpServerConnection"); + m_portFrom = portFrom; + m_portTo = portTo; + m_hostAddress = hostAddress; + } + + void setFileName(const QString &fileName) + { + m_pluginName = QLatin1String("QLocalClientConnection"); + m_fileName = fileName; + } + + const QString &pluginName() const + { + return m_pluginName; + } + + void run() override; + +private: + QQmlDebugServerImpl *m_server; + QString m_pluginName; + int m_portFrom; + int m_portTo; + QString m_hostAddress; + QString m_fileName; +}; + +class QQmlDebugServerImpl : public QQmlDebugServer +{ + Q_OBJECT +public: + QQmlDebugServerImpl(); + + bool blockingMode() const override; + + QQmlDebugService *service(const QString &name) const override; + + void addEngine(QJSEngine *engine) override; + void removeEngine(QJSEngine *engine) override; + bool hasEngine(QJSEngine *engine) const override; + + bool addService(const QString &name, QQmlDebugService *service) override; + bool removeService(const QString &name) override; + + bool open(const QVariantHash &configuration) override; + void setDevice(QIODevice *socket) override; + + void parseArguments(); + + static void cleanup(); + +private: + friend class QQmlDebugServerThread; + friend class QQmlDebugServerFactory; + + class EngineCondition { + public: + EngineCondition() : numServices(0), condition(new QWaitCondition) {} + + bool waitForServices(QMutex *locked, int numEngines); + bool isWaiting() const { return numServices > 0; } + + void wake(); + private: + int numServices; + + // shared pointer to allow for QHash-inflicted copying. + QSharedPointer condition; + }; + + bool canSendMessage(const QString &name); + void doSendMessage(const QString &name, const QByteArray &message); + void wakeEngine(QJSEngine *engine); + void sendMessage(const QString &name, const QByteArray &message); + void sendMessages(const QString &name, const QList &messages); + void changeServiceState(const QString &serviceName, QQmlDebugService::State state); + void removeThread(); + void receiveMessage(); + void protocolError(); + + QQmlDebugServerConnection *m_connection; + QHash m_plugins; + QStringList m_clientPlugins; + bool m_gotHello; + bool m_blockingMode; + + QHash m_engineConditions; + + mutable QMutex m_helloMutex; + QWaitCondition m_helloCondition; + QQmlDebugServerThread m_thread; + QPacketProtocol *m_protocol; + QAtomicInt m_changeServiceStateCalls; +}; + +void QQmlDebugServerImpl::cleanup() +{ + QQmlDebugServerImpl *server = static_cast( + QQmlDebugConnector::instance()); + if (!server) + return; + + { + QObject signalSource; + for (QHash::ConstIterator i = server->m_plugins.constBegin(); + i != server->m_plugins.constEnd(); ++i) { + server->m_changeServiceStateCalls.ref(); + QString key = i.key(); + // Process this in the server's thread. + connect(&signalSource, &QObject::destroyed, server, [key, server](){ + server->changeServiceState(key, QQmlDebugService::NotConnected); + }, Qt::QueuedConnection); + } + } + + // Wait for changeServiceState calls to finish + // (while running an event loop because some services + // might again defer execution of stuff in the GUI thread) + QEventLoop loop; + while (!server->m_changeServiceStateCalls.testAndSetOrdered(0, 0)) + loop.processEvents(); + + // Stop the thread while the application is still there. + server->m_thread.exit(); + server->m_thread.wait(); +} + +void QQmlDebugServerThread::run() +{ + Q_ASSERT_X(m_server != nullptr, Q_FUNC_INFO, "There should always be a debug server available here."); + QQmlDebugServerConnection *connection = loadQQmlDebugServerConnection(m_pluginName); + if (connection) { + { + QMutexLocker connectionLocker(&m_server->m_helloMutex); + m_server->m_connection = connection; + connection->setServer(m_server); + m_server->m_helloCondition.wakeAll(); + } + + if (m_fileName.isEmpty()) { + if (!connection->setPortRange(m_portFrom, m_portTo, m_server->blockingMode(), + m_hostAddress)) + return; + } else if (!connection->setFileName(m_fileName, m_server->blockingMode())) { + return; + } + + if (m_server->blockingMode()) + connection->waitForConnection(); + } else { + qWarning() << "QML Debugger: Couldn't load plugin" << m_pluginName; + return; + } + + exec(); + + // make sure events still waiting are processed + QEventLoop eventLoop; + eventLoop.processEvents(QEventLoop::AllEvents); +} + +bool QQmlDebugServerImpl::blockingMode() const +{ + return m_blockingMode; +} + +static void cleanupOnShutdown() +{ + // We cannot do this in the destructor as the connection plugin will get unloaded before the + // server plugin and we need the connection to send any remaining data. This function is + // triggered before any plugins are unloaded. + QQmlDebugServerImpl::cleanup(); +} + +QQmlDebugServerImpl::QQmlDebugServerImpl() : + m_connection(nullptr), + m_gotHello(false), + m_blockingMode(false) +{ + static bool postRoutineAdded = false; + if (!postRoutineAdded) { + qAddPostRoutine(cleanupOnShutdown); + postRoutineAdded = true; + } + + // used in sendMessages + qRegisterMetaType >("QList"); + // used in changeServiceState + qRegisterMetaType("QQmlDebugService::State"); + + m_thread.setServer(this); + moveToThread(&m_thread); + + // Remove the thread immmediately when it finishes, so that we don't have to wait for the + // event loop to signal that. + QObject::connect(&m_thread, &QThread::finished, this, &QQmlDebugServerImpl::removeThread, + Qt::DirectConnection); + m_thread.setObjectName(QStringLiteral("QQmlDebugServerThread")); + parseArguments(); +} + +bool QQmlDebugServerImpl::open(const QVariantHash &configuration = QVariantHash()) +{ + if (m_thread.isRunning()) + return false; + if (!configuration.isEmpty()) { + m_blockingMode = configuration[QLatin1String("block")].toBool(); + if (configuration.contains(QLatin1String("portFrom"))) { + int portFrom = configuration[QLatin1String("portFrom")].toInt(); + int portTo = configuration[QLatin1String("portTo")].toInt(); + m_thread.setPortRange(portFrom, portTo == -1 ? portFrom : portTo, + configuration[QLatin1String("hostAddress")].toString()); + } else if (configuration.contains(QLatin1String("fileName"))) { + m_thread.setFileName(configuration[QLatin1String("fileName")].toString()); + } else { + return false; + } + } + + if (m_thread.pluginName().isEmpty()) + return false; + + QMutexLocker locker(&m_helloMutex); + m_thread.start(); + m_helloCondition.wait(&m_helloMutex); // wait for connection + if (m_blockingMode && !m_gotHello) + m_helloCondition.wait(&m_helloMutex); // wait for hello + return true; +} + +void QQmlDebugServerImpl::parseArguments() +{ + // format: qmljsdebugger=port:[,port_to],host:][,block] + const QString args = commandLineArguments(); + if (args.isEmpty()) + return; // Manual initialization, through QQmlDebugServer::open() + + // ### remove port definition when protocol is changed + int portFrom = 0; + int portTo = 0; + bool block = false; + bool ok = false; + QString hostAddress; + QString fileName; + QStringList services; + + const auto lstjsDebugArguments = args.splitRef(QLatin1Char(','), Qt::SkipEmptyParts); + for (auto argsIt = lstjsDebugArguments.begin(), argsItEnd = lstjsDebugArguments.end(); argsIt != argsItEnd; ++argsIt) { + const QStringRef &strArgument = *argsIt; + if (strArgument.startsWith(QLatin1String("port:"))) { + portFrom = strArgument.mid(5).toInt(&ok); + portTo = portFrom; + const auto argsNext = argsIt + 1; + if (argsNext == argsItEnd) + break; + if (ok) { + portTo = argsNext->toString().toInt(&ok); + if (ok) { + ++argsIt; + } else { + portTo = portFrom; + ok = true; + } + } + } else if (strArgument.startsWith(QLatin1String("host:"))) { + hostAddress = strArgument.mid(5).toString(); + } else if (strArgument == QLatin1String("block")) { + block = true; + } else if (strArgument.startsWith(QLatin1String("file:"))) { + fileName = strArgument.mid(5).toString(); + ok = !fileName.isEmpty(); + } else if (strArgument.startsWith(QLatin1String("services:"))) { + services.append(strArgument.mid(9).toString()); + } else if (!services.isEmpty()) { + services.append(strArgument.toString()); + } else if (!strArgument.startsWith(QLatin1String("connector:"))) { + const QString message = tr("QML Debugger: Invalid argument \"%1\" detected." + " Ignoring the same.").arg(strArgument.toString()); + qWarning("%s", qPrintable(message)); + } + } + + if (ok) { + setServices(services); + m_blockingMode = block; + if (!fileName.isEmpty()) + m_thread.setFileName(fileName); + else + m_thread.setPortRange(portFrom, portTo, hostAddress); + } else { + QString usage; + QTextStream str(&usage); + str << tr("QML Debugger: Ignoring \"-qmljsdebugger=%1\".").arg(args) << '\n' + << tr("The format is \"-qmljsdebugger=[file:|port:][,]" + "[,host:][,block][,services:][,]*\"") << '\n' + << tr("\"file:\" can be used to specify the name of a file the debugger will try " + "to connect to using a QLocalSocket. If \"file:\" is given any \"host:\" and" + "\"port:\" arguments will be ignored.") << '\n' + << tr("\"host:\" and \"port:\" can be used to specify an address and a single " + "port or a range of ports the debugger will try to bind to with a " + "QTcpServer.") << '\n' + << tr("\"block\" makes the debugger and some services wait for clients to be " + "connected and ready before the first QML engine starts.") << '\n' + << tr("\"services:\" can be used to specify which debug services the debugger " + "should load. Some debug services interact badly with others. The V4 " + "debugger should not be loaded when using the QML profiler as it will force " + "any V4 engines to use the JavaScript interpreter rather than the JIT. The " + "following debug services are available by default:") << '\n' + << QQmlEngineDebugService::s_key << "\t- " << tr("The QML debugger") << '\n' + << QV4DebugService::s_key << "\t- " << tr("The V4 debugger") << '\n' + << QQmlInspectorService::s_key << "\t- " << tr("The QML inspector") << '\n' + << QQmlProfilerService::s_key << "\t- " << tr("The QML profiler") << '\n' + << QQmlEngineControlService::s_key << "\t- " + //: Please preserve the line breaks and formatting + << tr("Allows the client to delay the starting and stopping of\n" + "\t\t QML engines until other services are ready. QtCreator\n" + "\t\t uses this service with the QML profiler in order to\n" + "\t\t profile multiple QML engines at the same time.") + << '\n' << QDebugMessageService::s_key << "\t- " + //: Please preserve the line breaks and formatting + << tr("Sends qDebug() and similar messages over the QML debug\n" + "\t\t connection. QtCreator uses this for showing debug\n" + "\t\t messages in the debugger console.") << '\n' + << '\n' << QQmlDebugTranslationService::s_key << "\t- " + //: Please preserve the line breaks and formatting + << tr("helps to see if a translated text\n" + "\t\t will result in an elided text\n" + "\t\t in QML elements.") << '\n' + << tr("Other services offered by qmltooling plugins that implement " + "QQmlDebugServiceFactory and which can be found in the standard plugin " + "paths will also be available and can be specified. If no \"services\" " + "argument is given, all services found this way, including the default " + "ones, are loaded."); + qWarning("%s", qPrintable(usage)); + } +} + +void QQmlDebugServerImpl::receiveMessage() +{ + typedef QHash::const_iterator DebugServiceConstIt; + + // to be executed in debugger thread + Q_ASSERT(QThread::currentThread() == thread()); + + if (!m_protocol) + return; + + QQmlDebugPacket in(m_protocol->read()); + + QString name; + + in >> name; + if (name == QLatin1String("QDeclarativeDebugServer")) { + int op = -1; + in >> op; + if (op == 0) { + int version; + in >> version >> m_clientPlugins; + + //Get the supported QDataStream version + if (!in.atEnd()) { + in >> s_dataStreamVersion; + if (s_dataStreamVersion > QDataStream::Qt_DefaultCompiledVersion) + s_dataStreamVersion = QDataStream::Qt_DefaultCompiledVersion; + } + + bool clientSupportsMultiPackets = false; + if (!in.atEnd()) + in >> clientSupportsMultiPackets; + + // Send the hello answer immediately, since it needs to arrive before + // the plugins below start sending messages. + + QQmlDebugPacket out; + QStringList pluginNames; + QList pluginVersions; + if (clientSupportsMultiPackets) { // otherwise, disable all plugins + const int count = m_plugins.count(); + pluginNames.reserve(count); + pluginVersions.reserve(count); + for (QHash::ConstIterator i = m_plugins.constBegin(); + i != m_plugins.constEnd(); ++i) { + pluginNames << i.key(); + pluginVersions << i.value()->version(); + } + } + + out << QString(QStringLiteral("QDeclarativeDebugClient")) << 0 << protocolVersion + << pluginNames << pluginVersions << dataStreamVersion(); + + m_protocol->send(out.data()); + m_connection->flush(); + + QMutexLocker helloLock(&m_helloMutex); + m_gotHello = true; + + for (DebugServiceConstIt iter = m_plugins.constBegin(), cend = m_plugins.constEnd(); iter != cend; ++iter) { + QQmlDebugService::State newState = QQmlDebugService::Unavailable; + if (m_clientPlugins.contains(iter.key())) + newState = QQmlDebugService::Enabled; + m_changeServiceStateCalls.ref(); + changeServiceState(iter.key(), newState); + } + + m_helloCondition.wakeAll(); + + } else if (op == 1) { + // Service Discovery + QStringList oldClientPlugins = m_clientPlugins; + in >> m_clientPlugins; + + for (DebugServiceConstIt iter = m_plugins.constBegin(), cend = m_plugins.constEnd(); iter != cend; ++iter) { + const QString &pluginName = iter.key(); + QQmlDebugService::State newState = QQmlDebugService::Unavailable; + if (m_clientPlugins.contains(pluginName)) + newState = QQmlDebugService::Enabled; + + if (oldClientPlugins.contains(pluginName) + != m_clientPlugins.contains(pluginName)) { + m_changeServiceStateCalls.ref(); + changeServiceState(iter.key(), newState); + } + } + + } else { + qWarning("QML Debugger: Invalid control message %d.", op); + protocolError(); + return; + } + + } else { + if (m_gotHello) { + QHash::Iterator iter = m_plugins.find(name); + if (iter == m_plugins.end()) { + qWarning() << "QML Debugger: Message received for missing plugin" << name << '.'; + } else { + QQmlDebugService *service = *iter; + QByteArray message; + while (!in.atEnd()) { + in >> message; + service->messageReceived(message); + } + } + } else { + qWarning("QML Debugger: Invalid hello message."); + } + + } +} + +void QQmlDebugServerImpl::changeServiceState(const QString &serviceName, + QQmlDebugService::State newState) +{ + // to be executed in debugger thread + Q_ASSERT(QThread::currentThread() == thread()); + + QQmlDebugService *service = m_plugins.value(serviceName); + if (service && service->state() != newState) { + service->stateAboutToBeChanged(newState); + service->setState(newState); + service->stateChanged(newState); + } + + m_changeServiceStateCalls.deref(); +} + +void QQmlDebugServerImpl::removeThread() +{ + Q_ASSERT(m_thread.isFinished()); + Q_ASSERT(QThread::currentThread() == thread()); + + QThread *parentThread = m_thread.thread(); + + delete m_connection; + m_connection = nullptr; + + // Move it back to the parent thread so that we can potentially restart it on a new thread. + moveToThread(parentThread); +} + +QQmlDebugService *QQmlDebugServerImpl::service(const QString &name) const +{ + return m_plugins.value(name); +} + +void QQmlDebugServerImpl::addEngine(QJSEngine *engine) +{ + // to be executed outside of debugger thread + Q_ASSERT(QThread::currentThread() != &m_thread); + + QMutexLocker locker(&m_helloMutex); + Q_ASSERT(!m_engineConditions.contains(engine)); + + for (QQmlDebugService *service : qAsConst(m_plugins)) + service->engineAboutToBeAdded(engine); + + m_engineConditions[engine].waitForServices(&m_helloMutex, m_plugins.count()); + + for (QQmlDebugService *service : qAsConst(m_plugins)) + service->engineAdded(engine); +} + +void QQmlDebugServerImpl::removeEngine(QJSEngine *engine) +{ + // to be executed outside of debugger thread + Q_ASSERT(QThread::currentThread() != &m_thread); + + QMutexLocker locker(&m_helloMutex); + Q_ASSERT(m_engineConditions.contains(engine)); + + for (QQmlDebugService *service : qAsConst(m_plugins)) + service->engineAboutToBeRemoved(engine); + + m_engineConditions[engine].waitForServices(&m_helloMutex, m_plugins.count()); + + for (QQmlDebugService *service : qAsConst(m_plugins)) + service->engineRemoved(engine); + + m_engineConditions.remove(engine); +} + +bool QQmlDebugServerImpl::hasEngine(QJSEngine *engine) const +{ + QMutexLocker locker(&m_helloMutex); + QHash::ConstIterator i = m_engineConditions.constFind(engine); + // if we're still waiting the engine isn't fully "there", yet, nor fully removed. + return i != m_engineConditions.constEnd() && !i.value().isWaiting(); +} + +bool QQmlDebugServerImpl::addService(const QString &name, QQmlDebugService *service) +{ + // to be executed before thread starts + Q_ASSERT(!m_thread.isRunning()); + + if (!service || m_plugins.contains(name)) + return false; + + connect(service, &QQmlDebugService::messageToClient, + this, &QQmlDebugServerImpl::sendMessage); + connect(service, &QQmlDebugService::messagesToClient, + this, &QQmlDebugServerImpl::sendMessages); + + connect(service, &QQmlDebugService::attachedToEngine, + this, &QQmlDebugServerImpl::wakeEngine, Qt::QueuedConnection); + connect(service, &QQmlDebugService::detachedFromEngine, + this, &QQmlDebugServerImpl::wakeEngine, Qt::QueuedConnection); + + service->setState(QQmlDebugService::Unavailable); + m_plugins.insert(name, service); + + return true; +} + +bool QQmlDebugServerImpl::removeService(const QString &name) +{ + // to be executed after thread ends + Q_ASSERT(!m_thread.isRunning()); + + QQmlDebugService *service = m_plugins.value(name); + if (!service) + return false; + + m_plugins.remove(name); + service->setState(QQmlDebugService::NotConnected); + + disconnect(service, &QQmlDebugService::detachedFromEngine, + this, &QQmlDebugServerImpl::wakeEngine); + disconnect(service, &QQmlDebugService::attachedToEngine, + this, &QQmlDebugServerImpl::wakeEngine); + + disconnect(service, &QQmlDebugService::messagesToClient, + this, &QQmlDebugServerImpl::sendMessages); + disconnect(service, &QQmlDebugService::messageToClient, + this, &QQmlDebugServerImpl::sendMessage); + + return true; +} + +bool QQmlDebugServerImpl::canSendMessage(const QString &name) +{ + // to be executed in debugger thread + Q_ASSERT(QThread::currentThread() == thread()); + return m_connection && m_connection->isConnected() && m_protocol && + m_clientPlugins.contains(name); +} + +void QQmlDebugServerImpl::doSendMessage(const QString &name, const QByteArray &message) +{ + QQmlDebugPacket out; + out << name << message; + m_protocol->send(out.data()); +} + +void QQmlDebugServerImpl::sendMessage(const QString &name, const QByteArray &message) +{ + if (canSendMessage(name)) { + doSendMessage(name, message); + m_connection->flush(); + } +} + +void QQmlDebugServerImpl::sendMessages(const QString &name, const QList &messages) +{ + if (canSendMessage(name)) { + QQmlDebugPacket out; + out << name; + for (const QByteArray &message : messages) + out << message; + m_protocol->send(out.data()); + m_connection->flush(); + } +} + +void QQmlDebugServerImpl::wakeEngine(QJSEngine *engine) +{ + // to be executed in debugger thread + Q_ASSERT(QThread::currentThread() == thread()); + + QMutexLocker locker(&m_helloMutex); + m_engineConditions[engine].wake(); +} + +bool QQmlDebugServerImpl::EngineCondition::waitForServices(QMutex *locked, int num) +{ + Q_ASSERT_X(numServices == 0, Q_FUNC_INFO, "Request to wait again before previous wait finished"); + numServices = num; + return numServices > 0 ? condition->wait(locked) : true; +} + +void QQmlDebugServerImpl::EngineCondition::wake() +{ + if (--numServices == 0) + condition->wakeAll(); + Q_ASSERT_X(numServices >=0, Q_FUNC_INFO, "Woken more often than #services."); +} + +void QQmlDebugServerImpl::setDevice(QIODevice *socket) +{ + m_protocol = new QPacketProtocol(socket, this); + QObject::connect(m_protocol, &QPacketProtocol::readyRead, + this, &QQmlDebugServerImpl::receiveMessage); + QObject::connect(m_protocol, &QPacketProtocol::error, + this, &QQmlDebugServerImpl::protocolError); + + if (blockingMode()) + m_protocol->waitForReadyRead(-1); +} + +void QQmlDebugServerImpl::protocolError() +{ + qWarning("QML Debugger: A protocol error has occurred! Giving up ..."); + m_connection->disconnect(); + // protocol might still be processing packages at this point + m_protocol->deleteLater(); + m_protocol = nullptr; +} + +QQmlDebugConnector *QQmlDebugServerFactory::create(const QString &key) +{ + // Cannot parent it to this because it gets moved to another thread + return (key == QLatin1String("QQmlDebugServer") ? new QQmlDebugServerImpl : nullptr); +} + +QT_END_NAMESPACE + +#include "qqmldebugserverfactory.moc" diff --git a/src/qml/debugger/debugger.pri b/src/qml/debugger/debugger.pri index 1281886816..6f976e149e 100644 --- a/src/qml/debugger/debugger.pri +++ b/src/qml/debugger/debugger.pri @@ -15,6 +15,7 @@ qtConfig(qml-debug) { $$PWD/qqmldebugservice.cpp \ $$PWD/qqmlabstractprofileradapter.cpp \ $$PWD/qqmlprofiler.cpp \ + $$PWD/qqmldebugserver.cpp \ $$PWD/qqmldebugserviceinterfaces.cpp } diff --git a/src/qml/debugger/qqmldebugconnector_p.h b/src/qml/debugger/qqmldebugconnector_p.h index 3e8a3bc8f6..9fa5054b4a 100644 --- a/src/qml/debugger/qqmldebugconnector_p.h +++ b/src/qml/debugger/qqmldebugconnector_p.h @@ -65,6 +65,7 @@ QT_BEGIN_NAMESPACE class Q_QML_PRIVATE_EXPORT QQmlDebugConnector { + virtual ~QQmlDebugConnector() = default; // don't break 'override' on ~QQmlDebugServer public: static QQmlDebugConnector *instance() { return nullptr; } diff --git a/src/qml/debugger/qqmldebugserver.cpp b/src/qml/debugger/qqmldebugserver.cpp new file mode 100644 index 0000000000..5119fc4209 --- /dev/null +++ b/src/qml/debugger/qqmldebugserver.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmldebugserver_p.h" + +QT_BEGIN_NAMESPACE + +QQmlDebugServer::~QQmlDebugServer() + = default; + +QT_END_NAMESPACE + +#include "moc_qqmldebugserver_p.cpp" diff --git a/src/qml/debugger/qqmldebugserver_p.h b/src/qml/debugger/qqmldebugserver_p.h index 87ef83a165..f73729ca03 100644 --- a/src/qml/debugger/qqmldebugserver_p.h +++ b/src/qml/debugger/qqmldebugserver_p.h @@ -62,6 +62,7 @@ class Q_QML_PRIVATE_EXPORT QQmlDebugServer : public QQmlDebugConnector { Q_OBJECT public: + ~QQmlDebugServer() override; virtual void setDevice(QIODevice *socket) = 0; }; -- cgit v1.2.3 From e12c9455a04aecc6334bdbad755b232c1dccdce6 Mon Sep 17 00:00:00 2001 From: Tang Haixiang Date: Wed, 26 Jan 2022 14:06:09 +0800 Subject: Modify m_compareRegister bitfield It's from https://trac.webkit.org/changeset/246151/webkit/trunk/ Source/JavaScriptCore/assembler/ARM64Assembler.h Fixes: QTBUG-100221 Fixes: QTBUG-100279 Change-Id: I7a5ec6d97bf52f8cc7bcfb70f184565fc4b78624 Reviewed-by: Ulf Hermann (cherry picked from commit aacf799ca7aab57133855ed4c1c639c6e8dffe63) Reviewed-by: Qt Cherry-pick Bot --- src/3rdparty/masm/assembler/ARM64Assembler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/3rdparty/masm/assembler/ARM64Assembler.h b/src/3rdparty/masm/assembler/ARM64Assembler.h index ca6b33d39a..3e988a277c 100644 --- a/src/3rdparty/masm/assembler/ARM64Assembler.h +++ b/src/3rdparty/masm/assembler/ARM64Assembler.h @@ -676,11 +676,11 @@ public: struct RealTypes { int64_t m_from : 48; int64_t m_to : 48; + RegisterID m_compareRegister; JumpType m_type : 8; JumpLinkType m_linkType : 8; Condition m_condition : 4; unsigned m_bitNumber : 6; - RegisterID m_compareRegister : 6; bool m_is64Bit : 1; } realTypes; } data; -- cgit v1.2.3 From 0e88794676660166aaf327089eaaa1aff902a317 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Fri, 4 Feb 2022 15:44:14 +0100 Subject: QML/JS: Reject yield expression not directly in generator functions If an inner function contains a yield expression, we need to reject the program even if that function is inside of a generator function. Fixes: QTBUG-98356 Change-Id: I2e820a1ca5f0da4080e313fd9809aa8bfdc1b681 Reviewed-by: Qt CI Bot Reviewed-by: Ulf Hermann (cherry picked from commit dde1d86baabac1eddd84a11b7d2ed49e26c511bd) --- src/qml/compiler/qv4codegen.cpp | 11 +++++++++++ tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 14 ++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index ded08907dc..0c945ab898 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -2927,6 +2927,17 @@ bool Codegen::visit(YieldExpression *ast) return false; } + auto innerMostCurentFunctionContext = _context; + while (innerMostCurentFunctionContext && innerMostCurentFunctionContext->contextType != ContextType::Function) + innerMostCurentFunctionContext = innerMostCurentFunctionContext->parent; + + Q_ASSERT(innerMostCurentFunctionContext); // yield outside function would have been rejected by parser + + if (!innerMostCurentFunctionContext->isGenerator) { + throwSyntaxError(ast->firstSourceLocation(), QLatin1String("Yield is only valid in generator functions")); + return false; + } + RegisterScope scope(this); TailCallBlocker blockTailCalls(this); Reference expr = ast->expression ? expression(ast->expression) : Reference::fromConst(this, Encode::undefined()); diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 696566d987..2291c31895 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -241,6 +241,7 @@ private slots: void topLevelGeneratorFunction(); void generatorCrashNewProperty(); void generatorCallsGC(); + void noYieldInInnerFunction(); void qtbug_10696(); void qtbug_11606(); void qtbug_11600(); @@ -6516,6 +6517,19 @@ void tst_qqmlecmascript::generatorCallsGC() QVERIFY2(o != nullptr, qPrintable(component.errorString())); } +void tst_qqmlecmascript::noYieldInInnerFunction() +{ + QJSEngine engine; + const QString program = R"( + function *a() { + (function() { yield 1; })(); + }; + )"; + auto result = engine.evaluate(program); + QVERIFY(result.isError()); + QCOMPARE(result.errorType(), QJSValue::SyntaxError); +} + // Test the "Qt.include" method void tst_qqmlecmascript::include() { -- cgit v1.2.3 From 0121c6737c7374d6b21eee4eeed861da2ef77999 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 3 May 2022 12:23:18 +0200 Subject: MPTA: don't allow more than one touchpoint to react to mouse On mouse press, if MPTA filters events for a child, addTouchPoint() can be called once during filtering and start reacting to that point, and then called again during direct delivery of the same mouse press. Now it will ignore the second of the declared touchpoint prototypes because the first one is already "taken", and a mouse event can never provide more than one point. Followup to 0012f8bd152a36a67abc696465f27d612625b5d9 Fixes: QTBUG-83662 Change-Id: Ia97600441f0a2633f77b0db9c83cc4de3a9e5931 Reviewed-by: Fabian Kosmale (cherry picked from commit 9b64eee22d9e2d40d1283e8844cb1d8899232547) Reviewed-by: Shawn Rutledge --- src/quick/items/qquickmultipointtoucharea.cpp | 7 +++- .../data/nestedPinchArea.qml | 44 ++++++++++++++++++++ .../tst_qquickmultipointtoucharea.cpp | 48 ++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 tests/auto/quick/qquickmultipointtoucharea/data/nestedPinchArea.qml diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp index 58ad929b19..480731aee9 100644 --- a/src/quick/items/qquickmultipointtoucharea.cpp +++ b/src/quick/items/qquickmultipointtoucharea.cpp @@ -685,7 +685,7 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event) 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()); } @@ -730,12 +730,15 @@ void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *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/tests/auto/quick/qquickmultipointtoucharea/data/nestedPinchArea.qml b/tests/auto/quick/qquickmultipointtoucharea/data/nestedPinchArea.qml new file mode 100644 index 0000000000..0e51804b30 --- /dev/null +++ b/tests/auto/quick/qquickmultipointtoucharea/data/nestedPinchArea.qml @@ -0,0 +1,44 @@ +import QtQuick 2.15 + +MultiPointTouchArea { + width: 240 + height: 320 + mouseEnabled: true + property int pressedCount: 0 + property int updatedCount: 0 + property int releasedCount: 0 + + onPressed: (points) => { pressedCount = points.length } + onUpdated: (points) => { updatedCount = points.length } + onReleased: (points) => { releasedCount = points.length } + + touchPoints: [ + TouchPoint { + id: point1 + objectName: "point1" + }, + TouchPoint { + id: point2 + objectName: "point2" + } + ] + + PinchArea { + anchors.fill: parent + } + + Rectangle { + width: 30; height: 30 + color: "green" + x: point1.x + y: point1.y + } + + Rectangle { + id: rectangle + width: 30; height: 30 + color: "yellow" + x: point2.x + y: point2.y + } +} diff --git a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp index c18a220996..a9d557915a 100644 --- a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp +++ b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp @@ -77,6 +77,7 @@ private slots: void mouseGestureStarted(); void cancel(); void stationaryTouchWithChangingPressure(); + void nestedPinchAreaMouse(); private: QQuickView *createAndShowView(const QString &file); @@ -1408,6 +1409,53 @@ void tst_QQuickMultiPointTouchArea::stationaryTouchWithChangingPressure() // QTB QCOMPARE(point1->pressure(), 0); } +void tst_QQuickMultiPointTouchArea::nestedPinchAreaMouse() +{ + QScopedPointer window(createAndShowView("nestedPinchArea.qml")); + QQuickMultiPointTouchArea *mpta = qobject_cast(window->rootObject()); + QVERIFY(mpta); + + QQuickTouchPoint *point1 = mpta->findChild("point1"); + QCOMPARE(point1->pressed(), false); + QQuickTouchPoint *point2 = mpta->findChild("point2"); + QCOMPARE(point2->pressed(), false); + QSignalSpy pressedSpy(mpta, &QQuickMultiPointTouchArea::pressed); + QSignalSpy updatedSpy(mpta, &QQuickMultiPointTouchArea::updated); + QSignalSpy releasedSpy(mpta, &QQuickMultiPointTouchArea::released); + + QPoint p1(20, 20); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(point1->pressed(), true); + QCOMPARE(point2->pressed(), false); + QCOMPARE(pressedSpy.count(), 1); + QCOMPARE(mpta->property("pressedCount").toInt(), 1); + QCOMPARE(updatedSpy.count(), 0); + QCOMPARE(mpta->property("updatedCount").toInt(), 0); + QCOMPARE(releasedSpy.count(), 0); + QCOMPARE(mpta->property("releasedCount").toInt(), 0); + + p1 += QPoint(0, 15); + QTest::mouseMove(window.data(), p1); + QCOMPARE(point1->pressed(), true); + QCOMPARE(point2->pressed(), false); + QCOMPARE(pressedSpy.count(), 1); + QCOMPARE(mpta->property("pressedCount").toInt(), 1); + QCOMPARE(updatedSpy.count(), 1); + QCOMPARE(mpta->property("updatedCount").toInt(), 1); + QCOMPARE(releasedSpy.count(), 0); + QCOMPARE(mpta->property("releasedCount").toInt(), 0); + + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(point1->pressed(), false); + QCOMPARE(point2->pressed(), false); + QCOMPARE(pressedSpy.count(), 1); + QCOMPARE(mpta->property("pressedCount").toInt(), 1); + QCOMPARE(updatedSpy.count(), 1); + QCOMPARE(mpta->property("updatedCount").toInt(), 1); + QCOMPARE(releasedSpy.count(), 1); + QCOMPARE(mpta->property("releasedCount").toInt(), 1); +} + QTEST_MAIN(tst_QQuickMultiPointTouchArea) -- cgit v1.2.3 From ea898f614dcded4012d45a254b044dc7b37c40c0 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 2 May 2022 17:22:46 +0200 Subject: Text: don't fall back to full-width layout if availableWidth == 0 If Text.width == Text.rightPadding, there is no space to render any text; but in that case, QQuickTextPrivate::availableWidth() returns 0: it's incorrect to fall back to layout.maximumWidth() and allow rendering the whole line. Prior to 6ec2693d4a3c95ca9ff0c349d3c587a7f1402c05 we were checking width() here, so let's do that again. Fixes: QTBUG-83413 Change-Id: I3ee3b49406577c3aa005a3ca3606308ff0a21d8d Reviewed-by: Oliver Eftevaag (cherry picked from commit 406ff6b53d02b8db4231e473982fe593fb1e48c6) Reviewed-by: Shawn Rutledge --- src/quick/items/qquicktext.cpp | 2 +- tests/auto/quick/qquicktext/data/padding.qml | 26 +++++++++++++ .../auto/quick/qquicktext/data/paddingInLoader.qml | 14 +++++++ tests/auto/quick/qquicktext/tst_qquicktext.cpp | 45 ++++++++++++++++++++++ 4 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 tests/auto/quick/qquicktext/data/paddingInLoader.qml diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index b348ce74a8..844a25b010 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -965,7 +965,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline) const qreal availWidth = availableWidth(); const qreal availHeight = availableHeight(); - lineWidth = q->widthValid() && availWidth > 0 ? availWidth : naturalWidth; + lineWidth = q->widthValid() && q->width() > 0 ? availWidth : naturalWidth; maxHeight = q->heightValid() ? availHeight : FLT_MAX; // If the width of the item has changed and it's possible the result of wrapping, diff --git a/tests/auto/quick/qquicktext/data/padding.qml b/tests/auto/quick/qquicktext/data/padding.qml index ab0a37d041..f830af0e40 100644 --- a/tests/auto/quick/qquicktext/data/padding.qml +++ b/tests/auto/quick/qquicktext/data/padding.qml @@ -9,4 +9,30 @@ Text { leftPadding: 30 rightPadding: 40 bottomPadding: 50 + + Rectangle { + width: parent.leftPadding + height: parent.height + color: "#6600FF00" + } + + Rectangle { + width: parent.width + height: parent.topPadding + color: "#66888800" + } + + Rectangle { + x: parent.width - parent.rightPadding + width: parent.rightPadding + height: parent.height + color: "#6600FFFF" + } + + Rectangle { + y: parent.height - parent.bottomPadding + width: parent.width + height: parent.bottomPadding + color: "#66880088" + } } diff --git a/tests/auto/quick/qquicktext/data/paddingInLoader.qml b/tests/auto/quick/qquicktext/data/paddingInLoader.qml new file mode 100644 index 0000000000..6ef7c25a9b --- /dev/null +++ b/tests/auto/quick/qquicktext/data/paddingInLoader.qml @@ -0,0 +1,14 @@ +import QtQuick 2.12 + +Item { + width: 30 + height: 30 + Loader { + anchors.fill: parent + sourceComponent: Text { + rightPadding: 30 + text: "Some text" + elide: Text.ElideRight + } + } +} diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp index fe3f696dfa..ff191bbc7f 100644 --- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp @@ -55,6 +55,8 @@ QT_BEGIN_NAMESPACE extern void qt_setQtEnableTestFont(bool value); QT_END_NAMESPACE +Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests") + class tst_qquicktext : public QQmlDataTest { Q_OBJECT @@ -153,6 +155,7 @@ private slots: void growFromZeroWidth(); void padding(); + void paddingInLoader(); void hintingPreference(); @@ -4342,6 +4345,20 @@ void tst_qquicktext::padding() obj->setElideMode(QQuickText::ElideRight); QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding()); QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding()); + + obj->setLeftPadding(0); + QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding()); + + obj->setWidth(cw); + obj->setRightPadding(cw); + QCOMPARE(obj->contentWidth(), 0); + + for (int incr = 1; incr < 50 && qFuzzyIsNull(obj->contentWidth()); ++incr) + obj->setWidth(cw + incr); + QVERIFY(obj->contentWidth() > 0); + qCDebug(lcTests) << "increasing Text width from" << cw << "to" << obj->width() + << "rendered a character: contentWidth now" << obj->contentWidth(); + obj->setElideMode(QQuickText::ElideNone); obj->resetWidth(); @@ -4386,6 +4403,34 @@ void tst_qquicktext::padding() delete root; } +void tst_qquicktext::paddingInLoader() // QTBUG-83413 +{ + QQuickView view(testFileUrl("paddingInLoader.qml")); + view.show(); + view.requestActivate(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + QQuickText *qtext = view.rootObject()->findChild(); + QVERIFY(qtext); + QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(qtext); + QVERIFY(textPrivate); + QCOMPARE(qtext->contentWidth(), 0); // does not render text, because width == rightPadding + QCOMPARE(textPrivate->availableWidth(), 0); + + qtext->setLeftPadding(qtext->width()); + qtext->setRightPadding(0); + QCOMPARE(qtext->contentWidth(), 0); // does not render text, because width == leftPadding + QCOMPARE(textPrivate->availableWidth(), 0); + + qtext->setRightPadding(qtext->width()); + QCOMPARE(qtext->contentWidth(), 0); // does not render text: available space is negative + QCOMPARE(textPrivate->availableWidth(), -qtext->width()); + + qtext->setLeftPadding(2); + qtext->setRightPadding(2); + QVERIFY(qtext->contentWidth() > 0); // finally space is available to render text + QCOMPARE(textPrivate->availableWidth(), qtext->width() - 4); +} + void tst_qquicktext::hintingPreference() { { -- cgit v1.2.3 From bba59e282eaf570fb2e4aa65da52048836dd18b9 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 10 May 2022 10:23:01 +0200 Subject: (manual) includemocs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - moc_qqmlcomponentattached_p.cpp → qqmlcomponent.cpp Fixes: QTBUG-102948 Change-Id: I54c2932416d3f3699772b85ba96134b0ef1b6a9e Reviewed-by: Ulf Hermann Reviewed-by: Qt CI Bot (cherry picked from commit 79daf29782b1f9596508de201a677214a31200a5) Reviewed-by: Qt Cherry-pick Bot --- src/qml/qml/qqmlcomponent.cpp | 1 + src/qml/qml/qqmlcomponentattached_p.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 4618591e4c..abf8e06e16 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1775,3 +1775,4 @@ void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s) QT_END_NAMESPACE #include "moc_qqmlcomponent.cpp" +#include "moc_qqmlcomponentattached_p.cpp" diff --git a/src/qml/qml/qqmlcomponentattached_p.h b/src/qml/qml/qqmlcomponentattached_p.h index 0ea2b956f1..9859dd5d90 100644 --- a/src/qml/qml/qqmlcomponentattached_p.h +++ b/src/qml/qml/qqmlcomponentattached_p.h @@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE +// implemented in qqmlcomponent.cpp class Q_QML_PRIVATE_EXPORT QQmlComponentAttached : public QObject { Q_OBJECT -- cgit v1.2.3 From 79af79e9fdbd2a4d52a4e8994eb58cfddfeb8e9b Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 5 Nov 2020 15:29:29 +0100 Subject: Fix tst_QQuickText::fontSizeMode The test hardcodes the height of the Text element to be 35, and then it does a pre-check that this is higher than the height of the font. This is obviously a bit flaky and caused an error because the font at the given size was 35.7 and was rounded up. I did attempt to make the logic a bit more dynamic, and have the object's initial height be based on the height of the font, but other parts of the test would then fail because they depend on the size of the object. In the end, the simplest way seemed to be to just decrease the font size until it fit inside the original Text height and leave it at that. Fixes: QTBUG-88207 Change-Id: I9c327806bde8c339b299302004dfb72b34e87bcd Reviewed-by: Qt CI Bot Reviewed-by: Liang Qi Reviewed-by: Lars Knoll (cherry picked from commit d316dc5686b22677384fa76ae7851db7dd50f2f7) --- tests/auto/quick/qquicktext/data/fontSizeMode.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/quick/qquicktext/data/fontSizeMode.qml b/tests/auto/quick/qquicktext/data/fontSizeMode.qml index 48e7c7b6d0..d5e794824f 100644 --- a/tests/auto/quick/qquicktext/data/fontSizeMode.qml +++ b/tests/auto/quick/qquicktext/data/fontSizeMode.qml @@ -16,7 +16,7 @@ Item { height: 35 minimumPointSize: 8 minimumPixelSize: 8 - font.pixelSize: 25 + font.pixelSize: 23 font.family: "Helvetica" } } -- cgit v1.2.3