diff options
Diffstat (limited to 'src/declarative/qml')
-rw-r--r-- | src/declarative/qml/qdeclarativecomponent.cpp | 20 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativedeclarativedata_p.h | 17 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeengine.cpp | 62 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeengine.h | 4 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeobjectscriptclass.cpp | 153 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeobjectscriptclass_p.h | 3 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativevme.cpp | 2 |
7 files changed, 204 insertions, 57 deletions
diff --git a/src/declarative/qml/qdeclarativecomponent.cpp b/src/declarative/qml/qdeclarativecomponent.cpp index d6bb216..d3608c4 100644 --- a/src/declarative/qml/qdeclarativecomponent.cpp +++ b/src/declarative/qml/qdeclarativecomponent.cpp @@ -512,7 +512,6 @@ QDeclarativeComponent::QDeclarativeComponent(QDeclarativeComponentPrivate &dd, Q { } - /*! \internal A version of create which returns a scriptObject, for use in script @@ -526,7 +525,9 @@ QScriptValue QDeclarativeComponent::createObject() return QScriptValue(); } QObject* ret = create(ctxt); - return QDeclarativeEnginePrivate::qmlScriptObject(ret, d->engine); + QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(d->engine); + QDeclarativeDeclarativeData::get(ret, true)->setImplicitDestructible(); + return priv->objectClass->newQObject(ret, QMetaType::QObjectStar); } /*! @@ -541,7 +542,12 @@ QObject *QDeclarativeComponent::create(QDeclarativeContext *context) { Q_D(QDeclarativeComponent); - return d->create(context, QBitField()); + if (!context) + context = d->engine->rootContext(); + + QObject *rv = beginCreate(context); + completeCreate(); + return rv; } QObject *QDeclarativeComponentPrivate::create(QDeclarativeContext *context, @@ -586,7 +592,13 @@ QObject *QDeclarativeComponentPrivate::create(QDeclarativeContext *context, QObject *QDeclarativeComponent::beginCreate(QDeclarativeContext *context) { Q_D(QDeclarativeComponent); - return d->beginCreate(context, QBitField()); + QObject *rv = d->beginCreate(context, QBitField()); + if (rv) { + QDeclarativeDeclarativeData *ddata = QDeclarativeDeclarativeData::get(rv); + Q_ASSERT(ddata); + ddata->indestructible = true; + } + return rv; } QObject * diff --git a/src/declarative/qml/qdeclarativedeclarativedata_p.h b/src/declarative/qml/qdeclarativedeclarativedata_p.h index ae40130..ffce9c9 100644 --- a/src/declarative/qml/qdeclarativedeclarativedata_p.h +++ b/src/declarative/qml/qdeclarativedeclarativedata_p.h @@ -67,12 +67,21 @@ class Q_AUTOTEST_EXPORT QDeclarativeDeclarativeData : public QDeclarativeData { public: QDeclarativeDeclarativeData(QDeclarativeContext *ctxt = 0) - : context(ctxt), bindings(0), nextContextObject(0), prevContextObject(0), - bindingBitsSize(0), bindingBits(0), outerContext(0), lineNumber(0), - columnNumber(0), deferredComponent(0), deferredIdx(0), attachedProperties(0), - propertyCache(0), guards(0) {} + : indestructible(true), explicitIndestructibleSet(false), context(ctxt), + bindings(0), nextContextObject(0), prevContextObject(0), bindingBitsSize(0), bindingBits(0), + outerContext(0), lineNumber(0), columnNumber(0), deferredComponent(0), deferredIdx(0), + attachedProperties(0), propertyCache(0), guards(0) {} virtual void destroyed(QObject *); + virtual void parentChanged(QObject *, QObject *); + + void setImplicitDestructible() { + if (!explicitIndestructibleSet) indestructible = false; + } + + quint32 indestructible:1; + quint32 explicitIndestructibleSet:1; + quint32 dummy:29; QDeclarativeContext *context; QDeclarativeAbstractBinding *bindings; diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index 41d55d7..791df9f 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -668,6 +668,59 @@ void QDeclarativeEngine::setContextForObject(QObject *object, QDeclarativeContex context->d_func()->contextObjects = data; } +/*! +\enum QDeclarativeEngine::ObjectOwnership + +Ownership controls whether or not QML automatically destroys the QObject when the object +is garbage collected by the JavaScript engine. The two ownership options are: + +\o CppOwnership The object is owned by C++ code, and will never be deleted by QML. The +JavaScript destroy() method cannot be used on objects with CppOwnership. This option +is similar to QScriptEngine::QtOwnership. + +\o JavaScriptOwnership The object is owned by JavaScript. When the object is returned to QML +as the return value of a method call or property access, QML will delete the object if there +are no remaining JavaScript references to it and it has no QObject::parent(). This option +is similar to QScriptEngine::ScriptOwnership. + +Generally an application doesn't need to set an object's ownership explicitly. QML uses +a heuristic to set the default object ownership. By default, an object that is created by +QML has JavaScriptOwnership. The exception to this are the root objects created by calling +QDeclarativeCompnent::create() or QDeclarativeComponent::beginCreate() which have +CppOwnership by default. The ownership of these root-level objects is considered to have +been transfered to the C++ caller. + +Objects not-created by QML have CppOwnership by default. The exception to this is objects +returned from a C++ method call. The ownership of these objects is passed to JavaScript. + +Calling setObjectOwnership() overrides the default ownership heuristic used by QML. +*/ + +/*! +Sets the \a ownership of \a object. +*/ +void QDeclarativeEngine::setObjectOwnership(QObject *object, ObjectOwnership ownership) +{ + QDeclarativeDeclarativeData *ddata = QDeclarativeDeclarativeData::get(object, true); + if (!ddata) + return; + + ddata->indestructible = (ownership == CppOwnership)?true:false; + ddata->explicitIndestructibleSet = true; +} + +/*! +Returns the ownership of \a object. +*/ +QDeclarativeEngine::ObjectOwnership QDeclarativeEngine::objectOwnership(QObject *object) +{ + QDeclarativeDeclarativeData *ddata = QDeclarativeDeclarativeData::get(object, false); + if (!ddata) + return CppOwnership; + else + return ddata->indestructible?CppOwnership:JavaScriptOwnership; +} + void qmlExecuteDeferred(QObject *object) { QDeclarativeDeclarativeData *data = QDeclarativeDeclarativeData::get(object); @@ -778,6 +831,11 @@ void QDeclarativeDeclarativeData::destroyed(QObject *object) delete this; } +void QDeclarativeDeclarativeData::parentChanged(QObject *, QObject *parent) +{ + if (!parent && scriptValue.isValid()) scriptValue = QScriptValue(); +} + bool QDeclarativeDeclarativeData::hasBindingBit(int bit) const { if (bindingBitsSize > bit) @@ -858,6 +916,7 @@ QScriptValue QDeclarativeEnginePrivate::createComponent(QScriptContext *ctxt, QUrl url = QUrl(context->resolvedUrl(QUrl(arg))); QDeclarativeComponent *c = new QDeclarativeComponent(activeEngine, url, activeEngine); c->setCreationContext(context); + QDeclarativeDeclarativeData::get(c, true)->setImplicitDestructible(); return activeEnginePriv->objectClass->newQObject(c, qMetaTypeId<QDeclarativeComponent*>()); } } @@ -928,7 +987,8 @@ QScriptValue QDeclarativeEnginePrivate::createQmlObject(QScriptContext *ctxt, QS if(gobj && gparent) gobj->setParentItem(gparent); - return qmlScriptObject(obj, activeEngine); + QDeclarativeDeclarativeData::get(obj, true)->setImplicitDestructible(); + return activeEnginePriv->objectClass->newQObject(obj, QMetaType::QObjectStar); } QScriptValue QDeclarativeEnginePrivate::vector(QScriptContext *ctxt, QScriptEngine *engine) diff --git a/src/declarative/qml/qdeclarativeengine.h b/src/declarative/qml/qdeclarativeengine.h index fd66358..19e81b6 100644 --- a/src/declarative/qml/qdeclarativeengine.h +++ b/src/declarative/qml/qdeclarativeengine.h @@ -98,6 +98,10 @@ public: static QDeclarativeContext *contextForObject(const QObject *); static void setContextForObject(QObject *, QDeclarativeContext *); + enum ObjectOwnership { CppOwnership, JavaScriptOwnership }; + static void setObjectOwnership(QObject *, ObjectOwnership); + static ObjectOwnership objectOwnership(QObject *); + Q_SIGNALS: void quit (); diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp index e6f6e5f..dc4a676 100644 --- a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp +++ b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp @@ -59,6 +59,15 @@ QT_BEGIN_NAMESPACE struct ObjectData : public QScriptDeclarativeClass::Object { ObjectData(QObject *o, int t) : object(o), type(t) {} + + virtual ~ObjectData() { + if (object && !object->parent()) { + QDeclarativeDeclarativeData *ddata = QDeclarativeDeclarativeData::get(object, false); + if (ddata && !ddata->indestructible) + object->deleteLater(); + } + } + QDeclarativeGuard<QObject> object; int type; }; @@ -87,7 +96,7 @@ QDeclarativeObjectScriptClass::~QDeclarativeObjectScriptClass() { } -QScriptValue QDeclarativeObjectScriptClass::newQObject(QObject *object, int type) +QScriptValue QDeclarativeObjectScriptClass::newQObject(QObject *object, int type) { QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); @@ -96,7 +105,11 @@ QScriptValue QDeclarativeObjectScriptClass::newQObject(QObject *object, int type QDeclarativeDeclarativeData *ddata = QDeclarativeDeclarativeData::get(object, true); - if (!ddata->scriptValue.isValid()) { + if (!ddata) { + return scriptEngine->undefinedValue(); + } else if (!ddata->indestructible && !object->parent()) { + return newObject(scriptEngine, this, new ObjectData(object, type)); + } else if (!ddata->scriptValue.isValid()) { ddata->scriptValue = newObject(scriptEngine, this, new ObjectData(object, type)); return ddata->scriptValue; } else if (ddata->scriptValue.engine() == QDeclarativeEnginePrivate::getScriptEngine(engine)) { @@ -392,17 +405,30 @@ QScriptValue QDeclarativeObjectScriptClass::tostring(QScriptContext *context, QS QScriptValue QDeclarativeObjectScriptClass::destroy(QScriptContext *context, QScriptEngine *engine) { - QObject* obj = context->thisObject().toQObject(); - if(obj){ - int delay = 0; - if(context->argumentCount() > 0) - delay = context->argument(0).toInt32(); - if (delay > 0) - QTimer::singleShot(delay, obj, SLOT(deleteLater())); - else - obj->deleteLater(); - } - return engine->nullValue(); + QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine); + QScriptValue that = context->thisObject(); + + if (scriptClass(that) != p->objectClass) + return engine->undefinedValue(); + + ObjectData *data = (ObjectData *)p->objectClass->object(that); + if (!data->object) + return engine->undefinedValue(); + + QDeclarativeDeclarativeData *ddata = QDeclarativeDeclarativeData::get(data->object, false); + if (!ddata || ddata->indestructible) + return engine->currentContext()->throwError(QLatin1String("Invalid attempt to destroy() an indestructible object")); + + QObject *obj = data->object; + int delay = 0; + if (context->argumentCount() > 0) + delay = context->argument(0).toInt32(); + if (delay > 0) + QTimer::singleShot(delay, obj, SLOT(deleteLater())); + else + obj->deleteLater(); + + return engine->undefinedValue(); } QStringList QDeclarativeObjectScriptClass::propertyNames(Object *object) @@ -428,6 +454,14 @@ QStringList QDeclarativeObjectScriptClass::propertyNames(Object *object) return cache->propertyNames(); } +bool QDeclarativeObjectScriptClass::compare(Object *o1, Object *o2) +{ + ObjectData *d1 = (ObjectData *)o1; + ObjectData *d2 = (ObjectData *)o2; + + return d1 == d2 || d1->object == d2->object; +} + #if (QT_VERSION > QT_VERSION_CHECK(4, 6, 2)) || defined(QT_HAVE_QSCRIPTDECLARATIVECLASS_VALUE) struct MethodData : public QScriptDeclarativeClass::Object { @@ -441,6 +475,8 @@ QDeclarativeObjectMethodScriptClass::QDeclarativeObjectMethodScriptClass(QDeclar : QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine) { + qRegisterMetaType<QList<QObject *> >("QList<QObject *>"); + setSupportsCall(true); QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); @@ -551,7 +587,7 @@ private: inline void cleanup(); - char *data[16]; + char data[2 * sizeof(void *)]; int type; }; } @@ -569,11 +605,13 @@ MetaCallArgument::~MetaCallArgument() void MetaCallArgument::cleanup() { if (type == QMetaType::QString) { - ((QString *)data)->~QString(); + ((QString *)&data)->~QString(); } else if (type == -1 || type == qMetaTypeId<QVariant>()) { - ((QVariant *)data)->~QVariant(); + ((QVariant *)&data)->~QVariant(); } else if (type == qMetaTypeId<QScriptValue>()) { - ((QScriptValue *)data)->~QScriptValue(); + ((QScriptValue *)&data)->~QScriptValue(); + } else if (type == qMetaTypeId<QList<QObject *> >()) { + ((QList<QObject *> *)&data)->~QList<QObject *>(); } } @@ -582,7 +620,7 @@ void *MetaCallArgument::dataPtr() if (type == -1) return ((QVariant *)data)->data(); else - return (void *)data; + return (void *)&data; } void MetaCallArgument::initAsType(int callType, QDeclarativeEngine *e) @@ -593,7 +631,7 @@ void MetaCallArgument::initAsType(int callType, QDeclarativeEngine *e) QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(e); if (callType == qMetaTypeId<QScriptValue>()) { - new (data) QScriptValue(engine->undefinedValue()); + new (&data) QScriptValue(engine->undefinedValue()); type = callType; } else if (callType == QMetaType::Int || callType == QMetaType::UInt || @@ -602,17 +640,20 @@ void MetaCallArgument::initAsType(int callType, QDeclarativeEngine *e) callType == QMetaType::Float) { type = callType; } else if (callType == QMetaType::QObjectStar) { - *((QObject **)data) = 0; + *((QObject **)&data) = 0; type = callType; } else if (callType == QMetaType::QString) { - new (data) QString(); + new (&data) QString(); type = callType; } else if (callType == qMetaTypeId<QVariant>()) { - type = qMetaTypeId<QVariant>(); - new (data) QVariant(); + type = callType; + new (&data) QVariant(); + } else if (callType == qMetaTypeId<QList<QObject *> >()) { + type = callType; + new (&data) QList<QObject *>(); } else { type = -1; - new (data) QVariant(callType, (void *)0); + new (&data) QVariant(callType, (void *)0); } } @@ -621,47 +662,50 @@ void MetaCallArgument::fromScriptValue(int callType, QDeclarativeEngine *engine, if (type != 0) { cleanup(); type = 0; } if (callType == qMetaTypeId<QScriptValue>()) { - new (data) QScriptValue(value); + new (&data) QScriptValue(value); type = qMetaTypeId<QScriptValue>(); } else if (callType == QMetaType::Int) { - *((int *)data) = int(value.toInt32()); + *((int *)&data) = int(value.toInt32()); type = callType; } else if (callType == QMetaType::UInt) { - *((uint *)data) = uint(value.toUInt32()); + *((uint *)&data) = uint(value.toUInt32()); type = callType; } else if (callType == QMetaType::Bool) { - *((bool *)data) = value.toBool(); + *((bool *)&data) = value.toBool(); type = callType; } else if (callType == QMetaType::Double) { - *((double *)data) = double(value.toNumber()); + *((double *)&data) = double(value.toNumber()); type = callType; } else if (callType == QMetaType::Float) { - *((float *)data) = float(value.toNumber()); + *((float *)&data) = float(value.toNumber()); type = callType; } else if (callType == QMetaType::QString) { if (value.isNull() || value.isUndefined()) - new (data) QString(); + new (&data) QString(); else - new (data) QString(value.toString()); + new (&data) QString(value.toString()); type = callType; } else if (callType == QMetaType::QObjectStar) { - *((QObject **)data) = value.toQObject(); + *((QObject **)&data) = value.toQObject(); type = callType; } else if (callType == qMetaTypeId<QVariant>()) { - new (data) QVariant(QDeclarativeScriptClass::toVariant(engine, value)); + new (&data) QVariant(QDeclarativeScriptClass::toVariant(engine, value)); + type = callType; + } else if (callType == qMetaTypeId<QList<QObject*> >()) { + new (&data) QList<QObject *>(); // We don't support passing in QList<QObject*> type = callType; } else { - new (data) QVariant(); + new (&data) QVariant(); type = -1; QVariant v = QDeclarativeScriptClass::toVariant(engine, value); if (v.userType() == callType) { - *((QVariant *)data) = v; + *((QVariant *)&data) = v; } else if (v.canConvert((QVariant::Type)callType)) { - *((QVariant *)data) = v; - ((QVariant *)data)->convert((QVariant::Type)callType); + *((QVariant *)&data) = v; + ((QVariant *)&data)->convert((QVariant::Type)callType); } else { - *((QVariant *)data) = QVariant(callType, (void *)0); + *((QVariant *)&data) = QVariant(callType, (void *)0); } } } @@ -671,23 +715,36 @@ QScriptDeclarativeClass::Value MetaCallArgument::toValue(QDeclarativeEngine *e) QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(e); if (type == qMetaTypeId<QScriptValue>()) { - return QScriptDeclarativeClass::Value(engine, *((QScriptValue *)data)); + return QScriptDeclarativeClass::Value(engine, *((QScriptValue *)&data)); } else if (type == QMetaType::Int) { - return QScriptDeclarativeClass::Value(engine, *((int *)data)); + return QScriptDeclarativeClass::Value(engine, *((int *)&data)); } else if (type == QMetaType::UInt) { - return QScriptDeclarativeClass::Value(engine, *((uint *)data)); + return QScriptDeclarativeClass::Value(engine, *((uint *)&data)); } else if (type == QMetaType::Bool) { - return QScriptDeclarativeClass::Value(engine, *((bool *)data)); + return QScriptDeclarativeClass::Value(engine, *((bool *)&data)); } else if (type == QMetaType::Double) { - return QScriptDeclarativeClass::Value(engine, *((double *)data)); + return QScriptDeclarativeClass::Value(engine, *((double *)&data)); } else if (type == QMetaType::Float) { - return QScriptDeclarativeClass::Value(engine, *((float *)data)); + return QScriptDeclarativeClass::Value(engine, *((float *)&data)); } else if (type == QMetaType::QString) { - return QScriptDeclarativeClass::Value(engine, *((QString *)data)); + return QScriptDeclarativeClass::Value(engine, *((QString *)&data)); } else if (type == QMetaType::QObjectStar) { - return QScriptDeclarativeClass::Value(engine, QDeclarativeEnginePrivate::get(e)->objectClass->newQObject(*((QObject **)data))); + QObject *object = *((QObject **)&data); + QDeclarativeDeclarativeData::get(object, true)->setImplicitDestructible(); + QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(e); + return QScriptDeclarativeClass::Value(engine, priv->objectClass->newQObject(object)); + } else if (type == qMetaTypeId<QList<QObject *> >()) { + QList<QObject *> &list = *(QList<QObject *>*)&data; + QScriptValue rv = engine->newArray(list.count()); + QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(e); + for (int ii = 0; ii < list.count(); ++ii) { + QObject *object = list.at(ii); + QDeclarativeDeclarativeData::get(object, true)->setImplicitDestructible(); + rv.setProperty(ii, priv->objectClass->newQObject(object)); + } + return QScriptDeclarativeClass::Value(engine, rv); } else if (type == -1 || type == qMetaTypeId<QVariant>()) { - return QScriptDeclarativeClass::Value(engine, QDeclarativeEnginePrivate::get(e)->scriptValueFromVariant(*((QVariant *)data))); + return QScriptDeclarativeClass::Value(engine, QDeclarativeEnginePrivate::get(e)->scriptValueFromVariant(*((QVariant *)&data))); } else { return QScriptDeclarativeClass::Value(); } diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass_p.h b/src/declarative/qml/qdeclarativeobjectscriptclass_p.h index 04e760f..1f7d1c9 100644 --- a/src/declarative/qml/qdeclarativeobjectscriptclass_p.h +++ b/src/declarative/qml/qdeclarativeobjectscriptclass_p.h @@ -57,6 +57,7 @@ #include "qdeclarativetypenamecache_p.h" #include <private/qdeclarativescriptclass_p.h> +#include <QtScript/qscriptengine.h> QT_BEGIN_NAMESPACE @@ -99,6 +100,7 @@ public: ~QDeclarativeObjectScriptClass(); QScriptValue newQObject(QObject *, int type = QMetaType::QObjectStar); + QObject *toQObject(const QScriptValue &) const; int objectType(const QScriptValue &) const; @@ -118,6 +120,7 @@ public: void setProperty(QObject *, const Identifier &name, const QScriptValue &, QDeclarativeContext *evalContext = 0); virtual QStringList propertyNames(Object *); + virtual bool compare(Object *, Object *); protected: virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp index 6a08674..d916900 100644 --- a/src/declarative/qml/qdeclarativevme.cpp +++ b/src/declarative/qml/qdeclarativevme.cpp @@ -197,6 +197,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, QDeclarati QDeclarativeDeclarativeData *ddata = QDeclarativeDeclarativeData::get(o); Q_ASSERT(ddata); + ddata->setImplicitDestructible(); ddata->outerContext = ctxt; ddata->lineNumber = instr.line; ddata->columnNumber = instr.create.column; @@ -247,6 +248,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, QDeclarati QDeclarativeEngine::setContextForObject(qcomp, ctxt); QDeclarativeDeclarativeData *ddata = QDeclarativeDeclarativeData::get(qcomp); Q_ASSERT(ddata); + ddata->setImplicitDestructible(); ddata->outerContext = ctxt; ddata->lineNumber = instr.line; ddata->columnNumber = instr.create.column; |