aboutsummaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/obscuren/qml/cpp/capi.cpp
diff options
context:
space:
mode:
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.cpp882
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(&paramsdv[i], &param[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