#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) { if (context.file == NULL) return; 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