diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2012-05-11 14:13:47 +0100 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-05-11 17:23:20 +0200 |
commit | 5570040771ec610583473e2d9e8e069474364cf1 (patch) | |
tree | cb3b406776731996783cdcab3704a2338b944b11 /src/qml/qml/qqmlengine.cpp | |
parent | 125f4ceb393886015574a3c3fd0fc264a4f2deb6 (diff) |
Permit signals to be emitted in a different thread
The QQmlNotifier approach to connecting to signals did not
support the cross-thread signal/slot model used elsewhere in
Qt. This change allows one specific case of that - emitting
a signal in a different thread than the one the QObject
lives - to work.
Task-number: QTBUG-25647
Change-Id: Ia8fdaf4c7d7e2ccd7ff7657bb1d8e26277eb60aa
Reviewed-by: Aaron Kennedy <aaron.kennedy@nokia.com>
Diffstat (limited to 'src/qml/qml/qqmlengine.cpp')
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 49 |
1 files changed, 47 insertions, 2 deletions
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index b6a306085e..f948c31352 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -80,6 +80,8 @@ #include <QtCore/qcoreapplication.h> #include <QtCore/qdir.h> #include <QtCore/qmutex.h> +#include <QtCore/qthread.h> +#include <private/qthread_p.h> #include <QtNetwork/qnetworkconfigmanager.h> #include <private/qobject_p.h> @@ -470,8 +472,51 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in QQmlData *ddata = QQmlData::get(object, false); if (!ddata) return; // Probably being deleted - QQmlNotifierEndpoint *ep = ddata->notify(index); - if (ep) QQmlNotifier::emitNotify(ep, a); + // In general, QML only supports QObject's that live on the same thread as the QQmlEngine + // that they're exposed to. However, to make writing "worker objects" that calculate data + // in a separate thread easier, QML allows a QObject that lives in the same thread as the + // QQmlEngine to emit signals from a different thread. These signals are then automatically + // marshalled back onto the QObject's thread and handled by QML from there. This is tested + // by the qqmlecmascript::threadSignal() autotest. + if (ddata->notifyList && + QThread::currentThreadId() != QObjectPrivate::get(object)->threadData->threadId) { + + QMetaMethod m = object->metaObject()->method(index); + QList<QByteArray> parameterTypes = m.parameterTypes(); + + int *types = (int *)malloc((parameterTypes.count() + 1) * sizeof(int)); + void **args = (void **) malloc((parameterTypes.count() + 1) *sizeof(void *)); + + types[0] = 0; // return type + args[0] = 0; // return value + + for (int ii = 0; ii < parameterTypes.count(); ++ii) { + const QByteArray &typeName = parameterTypes.at(ii); + if (typeName.endsWith('*')) + types[ii + 1] = QMetaType::VoidStar; + else + types[ii + 1] = QMetaType::type(typeName); + + if (!types[ii + 1]) { + qWarning("QObject::connect: Cannot queue arguments of type '%s'\n" + "(Make sure '%s' is registered using qRegisterMetaType().)", + typeName.constData(), typeName.constData()); + free(types); + free(args); + return; + } + + args[ii + 1] = QMetaType::create(types[ii + 1], a[ii + 1]); + } + + QMetaCallEvent *ev = new QMetaCallEvent(index, 0, 0, object, index, + parameterTypes.count() + 1, types, args); + QCoreApplication::postEvent(object, ev); + + } else { + QQmlNotifierEndpoint *ep = ddata->notify(index); + if (ep) QQmlNotifier::emitNotify(ep, a); + } } int QQmlData::receivers(QAbstractDeclarativeData *d, const QObject *, int index) |