diff options
Diffstat (limited to 'Godeps/_workspace/src/github.com/obscuren/qml/cpp/capi.cpp')
-rw-r--r-- | Godeps/_workspace/src/github.com/obscuren/qml/cpp/capi.cpp | 882 |
1 files changed, 882 insertions, 0 deletions
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/capi.cpp b/Godeps/_workspace/src/github.com/obscuren/qml/cpp/capi.cpp new file mode 100644 index 000000000..c2255aaae --- /dev/null +++ b/Godeps/_workspace/src/github.com/obscuren/qml/cpp/capi.cpp @@ -0,0 +1,882 @@ +#include <QApplication> +#include <QQuickView> +#include <QQuickItem> +#include <QtQml> +#include <QDebug> +#include <QQuickImageProvider> + +#include <string.h> + +#include "govalue.h" +#include "govaluetype.h" +#include "connector.h" +#include "capi.h" + +static char *local_strdup(const char *str) +{ + char *strcopy = 0; + if (str) { + size_t len = strlen(str) + 1; + strcopy = (char *)malloc(len); + memcpy(strcopy, str, len); + } + return strcopy; +} + +error *errorf(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + QString str = QString().vsprintf(format, ap); + va_end(ap); + QByteArray ba = str.toUtf8(); + return local_strdup(ba.constData()); +} + +void panicf(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + QString str = QString().vsprintf(format, ap); + va_end(ap); + QByteArray ba = str.toUtf8(); + hookPanic(local_strdup(ba.constData())); +} + +void newGuiApplication() +{ + static char empty[1] = {0}; + static char *argv[] = {empty, 0}; + static int argc = 1; + new QApplication(argc, argv); + + // The event loop should never die. + qApp->setQuitOnLastWindowClosed(false); +} + +void applicationExec() +{ + qApp->exec(); +} + +void applicationExit() +{ + qApp->exit(0); +} + +void applicationFlushAll() +{ + qApp->processEvents(); +} + +void *currentThread() +{ + return QThread::currentThread(); +} + +void *appThread() +{ + return QCoreApplication::instance()->thread(); +} + +QQmlEngine_ *newEngine(QObject_ *parent) +{ + return new QQmlEngine(reinterpret_cast<QObject *>(parent)); +} + +QQmlContext_ *engineRootContext(QQmlEngine_ *engine) +{ + return reinterpret_cast<QQmlEngine *>(engine)->rootContext(); +} + +void engineSetContextForObject(QQmlEngine_ *engine, QObject_ *object) +{ + QQmlEngine *qengine = reinterpret_cast<QQmlEngine *>(engine); + QObject *qobject = reinterpret_cast<QObject *>(object); + + QQmlEngine::setContextForObject(qobject, qengine->rootContext()); +} + +void engineSetOwnershipCPP(QQmlEngine_ *engine, QObject_ *object) +{ + QQmlEngine *qengine = reinterpret_cast<QQmlEngine *>(engine); + QObject *qobject = reinterpret_cast<QObject *>(object); + + qengine->setObjectOwnership(qobject, QQmlEngine::CppOwnership); +} + +void engineSetOwnershipJS(QQmlEngine_ *engine, QObject_ *object) +{ + QQmlEngine *qengine = reinterpret_cast<QQmlEngine *>(engine); + QObject *qobject = reinterpret_cast<QObject *>(object); + + qengine->setObjectOwnership(qobject, QQmlEngine::JavaScriptOwnership); +} + +QQmlComponent_ *newComponent(QQmlEngine_ *engine, QObject_ *parent) +{ + QQmlEngine *qengine = reinterpret_cast<QQmlEngine *>(engine); + //QObject *qparent = reinterpret_cast<QObject *>(parent); + QQmlComponent *qcomponent = new QQmlComponent(qengine); + // Qt 5.2.0 returns NULL on qmlEngine(qcomponent) without this. + QQmlEngine::setContextForObject(qcomponent, qengine->rootContext()); + return qcomponent; +} + +class GoImageProvider : public QQuickImageProvider { + + // TODO Destroy this when engine is destroyed. + + public: + + GoImageProvider(void *imageFunc) : QQuickImageProvider(QQmlImageProviderBase::Image), imageFunc(imageFunc) {}; + + virtual QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) + { + QByteArray ba = id.toUtf8(); + int width = 0, height = 0; + if (requestedSize.isValid()) { + width = requestedSize.width(); + height = requestedSize.height(); + } + QImage *ptr = reinterpret_cast<QImage *>(hookRequestImage(imageFunc, (char*)ba.constData(), ba.size(), width, height)); + QImage image = *ptr; + delete ptr; + + *size = image.size(); + if (requestedSize.isValid() && requestedSize != *size) { + image = image.scaled(requestedSize, Qt::KeepAspectRatio); + } + return image; + }; + + private: + + void *imageFunc; +}; + +void engineAddImageProvider(QQmlEngine_ *engine, QString_ *providerId, void *imageFunc) +{ + QQmlEngine *qengine = reinterpret_cast<QQmlEngine *>(engine); + QString *qproviderId = reinterpret_cast<QString *>(providerId); + + qengine->addImageProvider(*qproviderId, new GoImageProvider(imageFunc)); +} + +void componentLoadURL(QQmlComponent_ *component, const char *url, int urlLen) +{ + QByteArray qurl(url, urlLen); + QString qsurl = QString::fromUtf8(qurl); + reinterpret_cast<QQmlComponent *>(component)->loadUrl(qsurl); +} + +void componentSetData(QQmlComponent_ *component, const char *data, int dataLen, const char *url, int urlLen) +{ + QByteArray qdata(data, dataLen); + QByteArray qurl(url, urlLen); + QString qsurl = QString::fromUtf8(qurl); + reinterpret_cast<QQmlComponent *>(component)->setData(qdata, qsurl); +} + +char *componentErrorString(QQmlComponent_ *component) +{ + QQmlComponent *qcomponent = reinterpret_cast<QQmlComponent *>(component); + if (qcomponent->isReady()) { + return NULL; + } + if (qcomponent->isError()) { + QByteArray ba = qcomponent->errorString().toUtf8(); + return local_strdup(ba.constData()); + } + return local_strdup("component is not ready (why!?)"); +} + +QObject_ *componentCreate(QQmlComponent_ *component, QQmlContext_ *context) +{ + QQmlComponent *qcomponent = reinterpret_cast<QQmlComponent *>(component); + QQmlContext *qcontext = reinterpret_cast<QQmlContext *>(context); + + if (!qcontext) { + qcontext = qmlContext(qcomponent); + } + return qcomponent->create(qcontext); +} + +QQuickWindow_ *componentCreateWindow(QQmlComponent_ *component, QQmlContext_ *context) +{ + QQmlComponent *qcomponent = reinterpret_cast<QQmlComponent *>(component); + QQmlContext *qcontext = reinterpret_cast<QQmlContext *>(context); + + if (!qcontext) { + qcontext = qmlContext(qcomponent); + } + QObject *obj = qcomponent->create(qcontext); + if (!objectIsWindow(obj)) { + QQuickView *view = new QQuickView(qmlEngine(qcomponent), 0); + view->setContent(qcomponent->url(), qcomponent, obj); + view->setResizeMode(QQuickView::SizeRootObjectToView); + obj = view; + } + return obj; +} + +// Workaround for bug https://bugs.launchpad.net/bugs/1179716 +struct DoShowWindow : public QQuickWindow { + void show() { + QQuickWindow::show(); + QResizeEvent resize(size(), size()); + resizeEvent(&resize); + } +}; + +void windowShow(QQuickWindow_ *win) +{ + reinterpret_cast<DoShowWindow *>(win)->show(); +} + +void windowHide(QQuickWindow_ *win) +{ + reinterpret_cast<QQuickWindow *>(win)->hide(); +} + +uintptr_t windowPlatformId(QQuickWindow_ *win) +{ + return reinterpret_cast<QQuickWindow *>(win)->winId(); +} + +void windowConnectHidden(QQuickWindow_ *win) +{ + QQuickWindow *qwin = reinterpret_cast<QQuickWindow *>(win); + QObject::connect(qwin, &QWindow::visibleChanged, [=](bool visible){ + if (!visible) { + hookWindowHidden(win); + } + }); +} + +QObject_ *windowRootObject(QQuickWindow_ *win) +{ + if (objectIsView(win)) { + return reinterpret_cast<QQuickView *>(win)->rootObject(); + } + return win; +} + +QImage_ *windowGrabWindow(QQuickWindow_ *win) +{ + QQuickWindow *qwin = reinterpret_cast<QQuickWindow *>(win); + QImage *image = new QImage; + *image = qwin->grabWindow().convertToFormat(QImage::Format_ARGB32_Premultiplied); + return image; +} + +QImage_ *newImage(int width, int height) +{ + return new QImage(width, height, QImage::Format_ARGB32_Premultiplied); +} + +void delImage(QImage_ *image) +{ + delete reinterpret_cast<QImage *>(image); +} + +void imageSize(QImage_ *image, int *width, int *height) +{ + QImage *qimage = reinterpret_cast<QImage *>(image); + *width = qimage->width(); + *height = qimage->height(); +} + +unsigned char *imageBits(QImage_ *image) +{ + QImage *qimage = reinterpret_cast<QImage *>(image); + return qimage->bits(); +} + +const unsigned char *imageConstBits(QImage_ *image) +{ + QImage *qimage = reinterpret_cast<QImage *>(image); + return qimage->constBits(); +} + +void contextSetObject(QQmlContext_ *context, QObject_ *value) +{ + QQmlContext *qcontext = reinterpret_cast<QQmlContext *>(context); + QObject *qvalue = reinterpret_cast<QObject *>(value); + + // Give qvalue an engine reference if it doesn't yet have one. + if (!qmlEngine(qvalue)) { + QQmlEngine::setContextForObject(qvalue, qcontext->engine()->rootContext()); + } + + qcontext->setContextObject(qvalue); +} + +void contextSetProperty(QQmlContext_ *context, QString_ *name, DataValue *value) +{ + const QString *qname = reinterpret_cast<QString *>(name); + QQmlContext *qcontext = reinterpret_cast<QQmlContext *>(context); + + QVariant var; + unpackDataValue(value, &var); + + // Give qvalue an engine reference if it doesn't yet have one . + QObject *obj = var.value<QObject *>(); + if (obj && !qmlEngine(obj)) { + QQmlEngine::setContextForObject(obj, qcontext); + } + + qcontext->setContextProperty(*qname, var); +} + +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); +} + +QQmlContext_ *contextSpawn(QQmlContext_ *context) +{ + QQmlContext *qcontext = reinterpret_cast<QQmlContext *>(context); + return new QQmlContext(qcontext); +} + +void delObject(QObject_ *object) +{ + delete reinterpret_cast<QObject *>(object); +} + +void delObjectLater(QObject_ *object) +{ + reinterpret_cast<QObject *>(object)->deleteLater(); +} + +const char *objectTypeName(QObject_ *object) +{ + return reinterpret_cast<QObject *>(object)->metaObject()->className(); +} + +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 *objectSetProperty(QObject_ *object, const char *name, DataValue *value) +{ + QObject *qobject = reinterpret_cast<QObject *>(object); + QVariant var; + unpackDataValue(value, &var); + + // Give qvalue an engine reference if it doesn't yet have one. + QObject *obj = var.value<QObject *>(); + if (obj && !qmlEngine(obj)) { + QQmlContext *context = qmlContext(qobject); + if (context) { + QQmlEngine::setContextForObject(obj, context); + } + } + + // Check that the types are compatible. There's probably more to be done here. + const QMetaObject *metaObject = qobject->metaObject(); + int propIndex = metaObject->indexOfProperty(name); + if (propIndex == -1) { + return errorf("cannot set non-existent property \"%s\" on type %s", name, qobject->metaObject()->className()); + } + + QMetaProperty prop = metaObject->property(propIndex); + int propType = prop.userType(); + void *valueArg; + if (propType == QMetaType::QVariant) { + valueArg = (void *)&var; + } else { + int varType = var.userType(); + QVariant saved = var; + if (propType != varType && !var.convert(propType)) { + if (varType == QMetaType::QObjectStar) { + return errorf("cannot set property \"%s\" with type %s to value of %s*", + name, QMetaType::typeName(propType), saved.value<QObject*>()->metaObject()->className()); + } else { + return errorf("cannot set property \"%s\" with type %s to value of %s", + name, QMetaType::typeName(propType), QMetaType::typeName(varType)); + } + } + valueArg = (void *)var.constData(); + } + + int status = -1; + int flags = 0; + void *args[] = {valueArg, 0, &status, &flags}; + QMetaObject::metacall(qobject, QMetaObject::WriteProperty, propIndex, args); + return 0; +} + +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); +} + +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); +} + +void objectSetParent(QObject_ *object, QObject_ *parent) +{ + QObject *qobject = reinterpret_cast<QObject *>(object); + QObject *qparent = reinterpret_cast<QObject *>(parent); + + qobject->setParent(qparent); +} + +error *objectConnect(QObject_ *object, const char *signal, int signalLen, QQmlEngine_ *engine, void *func, int argsLen) +{ + QObject *qobject = reinterpret_cast<QObject *>(object); + QQmlEngine *qengine = reinterpret_cast<QQmlEngine *>(engine); + QByteArray qsignal(signal, signalLen); + + const QMetaObject *meta = qobject->metaObject(); + // Walk backwards so descendants have priority. + for (int i = meta->methodCount()-1; i >= 0; i--) { + QMetaMethod method = meta->method(i); + if (method.methodType() == QMetaMethod::Signal) { + QByteArray name = method.name(); + if (name.length() == signalLen && qstrncmp(name.constData(), signal, signalLen) == 0) { + if (method.parameterCount() < argsLen) { + // TODO Might continue looking to see if a different signal has the same name and enough arguments. + return errorf("signal \"%s\" has too few parameters for provided function", name.constData()); + } + Connector *connector = new Connector(qobject, method, qengine, func, argsLen); + const QMetaObject *connmeta = connector->metaObject(); + QObject::connect(qobject, method, connector, connmeta->method(connmeta->methodOffset())); + return 0; + } + } + } + // Cannot use constData here as the byte array is not null-terminated. + return errorf("object does not expose a \"%s\" signal", qsignal.data()); +} + +QQmlContext_ *objectContext(QObject_ *object) +{ + return qmlContext(static_cast<QObject *>(object)); +} + +int objectIsComponent(QObject_ *object) +{ + QObject *qobject = static_cast<QObject *>(object); + return dynamic_cast<QQmlComponent *>(qobject) ? 1 : 0; +} + +int objectIsWindow(QObject_ *object) +{ + QObject *qobject = static_cast<QObject *>(object); + return dynamic_cast<QQuickWindow *>(qobject) ? 1 : 0; +} + +int objectIsView(QObject_ *object) +{ + QObject *qobject = static_cast<QObject *>(object); + return dynamic_cast<QQuickView *>(qobject) ? 1 : 0; +} + +error *objectGoAddr(QObject_ *object, GoAddr **addr) +{ + QObject *qobject = static_cast<QObject *>(object); + GoValue *goValue = dynamic_cast<GoValue *>(qobject); + if (goValue) { + *addr = goValue->addr; + return 0; + } + GoPaintedValue *goPaintedValue = dynamic_cast<GoPaintedValue *>(qobject); + if (goPaintedValue) { + *addr = goPaintedValue->addr; + return 0; + } + return errorf("QML object is not backed by a Go value"); +} + +QString_ *newString(const char *data, int len) +{ + // This will copy data only once. + QByteArray ba = QByteArray::fromRawData(data, len); + return new QString(ba); +} + +void delString(QString_ *s) +{ + delete reinterpret_cast<QString *>(s); +} + +GoValue_ *newGoValue(GoAddr *addr, GoTypeInfo *typeInfo, QObject_ *parent) +{ + QObject *qparent = reinterpret_cast<QObject *>(parent); + if (typeInfo->paint) { + return new GoPaintedValue(addr, typeInfo, qparent); + } + return new GoValue(addr, typeInfo, qparent); +} + +void goValueActivate(GoValue_ *value, GoTypeInfo *typeInfo, int addrOffset) +{ + GoMemberInfo *fieldInfo = typeInfo->fields; + for (int i = 0; i < typeInfo->fieldsLen; i++) { + if (fieldInfo->addrOffset == addrOffset) { + if (typeInfo->paint) { + static_cast<GoPaintedValue *>(value)->activate(fieldInfo->metaIndex); + } else { + static_cast<GoValue *>(value)->activate(fieldInfo->metaIndex); + } + return; + } + fieldInfo++; + } + + // TODO Return an error; probably an unexported field. +} + +void unpackDataValue(DataValue *value, QVariant_ *var) +{ + QVariant *qvar = reinterpret_cast<QVariant *>(var); + switch (value->dataType) { + case DTString: + *qvar = QString::fromUtf8(*(char **)value->data, value->len); + break; + case DTBool: + *qvar = bool(*(char *)(value->data) != 0); + break; + case DTInt64: + *qvar = *(qint64*)(value->data); + break; + case DTInt32: + *qvar = *(qint32*)(value->data); + break; + case DTUint64: + *qvar = *(quint64*)(value->data); + break; + case DTUint32: + *qvar = *(quint32*)(value->data); + break; + case DTFloat64: + *qvar = *(double*)(value->data); + break; + case DTFloat32: + *qvar = *(float*)(value->data); + break; + case DTColor: + *qvar = QColor::fromRgba(*(QRgb*)(value->data)); + break; + case DTVariantList: + *qvar = **(QVariantList**)(value->data); + delete *(QVariantList**)(value->data); + break; + case DTObject: + qvar->setValue(*(QObject**)(value->data)); + break; + case DTInvalid: + // null would be more natural, but an invalid variant means + // it has proper semantics when dealing with non-qml qt code. + //qvar->setValue(QJSValue(QJSValue::NullValue)); + qvar->clear(); + break; + default: + panicf("unknown data type: %d", value->dataType); + break; + } +} + +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; + case QMetaType::User: + { + static const int qjstype = QVariant::fromValue(QJSValue()).userType(); + if (qvar->userType() == qjstype) { + auto var = qvar->value<QJSValue>().toVariant(); + packDataValue(&var, value); + } + } + 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; + } +} + +QVariantList_ *newVariantList(DataValue *list, int len) +{ + QVariantList *vlist = new QVariantList(); + vlist->reserve(len); + for (int i = 0; i < len; i++) { + QVariant var; + unpackDataValue(&list[i], &var); + vlist->append(var); + } + return vlist; +} + +QObject *listPropertyAt(QQmlListProperty<QObject> *list, int i) +{ + return reinterpret_cast<QObject *>(hookListPropertyAt(list->data, (intptr_t)list->dummy1, (intptr_t)list->dummy2, i)); +} + +int listPropertyCount(QQmlListProperty<QObject> *list) +{ + return hookListPropertyCount(list->data, (intptr_t)list->dummy1, (intptr_t)list->dummy2); +} + +void listPropertyAppend(QQmlListProperty<QObject> *list, QObject *obj) +{ + hookListPropertyAppend(list->data, (intptr_t)list->dummy1, (intptr_t)list->dummy2, obj); +} + +void listPropertyClear(QQmlListProperty<QObject> *list) +{ + hookListPropertyClear(list->data, (intptr_t)list->dummy1, (intptr_t)list->dummy2); +} + +QQmlListProperty_ *newListProperty(GoAddr *addr, intptr_t reflectIndex, intptr_t setIndex) +{ + QQmlListProperty<QObject> *list = new QQmlListProperty<QObject>(); + list->data = addr; + list->dummy1 = (void*)reflectIndex; + list->dummy2 = (void*)setIndex; + list->at = listPropertyAt; + list->count = listPropertyCount; + list->append = listPropertyAppend; + list->clear = listPropertyClear; + return list; +} + +void internalLogHandler(QtMsgType severity, const QMessageLogContext &context, const QString &text) +{ + QByteArray textba = text.toUtf8(); + LogMessage message = {severity, textba.constData(), textba.size(), context.file, (int)strlen(context.file), context.line}; + hookLogHandler(&message); +} + +void installLogHandler() +{ + qInstallMessageHandler(internalLogHandler); +} + + +extern bool qRegisterResourceData(int version, const unsigned char *tree, const unsigned char *name, const unsigned char *data); +extern bool qUnregisterResourceData(int version, const unsigned char *tree, const unsigned char *name, const unsigned char *data); + +void registerResourceData(int version, char *tree, char *name, char *data) +{ + qRegisterResourceData(version, (unsigned char*)tree, (unsigned char*)name, (unsigned char*)data); +} + +void unregisterResourceData(int version, char *tree, char *name, char *data) +{ + qUnregisterResourceData(version, (unsigned char*)tree, (unsigned char*)name, (unsigned char*)data); +} + +// vim:ts=4:sw=4:et:ft=cpp |