Qt 6.x
The Qt SDK
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
13{
15
16 QQmlIncubator::IncubationMode mode = i.incubationMode();
17
20
23
24 // Need to find the first constructing context and see if it is asynchronous
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
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
100{
101 clear();
102}
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
189: d(nullptr)
190{
191}
192
195{
196 if (d) QQmlEnginePrivate::get(d)->setIncubationController(nullptr);
197 d = nullptr;
198}
199
205{
206 return QQmlEnginePrivate::get(d);
207}
208
213{
214 return d ? d->incubatorCount : 0;
215}
216
224{
226}
227
229{
230 while (QQmlIncubator::Loading == status) {
234 incubate(i);
235 }
236}
237
238
240{
241 if (!compilationUnit)
242 return;
243
245
247 // get a copy of the engine pointer as it might get reset;
249
250 // Incubating objects takes quite a bit more stack space than our usual V4 function
251 enum { EstimatedSizeInV4Frames = 2 };
254 if (callDepthRecorder.hasOverflow()) {
256 error.setMessageType(QtCriticalMsg);
257 error.setUrl(compilationUnit->url());
258 error.setDescription(QQmlComponent::tr("Maximum call stack size exceeded."));
259 errors << error;
261 goto finishIncubate;
262 }
263
264 if (!vmeGuard.isOK()) {
266 error.setMessageType(QtInfoMsg);
267 error.setUrl(compilationUnit->url());
268 error.setDescription(QQmlComponent::tr("Object or context destroyed during incubation"));
269 errors << error;
271
272 goto finishIncubate;
273 }
274
275 vmeGuard.clear();
276
279 QObject *tresult = nullptr;
280 tresult = creator->create(subComponentToCreate, /*parent*/nullptr, &i);
281 if (!tresult)
283 else {
285 for (auto it = initialProperties.cbegin(); it != initialProperties.cend(); ++it) {
286 auto component = tresult;
287 auto name = it.key();
290 if (!prop.isValid() || !prop.write(it.value())) {
292 error.setUrl(compilationUnit->url());
293 error.setDescription(QLatin1String("Could not set property %1").arg(name));
295 }
296 }
297 }
299
300 if (watcher.hasRecursed())
301 return;
302
303 result = tresult;
304 if (errors.isEmpty() && result == nullptr)
305 goto finishIncubate;
306
307 if (result) {
308 QQmlData *ddata = QQmlData::get(result);
309 Q_ASSERT(ddata);
310 //see QQmlComponent::beginCreate for explanation of indestructible
311 ddata->indestructible = true;
312 ddata->explicitIndestructibleSet = true;
313 ddata->rootObjectInCreation = false;
314 if (q) {
315 q->setInitialState(result);
316 if (creator && !creator->requiredProperties()->empty()) {
317 const RequiredProperties *unsetRequiredProperties = creator->requiredProperties();
318 for (const auto& unsetRequiredProperty: *unsetRequiredProperties)
320 }
321 }
322 }
323
324 if (watcher.hasRecursed())
325 return;
326
327 if (errors.isEmpty())
329 else
331
333
334 if (watcher.hasRecursed())
335 return;
336
337 if (i.shouldInterrupt())
338 goto finishIncubate;
339 }
340
342 do {
343 if (watcher.hasRecursed())
344 return;
345
346 if (creator->finalize(i)) {
349 goto finishIncubate;
350 }
351 } while (!i.shouldInterrupt());
352 }
353
354finishIncubate:
357 clear();
358
359 if (isWaiting) {
362 if (!watcher.hasRecursed())
363 isWaiting->incubate(i);
364 } else {
366 }
367
369
373 }
374 } else if (!creator.isNull()) {
376 }
377}
378
386{
387 auto compPriv = QQmlComponentPrivate::get(component);
388 Q_ASSERT(compPriv->loadedType.isCreatable());
389 std::unique_ptr<QObject> object(component->beginCreate(context));
390 component->setInitialProperties(object.get(), initialProperties);
391 if (auto props = compPriv->state.requiredProperties()) {
394 }
395 q->setInitialState(object.get());
397 for (const RequiredPropertyInfo &unsetRequiredProperty :
398 std::as_const(*requiredPropertiesFromComponent)) {
400 }
401 } else {
402 compPriv->completeCreate();
403 result = object.release();
405 }
407
408}
409
414{
415 if (!d || !d->incubatorCount)
416 return;
417
420 do {
421 static_cast<QQmlIncubatorPrivate*>(d->incubatorList.first())->incubate(i);
422 } while (d && d->incubatorCount != 0 && !i.shouldInterrupt());
423}
424
437void QQmlIncubationController::incubateWhile(std::atomic<bool> *flag, int msecs)
438{
439 if (!d || !d->incubatorCount)
440 return;
441
443 do {
444 static_cast<QQmlIncubatorPrivate*>(d->incubatorList.first())->incubate(i);
445 } while (d && d->incubatorCount != 0 && !i.shouldInterrupt());
446}
447
536{
537 d->ref.ref();
538}
539
542{
543 d->q = nullptr;
544
545 if (!d->ref.deref()) {
546 delete d;
547 }
548 d = nullptr;
549}
550
582{
584
585 Status s = status();
586
587 if (s == Null)
588 return;
589
590 QQmlEnginePrivate *enginePriv = d->enginePriv;
591 if (s == Loading) {
593 if (d->result) d->result->deleteLater();
594 d->result = nullptr;
595 }
596
597 d->clear();
598
600 Q_ASSERT(d->waitingOnMe.data() == nullptr);
602
603 d->errors.clear();
605 d->result = nullptr;
606
607 if (s == Loading) {
608 Q_ASSERT(enginePriv);
609
610 enginePriv->inProgressCreations--;
611 if (0 == enginePriv->inProgressCreations) {
612 while (enginePriv->erroredBindings)
613 enginePriv->warning(enginePriv->erroredBindings->removeError());
614 }
615 }
616
617 d->changeStatus(Null);
618}
619
625{
627 d->forceCompletion(i);
628}
629
634{
635 return status() == Null;
636}
637
642{
643 return status() == Ready;
644}
645
650{
651 return status() == Error;
652}
653
658{
659 return status() == Loading;
660}
661
666{
667 return d->errors;
668}
669
674{
675 return d->mode;
676}
677
682{
683 return d->status;
684}
685
690{
691 if (status() != Ready)
692 return nullptr;
693 else
694 return d->result;
695}
696
707{
708 if (creator)
709 return creator->requiredProperties();
710 else
712}
713
715{
716 if (creator)
718 else
720}
721
730{
731 d->initialProperties = initialProperties;
732}
733
740{
742}
743
754{
755 Q_UNUSED(object);
756}
757
759{
760 if (s == status)
761 return;
762
763 status = s;
764 if (q)
765 q->statusChanged(status);
766}
767
769{
770 if (!errors.isEmpty())
774 else if (compilationUnit)
776 else
777 return QQmlIncubator::Null;
778}
779
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:1329
bool isEmpty() const noexcept
Returns true if the hash contains no items; otherwise returns false.
Definition qhash.h:926
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
N * first() const
Returns the first entry in this list, or null if the list is empty.
Definition qlist.h:74
bool isEmpty() const noexcept
Definition qlist.h:390
void push_back(parameter_type t)
Definition qlist.h:672
void clear()
Definition qlist.h:417
const_iterator cend() const
Definition qmap.h:604
const_iterator cbegin() const
Definition qmap.h:600
\inmodule QtCore
Definition qobject.h:90
void deleteLater()
\threadsafe
Definition qobject.cpp:2352
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
quint32 explicitIndestructibleSet
Definition qqmldata_p.h:95
static QQmlData * get(QObjectPrivate *priv, bool create)
Definition qqmldata_p.h:199
quint32 rootObjectInCreation
Definition qqmldata_p.h:104
quint32 indestructible
Definition qqmldata_p.h:92
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 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 GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
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