7#include <private/qmetaobject_p.h>
8#include <private/qqmlabstractbinding_p.h>
9#include <private/qqmlboundsignal_p.h>
10#include <private/qqmlcontextdata_p.h>
11#include <private/qqmlnotifier_p.h>
13#include <QtCore/qtyperevision.h>
14#include <private/qthread_p.h>
18QQmlData::QQmlData(Ownership ownership)
19 : ownMemory(ownership == OwnsMemory)
20 , indestructible(
true)
21 , explicitIndestructibleSet(
false)
22 , hasTaintedV4Object(
false)
23 , isQueuedForDeletion(
false)
24 , rootObjectInCreation(
false)
25 , hasInterceptorMetaObject(
false)
26 , hasVMEMetaObject(
false)
27 , hasConstWrapper(
false)
29 , bindingBitsArraySize(InlineBindingArraySize)
31 memset(bindingBitsValue, 0,
sizeof(bindingBitsValue));
35QQmlData::~QQmlData() =
default;
37void QQmlData::destroyed(QAbstractDeclarativeData *d, QObject *o)
39 QQmlData *ddata =
static_cast<QQmlData *>(d);
52 QMetaMethod method = target->metaObject()->method(methodIndex);
53 Q_ASSERT(method.methodType() == QMetaMethod::Signal);
54 int signalIndex = QMetaObjectPrivate::signalIndex(method);
55 QQmlData *ddata = QQmlData::get(target,
false);
56 QQmlNotifierEndpoint *ep = ddata->notify(signalIndex);
57 if (ep) QQmlNotifier::emitNotify(ep, a);
65void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object,
int index,
void **a)
67 QQmlData *ddata = QQmlData::get(object,
false);
79 if (!ddata->notifyList.loadRelaxed())
82 auto objectThreadData = QObjectPrivate::get(object)->threadData.loadRelaxed();
83 if (QThread::currentThreadId() != objectThreadData->threadId.loadRelaxed()) {
84 if (!objectThreadData->thread.loadAcquire())
87 QMetaMethod m = QMetaObjectPrivate::signal(object->metaObject(), index);
88 const QList<QByteArray> parameterTypes = m.parameterTypes();
90 QVarLengthArray<
const QtPrivate::QMetaTypeInterface *, 16> argTypes;
91 argTypes.reserve(1 + parameterTypes.size());
92 argTypes.emplace_back(
nullptr);
93 for (
const QByteArray &typeName: parameterTypes) {
95 if (typeName.endsWith(
'*'))
96 type = QMetaType(QMetaType::VoidStar);
98 type = QMetaType::fromName(typeName);
100 if (!type.isValid()) {
101 qWarning(
"QObject::connect: Cannot queue arguments of type '%s'\n"
102 "(Make sure '%s' is registered using qRegisterMetaType().)",
103 typeName.constData(), typeName.constData());
107 argTypes.emplace_back(type.iface());
110 auto ev = std::make_unique<QQueuedMetaCallEvent>(m.methodIndex(), 0,
nullptr, object, index,
111 argTypes.size(), argTypes.data(), a);
113 QQmlThreadNotifierProxyObject *mpo =
new QQmlThreadNotifierProxyObject;
114 mpo->target = object;
115 mpo->moveToThread(objectThreadData->thread.loadAcquire());
116 QCoreApplication::postEvent(mpo, ev.release());
119 QQmlNotifierEndpoint *ep = ddata->notify(index);
120 if (ep) QQmlNotifier::emitNotify(ep, a);
124int QQmlData::receivers(QAbstractDeclarativeData *d,
const QObject *,
int index)
126 QQmlData *ddata =
static_cast<QQmlData *>(d);
127 return ddata->endpointCount(index);
130bool QQmlData::isSignalConnected(QAbstractDeclarativeData *d,
const QObject *,
int index)
132 QQmlData *ddata =
static_cast<QQmlData *>(d);
133 return ddata->signalHasEndpoint(index);
136int QQmlData::endpointCount(
int index)
139 QQmlNotifierEndpoint *ep = notify(index);
150void QQmlData::markAsDeleted(QObject *o)
152 QVarLengthArray<QObject *> workStack;
153 workStack.push_back(o);
154 while (!workStack.isEmpty()) {
155 auto currentObject = workStack.last();
156 workStack.pop_back();
157 QQmlData::setQueuedForDeletion(currentObject);
158 auto currentObjectPriv = QObjectPrivate::get(currentObject);
159 for (QObject *child: std::as_const(currentObjectPriv->children))
160 workStack.push_back(child);
164void QQmlData::setQueuedForDeletion(QObject *object)
167 if (QQmlData *ddata = QQmlData::get(object)) {
168 if (ddata->ownContext) {
169 Q_ASSERT(ddata->ownContext.data() == ddata->context);
170 ddata->ownContext->deepClearContextObject(object);
171 ddata->ownContext.reset();
172 ddata->context =
nullptr;
174 ddata->isQueuedForDeletion =
true;
181 ddata->disconnectNotifiers(DeleteNotifyList::No);
186void QQmlData::flushPendingBinding(
int coreIndex)
188 clearPendingBindingBit(coreIndex);
191 QQmlAbstractBinding *b = bindings;
192 while (b && (b->targetPropertyIndex().coreIndex() != coreIndex ||
193 b->targetPropertyIndex().hasValueTypeIndex()))
194 b = b->nextBinding();
196 if (b && b->targetPropertyIndex().coreIndex() == coreIndex &&
197 !b->targetPropertyIndex().hasValueTypeIndex())
198 b->setEnabled(
true, QQmlPropertyData::BypassInterceptor |
199 QQmlPropertyData::DontRemoveBinding);
202QQmlData::DeferredData::DeferredData() =
default;
203QQmlData::DeferredData::~DeferredData() =
default;
215void QQmlData::deferData(
216 int objectIndex,
const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
217 const QQmlRefPointer<QQmlContextData> &context,
const QString &inlineComponentName)
219 QQmlData::DeferredData *deferData =
new QQmlData::DeferredData;
220 deferData->deferredIdx = objectIndex;
221 deferData->compilationUnit = compilationUnit;
222 deferData->context = context;
223 deferData->inlineComponentName = inlineComponentName;
225 const QV4::CompiledData::Object *compiledObject = compilationUnit->objectAt(objectIndex);
226 const QV4::CompiledData::BindingPropertyData *propertyData
227 = compilationUnit->bindingPropertyDataPerObjectAt(objectIndex);
229 const QV4::CompiledData::Binding *binding = compiledObject->bindingTable();
230 for (quint32 i = 0; i < compiledObject->nBindings; ++i, ++binding) {
231 const QQmlPropertyData *property = propertyData->at(i);
232 if (binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding))
233 deferData->bindings.insert(property ? property->coreIndex() : -1, binding);
236 deferredData.append(deferData);
239void QQmlData::releaseDeferredData()
241 auto it = deferredData.begin();
242 while (it != deferredData.end()) {
243 DeferredData *deferData = *it;
244 if (deferData->bindings.isEmpty()) {
246 it = deferredData.erase(it);
253void QQmlData::addNotify(
int index, QQmlNotifierEndpoint *endpoint)
257 QQmlNotifyList *list = notifyList.loadRelaxed();
260 list =
new QQmlNotifyList;
266 notifyList.storeRelaxed(list);
269 Q_ASSERT(!endpoint->isConnected());
271 index = qMin(index, 0xFFFF - 1);
276 list->connectionMask.storeRelaxed(
277 list->connectionMask.loadRelaxed() | (1ULL << quint64(index % 64)));
279 if (index < list->notifiesSize) {
280 endpoint->next = list->notifies[index];
281 if (endpoint->next) endpoint->next->prev = &endpoint->next;
282 endpoint->prev = &list->notifies[index];
283 list->notifies[index] = endpoint;
285 list->maximumTodoIndex = qMax(
int(list->maximumTodoIndex), index);
287 endpoint->next = list->todo;
288 if (endpoint->next) endpoint->next->prev = &endpoint->next;
289 endpoint->prev = &list->todo;
290 list->todo = endpoint;
294void QQmlData::disconnectNotifiers(QQmlData::DeleteNotifyList doDelete)
297 if (QQmlNotifyList *list = notifyList.loadRelaxed()) {
298 while (QQmlNotifierEndpoint *todo = list->todo)
300 for (
int ii = 0; ii < list->notifiesSize; ++ii) {
301 while (QQmlNotifierEndpoint *ep = list->notifies[ii])
304 free(list->notifies);
306 if (doDelete == DeleteNotifyList::Yes) {
310 notifyList.storeRelaxed(
nullptr);
316 list->connectionMask.storeRelaxed(0);
317 list->maximumTodoIndex = 0;
318 list->notifiesSize = 0;
319 list->notifies =
nullptr;
325QHash<QQmlAttachedPropertiesFunc, QObject *> *QQmlData::attachedProperties()
const
327 if (!extendedData) extendedData =
new QQmlDataExtended;
328 return &extendedData->attachedProperties;
331void QQmlData::removeFromContext()
333 if (nextContextObject)
334 nextContextObject->prevContextObject = prevContextObject;
335 if (prevContextObject)
336 *prevContextObject = nextContextObject;
337 else if (outerContext && outerContext->ownedObjects() ==
this)
338 outerContext->setOwnedObjects(nextContextObject);
340 nextContextObject =
nullptr;
341 prevContextObject =
nullptr;
342 outerContext =
nullptr;
346void QQmlData::clearBindings()
348 if (QQmlAbstractBinding *binding = std::exchange(bindings,
nullptr)) {
349 for (QQmlAbstractBinding *next = binding; next; next = next->nextBinding())
350 next->setAddedToObject(
false);
351 if (!binding->ref.deref())
356bool QQmlData::clearSignalHandlers()
358 for (QQmlBoundSignal *signalHandler = std::exchange(signalHandlers,
nullptr); signalHandler;) {
359 if (signalHandler->isNotifying()) {
360 signalHandlers = signalHandler;
364 QQmlBoundSignal *next = signalHandler->m_nextSignal;
365 signalHandler->m_prevSignal =
nullptr;
366 signalHandler->m_nextSignal =
nullptr;
367 delete signalHandler;
368 signalHandler = next;
374void QQmlData::clear()
379 compilationUnit.reset();
380 qDeleteAll(std::exchange(deferredData, {}));
382 if (!clearSignalHandlers())
383 qFatal(
"Can't clear QQmlData from signal handler");
385 BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize)
388 memset(bits, 0, bindingBitsArraySize *
sizeof(BindingBitsType));
390 propertyCache.reset();
393 disconnectNotifiers(DeleteNotifyList::No);
395 delete std::exchange(extendedData,
nullptr);
396 propertyObservers.clear();
400 rootObjectInCreation =
false;
401 hasInterceptorMetaObject =
false;
402 hasVMEMetaObject =
false;
406void QQmlData::destroyed(QObject *object)
411 compilationUnit.reset();
412 qDeleteAll(deferredData);
413 deferredData.clear();
415 if (!clearSignalHandlers()) {
420 QString locationString;
421 QQmlBoundSignalExpression *expr = signalHandlers->expression();
423 QQmlSourceLocation location = expr->sourceLocation();
424 if (location.sourceFile.isEmpty())
425 location.sourceFile = QStringLiteral(
"<Unknown File>");
426 locationString.append(location.sourceFile);
427 locationString.append(QStringLiteral(
":%0: ").arg(location.line));
428 QString source = expr->expression();
429 if (source.size() > 100) {
431 source.append(QLatin1String(
" ..."));
433 locationString.append(source);
435 locationString = QStringLiteral(
"<Unknown Location>");
437 qFatal(
"Object %p destroyed while one of its QML signal handlers is in progress.\n"
438 "Most likely the object was deleted synchronously (use QObject::deleteLater() "
439 "instead), or the application is running a nested event loop.\n"
440 "This behavior is NOT supported!\n"
441 "%s", object, qPrintable(locationString));
444 if (bindingBitsArraySize > InlineBindingArraySize)
448 propertyCache.reset();
453 auto *guard = guards;
454 guard->setObject(
nullptr);
455 if (guard->objectDestroyed)
456 guard->objectDestroyed(guard);
459 disconnectNotifiers(DeleteNotifyList::Yes);
473QQmlData::BindingBitsType *QQmlData::growBits(QObject *obj,
int bit)
475 BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits;
476 int props = QQmlMetaObject(obj).propertyCount();
477 Q_ASSERT(bit < 2 * props);
480 uint arraySize = (2 *
static_cast<uint>(props) + BitsPerType - 1) / BitsPerType;
481 Q_ASSERT(arraySize > 1);
482 Q_ASSERT(arraySize <= 0xffff);
484 BindingBitsType *newBits =
static_cast<BindingBitsType *>(malloc(arraySize*
sizeof(BindingBitsType)));
485 memcpy(newBits, bits, bindingBitsArraySize *
sizeof(BindingBitsType));
486 memset(newBits + bindingBitsArraySize, 0,
sizeof(BindingBitsType) * (arraySize - bindingBitsArraySize));
488 if (bindingBitsArraySize > InlineBindingArraySize)
490 bindingBits = newBits;
492 bindingBitsArraySize = arraySize;
496QQmlData *QQmlData::createQQmlData(QObjectPrivate *priv)
499 Q_ASSERT(!priv->isDeletingChildren);
500 priv->declarativeData =
new QQmlData(OwnsMemory);
501 return static_cast<QQmlData *>(priv->declarativeData);
504QQmlPropertyCache::ConstPtr QQmlData::createPropertyCache(QObject *object)
506 QQmlData *ddata = QQmlData::get(object,
true);
507 ddata->propertyCache = QQmlMetaType::propertyCache(object, QTypeRevision {});
508 return ddata->propertyCache;
QHash< QQmlAttachedPropertiesFunc, QObject * > attachedProperties
~QQmlDataExtended()=default
QPointer< QObject > target
int qt_metacall(QMetaObject::Call, int methodIndex, void **a) override
Combined button and popup list for selecting options.