void contextGetProperty(QQmlContext_ *context, QString_ *name, DataValue *result) { QQmlContext *qcontext = reinterpret_cast<QQmlContext *>(context); const QString *qname = reinterpret_cast<QString *>(name); QVariant var = qcontext->contextProperty(*qname); packDataValue(&var, result); }
void objectFindChild(QObject_ *object, QString_ *name, DataValue *resultdv) { QObject *qobject = reinterpret_cast<QObject *>(object); QString *qname = reinterpret_cast<QString *>(name); QVariant var; QObject *result = qobject->findChild<QObject *>(*qname); if (result) { var.setValue(result); } packDataValue(&var, resultdv); }
int objectGetProperty(QObject_ *object, const char *name, DataValue *result) { QObject *qobject = reinterpret_cast<QObject *>(object); QVariant var = qobject->property(name); packDataValue(&var, result); if (!var.isValid() && qobject->metaObject()->indexOfProperty(name) == -1) { // TODO May have to check the dynamic property names too. return 0; } return 1; }
error *objectInvoke(QObject_ *object, const char *method, int methodLen, DataValue *resultdv, DataValue *paramsdv, int paramsLen) { QObject *qobject = reinterpret_cast<QObject *>(object); QVariant result; QVariant param[MaxParams]; QGenericArgument arg[MaxParams]; for (int i = 0; i < paramsLen; i++) { unpackDataValue(¶msdv[i], ¶m[i]); arg[i] = Q_ARG(QVariant, param[i]); } if (paramsLen > 10) { panicf("fix the parameter dispatching"); } const QMetaObject *metaObject = qobject->metaObject(); // Walk backwards so descendants have priority. for (int i = metaObject->methodCount()-1; i >= 0; i--) { QMetaMethod metaMethod = metaObject->method(i); QMetaMethod::MethodType methodType = metaMethod.methodType(); if (methodType == QMetaMethod::Method || methodType == QMetaMethod::Slot) { QByteArray name = metaMethod.name(); if (name.length() == methodLen && qstrncmp(name.constData(), method, methodLen) == 0) { if (metaMethod.parameterCount() < paramsLen) { // TODO Might continue looking to see if a different signal has the same name and enough arguments. return errorf("method \"%s\" has too few parameters for provided arguments", method); } bool ok; if (metaMethod.returnType() == QMetaType::Void) { ok = metaMethod.invoke(qobject, Qt::DirectConnection, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9]); } else { ok = metaMethod.invoke(qobject, Qt::DirectConnection, Q_RETURN_ARG(QVariant, result), arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9]); } if (!ok) { return errorf("invalid parameters to method \"%s\"", method); } packDataValue(&result, resultdv); return 0; } } } return errorf("object does not expose a method \"%s\"", method); }
int GoValueMetaObject::metaCall(QMetaObject::Call c, int idx, void **a) { //qWarning() << "GoValueMetaObject::metaCall" << c << idx; switch (c) { case QMetaObject::ReadProperty: case QMetaObject::WriteProperty: { // TODO Cache propertyOffset, methodOffset (and maybe qmlEngine) int propOffset = propertyOffset(); if (idx < propOffset) { return value->qt_metacall(c, idx, a); } GoMemberInfo *memberInfo = typeInfo->fields; for (int i = 0; i < typeInfo->fieldsLen; i++) { if (memberInfo->metaIndex == idx) { if (c == QMetaObject::ReadProperty) { DataValue result; hookGoValueReadField(qmlEngine(value), ref, memberInfo->reflectIndex, memberInfo->reflectGetIndex, memberInfo->reflectSetIndex, &result); if (memberInfo->memberType == DTListProperty) { if (result.dataType != DTListProperty) { panicf("reading DTListProperty field returned non-DTListProperty result"); } QQmlListProperty<QObject> *in = *reinterpret_cast<QQmlListProperty<QObject> **>(result.data); QQmlListProperty<QObject> *out = reinterpret_cast<QQmlListProperty<QObject> *>(a[0]); *out = *in; // TODO Could provide a single variable in the stack to ReadField instead. delete in; } else { QVariant *out = reinterpret_cast<QVariant *>(a[0]); unpackDataValue(&result, out); } } else { DataValue assign; QVariant *in = reinterpret_cast<QVariant *>(a[0]); packDataValue(in, &assign); hookGoValueWriteField(qmlEngine(value), ref, memberInfo->reflectIndex, memberInfo->reflectSetIndex, &assign); activate(value, methodOffset() + (idx - propOffset), 0); } return -1; } memberInfo++; } QMetaProperty prop = property(idx); qWarning() << "Property" << prop.name() << "not found!?"; break; } case QMetaObject::InvokeMetaMethod: { if (idx < methodOffset()) { return value->qt_metacall(c, idx, a); } GoMemberInfo *memberInfo = typeInfo->methods; for (int i = 0; i < typeInfo->methodsLen; i++) { if (memberInfo->metaIndex == idx) { // args[0] is the result if any. DataValue args[1 + MaxParams]; for (int i = 1; i < memberInfo->numIn+1; i++) { packDataValue(reinterpret_cast<QVariant *>(a[i]), &args[i]); } hookGoValueCallMethod(qmlEngine(value), ref, memberInfo->reflectIndex, args); if (memberInfo->numOut > 0) { unpackDataValue(&args[0], reinterpret_cast<QVariant *>(a[0])); } return -1; } memberInfo++; } QMetaMethod m = method(idx); qWarning() << "Method" << m.name() << "not found!?"; break; } default: break; // Unhandled. } return -1; }
void packDataValue(QVariant_ *var, DataValue *value) { QVariant *qvar = reinterpret_cast<QVariant *>(var); // Some assumptions are made below regarding the size of types. // There's apparently no better way to handle this since that's // how the types with well defined sizes (qint64) are mapped to // meta-types (QMetaType::LongLong). switch ((int)qvar->type()) { case QVariant::Invalid: value->dataType = DTInvalid; break; case QMetaType::QUrl: *qvar = qvar->value<QUrl>().toString(); // fallthrough case QMetaType::QString: { value->dataType = DTString; QByteArray ba = qvar->toByteArray(); *(char**)(value->data) = local_strdup(ba.constData()); value->len = ba.size(); break; } case QMetaType::Bool: value->dataType = DTBool; *(qint8*)(value->data) = (qint8)qvar->toInt(); break; case QMetaType::LongLong: // Some of these entries will have to be fixed when handling platforms // where sizeof(long long) != 8 or sizeof(int) != 4. value->dataType = DTInt64; *(qint64*)(value->data) = qvar->toLongLong(); break; case QMetaType::ULongLong: value->dataType = DTUint64; *(quint64*)(value->data) = qvar->toLongLong(); break; case QMetaType::Int: value->dataType = DTInt32; *(qint32*)(value->data) = qvar->toInt(); break; case QMetaType::UInt: value->dataType = DTUint32; *(quint32*)(value->data) = qvar->toUInt(); break; case QMetaType::VoidStar: value->dataType = DTUintptr; *(uintptr_t*)(value->data) = (uintptr_t)qvar->value<void *>(); break; case QMetaType::Double: value->dataType = DTFloat64; *(double*)(value->data) = qvar->toDouble(); break; case QMetaType::Float: value->dataType = DTFloat32; *(float*)(value->data) = qvar->toFloat(); break; case QMetaType::QColor: value->dataType = DTColor; *(unsigned int*)(value->data) = qvar->value<QColor>().rgba(); break; case QMetaType::QVariantList: { QVariantList varlist = qvar->toList(); int len = varlist.size(); DataValue *dvlist = (DataValue *) malloc(sizeof(DataValue) * len); for (int i = 0; i < len; i++) { packDataValue((void*)&varlist.at(i), &dvlist[i]); } value->dataType = DTValueList; value->len = len; *(DataValue**)(value->data) = dvlist; } break; case QMetaType::QVariantMap: { QVariantMap varmap = qvar->toMap(); int len = varmap.size() * 2; DataValue *dvlist = (DataValue *) malloc(sizeof(DataValue) * len); QMapIterator<QString, QVariant> it(varmap); for (int i = 0; i < len; i += 2) { if (!it.hasNext()) { panicf("QVariantMap mutated during iteration"); } it.next(); QVariant key = it.key(); QVariant val = it.value(); packDataValue((void*)&key, &dvlist[i]); packDataValue((void*)&val, &dvlist[i+1]); } value->dataType = DTValueMap; value->len = len; *(DataValue**)(value->data) = dvlist; } break; default: if (qvar->type() == (int)QMetaType::QObjectStar || qvar->canConvert<QObject *>()) { QObject *qobject = qvar->value<QObject *>(); GoValue *goValue = dynamic_cast<GoValue *>(qobject); if (goValue) { value->dataType = DTGoAddr; *(void **)(value->data) = goValue->addr; break; } GoPaintedValue *goPaintedValue = dynamic_cast<GoPaintedValue *>(qobject); if (goPaintedValue) { value->dataType = DTGoAddr; *(void **)(value->data) = goPaintedValue->addr; break; } value->dataType = DTObject; *(void **)(value->data) = qobject; break; } { QQmlListReference ref = qvar->value<QQmlListReference>(); if (ref.isValid() && ref.canCount() && ref.canAt()) { int len = ref.count(); DataValue *dvlist = (DataValue *) malloc(sizeof(DataValue) * len); QVariant elem; for (int i = 0; i < len; i++) { elem.setValue(ref.at(i)); packDataValue(&elem, &dvlist[i]); } value->dataType = DTValueList; value->len = len; *(DataValue**)(value->data) = dvlist; break; } } if (qstrncmp(qvar->typeName(), "QQmlListProperty<", 17) == 0) { QQmlListProperty<QObject> *list = reinterpret_cast<QQmlListProperty<QObject>*>(qvar->data()); if (list->count && list->at) { int len = list->count(list); DataValue *dvlist = (DataValue *) malloc(sizeof(DataValue) * len); QVariant elem; for (int i = 0; i < len; i++) { elem.setValue(list->at(list, i)); packDataValue(&elem, &dvlist[i]); } value->dataType = DTValueList; value->len = len; *(DataValue**)(value->data) = dvlist; break; } } panicf("unsupported variant type: %d (%s)", qvar->type(), qvar->typeName()); break; } }
int GoValueMetaObject::metaCall(QMetaObject::Call c, int idx, void **a) { switch (c) { case QMetaObject::ReadProperty: case QMetaObject::WriteProperty: { // TODO Cache propertyOffset, methodOffset, and qmlEngine results? if (idx < propertyOffset()) { return value->qt_metacall(c, idx, a); } GoMemberInfo *memberInfo = valuePriv->typeInfo->fields; for (int i = 0; i < valuePriv->typeInfo->fieldsLen; i++) { if (memberInfo->metaIndex == idx) { if (c == QMetaObject::ReadProperty) { DataValue result; hookGoValueReadField(qmlEngine(value), valuePriv->addr, memberInfo->reflectIndex, &result); QVariant *out = reinterpret_cast<QVariant *>(a[0]); unpackDataValue(&result, out); } else { DataValue assign; QVariant *in = reinterpret_cast<QVariant *>(a[0]); packDataValue(in, &assign); hookGoValueWriteField(qmlEngine(value), valuePriv->addr, memberInfo->reflectIndex, &assign); } return -1; } memberInfo++; } QMetaProperty prop = property(idx); qWarning() << "Property" << prop.name() << "not found!?"; break; } case QMetaObject::InvokeMetaMethod: { if (idx < methodOffset()) { return value->qt_metacall(c, idx, a); } GoMemberInfo *memberInfo = valuePriv->typeInfo->methods; for (int i = 0; i < valuePriv->typeInfo->methodsLen; i++) { if (memberInfo->metaIndex == idx) { // args[0] is the result if any. DataValue args[1 + MaxParams]; for (int i = 1; i < memberInfo->numIn+1; i++) { packDataValue(reinterpret_cast<QVariant *>(a[i]), &args[i]); } hookGoValueCallMethod(qmlEngine(value), valuePriv->addr, memberInfo->reflectIndex, args); if (memberInfo->numOut > 0) { unpackDataValue(&args[0], reinterpret_cast<QVariant *>(a[0])); } return -1; } memberInfo++; } QMetaMethod m = method(idx); qWarning() << "Method" << m.name() << "not found!?"; break; } default: break; // Unhandled. } return -1; }
void packDataValue(QVariant_ *var, DataValue *value) { QVariant *qvar = reinterpret_cast<QVariant *>(var); // Some assumptions are made below regarding the size of types. // There's apparently no better way to handle this since that's // how the types with well defined sizes (qint64) are mapped to // meta-types (QMetaType::LongLong). switch ((int)qvar->type()) { case QVariant::Invalid: value->dataType = DTInvalid; break; case QMetaType::QUrl: *qvar = qvar->value<QUrl>().toString(); // fallthrough case QMetaType::QString: { value->dataType = DTString; QByteArray ba = qvar->toByteArray(); *(char**)(value->data) = local_strdup(ba.constData()); value->len = ba.size(); break; } case QMetaType::Bool: value->dataType = DTBool; *(qint8*)(value->data) = (qint8)qvar->toInt(); break; case QMetaType::LongLong: value->dataType = DTInt64; *(qint64*)(value->data) = qvar->toLongLong(); break; case QMetaType::Int: value->dataType = DTInt32; *(qint32*)(value->data) = qvar->toInt(); break; case QMetaType::Double: value->dataType = DTFloat64; *(double*)(value->data) = qvar->toDouble(); break; case QMetaType::Float: value->dataType = DTFloat32; *(float*)(value->data) = qvar->toFloat(); break; case QMetaType::QColor: value->dataType = DTColor; *(unsigned int*)(value->data) = qvar->value<QColor>().rgba(); break; case QMetaType::QVariantList: { QVariantList varlist = qvar->toList(); int len = varlist.size(); DataValue *dvlist = (DataValue *) malloc(sizeof(DataValue) * len); for (int i = 0; i < len; i++) { packDataValue((void*)&varlist.at(i), &dvlist[i]); } value->dataType = DTList; value->len = len; *(DataValue**)(value->data) = dvlist; } break; default: if (qvar->type() == (int)QMetaType::QObjectStar || qvar->canConvert<QObject *>()) { QObject *qobject = qvar->value<QObject *>(); GoValue *govalue = dynamic_cast<GoValue *>(qobject); if (govalue) { value->dataType = DTGoAddr; *(void **)(value->data) = govalue->addr; } else { value->dataType = DTObject; *(void **)(value->data) = qobject; } break; } if (qstrncmp(qvar->typeName(), "QQmlListProperty<", 17) == 0) { QQmlListProperty<QObject> *list = reinterpret_cast<QQmlListProperty<QObject>*>(qvar->data()); if (list->count && list->at) { int len = list->count(list); DataValue *dvlist = (DataValue *) malloc(sizeof(DataValue) * len); QVariant elem; for (int i = 0; i < len; i++) { elem.setValue(list->at(list, i)); packDataValue(&elem, &dvlist[i]); } value->dataType = DTList; value->len = len; *(DataValue**)(value->data) = dvlist; break; } } panicf("unsupported variant type: %d (%s)", qvar->type(), qvar->typeName()); break; } }