aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside2/libpyside/signalmanager.cpp.in
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside2/libpyside/signalmanager.cpp.in')
-rw-r--r--sources/pyside2/libpyside/signalmanager.cpp.in726
1 files changed, 726 insertions, 0 deletions
diff --git a/sources/pyside2/libpyside/signalmanager.cpp.in b/sources/pyside2/libpyside/signalmanager.cpp.in
new file mode 100644
index 000000000..473057cbc
--- /dev/null
+++ b/sources/pyside2/libpyside/signalmanager.cpp.in
@@ -0,0 +1,726 @@
+// -*- mode: cpp;-*-
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "signalmanager.h"
+#include "pysidesignal.h"
+#include "pysideproperty.h"
+#include "pysideproperty_p.h"
+#include "pyside.h"
+#include "dynamicqmetaobject.h"
+#include "pysidemetafunction_p.h"
+
+#include <QtCore>
+#include <QHash>
+#include <QStringList>
+#include <QMetaMethod>
+#include <autodecref.h>
+#include <gilstate.h>
+#include <QDebug>
+#include <limits>
+#include <algorithm>
+#include <typeresolver.h>
+#include <basewrapper.h>
+#include <sbkconverter.h>
+#include <conversions.h>
+
+// These private headers are needed to throw JavaScript exceptions
+#if @QML_PRIVATE_API_SUPPORT@
+ #include <private/qv4engine_p.h>
+ #include <private/qv4context_p.h>
+ #include <private/qqmldata_p.h>
+#if QT_VERSION < 0x050700
+ #include <private/qqmlcontextwrapper_p.h>
+#endif
+#endif
+
+#if QSLOT_CODE != 1 || QSIGNAL_CODE != 2
+#error QSLOT_CODE and/or QSIGNAL_CODE changed! change the hardcoded stuff to the correct value!
+#endif
+#define PYSIDE_SLOT '1'
+#define PYSIDE_SIGNAL '2'
+#include "globalreceiverv2.h"
+#include "globalreceiver.h"
+
+#define PYTHON_TYPE "PyObject"
+
+namespace {
+ static PyObject *metaObjectAttr = 0;
+
+ static int callMethod(QObject* object, int id, void** args);
+ static PyObject* parseArguments(const QList< QByteArray >& paramTypes, void** args);
+ static bool emitShortCircuitSignal(QObject* source, int signalIndex, PyObject* args);
+
+#ifdef IS_PY3K
+ static void destroyMetaObject(PyObject* obj)
+ {
+ void* ptr = PyCapsule_GetPointer(obj, 0);
+ PySide::DynamicQMetaObject* meta = reinterpret_cast<PySide::DynamicQMetaObject*>(ptr);
+ SbkObject* wrapper = Shiboken::BindingManager::instance().retrieveWrapper(meta);
+ if (wrapper)
+ Shiboken::BindingManager::instance().releaseWrapper(wrapper);
+ delete meta;
+ }
+
+#else
+ static void destroyMetaObject(void* obj)
+ {
+ PySide::DynamicQMetaObject* meta = reinterpret_cast<PySide::DynamicQMetaObject*>(obj);
+ SbkObject* wrapper = Shiboken::BindingManager::instance().retrieveWrapper(meta);
+ if (wrapper)
+ Shiboken::BindingManager::instance().releaseWrapper(wrapper);
+ delete meta;
+ }
+#endif
+}
+
+namespace PySide {
+
+
+PyObjectWrapper::PyObjectWrapper()
+ :m_me(Py_None)
+{
+ Py_INCREF(m_me);
+}
+
+PyObjectWrapper::PyObjectWrapper(PyObject* me)
+ : m_me(me)
+{
+ Py_INCREF(m_me);
+}
+
+PyObjectWrapper::PyObjectWrapper(const PyObjectWrapper &other)
+ : m_me(other.m_me)
+{
+ Py_INCREF(m_me);
+}
+
+PyObjectWrapper::~PyObjectWrapper()
+{
+ // Check that Python is still initialized as sometimes this is called by a static destructor
+ // after Python interpeter is shutdown.
+ if (!Py_IsInitialized())
+ return;
+
+ Shiboken::GilState gil;
+ Py_DECREF(m_me);
+}
+
+PyObjectWrapper& PyObjectWrapper::operator=(const PySide::PyObjectWrapper& other)
+{
+ Py_INCREF(other.m_me);
+ Py_DECREF(m_me);
+ m_me = other.m_me;
+ return *this;
+}
+
+PyObjectWrapper::operator PyObject*() const
+{
+ return m_me;
+}
+
+QDataStream &operator<<(QDataStream& out, const PyObjectWrapper& myObj)
+{
+ if (Py_IsInitialized() == 0) {
+ qWarning() << "Stream operator for PyObject called without python interpreter.";
+ return out;
+ }
+
+ static PyObject *reduce_func = 0;
+
+ Shiboken::GilState gil;
+ if (!reduce_func) {
+ Shiboken::AutoDecRef pickleModule(PyImport_ImportModule("pickle"));
+ reduce_func = PyObject_GetAttrString(pickleModule, "dumps");
+ }
+ Shiboken::AutoDecRef repr(PyObject_CallFunctionObjArgs(reduce_func, (PyObject*)myObj, NULL));
+ if (repr.object()) {
+ const char* buff = 0;
+ Py_ssize_t size = 0;
+ if (PyBytes_Check(repr.object())) {
+ buff = PyBytes_AS_STRING(repr.object());
+ size = PyBytes_GET_SIZE(repr.object());
+ } else if (Shiboken::String::check(repr.object())) {
+ buff = Shiboken::String::toCString(repr.object());
+ size = Shiboken::String::len(repr.object());
+ }
+ QByteArray data(buff, size);
+ out << data;
+ }
+ return out;
+}
+
+QDataStream &operator>>(QDataStream& in, PyObjectWrapper& myObj)
+{
+ if (Py_IsInitialized() == 0) {
+ qWarning() << "Stream operator for PyObject called without python interpreter.";
+ return in;
+ }
+
+ static PyObject *eval_func = 0;
+
+ Shiboken::GilState gil;
+ if (!eval_func) {
+ Shiboken::AutoDecRef pickleModule(PyImport_ImportModule("pickle"));
+ eval_func = PyObject_GetAttrString(pickleModule, "loads");
+ }
+
+ QByteArray repr;
+ in >> repr;
+ Shiboken::AutoDecRef pyCode(PyBytes_FromStringAndSize(repr.data(), repr.size()));
+ Shiboken::AutoDecRef value(PyObject_CallFunctionObjArgs(eval_func, pyCode.object(), 0));
+ if (!value.object()) {
+ value = Py_None;
+ }
+ myObj = PyObjectWrapper(value);
+ return in;
+}
+
+};
+
+namespace Shiboken {
+
+template<>
+struct Converter<PySide::PyObjectWrapper>
+{
+ static PySide::PyObjectWrapper toCpp(PyObject* obj)
+ {
+ return PySide::PyObjectWrapper(obj);
+ }
+
+ static PyObject* toPython(void* obj)
+ {
+ return toPython(*reinterpret_cast<PySide::PyObjectWrapper*>(obj));
+ }
+
+ static PyObject* toPython(const PySide::PyObjectWrapper& obj)
+ {
+ Py_INCREF((PyObject*)obj);
+ return obj;
+ }
+};
+
+};
+
+using namespace PySide;
+
+struct SignalManager::SignalManagerPrivate
+{
+ SharedMap m_globalReceivers;
+
+ //Deprecated
+ GlobalReceiver m_globalReceiver;
+
+ SignalManagerPrivate()
+ {
+ m_globalReceivers = SharedMap( new QMap<QByteArray, GlobalReceiverV2*>() );
+ }
+
+ ~SignalManagerPrivate()
+ {
+ if (!m_globalReceivers.isNull()) {
+ // Delete receivers by always retrieving the current first element, because deleting a
+ // receiver can indirectly delete another one, and if we use qDeleteAll, that could
+ // cause either a double delete, or iterator invalidation, and thus undefined behavior.
+ while (!m_globalReceivers->isEmpty())
+ delete *m_globalReceivers->cbegin();
+ Q_ASSERT(m_globalReceivers->isEmpty());
+ }
+ }
+};
+
+static void clearSignalManager()
+{
+ PySide::SignalManager::instance().clear();
+}
+
+static void PyObject_PythonToCpp_PyObject_PTR(PyObject* pyIn, void* cppOut)
+{
+ *((PyObject**)cppOut) = pyIn;
+}
+static PythonToCppFunc is_PyObject_PythonToCpp_PyObject_PTR_Convertible(PyObject* pyIn)
+{
+ return PyObject_PythonToCpp_PyObject_PTR;
+}
+static PyObject* PyObject_PTR_CppToPython_PyObject(const void* cppIn)
+{
+ PyObject* pyOut = (PyObject*)cppIn;
+ if (pyOut)
+ Py_INCREF(pyOut);
+ return pyOut;
+}
+
+SignalManager::SignalManager() : m_d(new SignalManagerPrivate)
+{
+ // Register Qt primitive typedefs used on signals.
+ using namespace Shiboken;
+
+ // Register PyObject type to use in queued signal and slot connections
+ qRegisterMetaType<PyObjectWrapper>(PYTHON_TYPE);
+ qRegisterMetaTypeStreamOperators<PyObjectWrapper>(PYTHON_TYPE);
+ qRegisterMetaTypeStreamOperators<PyObjectWrapper>("PyObjectWrapper");
+ qRegisterMetaTypeStreamOperators<PyObjectWrapper>("PySide::PyObjectWrapper");
+
+ SbkConverter* converter = Shiboken::Conversions::createConverter(&PyBaseObject_Type, 0);
+ Shiboken::Conversions::setCppPointerToPythonFunction(converter, PyObject_PTR_CppToPython_PyObject);
+ Shiboken::Conversions::setPythonToCppPointerFunctions(converter, PyObject_PythonToCpp_PyObject_PTR, is_PyObject_PythonToCpp_PyObject_PTR_Convertible);
+ Shiboken::Conversions::registerConverterName(converter, PYTHON_TYPE);
+ Shiboken::Conversions::registerConverterName(converter, "object");
+ Shiboken::Conversions::registerConverterName(converter, "PyObjectWrapper");
+ Shiboken::Conversions::registerConverterName(converter, "PySide::PyObjectWrapper");
+
+ PySide::registerCleanupFunction(clearSignalManager);
+
+ if (!metaObjectAttr)
+ metaObjectAttr = Shiboken::String::fromCString("__METAOBJECT__");
+}
+
+void SignalManager::clear()
+{
+ delete m_d;
+ m_d = new SignalManagerPrivate();
+}
+
+SignalManager::~SignalManager()
+{
+ delete m_d;
+}
+
+SignalManager& SignalManager::instance()
+{
+ static SignalManager me;
+ return me;
+}
+
+QObject* SignalManager::globalReceiver()
+{
+ return &m_d->m_globalReceiver;
+}
+
+void SignalManager::globalReceiverConnectNotify(QObject* source, int slotIndex)
+{
+ m_d->m_globalReceiver.connectNotify(source, slotIndex);
+}
+
+void SignalManager::globalReceiverDisconnectNotify(QObject* source, int slotIndex)
+{
+ m_d->m_globalReceiver.disconnectNotify(source, slotIndex);
+}
+
+void SignalManager::addGlobalSlot(const char* slot, PyObject* callback)
+{
+ addGlobalSlotGetIndex(slot, callback);
+}
+
+int SignalManager::addGlobalSlotGetIndex(const char* slot, PyObject* callback)
+{
+ return m_d->m_globalReceiver.addSlot(slot, callback);
+}
+
+QObject* SignalManager::globalReceiver(QObject *sender, PyObject *callback)
+{
+ SharedMap globalReceivers = m_d->m_globalReceivers;
+ QByteArray hash = GlobalReceiverV2::hash(callback);
+ GlobalReceiverV2* gr = 0;
+ if (!globalReceivers->contains(hash)) {
+ gr = (*globalReceivers)[hash] = new GlobalReceiverV2(callback, globalReceivers);
+ if (sender) {
+ gr->incRef(sender); // create a link reference
+ gr->decRef(); // remove extra reference
+ }
+ } else {
+ gr = (*globalReceivers)[hash];
+ if (sender)
+ gr->incRef(sender);
+ }
+
+ return reinterpret_cast<QObject*>(gr);
+}
+
+int SignalManager::countConnectionsWith(const QObject *object)
+{
+ int count = 0;
+ for (GlobalReceiverV2Map::const_iterator it = m_d->m_globalReceivers->cbegin(), end = m_d->m_globalReceivers->cend(); it != end; ++it) {
+ if (it.value()->refCount(object))
+ count++;
+ }
+ return count;
+}
+
+void SignalManager::notifyGlobalReceiver(QObject* receiver)
+{
+ reinterpret_cast<GlobalReceiverV2*>(receiver)->notify();
+}
+
+void SignalManager::releaseGlobalReceiver(const QObject* source, QObject* receiver)
+{
+ GlobalReceiverV2* gr = reinterpret_cast<GlobalReceiverV2*>(receiver);
+ gr->decRef(source);
+}
+
+int SignalManager::globalReceiverSlotIndex(QObject* receiver, const char* signature) const
+{
+ return reinterpret_cast<GlobalReceiverV2*>(receiver)->addSlot(signature);
+}
+
+bool SignalManager::emitSignal(QObject* source, const char* signal, PyObject* args)
+{
+ if (!Signal::checkQtSignal(signal))
+ return false;
+ signal++;
+
+ int signalIndex = source->metaObject()->indexOfSignal(signal);
+ if (signalIndex != -1) {
+ // cryptic but works!
+ // if the signature doesn't have a '(' it's a shor circuited signal, i.e. std::find
+ // returned the string null terminator.
+ bool isShortCircuit = !*std::find(signal, signal + std::strlen(signal), '(');
+ if (isShortCircuit)
+ return emitShortCircuitSignal(source, signalIndex, args);
+ else
+ return MetaFunction::call(source, signalIndex, args);
+ }
+ return false;
+}
+
+int SignalManager::qt_metacall(QObject* object, QMetaObject::Call call, int id, void** args)
+{
+ const QMetaObject* metaObject = object->metaObject();
+ PySideProperty* pp = 0;
+ PyObject* pp_name = 0;
+ QMetaProperty mp;
+ PyObject* pySelf = 0;
+ int methodCount = metaObject->methodCount();
+ int propertyCount = metaObject->propertyCount();
+
+ if (call != QMetaObject::InvokeMetaMethod) {
+ mp = metaObject->property(id);
+ if (!mp.isValid()) {
+ return id - methodCount;
+ }
+
+ Shiboken::GilState gil;
+ pySelf = (PyObject*)Shiboken::BindingManager::instance().retrieveWrapper(object);
+ Q_ASSERT(pySelf);
+ pp_name = Shiboken::String::fromCString(mp.name());
+ pp = Property::getObject(pySelf, pp_name);
+ if (!pp) {
+ qWarning("Invalid property: %s.", mp.name());
+ Py_XDECREF(pp_name);
+ return id - methodCount;
+ }
+ }
+
+ switch(call) {
+#ifndef QT_NO_PROPERTIES
+ case QMetaObject::ReadProperty:
+ case QMetaObject::WriteProperty:
+ case QMetaObject::ResetProperty:
+ case QMetaObject::QueryPropertyDesignable:
+ case QMetaObject::QueryPropertyScriptable:
+ case QMetaObject::QueryPropertyStored:
+ case QMetaObject::QueryPropertyEditable:
+ case QMetaObject::QueryPropertyUser:
+ pp->d->metaCallHandler(pp, pySelf, call, args);
+ break;
+#endif
+ case QMetaObject::InvokeMetaMethod:
+ id = callMethod(object, id, args);
+ break;
+
+ default:
+ qWarning("Unsupported meta invocation type.");
+ }
+
+ // WARNING Isn't safe to call any metaObject and/or object methods beyond this point
+ // because the object can be deleted inside the called slot.
+
+ if (call == QMetaObject::InvokeMetaMethod) {
+ id = id - methodCount;
+ } else {
+ id = id - propertyCount;
+ }
+
+ if (pp || pp_name) {
+ Shiboken::GilState gil;
+ Py_XDECREF(pp);
+ Py_XDECREF(pp_name);
+ }
+
+ // Bubbles Python exceptions up to the Javascript engine, if called from one
+ {
+ Shiboken::GilState gil;
+
+ if (PyErr_Occurred()) {
+
+#if @QML_PRIVATE_API_SUPPORT@
+ // This JS engine grabber based off of Qt 5.5's `qjsEngine` function
+ QQmlData *data = QQmlData::get(object, false);
+
+ if (data && !data->jsWrapper.isNullOrUndefined()) {
+ QV4::ExecutionEngine *engine = data->jsWrapper.engine();
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
+ QV4::Heap::ExecutionContext *ctx = engine->current;
+#elif QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
+ QV4::Heap::ExecutionContext *ctx = engine->currentContext();
+#else
+ QV4::ExecutionContext *ctx = engine->currentContext();
+#endif
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
+ if (ctx->type == QV4::Heap::ExecutionContext::Type_CallContext ||
+ ctx->type == QV4::Heap::ExecutionContext::Type_SimpleCallContext) {
+#elif QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
+ if (ctx->d()->type == QV4::ExecutionContext::Type_CallContext ||
+ ctx->d()->type == QV4::ExecutionContext::Type_SimpleCallContext) {
+#else
+ if (ctx->type == QV4::ExecutionContext::Type_CallContext ||
+ ctx->type == QV4::ExecutionContext::Type_SimpleCallContext) {
+#endif
+ PyObject *errType, *errValue, *errTraceback;
+ PyErr_Fetch(&errType, &errValue, &errTraceback);
+ // PYSIDE-464: The error is only valid before PyErr_Restore,
+ // PYSIDE-464: therefore we take local copies.
+ Shiboken::AutoDecRef objStr(PyObject_Str(errValue));
+ const QString errString = QLatin1String(Shiboken::String::toCString(objStr));
+ const bool isSyntaxError = errType == PyExc_SyntaxError;
+ const bool isTypeError = errType == PyExc_TypeError;
+ PyErr_Restore(errType, errValue, errTraceback);
+
+ PyErr_Print(); // Note: PyErr_Print clears the error.
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
+ if (isSyntaxError) {
+ return engine->throwSyntaxError(errString);
+ } else if (isTypeError) {
+ return engine->throwTypeError(errString);
+ } else {
+ return engine->throwError(errString);
+ }
+#else
+ if (isSyntaxError) {
+ return ctx->throwSyntaxError(errString);
+ } else if (isTypeError) {
+ return ctx->throwTypeError(errString);
+ } else {
+ return ctx->throwError(errString);
+ }
+#endif
+ }
+ }
+#endif
+
+ int reclimit = Py_GetRecursionLimit();
+ // Inspired by Python's errors.c: PyErr_GivenExceptionMatches() function.
+ // Temporarily bump the recursion limit, so that PyErr_Print will not raise a recursion
+ // error again. Don't do it when the limit is already insanely high, to avoid overflow.
+ if (reclimit < (1 << 30))
+ Py_SetRecursionLimit(reclimit + 5);
+ PyErr_Print();
+ Py_SetRecursionLimit(reclimit);
+ }
+ }
+
+ return id;
+}
+
+int SignalManager::callPythonMetaMethod(const QMetaMethod& method, void** args, PyObject* pyMethod, bool isShortCuit)
+{
+ Q_ASSERT(pyMethod);
+
+ Shiboken::GilState gil;
+ PyObject* pyArguments = 0;
+
+ if (isShortCuit){
+ pyArguments = reinterpret_cast<PyObject*>(args[1]);
+ } else {
+ pyArguments = parseArguments(method.parameterTypes(), args);
+ }
+
+ if (pyArguments) {
+ Shiboken::Conversions::SpecificConverter* retConverter = NULL;
+ const char* returnType = method.typeName();
+ if (returnType && std::strcmp("", returnType) && std::strcmp("void", returnType)) {
+ retConverter = new Shiboken::Conversions::SpecificConverter(returnType);
+ if (!retConverter || !*retConverter) {
+ PyErr_Format(PyExc_RuntimeError, "Can't find converter for '%s' to call Python meta method.", returnType);
+ return -1;
+ }
+ }
+
+ Shiboken::AutoDecRef retval(PyObject_CallObject(pyMethod, pyArguments));
+
+ if (!isShortCuit && pyArguments){
+ Py_DECREF(pyArguments);
+ }
+
+ if (!retval.isNull() && retval != Py_None && !PyErr_Occurred() && retConverter) {
+ retConverter->toCpp(retval, args[0]);
+ }
+ delete retConverter;
+ }
+
+ return -1;
+}
+
+bool SignalManager::registerMetaMethod(QObject* source, const char* signature, QMetaMethod::MethodType type)
+{
+ int ret = registerMetaMethodGetIndex(source, signature, type);
+ return (ret != -1);
+}
+
+int SignalManager::registerMetaMethodGetIndex(QObject* source, const char* signature, QMetaMethod::MethodType type)
+{
+ Q_ASSERT(source);
+ const QMetaObject* metaObject = source->metaObject();
+ int methodIndex = metaObject->indexOfMethod(signature);
+ // Create the dynamic signal is needed
+ if (methodIndex == -1) {
+ SbkObject* self = Shiboken::BindingManager::instance().retrieveWrapper(source);
+ if (!Shiboken::Object::hasCppWrapper(self)) {
+ qWarning() << "Invalid Signal signature:" << signature;
+ return -1;
+ } else {
+ DynamicQMetaObject *dmo = 0;
+ PyObject *pySelf = reinterpret_cast<PyObject*>(self);
+ PyObject* dict = self->ob_dict;
+
+ // Create a instance meta object
+ if (!dict || !PyDict_Contains(dict, metaObjectAttr)) {
+ dmo = new DynamicQMetaObject(pySelf->ob_type, metaObject);
+#ifdef IS_PY3K
+ PyObject* pyDmo = PyCapsule_New(dmo, 0, destroyMetaObject);
+#else
+ PyObject* pyDmo = PyCObject_FromVoidPtr(dmo, destroyMetaObject);
+#endif
+
+ PyObject_SetAttr(pySelf, metaObjectAttr, pyDmo);
+ Py_DECREF(pyDmo);
+ } else {
+ dmo = reinterpret_cast<DynamicQMetaObject*>(const_cast<QMetaObject*>(metaObject));
+ }
+
+ if (type == QMetaMethod::Signal)
+ return dmo->addSignal(signature);
+ else
+ return dmo->addSlot(signature);
+ }
+ }
+ return methodIndex;
+}
+
+bool SignalManager::hasConnectionWith(const QObject *object)
+{
+ return m_d->m_globalReceiver.hasConnectionWith(object);
+}
+
+const QMetaObject* SignalManager::retriveMetaObject(PyObject *self)
+{
+ Shiboken::GilState gil;
+ DynamicQMetaObject *mo = 0;
+ Q_ASSERT(self);
+
+ PyObject* dict = reinterpret_cast<SbkObject*>(self)->ob_dict;
+ if (dict && PyDict_Contains(dict, metaObjectAttr)) {
+ PyObject *pyMo = PyDict_GetItem(dict, metaObjectAttr);
+
+#ifdef IS_PY3K
+ mo = reinterpret_cast<DynamicQMetaObject*>(PyCapsule_GetPointer(pyMo, 0));
+#else
+ mo = reinterpret_cast<DynamicQMetaObject*>(PyCObject_AsVoidPtr(pyMo));
+#endif
+ } else {
+ mo = reinterpret_cast<DynamicQMetaObject*>(Shiboken::Object::getTypeUserData(reinterpret_cast<SbkObject*>(self)));
+ }
+
+ mo->update();
+ return mo;
+}
+
+namespace {
+
+static int callMethod(QObject* object, int id, void** args)
+{
+ const QMetaObject* metaObject = object->metaObject();
+ QMetaMethod method = metaObject->method(id);
+
+ if (method.methodType() == QMetaMethod::Signal) {
+ // emit python signal
+ QMetaObject::activate(object, id, args);
+ } else {
+ Shiboken::GilState gil;
+ PyObject* self = (PyObject*)Shiboken::BindingManager::instance().retrieveWrapper(object);
+ QByteArray methodName = method.methodSignature();
+ methodName.truncate(methodName.indexOf('('));
+ Shiboken::AutoDecRef pyMethod(PyObject_GetAttrString(self, methodName));
+ return SignalManager::callPythonMetaMethod(method, args, pyMethod, false);
+ }
+ return -1;
+}
+
+
+static PyObject* parseArguments(const QList<QByteArray>& paramTypes, void** args)
+{
+ int argsSize = paramTypes.count();
+ PyObject* preparedArgs = PyTuple_New(argsSize);
+
+ for (int i = 0, max = argsSize; i < max; ++i) {
+ void* data = args[i+1];
+ const char* dataType = paramTypes[i].constData();
+ Shiboken::Conversions::SpecificConverter converter(dataType);
+ if (converter) {
+ PyTuple_SET_ITEM(preparedArgs, i, converter.toPython(data));
+ } else {
+ PyErr_Format(PyExc_TypeError, "Can't call meta function because I have no idea how to handle %s", dataType);
+ Py_DECREF(preparedArgs);
+ return 0;
+ }
+ }
+ return preparedArgs;
+}
+
+static bool emitShortCircuitSignal(QObject* source, int signalIndex, PyObject* args)
+{
+ void* signalArgs[2] = {0, args};
+ source->qt_metacall(QMetaObject::InvokeMetaMethod, signalIndex, signalArgs);
+ return true;
+}
+
+} //namespace