diff options
Diffstat (limited to 'src')
13 files changed, 361 insertions, 158 deletions
diff --git a/src/corelib/animation/qpropertyanimation.cpp b/src/corelib/animation/qpropertyanimation.cpp index b4c6b6ff8a6..73ce8ca02c1 100644 --- a/src/corelib/animation/qpropertyanimation.cpp +++ b/src/corelib/animation/qpropertyanimation.cpp @@ -21,7 +21,12 @@ makes it possible to animate many of Qt's widgets. Let's look at an example: - \snippet code/src_corelib_animation_qpropertyanimation.cpp 0 + \snippet code/src_corelib_animation_qpropertyanimation.cpp includes + \snippet code/src_corelib_animation_qpropertyanimation.cpp class_decl + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_impl + \snippet code/src_corelib_animation_qpropertyanimation.cpp first_example + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_close + \snippet code/src_corelib_animation_qpropertyanimation.cpp main \note You can also control an animation's lifespan by choosing a \l{QAbstractAnimation::DeletionPolicy}{delete policy} while starting the diff --git a/src/corelib/doc/snippets/code/src_corelib_animation_qparallelanimationgroup.cpp b/src/corelib/doc/snippets/code/src_corelib_animation_qparallelanimationgroup.cpp index 6328cb00119..db3a9ee2dc0 100644 --- a/src/corelib/doc/snippets/code/src_corelib_animation_qparallelanimationgroup.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_animation_qparallelanimationgroup.cpp @@ -1,10 +1,15 @@ // Copyright (C) 2018 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause -//! [0] - QParallelAnimationGroup *group = new QParallelAnimationGroup; - group->addAnimation(anim1); - group->addAnimation(anim2); +#include <QParallelAnimationGroup> - group->start(); -//! [0] +void example(QAbstractAnimation *anim1, QAbstractAnimation *anim2) +{ + //! [0] + QParallelAnimationGroup *group = new QParallelAnimationGroup; + group->addAnimation(anim1); + group->addAnimation(anim2); + + group->start(); + //! [0] +} diff --git a/src/corelib/doc/snippets/code/src_corelib_animation_qpropertyanimation.cpp b/src/corelib/doc/snippets/code/src_corelib_animation_qpropertyanimation.cpp index 4b77ab607db..7f259e99fb8 100644 --- a/src/corelib/doc/snippets/code/src_corelib_animation_qpropertyanimation.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_animation_qpropertyanimation.cpp @@ -1,28 +1,102 @@ // Copyright (C) 2018 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +#include <QParallelAnimationGroup> +#include <QSequentialAnimationGroup> -//! [0] +//! [includes] #include <QApplication> #include <QPushButton> #include <QPropertyAnimation> +//![includes] + +//! [class_decl] class MyButtonWidget : public QWidget { public: MyButtonWidget(QWidget *parent = nullptr); }; +//! [class_decl] + +//! [ctor_impl] MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent) { - QPushButton *button = new QPushButton(tr("Animated Button"), this); - QPropertyAnimation *anim = new QPropertyAnimation(button, "pos", this); - anim->setDuration(10000); - anim->setStartValue(QPoint(0, 0)); - anim->setEndValue(QPoint(100, 250)); - anim->start(); +//![ctor_impl] + { + //! [first_example] + QPushButton *button = new QPushButton(tr("Animated Button"), this); + QPropertyAnimation *anim = new QPropertyAnimation(button, "pos", this); + anim->setDuration(10000); + anim->setStartValue(QPoint(0, 0)); + anim->setEndValue(QPoint(100, 250)); + anim->start(); + //! [first_example] + } + + { + //! [easing-curve] + QPushButton *button = new QPushButton(tr("Animated Button"), this); + QPropertyAnimation *anim = new QPropertyAnimation(button, "pos", this); + anim->setDuration(10000); + anim->setStartValue(QPoint(0, 0)); + anim->setEndValue(QPoint(100, 250)); + anim->setEasingCurve(QEasingCurve::OutBounce); + anim->start(); + //! [easing-curve] + } + + { + //! [animation-group1] + QPushButton *bonnie = new QPushButton(tr("Bonnie"), this); + QPushButton *clyde = new QPushButton(tr("Clyde"), this); + + QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "pos", this); + anim1->setDuration(3000); + anim1->setStartValue(QPoint(0, 0)); + anim1->setEndValue(QPoint(100, 250)); + + QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "pos", this); + anim2->setDuration(3000); + anim2->setStartValue(QPoint(100, 250)); + anim2->setEndValue(QPoint(500, 500)); + + QParallelAnimationGroup *parallelAnim = new QParallelAnimationGroup; + parallelAnim->addAnimation(anim1); + parallelAnim->addAnimation(anim2); + parallelAnim->start(); + //! [animation-group1] + } + + { + //! [animation-group2] + QPushButton *bonnie = new QPushButton(tr("Bonnie"), this); + QPushButton *clyde = new QPushButton(tr("Clyde"), this); + + QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "pos", this); + anim1->setDuration(3000); + anim1->setStartValue(QPoint(0, 0)); + anim1->setEndValue(QPoint(100, 250)); + + QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "pos", this); + anim2->setDuration(3000); + anim2->setStartValue(QPoint(0, 0)); + anim2->setEndValue(QPoint(200, 250)); + + QSequentialAnimationGroup *sequenceAnim = new QSequentialAnimationGroup; + sequenceAnim->addAnimation(anim1); + sequenceAnim->addAnimation(anim2); + sequenceAnim->start(); + //! [animation-group2] + } + +//! [ctor_close] } +//! [ctor_close] + +//! [main] int main(int argc, char *argv[]) { QApplication a(argc, argv); @@ -31,65 +105,4 @@ int main(int argc, char *argv[]) buttonAnimWidget.show(); return a.exec(); } -//! [0] - - -//! [easing-curve] -MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent) -{ - QPushButton *button = new QPushButton(tr("Animated Button"), this); - QPropertyAnimation *anim = new QPropertyAnimation(button, "pos", this); - anim->setDuration(10000); - anim->setStartValue(QPoint(0, 0)); - anim->setEndValue(QPoint(100, 250)); - anim->setEasingCurve(QEasingCurve::OutBounce); - anim->start(); -} -//! [easing-curve] - - -//! [animation-group1] -MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent) -{ - QPushButton *bonnie = new QPushButton(tr("Bonnie"), this); - QPushButton *clyde = new QPushButton(tr("Clyde"), this); - - QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "pos", this); - anim1->setDuration(3000); - anim1->setStartValue(QPoint(0, 0)); - anim1->setEndValue(QPoint(100, 250)); - - QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "pos", this); - anim2->setDuration(3000); - anim2->setStartValue(QPoint(100, 250)); - anim2->setEndValue(QPoint(500, 500)); - - QParallelAnimationGroup *parallelAnim = new QParallelAnimationGroup; - parallelAnim->addAnimation(anim1); - parallelAnim->addAnimation(anim2); - parallelAnim->start(); -} -//! [animation-group1] - -//! [animation-group2] -MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent) -{ - QPushButton *bonnie = new QPushButton(tr("Bonnie"), this); - QPushButton *clyde = new QPushButton(tr("Clyde"), this); - - QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "pos", this); - anim1->setDuration(3000); - anim1->setStartValue(QPoint(0, 0)); - anim1->setEndValue(QPoint(100, 250)); - - QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "pos", this); - anim2->setDuration(3000); - anim2->setStartValue(QPoint(0, 0)); - anim2->setEndValue(QPoint(200, 250)); - - QSequentialAnimationGroup *sequenceAnim = new QSequentialAnimationGroup; - sequenceAnim->addAnimation(anim1); - sequenceAnim->addAnimation(anim2); - sequenceAnim->start(); -} -//! [animation-group2] +//! [main] diff --git a/src/corelib/doc/snippets/code/src_corelib_animation_qsequentialanimationgroup.cpp b/src/corelib/doc/snippets/code/src_corelib_animation_qsequentialanimationgroup.cpp index a429fe20b2d..c00a723a26c 100644 --- a/src/corelib/doc/snippets/code/src_corelib_animation_qsequentialanimationgroup.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_animation_qsequentialanimationgroup.cpp @@ -1,6 +1,10 @@ // Copyright (C) 2018 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +#include <QSequentialAnimationGroup> + +void example(QAbstractAnimation *anim1, QAbstractAnimation *anim2) +{ //! [0] QSequentialAnimationGroup *group = new QSequentialAnimationGroup; @@ -9,3 +13,4 @@ group->start(); //! [0] +} diff --git a/src/corelib/doc/snippets/code/src_corelib_animation_qvariantanimation.cpp b/src/corelib/doc/snippets/code/src_corelib_animation_qvariantanimation.cpp index be7f549f655..be7e51e1b44 100644 --- a/src/corelib/doc/snippets/code/src_corelib_animation_qvariantanimation.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_animation_qvariantanimation.cpp @@ -1,14 +1,22 @@ // Copyright (C) 2018 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +#include <QVariantAnimation> +#include <QColor> + //! [0] - QVariant myColorInterpolator(const QColor &start, const QColor &end, qreal progress) - { - ... - return QColor(...); - } - ... +QVariant myColorInterpolator(const QColor &start, const QColor &end, qreal progress) +{ + // ... + return QColor(/*...*/); +} +// ... +void someFunc() +{ + // ... qRegisterAnimationInterpolator<QColor>(myColorInterpolator); + // ... +} //! [0] //! [1] diff --git a/src/corelib/doc/snippets/code/src_corelib_concurrent_qthreadpool.cpp b/src/corelib/doc/snippets/code/src_corelib_concurrent_qthreadpool.cpp index 4cba70e62d4..56a0532ac21 100644 --- a/src/corelib/doc/snippets/code/src_corelib_concurrent_qthreadpool.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_concurrent_qthreadpool.cpp @@ -1,6 +1,10 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +#include <QThreadPool> +#include <QRunnable> +#include <QDebug> + //! [0] class HelloWorldTask : public QRunnable { @@ -10,7 +14,12 @@ class HelloWorldTask : public QRunnable } }; -HelloWorldTask *hello = new HelloWorldTask(); -// QThreadPool takes ownership and deletes 'hello' automatically -QThreadPool::globalInstance()->start(hello); +int main() +{ + //... + HelloWorldTask *hello = new HelloWorldTask(); + // QThreadPool takes ownership and deletes 'hello' automatically + QThreadPool::globalInstance()->start(hello); + //... +} //! [0] diff --git a/src/corelib/doc/src/animation.qdoc b/src/corelib/doc/src/animation.qdoc index d2e182f4806..ba5976f11eb 100644 --- a/src/corelib/doc/src/animation.qdoc +++ b/src/corelib/doc/src/animation.qdoc @@ -91,7 +91,12 @@ The following example demonstrates how you can animate a QPushButton widget: - \snippet code/src_corelib_animation_qpropertyanimation.cpp 0 + \snippet code/src_corelib_animation_qpropertyanimation.cpp includes + \snippet code/src_corelib_animation_qpropertyanimation.cpp class_decl + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_impl + \snippet code/src_corelib_animation_qpropertyanimation.cpp first_example + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_close + \snippet code/src_corelib_animation_qpropertyanimation.cpp main The example animates the \c pos Qt property of a QPushButton, to move it from the top--left corner of the screen to the end position (250, 250), @@ -174,7 +179,9 @@ path. + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_impl \snippet code/src_corelib_animation_qpropertyanimation.cpp easing-curve + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_close In this example, the animation follows a curve that makes the \c button bounce like a ball. QEasingCurve offers a large collection of curves @@ -199,13 +206,17 @@ The two following examples demonstrate the use of both QSequentialAnimationGroup and QParallelAnimationGroup: + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_impl \snippet code/src_corelib_animation_qpropertyanimation.cpp animation-group1 + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_close A parallel group plays more than one animation at the same time. Its \l{QAbstractAnimation::}{start()} function starts all animations that are part of the group. + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_impl \snippet code/src_corelib_animation_qpropertyanimation.cpp animation-group2 + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_close As the name suggests, a QSequentialAnimationGroup plays its animations in sequence. It starts the next animation in @@ -225,7 +236,12 @@ independent QPropertyAnimation has the QApplication instance as its parent: - \snippet code/src_corelib_animation_qpropertyanimation.cpp 0 + \snippet code/src_corelib_animation_qpropertyanimation.cpp includes + \snippet code/src_corelib_animation_qpropertyanimation.cpp class_decl + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_impl + \snippet code/src_corelib_animation_qpropertyanimation.cpp first_example + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_close + \snippet code/src_corelib_animation_qpropertyanimation.cpp main \note You can also control the animation's lifespan by choosing a \l{QAbstractAnimation::DeletionPolicy}{delete policy} while starting it. diff --git a/src/corelib/io/qdirlisting.cpp b/src/corelib/io/qdirlisting.cpp index c626033dcdb..1fec92a01e2 100644 --- a/src/corelib/io/qdirlisting.cpp +++ b/src/corelib/io/qdirlisting.cpp @@ -510,16 +510,14 @@ bool QDirListingPrivate::matchesFilters(QDirEntryInfo &entryInfo) const if (!iteratorFlags.testAnyFlag(F::IncludeHidden) && entryInfo.isHidden()) return false; - if (entryInfo.isSymLink()) { - // With ResolveSymlinks, we look at the type of the link's target, - // and exclude broken symlinks (where the target doesn't exist). - if (iteratorFlags.testAnyFlag(F::ResolveSymlinks)) { - if (!entryInfo.exists()) - return false; - } else if (iteratorFlags.testAnyFlags(F::FilesOnly) - || iteratorFlags.testAnyFlags(F::DirsOnly)) { - return false; // symlink is not a file or dir - } + // With ResolveSymlinks, we look at the type of the link's target, + // and exclude broken symlinks (where the target doesn't exist). + if (iteratorFlags.testAnyFlag(F::ResolveSymlinks)) { + if (entryInfo.isSymLink() && !entryInfo.exists()) + return false; + } else if ((iteratorFlags.testAnyFlags(F::FilesOnly) + || iteratorFlags.testAnyFlags(F::DirsOnly)) && entryInfo.isSymLink()) { + return false; // symlink is not a file or dir } if (iteratorFlags.testAnyFlag(F::ExcludeOther) diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index de5f27f9619..8684a02b727 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -1733,16 +1733,8 @@ bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase * "queued connections"); return false; } - auto event = std::make_unique<QMetaCallEvent>(std::move(slot), nullptr, -1, parameterCount); - void **args = event->args(); - QMetaType *types = event->types(); - - for (int i = 1; i < parameterCount; ++i) { - types[i] = QMetaType(metaTypes[i]); - args[i] = types[i].create(argv[i]); - } - - QCoreApplication::postEvent(object, event.release()); + QCoreApplication::postEvent(object, new QQueuedMetaCallEvent(std::move(slot), nullptr, -1, + parameterCount, metaTypes, params)); } else if (type == Qt::BlockingQueuedConnection) { #if QT_CONFIG(thread) if (receiverInSameThread) @@ -2889,31 +2881,27 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target, return InvokeFailReason::CouldNotQueueParameter; } - auto event = std::make_unique<QMetaCallEvent>(idx_offset, idx_relative, callFunction, nullptr, -1, paramCount); - QMetaType *types = event->types(); - void **args = event->args(); - + QVarLengthArray<const QtPrivate::QMetaTypeInterface *> argTypes; + argTypes.emplace_back(nullptr); // return type // fill in the meta types first for (int i = 1; i < paramCount; ++i) { - types[i] = QMetaType(methodMetaTypes[i - 1]); - if (!types[i].iface() && (!MetaTypesAreOptional || metaTypes)) - types[i] = QMetaType(metaTypes[i]); - if (!types[i].iface()) - types[i] = priv->parameterMetaType(i - 1); - if (!types[i].iface() && typeNames[i]) - types[i] = QMetaType::fromName(typeNames[i]); - if (!types[i].iface()) { + QMetaType type = QMetaType(methodMetaTypes[i - 1]); + if (!type.iface() && (!MetaTypesAreOptional || metaTypes)) + type = QMetaType(metaTypes[i]); + if (!type.iface()) + type = priv->parameterMetaType(i - 1); + if (!type.iface() && typeNames[i]) + type = QMetaType::fromName(typeNames[i]); + if (!type.iface()) { qWarning("QMetaMethod::invoke: Unable to handle unregistered datatype '%s'", typeNames[i]); return InvokeFailReason(int(InvokeFailReason::CouldNotQueueParameter) - i); } + argTypes.emplace_back(type.iface()); } - // now create copies of our parameters using those meta types - for (int i = 1; i < paramCount; ++i) - args[i] = types[i].create(parameters[i]); - - QCoreApplication::postEvent(object, event.release()); + QCoreApplication::postEvent(object, new QQueuedMetaCallEvent(idx_offset, idx_relative, callFunction, nullptr, + -1, paramCount, argTypes.data(), parameters)); } else { // blocking queued connection #if QT_CONFIG(thread) if (receiverInSameThread()) { diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 888c71f5a49..d67ada64c45 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -599,14 +599,19 @@ QMetaCallEvent::QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotO, /*! \internal */ +QMetaCallEvent::QMetaCallEvent(const QObject *sender, int signalId, Data &&data) + : QAbstractMetaCallEvent(sender, signalId), + d(std::move(data)), + prealloc_() +{ +} + +/*! + \internal + */ QMetaCallEvent::~QMetaCallEvent() { if (d.nargs_) { - QMetaType *t = types(); - for (int i = 0; i < d.nargs_; ++i) { - if (t[i].isValid() && d.args_[i]) - t[i].destroy(d.args_[i]); - } if (reinterpret_cast<void *>(d.args_) != reinterpret_cast<void *>(prealloc_)) free(d.args_); } @@ -628,6 +633,115 @@ void QMetaCallEvent::placeMetaCall(QObject *object) } /*! + \internal + + Constructs a QQueuedMetaCallEvent by copying the argument values using their meta-types. + */ +QQueuedMetaCallEvent::QQueuedMetaCallEvent(ushort method_offset, ushort method_relative, + QObjectPrivate::StaticMetaCallFunction callFunction, + const QObject *sender, int signalId, int argCount, + const QtPrivate::QMetaTypeInterface * const *argTypes, + const void * const *argValues) + : QMetaCallEvent(sender, signalId, {nullptr, nullptr, callFunction, argCount, + method_offset, method_relative}) +{ + allocArgs(); + copyArgValues(argCount, argTypes, argValues); +} + +/*! + \internal + + Constructs a QQueuedMetaCallEvent by copying the argument values using their meta-types. + */ +QQueuedMetaCallEvent::QQueuedMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj, + const QObject *sender, int signalId, int argCount, + const QtPrivate::QMetaTypeInterface * const *argTypes, + const void * const *argValues) + : QMetaCallEvent(sender, signalId, {QtPrivate::SlotObjUniquePtr(slotObj), nullptr, nullptr, argCount, + 0, ushort(-1)}) +{ + if (d.slotObj_) + d.slotObj_->ref(); + allocArgs(); + copyArgValues(argCount, argTypes, argValues); +} + +/*! + \internal + + Constructs a QQueuedMetaCallEvent by copying the argument values using their meta-types. + */ +QQueuedMetaCallEvent::QQueuedMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj, + const QObject *sender, int signalId, int argCount, + const QtPrivate::QMetaTypeInterface * const *argTypes, + const void * const *argValues) + : QMetaCallEvent(sender, signalId, {std::move(slotObj), nullptr, nullptr, argCount, + 0, ushort(-1)}) +{ + allocArgs(); + copyArgValues(argCount, argTypes, argValues); +} + +/*! + \internal + */ +QQueuedMetaCallEvent::~QQueuedMetaCallEvent() +{ + const QMetaType *t = types(); + int inplaceIndex = 0; + for (int i = 0; i < d.nargs_; ++i) { + if (t[i].isValid() && d.args_[i]) { + if (typeFitsInPlace(t[i]) && inplaceIndex < InplaceValuesCapacity) { + // Only destruct + void *where = &valuesPrealloc_[inplaceIndex++].storage; + t[i].destruct(where); + } else { + // Destruct and deallocate + t[i].destroy(d.args_[i]); + } + } + } +} + +/*! + \internal + */ +inline void QQueuedMetaCallEvent::copyArgValues(int argCount, const QtPrivate::QMetaTypeInterface * const *argTypes, + const void * const *argValues) +{ + void **args = d.args_; + QMetaType *types = this->types(); + int inplaceIndex = 0; + + types[0] = QMetaType(); // return type + args[0] = nullptr; // return value pointer + // no return value + + for (int n = 1; n < argCount; ++n) { + types[n] = QMetaType(argTypes[n]); + if (typeFitsInPlace(types[n]) && inplaceIndex < InplaceValuesCapacity) { + // Copy-construct in place + void *where = &valuesPrealloc_[inplaceIndex++].storage; + types[n].construct(where, argValues[n]); + args[n] = where; + } else { + // Allocate and copy-construct + args[n] = types[n].create(argValues[n]); + } + } +} + +/*! + \internal + */ +inline bool QQueuedMetaCallEvent::typeFitsInPlace(const QMetaType type) +{ + return (q20::cmp_less_equal(type.sizeOf(), sizeof(ArgValueStorage)) && + q20::cmp_less_equal(type.alignOf(), alignof(ArgValueStorage))); +} + +/*! \class QSignalBlocker \brief Exception-safe wrapper around QObject::blockSignals(). \since 5.3 @@ -4069,26 +4183,19 @@ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connect SlotObjectGuard slotObjectGuard { c->isSlotObject ? c->slotObj : nullptr }; locker.unlock(); - QMetaCallEvent *ev = c->isSlotObject ? - new QMetaCallEvent(c->slotObj, sender, signal, nargs) : - new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal, nargs); - - void **args = ev->args(); - QMetaType *types = ev->types(); - - types[0] = QMetaType(); // return type - args[0] = nullptr; // return value - - if (nargs > 1) { - for (int n = 1; n < nargs; ++n) - types[n] = QMetaType(argumentTypes[n - 1]); - - for (int n = 1; n < nargs; ++n) - args[n] = types[n].create(argv[n]); + QVarLengthArray<const QtPrivate::QMetaTypeInterface *> argTypes; + argTypes.emplace_back(nullptr); // return type + for (int n = 1; n < nargs; ++n) { + argTypes.emplace_back(QMetaType(argumentTypes[n - 1]).iface()); // convert type ids to QMetaTypeInterfaces } + auto ev = c->isSlotObject ? + std::make_unique<QQueuedMetaCallEvent>(c->slotObj, + sender, signal, nargs, argTypes.data(), argv) : + std::make_unique<QQueuedMetaCallEvent>(c->method_offset, c->method_relative, c->callFunction, + sender, signal, nargs, argTypes.data(), argv); + if (c->isSingleShot && !QObjectPrivate::removeConnection(c)) { - delete ev; return; } @@ -4096,11 +4203,10 @@ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connect if (!c->isSingleShot && !c->receiver.loadRelaxed()) { // the connection has been disconnected while we were unlocked locker.unlock(); - delete ev; return; } - QCoreApplication::postEvent(receiver, ev); + QCoreApplication::postEvent(receiver, ev.release()); } template <bool callbacks_enabled> diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index dca9c1af932..75aeba73583 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -351,7 +351,7 @@ private: class Q_CORE_EXPORT QMetaCallEvent : public QAbstractMetaCallEvent { public: - // blocking queued with latch - args always owned by caller + // blocking queued with latch - arguments always remain owned by the caller QMetaCallEvent(ushort method_offset, ushort method_relative, QObjectPrivate::StaticMetaCallFunction callFunction, const QObject *sender, int signalId, @@ -363,14 +363,17 @@ public: const QObject *sender, int signalId, void **args, QLatch *latch); - // queued - args allocated by event, copied by caller + // OLD - queued - args allocated by event, copied by caller + Q_DECL_DEPRECATED_X("Remove this constructor once the qtdeclarative patch is merged. Arguments are now copied by the QQueuedMetaCallEvent constructor and not the caller.") QMetaCallEvent(ushort method_offset, ushort method_relative, QObjectPrivate::StaticMetaCallFunction callFunction, const QObject *sender, int signalId, int nargs); + Q_DECL_DEPRECATED_X("Remove this constructor once the qtdeclarative patch is merged. Arguments are now copied by the QQueuedMetaCallEvent constructor and not the caller.") QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj, const QObject *sender, int signalId, int nargs); + Q_DECL_DEPRECATED_X("Remove this constructor once the qtdeclarative patch is merged. Arguments are now copied by the QQueuedMetaCallEvent constructor and not the caller.") QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj, const QObject *sender, int signalId, int nargs); @@ -378,14 +381,16 @@ public: ~QMetaCallEvent() override; inline int id() const { return d.method_offset_ + d.method_relative_; } - inline const void * const* args() const { return d.args_; } + Q_DECL_DEPRECATED_X("Remove this function once the qtdeclarative patch is merged. Arguments are now copied by the QQueuedMetaCallEvent constructor and not the caller.") inline void ** args() { return d.args_; } - inline const QMetaType *types() const { return reinterpret_cast<QMetaType *>(d.args_ + d.nargs_); } + Q_DECL_DEPRECATED_X("Remove this function once the qtdeclarative patch is merged. Arguments are now copied by the QQueuedMetaCallEvent constructor and not the caller.") inline QMetaType *types() { return reinterpret_cast<QMetaType *>(d.args_ + d.nargs_); } virtual void placeMetaCall(QObject *object) override; -private: +protected: + // Move to QQueuedMetaCallEvent once the qtdeclarative patch is merged. + // QMetaCallEvent should not alloc anything anymore. inline void allocArgs(); struct Data { @@ -396,9 +401,50 @@ private: ushort method_offset_; ushort method_relative_; } d; - // preallocate enough space for three arguments - alignas(void *) char prealloc_[3 * sizeof(void *) + 3 * sizeof(QMetaType)]; + + inline QMetaCallEvent(const QObject *sender, int signalId, Data &&data); + inline void * const *args() const { return d.args_; } + inline QMetaType const *types() const { return reinterpret_cast<QMetaType *>(d.args_ + d.nargs_); } + + // Space for 5 argument pointers and types (including 1 return arg). + // Contiguous so that we can make one calloc() for both the pointers and the types when necessary. + // Move to QQueuedMetaCallEvent once the qtdeclarative patch is merged. + alignas(void *) char prealloc_[5 * sizeof(void *) + 5 * sizeof(QMetaType)]; +}; + +class Q_CORE_EXPORT QQueuedMetaCallEvent : public QMetaCallEvent +{ +public: + // queued - arguments are allocated and copied from argValues by these constructors + QQueuedMetaCallEvent(ushort method_offset, ushort method_relative, + QObjectPrivate::StaticMetaCallFunction callFunction, + const QObject *sender, int signalId, + int argCount, const QtPrivate::QMetaTypeInterface * const *argTypes, + const void * const *argValues); + QQueuedMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj, + const QObject *sender, int signalId, + int argCount, const QtPrivate::QMetaTypeInterface * const *argTypes, + const void * const *argValues); + QQueuedMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj, + const QObject *sender, int signalId, + int argCount, const QtPrivate::QMetaTypeInterface * const *argTypes, + const void * const *argValues); + + ~QQueuedMetaCallEvent() override; + +private: + inline void copyArgValues(int argCount, const QtPrivate::QMetaTypeInterface * const *argTypes, + const void * const *argValues); + static inline bool typeFitsInPlace(const QMetaType type); + + struct ArgValueStorage { // size and alignment matching QString, QList, etc + static constexpr size_t MaxSize = 3 * sizeof(void *); + alignas(void *) char storage[MaxSize]; + }; + static constexpr int InplaceValuesCapacity = 3; + ArgValueStorage valuesPrealloc_[InplaceValuesCapacity]; }; +// The total QQueuedMetaCallEvent size is 224 bytes which is a 32-byte multiple, efficient for memory allocators. struct QAbstractDynamicMetaObject; struct Q_CORE_EXPORT QDynamicMetaObjectData diff --git a/src/widgets/dialogs/qmessagebox.cpp b/src/widgets/dialogs/qmessagebox.cpp index f9d58e4d906..acb63c4aa9b 100644 --- a/src/widgets/dialogs/qmessagebox.cpp +++ b/src/widgets/dialogs/qmessagebox.cpp @@ -562,6 +562,10 @@ void QMessageBoxPrivate::helperClicked(QPlatformDialogHelper::StandardButton hel and \l{QMessageBox::standardButtons} {standard buttons} for accepting a user response. + While the parent parameter is optional, specifying it gives a hint + to the window manager, which can then take care of positioning, and + maintain a proper stacking order of the dialog window. + Two APIs for using QMessageBox are provided, the property-based API, and the static functions. Calling one of the static functions is the simpler approach, but it is less flexible than using the diff --git a/src/widgets/doc/snippets/code/src_gui_dialogs_qmessagebox.cpp b/src/widgets/doc/snippets/code/src_gui_dialogs_qmessagebox.cpp index ebc07025ec0..062e2e5142a 100644 --- a/src/widgets/doc/snippets/code/src_gui_dialogs_qmessagebox.cpp +++ b/src/widgets/doc/snippets/code/src_gui_dialogs_qmessagebox.cpp @@ -12,7 +12,7 @@ int ret = QMessageBox::warning(this, tr("My Application"), //! [2] -QMessageBox msgBox; +QMessageBox msgBox(this); QPushButton *connectButton = msgBox.addButton(tr("Connect"), QMessageBox::ActionRole); QPushButton *abortButton = msgBox.addButton(QMessageBox::Abort); @@ -53,13 +53,13 @@ int main(int argc, char *argv[]) //! [4] //! [5] -QMessageBox msgBox; +QMessageBox msgBox(this); msgBox.setText("The document has been modified."); msgBox.exec(); //! [5] //! [6] -QMessageBox msgBox; +QMessageBox msgBox(this); msgBox.setText("The document has been modified."); msgBox.setInformativeText("Do you want to save your changes?"); msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); |