Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqmlincubator.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qqmlincubator.h"
5#include "qqmlcomponent.h"
6#include "qqmlincubator_p.h"
7
9#include <private/qqmlcomponent_p.h>
10
12 QQmlIncubator &i, const QQmlRefPointer<QQmlContextData> &forContext)
13{
14 QExplicitlySharedDataPointer<QQmlIncubatorPrivate> p(i.d);
15
16 QQmlIncubator::IncubationMode mode = i.incubationMode();
17
20
23
24 // Need to find the first constructing context and see if it is asynchronous
25 QExplicitlySharedDataPointer<QQmlIncubatorPrivate> parentIncubator;
26 QQmlRefPointer<QQmlContextData> cctxt = forContext;
27 while (cctxt) {
28 if (QQmlIncubatorPrivate *incubator = cctxt->incubator()) {
29 parentIncubator = incubator;
30 break;
31 }
32 cctxt = cctxt->parent();
33 }
34
35 if (parentIncubator && parentIncubator->isAsynchronous) {
37 p->waitingOnMe = parentIncubator;
38 parentIncubator->waitingFor.insert(p.data());
39 }
40 }
41
42 p->isAsynchronous = (mode != QQmlIncubator::Synchronous);
43
45
47 QRecursionWatcher<QQmlIncubatorPrivate, &QQmlIncubatorPrivate::recursion> watcher(p.data());
48
49 p->changeStatus(QQmlIncubator::Loading);
50
51 if (!watcher.hasRecursed()) {
53 p->incubate(i);
54 }
55 } else {
56 incubatorList.insert(p.data());
58
59 p->vmeGuard.guard(p->creator.data());
60 p->changeStatus(QQmlIncubator::Loading);
61
64 }
65}
66
74{
75 Q_D(QQmlEngine);
76 if (d->incubationController)
77 d->incubationController->d = nullptr;
78 d->incubationController = controller;
79 if (controller) controller->d = d;
80}
81
88{
89 Q_D(const QQmlEngine);
90 return d->incubationController;
91}
92
94 : q(q), status(QQmlIncubator::Null), mode(m), isAsynchronous(false), progress(Execute),
95 result(nullptr), enginePriv(nullptr), waitingOnMe(nullptr)
96{
97}
98
103
105{
106 // reset the tagged pointer
110 if (next.isInList()) {
111 next.remove();
114 if (controller)
116 }
117 enginePriv = nullptr;
118 if (!rootContext.isNull()) {
119 if (rootContext->incubator())
120 rootContext->setIncubator(nullptr);
122 }
123
124 if (nextWaitingFor.isInList()) {
127 waitingOnMe = nullptr;
128 }
129
130 // if we're waiting on any incubators then they should be cleared too.
131 while (waitingFor.first()) {
133 if (i)
134 i->clear();
135 }
136
137 bool guardOk = vmeGuard.isOK();
138
139 vmeGuard.clear();
140 if (creator && guardOk)
141 creator->clear();
142 creator.reset(nullptr);
143}
144
198
201{
202 if (d) QQmlEnginePrivate::get(d)->setIncubationController(nullptr);
203 d = nullptr;
204}
205
214
219{
220 return d ? d->incubatorCount : 0;
221}
222
233
243
244
246{
247 if (!compilationUnit)
248 return;
249
250 QExplicitlySharedDataPointer<QQmlIncubatorPrivate> protectThis(this);
251
252 QRecursionWatcher<QQmlIncubatorPrivate, &QQmlIncubatorPrivate::recursion> watcher(this);
253 // get a copy of the engine pointer as it might get reset;
255
256 // Incubating objects takes quite a bit more stack space than our usual V4 function
257 enum { EstimatedSizeInV4Frames = 2 };
260 if (callDepthRecorder.hasOverflow()) {
262 error.setMessageType(QtCriticalMsg);
263 error.setUrl(compilationUnit->url());
264 error.setDescription(QQmlComponent::tr("Maximum call stack size exceeded."));
265 errors << error;
267 goto finishIncubate;
268 }
269
270 if (!vmeGuard.isOK()) {
272 error.setMessageType(QtInfoMsg);
273 error.setUrl(compilationUnit->url());
274 error.setDescription(QQmlComponent::tr("Object or context destroyed during incubation"));
275 errors << error;
277
278 goto finishIncubate;
279 }
280
281 vmeGuard.clear();
282
285 QObject *tresult = nullptr;
286 tresult = creator->create(subComponentToCreate, /*parent*/nullptr, &i);
287 if (!tresult)
289 else {
291 for (auto it = initialProperties.cbegin(); it != initialProperties.cend(); ++it) {
292 auto component = tresult;
293 auto name = it.key();
296 if (!prop.isValid() || !prop.write(it.value())) {
298 error.setUrl(compilationUnit->url());
299 error.setDescription(QLatin1String("Could not set property %1").arg(name));
301 }
302 }
303 }
305
306 if (watcher.hasRecursed())
307 return;
308
309 result = tresult;
310 if (errors.isEmpty() && result == nullptr)
311 goto finishIncubate;
312
313 if (result) {
314 QQmlData *ddata = QQmlData::get(result);
315 Q_ASSERT(ddata);
316 //see QQmlComponent::beginCreate for explanation of indestructible
317 ddata->indestructible = true;
318 ddata->explicitIndestructibleSet = true;
319 ddata->rootObjectInCreation = false;
320 if (q) {
321 q->setInitialState(result);
322 if (creator && !creator->requiredProperties()->empty()) {
323 const RequiredProperties *unsetRequiredProperties = creator->requiredProperties();
324 for (const auto& unsetRequiredProperty: *unsetRequiredProperties)
326 }
327 }
328 }
329
330 if (watcher.hasRecursed())
331 return;
332
333 if (errors.isEmpty())
335 else
337
339
340 if (watcher.hasRecursed())
341 return;
342
343 if (i.shouldInterrupt())
344 goto finishIncubate;
345 }
346
348 do {
349 if (watcher.hasRecursed())
350 return;
351
352 if (creator->finalize(i)) {
355 goto finishIncubate;
356 }
357 } while (!i.shouldInterrupt());
358 }
359
360finishIncubate:
362 QExplicitlySharedDataPointer<QQmlIncubatorPrivate> isWaiting = waitingOnMe;
363 clear();
364
365 if (isWaiting) {
366 QRecursionWatcher<QQmlIncubatorPrivate, &QQmlIncubatorPrivate::recursion> watcher(isWaiting.data());
368 if (!watcher.hasRecursed())
369 isWaiting->incubate(i);
370 } else {
372 }
373
375
379 }
380 } else if (!creator.isNull()) {
382 }
383}
384
392{
393 auto compPriv = QQmlComponentPrivate::get(component);
394 Q_ASSERT(compPriv->loadedType.isCreatable());
395 std::unique_ptr<QObject> object(component->beginCreate(context));
396 component->setInitialProperties(object.get(), initialProperties);
397 if (auto props = compPriv->state.requiredProperties()) {
400 }
401 q->setInitialState(object.get());
403 for (const RequiredPropertyInfo &unsetRequiredProperty :
404 std::as_const(*requiredPropertiesFromComponent)) {
406 }
407 } else {
408 compPriv->completeCreate();
409 result = object.release();
411 }
413
414}
415
420{
421 if (!d || !d->incubatorCount)
422 return;
423
426 do {
427 static_cast<QQmlIncubatorPrivate*>(d->incubatorList.first())->incubate(i);
428 } while (d && d->incubatorCount != 0 && !i.shouldInterrupt());
429}
430
443void QQmlIncubationController::incubateWhile(std::atomic<bool> *flag, int msecs)
444{
445 if (!d || !d->incubatorCount)
446 return;
447
449 do {
450 static_cast<QQmlIncubatorPrivate*>(d->incubatorList.first())->incubate(i);
451 } while (d && d->incubatorCount != 0 && !i.shouldInterrupt());
452}
453
557
560{
561 d->q = nullptr;
562
563 if (!d->ref.deref()) {
564 delete d;
565 }
566 d = nullptr;
567}
568
600{
601 QRecursionWatcher<QQmlIncubatorPrivate, &QQmlIncubatorPrivate::recursion> watcher(d);
602
603 Status s = status();
604
605 if (s == Null)
606 return;
607
608 QQmlEnginePrivate *enginePriv = d->enginePriv;
609 if (s == Loading) {
611 if (d->result) d->result->deleteLater();
612 d->result = nullptr;
613 }
614
615 d->clear();
616
618 Q_ASSERT(d->waitingOnMe.data() == nullptr);
620
621 d->errors.clear();
623 d->result = nullptr;
624
625 if (s == Loading) {
626 Q_ASSERT(enginePriv);
627
628 enginePriv->inProgressCreations--;
629 if (0 == enginePriv->inProgressCreations) {
630 while (enginePriv->erroredBindings)
631 enginePriv->warning(enginePriv->erroredBindings->removeError());
632 }
633 }
634
635 d->changeStatus(Null);
636}
637
647
652{
653 return status() == Null;
654}
655
660{
661 return status() == Ready;
662}
663
668{
669 return status() == Error;
670}
671
676{
677 return status() == Loading;
678}
679
683QList<QQmlError> QQmlIncubator::errors() const
684{
685 return d->errors;
686}
687
695
700{
701 return d->status;
702}
703
708{
709 if (status() != Ready)
710 return nullptr;
711 else
712 return d->result;
713}
714
731
739
748{
749 d->initialProperties = initialProperties;
750}
751
761
782{
783 Q_UNUSED(object);
784}
785
787{
788 if (s == status)
789 return;
790
791 status = s;
792 if (q)
793 q->statusChanged(status);
794}
795
807
bool ref() noexcept
bool deref() noexcept
\inmodule QtCore
static constexpr ForeverConstant Forever
T * data() const noexcept
Returns a pointer to the shared data object.
bool empty() const noexcept
This function is provided for STL compatibility.
Definition qhash.h:1349
bool isEmpty() const noexcept
Returns true if the hash contains no items; otherwise returns false.
Definition qhash.h:928
void remove()
If in a list, remove this node otherwise do nothing.
bool isInList() const
Returns true if this node is in a list, false otherwise.
bool isEmpty() const
const N * first() const
Returns the first entry in this list, or null if the list is empty.
bool isEmpty() const noexcept
Definition qlist.h:401
void push_back(parameter_type t)
Definition qlist.h:675
void clear()
Definition qlist.h:434
const_iterator cend() const
Definition qmap.h:605
const_iterator cbegin() const
Definition qmap.h:601
\inmodule QtCore
Definition qobject.h:103
void deleteLater()
\threadsafe
Definition qobject.cpp:2435
static QQmlError unsetRequiredPropertyToQQmlError(const RequiredPropertyInfo &unsetRequiredProperty)
static QQmlComponentPrivate * get(QQmlComponent *c)
static QQmlProperty removePropertyFromRequired(QObject *createdComponent, const QString &name, RequiredProperties *requiredProperties, QQmlEngine *engine, bool *wasInRequiredProperties=nullptr)
The QQmlComponent class encapsulates a QML component definition.
QQmlIncubatorPrivate * incubator() const
void setIncubator(QQmlIncubatorPrivate *incubator)
The QQmlContext class defines a context within a QML engine.
Definition qqmlcontext.h:25
static QQmlData * get(QObjectPrivate *priv, bool create)
Definition qqmldata_p.h:199
Q_REQUIRED_RESULT QQmlError removeError()
void warning(const QQmlError &)
QIntrusiveList< Incubator, &Incubator::next > incubatorList
void incubate(QQmlIncubator &, const QQmlRefPointer< QQmlContextData > &)
static QQmlEnginePrivate * get(QQmlEngine *e)
void referenceScarceResources()
QQmlDelayedError * erroredBindings
unsigned int incubatorCount
void dereferenceScarceResources()
QQmlIncubationController * incubationController
The QQmlEngine class provides an environment for instantiating QML components.
Definition qqmlengine.h:57
QQmlIncubationController * incubationController() const
Returns the currently set incubation controller, or 0 if no controller has been set.
void setIncubationController(QQmlIncubationController *)
Sets the engine's incubation controller.
The QQmlError class encapsulates a QML error.
Definition qqmlerror.h:18
void setContextData(QQmlRefPointer< QQmlContextData > contextData)
QQmlIncubationController instances drive the progress of QQmlIncubators.
QQmlEngine * engine() const
Return the QQmlEngine this incubation controller is set on, or 0 if it has not been set on any engine...
void incubateFor(int msecs)
Incubate objects for msecs, or until there are no more objects to incubate.
int incubatingObjectCount() const
Return the number of objects currently incubating.
virtual void incubatingObjectCountChanged(int)
Called when the number of incubating objects changes.
void incubateWhile(std::atomic< bool > *flag, int msecs=0)
QQmlIncubationController()
Create a new incubation controller.
QQmlIncubator::Status calculateStatus() const
bool hadTopLevelRequiredProperties() const
RequiredProperties * requiredProperties()
Return a pointer to a list of properties which are required but haven't been set yet.
void changeStatus(QQmlIncubator::Status)
void forceCompletion(QQmlInstantiationInterrupt &i)
QIntrusiveListNode nextWaitingFor
static QQmlIncubatorPrivate * get(QQmlIncubator *incubator)
QQmlGuardedContextData rootContext
QExplicitlySharedDataPointer< QQmlIncubatorPrivate > waitingOnMe
void incubateCppBasedComponent(QQmlComponent *component, QQmlContext *context)
QQmlIncubatorPrivate(QQmlIncubator *q, QQmlIncubator::IncubationMode m)
void incubate(QQmlInstantiationInterrupt &i)
QPointer< QObject > result
QScopedPointer< QQmlObjectCreator > creator
QQmlRefPointer< QV4::ExecutableCompilationUnit > compilationUnit
QQmlEnginePrivate * enginePriv
QQmlIncubator::IncubationMode mode
QList< QQmlError > errors
QTaggedPointer< RequiredProperties, HadTopLevelRequired > requiredPropertiesFromComponent
QVariantMap initialProperties
QIntrusiveList< QQmlIncubatorPrivate, &QQmlIncubatorPrivate::nextWaitingFor > waitingFor
QQmlIncubator::Status status
The QQmlIncubator class allows QML objects to be created asynchronously.
QList< QQmlError > errors() const
Return the list of errors encountered while incubating the object.
void clear()
Clears the incubator.
void setInitialProperties(const QVariantMap &initialProperties)
Stores a mapping from property names to initial values, contained in initialProperties,...
virtual ~QQmlIncubator()
QObject * object() const
Return the incubated object if the status is Ready, otherwise 0.
bool isLoading() const
Returns true if the incubator's status() is Loading.
virtual void statusChanged(Status)
Called when the status of the incubator changes.
bool isError() const
Returns true if the incubator's status() is Error.
IncubationMode
Specifies the mode the incubator operates in.
virtual void setInitialState(QObject *)
Called after the object is first created, but before complex property bindings are evaluated and,...
bool isNull() const
Returns true if the incubator's status() is Null.
void forceCompletion()
Force any in-progress incubation to finish synchronously.
Status status() const
Return the current status of the incubator.
Status
Specifies the status of the QQmlIncubator.
IncubationMode incubationMode() const
Return the incubation mode passed to the QQmlIncubator constructor.
QQmlIncubator(IncubationMode=Asynchronous)
Create a new incubator with the specified mode.
bool isReady() const
Returns true if the incubator's status() is Ready.
bool finalize(QQmlInstantiationInterrupt &interrupt)
bool componentHadTopLevelRequiredProperties() const
QObject * create(int subComponentIndex=-1, QObject *parent=nullptr, QQmlInstantiationInterrupt *interrupt=nullptr, int flags=NormalObject)
RequiredProperties * requiredProperties()
QList< QQmlError > errors
QQmlRefPointer< QQmlContextData > rootContext() const
The QQmlProperty class abstracts accessing properties on objects created from QML.
bool isValid() const
Returns true if the QQmlProperty refers to a valid property, otherwise false.
bool write(const QVariant &) const
Sets the property value to value.
void reset(T *t=nullptr)
bool isNull() const
bool isOK() const
Definition qqmlvme.cpp:77
void guard(QQmlObjectCreator *)
Definition qqmlvme.cpp:51
void clear()
Definition qqmlvme.cpp:66
T * data() const noexcept
Returns the value of the pointer referenced by this object.
bool isNull() const noexcept
Returns true if this object refers to \nullptr.
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
QAtomicInt ref
Definition qshareddata.h:21
T * data() const noexcept
void setTag(Tag tag)
Tag tag() const noexcept
#define this
Definition dialogs.cpp:9
QSet< QString >::iterator it
static void * context
DBusConnection const char DBusError * error
@ QtCriticalMsg
Definition qlogging.h:32
@ QtInfoMsg
Definition qlogging.h:34
GLenum mode
const GLfloat * m
GLuint object
[3]
GLenum GLuint GLsizei const GLenum * props
GLuint name
GLdouble s
[6]
Definition qopenglext.h:235
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
static qreal component(const QPointF &point, unsigned int i)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int void * arg
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define Q_UNUSED(x)
QFutureWatcher< int > watcher
QDeadlineTimer deadline(30s)
QObject::connect nullptr