diff options
-rw-r--r-- | PySide/QtCore/glue/qobject_connect.cpp | 20 | ||||
-rw-r--r-- | libpyside/dynamicqmetaobject.cpp | 72 | ||||
-rw-r--r-- | libpyside/dynamicqmetaobject.h | 11 | ||||
-rw-r--r-- | libpyside/globalreceiver.cpp | 13 | ||||
-rw-r--r-- | libpyside/globalreceiver.h | 2 | ||||
-rw-r--r-- | libpyside/pyside.cpp | 4 | ||||
-rw-r--r-- | libpyside/signalmanager.cpp | 68 | ||||
-rw-r--r-- | libpyside/signalmanager.h | 5 |
8 files changed, 144 insertions, 51 deletions
diff --git a/PySide/QtCore/glue/qobject_connect.cpp b/PySide/QtCore/glue/qobject_connect.cpp index 91a272c3c..3296c2e89 100644 --- a/PySide/QtCore/glue/qobject_connect.cpp +++ b/PySide/QtCore/glue/qobject_connect.cpp @@ -59,11 +59,10 @@ static bool qobjectConnectCallback(QObject* source, const char* signal, PyObject return false; signal++; - if (!PySide::SignalManager::registerMetaMethod(source, signal, QMetaMethod::Signal)) + int signalIndex = PySide::SignalManager::registerMetaMethodGetIndex(source, signal, QMetaMethod::Signal); + if (signalIndex == -1) return false; - int signalIndex = source->metaObject()->indexOfMethod(signal); - PySide::SignalManager& signalManager = PySide::SignalManager::instance(); // Extract receiver from callback @@ -82,13 +81,14 @@ static bool qobjectConnectCallback(QObject* source, const char* signal, PyObject qWarning() << "You can't add dynamic slots on an object originated from C++."; return false; } - if (usingGlobalReceiver) { - signalManager.addGlobalSlot(slot, callback); - } else { - if (!PySide::SignalManager::registerMetaMethod(receiver, slot, QMetaMethod::Slot)) - return false; - } - slotIndex = metaObject->indexOfSlot(slot); + + if (usingGlobalReceiver) + slotIndex = signalManager.addGlobalSlotGetIndex(slot, callback); + else + slotIndex = PySide::SignalManager::registerMetaMethodGetIndex(receiver, slot, QMetaMethod::Slot); + + if (slotIndex == -1) + return false; } if (QMetaObject::connect(source, signalIndex, receiver, slotIndex, type)) { if (usingGlobalReceiver) diff --git a/libpyside/dynamicqmetaobject.cpp b/libpyside/dynamicqmetaobject.cpp index 205c7286e..dfc8ce281 100644 --- a/libpyside/dynamicqmetaobject.cpp +++ b/libpyside/dynamicqmetaobject.cpp @@ -87,6 +87,10 @@ public: QList<PropertyData> m_properties; QMap<QByteArray, QByteArray> m_info; QByteArray m_className; + bool m_invalid; + int m_methodOffset; + int m_propertyOffset; + int m_count; void updateMetaObject(QMetaObject* metaObj); void writeMethodsData(const QList<MethodData>& methods, unsigned int** data, QList<QByteArray>* strings, int* prtIndex, int nullIndex, int flags); @@ -95,8 +99,7 @@ public: static int registerString(const QByteArray& s, QList<QByteArray>* strings) { int idx = 0; - for (int i = 0; i < strings->count(); ++i) { - const QString &str = strings->at(i); + foreach(QByteArray str, *strings) { if (str == s) return idx; idx += str.length() + 1; @@ -197,11 +200,13 @@ uint PropertyData::flags() const // const QByteArray with EMPTY_META_METHOD, used to save some memory const QByteArray MethodData::m_emptySig(EMPTY_META_METHOD); -MethodData::MethodData() : m_signature(m_emptySig) +MethodData::MethodData() + : m_signature(m_emptySig) { } -MethodData::MethodData(QMetaMethod::MethodType mtype, const char* signature, const char* type) : m_signature(signature), m_type(type), m_mtype(mtype) +MethodData::MethodData(QMetaMethod::MethodType mtype, const char* signature, const char* type) + : m_signature(signature), m_type(type), m_mtype(mtype) { } @@ -289,9 +294,12 @@ DynamicQMetaObject::DynamicQMetaObject(PyTypeObject* type, const QMetaObject* ba d.extradata = 0; m_d->m_className = QByteArray(type->tp_name).split('.').last(); + m_d->m_invalid = true; + m_d->m_methodOffset = base->methodCount() - 1; + m_d->m_propertyOffset = base->propertyCount() - 1; + m_d->m_count = 0; + //qDebug() << "CREATED: " << m_d->m_className << "OFFSET:" << base->methodOffset() << "COUNT" << base->methodCount(); parsePythonType(type); - //TODO : fill type userData - m_d->updateMetaObject(this); } DynamicQMetaObject::DynamicQMetaObject(const char* className, const QMetaObject* metaObject) @@ -301,8 +309,11 @@ DynamicQMetaObject::DynamicQMetaObject(const char* className, const QMetaObject* d.stringdata = 0; d.data = 0; d.extradata = 0; + m_d->m_count = 0; + m_d->m_invalid = true; m_d->m_className = className; - m_d->updateMetaObject(this); + m_d->m_methodOffset = metaObject->methodCount() - 1; + m_d->m_propertyOffset = metaObject->propertyCount() - 1; } DynamicQMetaObject::~DynamicQMetaObject() @@ -312,7 +323,7 @@ DynamicQMetaObject::~DynamicQMetaObject() delete m_d; } -void DynamicQMetaObject::addMethod(QMetaMethod::MethodType mtype, const char* signature, const char* type) +int DynamicQMetaObject::addMethod(QMetaMethod::MethodType mtype, const char* signature, const char* type) { int index = -1; int counter = 0; @@ -321,19 +332,24 @@ void DynamicQMetaObject::addMethod(QMetaMethod::MethodType mtype, const char* si QList<MethodData>::iterator it = m_d->m_methods.begin(); for (; it != m_d->m_methods.end(); ++it) { if ((it->signature() == signature) && (it->methodType() == mtype)) - return; + return m_d->m_methodOffset + counter; else if (*it == blank) index = counter; counter++; } + //qDebug() << "FIRST:" << index; //has blank method - if (index != -1) + if (index != -1) { m_d->m_methods[index] = MethodData(mtype, signature, type); - else + } else { m_d->m_methods << MethodData(mtype, signature, type); + index = m_d->m_methods.size(); + } - m_d->updateMetaObject(this); + m_d->m_invalid = true; + return m_d->m_methodOffset + index; + //qDebug() << "RESULTS(" << signature << "): " << result << "/" << indexOfMethod(signature) << "/" << m_d->m_methods.size() << "/" << m_d->m_methodOffset << (void*)this; } void DynamicQMetaObject::removeMethod(QMetaMethod::MethodType mtype, uint index) @@ -343,20 +359,20 @@ void DynamicQMetaObject::removeMethod(QMetaMethod::MethodType mtype, uint index) for (; it != m_d->m_methods.end(); ++it) { if ((it->signature() == methodSig) && (it->methodType() == mtype)){ it->clear(); - m_d->updateMetaObject(this); + m_d->m_invalid = true; break; } } } -void DynamicQMetaObject::addSignal(const char* signal, const char* type) +int DynamicQMetaObject::addSignal(const char* signal, const char* type) { - addMethod(QMetaMethod::Signal, signal, type); + return addMethod(QMetaMethod::Signal, signal, type); } -void DynamicQMetaObject::addSlot(const char* slot, const char* type) +int DynamicQMetaObject::addSlot(const char* slot, const char* type) { - addMethod(QMetaMethod::Slot, slot, type); + return addMethod(QMetaMethod::Slot, slot, type); } void DynamicQMetaObject::removeSlot(uint index) @@ -369,11 +385,11 @@ void DynamicQMetaObject::removeSignal(uint index) removeMethod(QMetaMethod::Signal, index); } -void DynamicQMetaObject::addProperty(const char* propertyName, PyObject* data) +int DynamicQMetaObject::addProperty(const char* propertyName, PyObject* data) { int index = m_d->m_properties.indexOf(propertyName); if (index != -1) - return; + return m_d->m_propertyOffset + index; // retrieve notifyId int notifyId = -1; @@ -393,8 +409,10 @@ void DynamicQMetaObject::addProperty(const char* propertyName, PyObject* data) m_d->m_properties[index] = PropertyData(propertyName, notifyId, property); } else { m_d->m_properties << PropertyData(propertyName, notifyId, property); + index = m_d->m_properties.size(); } - m_d->updateMetaObject(this); + m_d->m_invalid = true; + return m_d->m_propertyOffset + index; } void DynamicQMetaObject::addInfo(const char* key, const char* value) @@ -409,7 +427,16 @@ void DynamicQMetaObject::addInfo(QMap<QByteArray, QByteArray> info) m_d->m_info[i.key()] = i.value(); ++i; } - m_d->updateMetaObject(this); + m_d->m_invalid = true; +} + +const QMetaObject* DynamicQMetaObject::update() const +{ + if (m_d->m_invalid) { + m_d->updateMetaObject(const_cast<DynamicQMetaObject*>(this)); + m_d->m_invalid = false; + } + return this; } void DynamicQMetaObject::DynamicQMetaObjectPrivate::writeMethodsData(const QList<MethodData>& methods, @@ -530,7 +557,8 @@ void DynamicQMetaObject::DynamicQMetaObjectPrivate::updateMetaObject(QMetaObject } //write signals/slots - writeMethodsData(m_methods, &data, &strings, &index, NULL_INDEX, AccessPublic); + if (n_methods) + writeMethodsData(m_methods, &data, &strings, &index, NULL_INDEX, AccessPublic); if (m_properties.size()) data[7] = index; diff --git a/libpyside/dynamicqmetaobject.h b/libpyside/dynamicqmetaobject.h index f95070c28..3ebaf1d08 100644 --- a/libpyside/dynamicqmetaobject.h +++ b/libpyside/dynamicqmetaobject.h @@ -39,11 +39,11 @@ public: ~DynamicQMetaObject(); - void addMethod(QMetaMethod::MethodType mtype, const char* signature, const char* type); + int addMethod(QMetaMethod::MethodType mtype, const char* signature, const char* type); void removeMethod(QMetaMethod::MethodType mtype, uint index); - void addSignal(const char* signal, const char* type = 0); - void addSlot(const char* slot, const char* type = 0); - void addProperty(const char* property, PyObject* data); + int addSignal(const char* signal, const char* type = 0); + int addSlot(const char* slot, const char* type = 0); + int addProperty(const char* property, PyObject* data); void addInfo(const char* key, const char* value); void addInfo(QMap<QByteArray, QByteArray> info); @@ -51,6 +51,8 @@ public: void removeSlot(uint index); void removeProperty(uint index); + const QMetaObject* update() const; + private: class DynamicQMetaObjectPrivate; DynamicQMetaObjectPrivate* m_d; @@ -58,5 +60,6 @@ private: void parsePythonType(PyTypeObject* type); }; + } #endif diff --git a/libpyside/globalreceiver.cpp b/libpyside/globalreceiver.cpp index 89902126c..435e22aa0 100644 --- a/libpyside/globalreceiver.cpp +++ b/libpyside/globalreceiver.cpp @@ -162,6 +162,8 @@ GlobalReceiver::GlobalReceiver() { //slot used to be notifyed of object destrouction m_metaObject.addSlot(RECEIVER_DESTROYED_SLOT_NAME); + m_metaObject.update(); + setObjectName("GLOBAL RECEIVER"); } GlobalReceiver::~GlobalReceiver() @@ -198,13 +200,12 @@ void GlobalReceiver::disconnectNotify(QObject* source, int slotId) const QMetaObject* GlobalReceiver::metaObject() const { - return &m_metaObject; + return m_metaObject.update(); } -void GlobalReceiver::addSlot(const char* slot, PyObject* callback) +int GlobalReceiver::addSlot(const char* slot, PyObject* callback) { - m_metaObject.addSlot(slot); - int slotId = m_metaObject.indexOfSlot(slot); + int slotId = m_metaObject.addSlot(slot); if (!m_slotReceivers.contains(slotId)) m_slotReceivers[slotId] = new DynamicSlotData(slotId, callback, this); @@ -219,8 +220,8 @@ void GlobalReceiver::addSlot(const char* slot, PyObject* callback) if (isShortCircuit) m_shortCircuitSlots << slotId; - Q_ASSERT(slotId >= QObject::staticMetaObject.methodCount()); + return slotId; } void GlobalReceiver::removeSlot(int slotId) @@ -248,7 +249,7 @@ int GlobalReceiver::qt_metacall(QMetaObject::Call call, int id, void** args) { Q_ASSERT(call == QMetaObject::InvokeMetaMethod); Q_ASSERT(id >= QObject::staticMetaObject.methodCount()); - QMetaMethod slot = m_metaObject.method(id); + QMetaMethod slot = metaObject()->method(id); Q_ASSERT(slot.methodType() == QMetaMethod::Slot); if (strcmp(slot.signature(), RECEIVER_DESTROYED_SLOT_NAME) == 0) { diff --git a/libpyside/globalreceiver.h b/libpyside/globalreceiver.h index 616d8d3a4..76c1246d6 100644 --- a/libpyside/globalreceiver.h +++ b/libpyside/globalreceiver.h @@ -41,7 +41,7 @@ public: ~GlobalReceiver(); int qt_metacall(QMetaObject::Call call, int id, void** args); const QMetaObject* metaObject() const; - void addSlot(const char* slot, PyObject* callback); + int addSlot(const char* slot, PyObject* callback); void removeSlot(int slotId); void connectNotify(QObject* sender, int slotId); void disconnectNotify(QObject* sender, int slotId); diff --git a/libpyside/pyside.cpp b/libpyside/pyside.cpp index 325e27402..45ada8f47 100644 --- a/libpyside/pyside.cpp +++ b/libpyside/pyside.cpp @@ -168,6 +168,7 @@ void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base, const s //create DynamicMetaObject based on python type TypeUserData* userData = new TypeUserData(reinterpret_cast<PyTypeObject*>(type), base); userData->cppObjSize = cppObjSize; + userData->mo.update(); Shiboken::ObjectType::setTypeUserData(type, userData, Shiboken::callCppDestructor<TypeUserData>); //initialize staticQMetaObject property @@ -196,6 +197,7 @@ void initQObjectSubType(SbkObjectType* type, PyObject* args, PyObject* kwds) if (PyType_IsSubtype(base, qObjType)) { baseMo = reinterpret_cast<QMetaObject*>(Shiboken::ObjectType::getTypeUserData(reinterpret_cast<SbkObjectType*>(base))); qobjBase = reinterpret_cast<SbkObjectType*>(base); + reinterpret_cast<DynamicQMetaObject*>(baseMo)->update(); break; } } @@ -216,9 +218,9 @@ PyObject* getMetaDataFromQObject(QObject* cppSelf, PyObject* self, PyObject* nam if (attr && Property::isPropertyType(attr)) { PyObject *value = Property::getValue(reinterpret_cast<PySideProperty*>(attr), self); + Py_DECREF(attr); if (!value) return 0; - Py_DECREF(attr); Py_INCREF(value); attr = value; } diff --git a/libpyside/signalmanager.cpp b/libpyside/signalmanager.cpp index bbbc1d3f0..b24d0b97e 100644 --- a/libpyside/signalmanager.cpp +++ b/libpyside/signalmanager.cpp @@ -25,6 +25,7 @@ #include "pysideproperty.h" #include "pysideproperty_p.h" #include "pyside.h" +#include "dynamicqmetaobject.h" #include <QHash> #include <QStringList> @@ -46,6 +47,14 @@ #define PYTHON_TYPE "PyObject" +namespace { + static PyObject *metaObjectAttr = 0; + static void destroyMetaObject(void* obj) + { + delete reinterpret_cast<PySide::DynamicQMetaObject*>(obj); + } +} + namespace PySide { static int callMethod(QObject* object, int id, void** args); @@ -189,6 +198,9 @@ SignalManager::SignalManager() : m_d(new SignalManagerPrivate) TypeResolver::createValueTypeResolver<PyObjectWrapper>("object"); TypeResolver::createValueTypeResolver<PyObjectWrapper>("PySide::PyObjectWrapper"); PySide::registerCleanupFunction(clearSignalManager); + + if (!metaObjectAttr) + metaObjectAttr = PyString_FromString("__METAOBJECT__"); } void SignalManager::clear() @@ -225,7 +237,12 @@ void SignalManager::globalReceiverDisconnectNotify(QObject* source, int slotInde void SignalManager::addGlobalSlot(const char* slot, PyObject* callback) { - m_d->m_globalReceiver.addSlot(slot, callback); + addGlobalSlotGetIndex(slot, callback); +} + +int SignalManager::addGlobalSlotGetIndex(const char* slot, PyObject* callback) +{ + return m_d->m_globalReceiver.addSlot(slot, callback); } static bool emitShortCircuitSignal(QObject* source, int signalIndex, PyObject* args) @@ -412,9 +429,14 @@ static int PySide::callMethod(QObject* object, int id, void** args) } 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); @@ -423,19 +445,51 @@ bool SignalManager::registerMetaMethod(QObject* source, const char* signature, Q SbkObject* self = Shiboken::BindingManager::instance().retrieveWrapper(source); if (!Shiboken::Object::hasCppWrapper(self)) { qWarning() << "Invalid Signal signature:" << signature; - return false; + return -1; } else { - PySide::DynamicQMetaObject* dynMetaObj = reinterpret_cast<PySide::DynamicQMetaObject*>(const_cast<QMetaObject*>(metaObject)); + 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); + PyObject *pyDmo = PyCObject_FromVoidPtr(dmo, destroyMetaObject); + PyObject_SetAttr(pySelf, metaObjectAttr, pyDmo); + Py_DECREF(pyDmo); + } else { + dmo = reinterpret_cast<DynamicQMetaObject*>(const_cast<QMetaObject*>(metaObject)); + } + if (type == QMetaMethod::Signal) - dynMetaObj->addSignal(signature); + return dmo->addSignal(signature); else - dynMetaObj->addSlot(signature); + return dmo->addSlot(signature); } } - return true; + 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); + mo = reinterpret_cast<DynamicQMetaObject*>(PyCObject_AsVoidPtr(pyMo)); + } else { + mo = reinterpret_cast<DynamicQMetaObject*>(Shiboken::Object::getTypeUserData(reinterpret_cast<SbkObject*>(self))); + } + + mo->update(); + return mo; +} + diff --git a/libpyside/signalmanager.h b/libpyside/signalmanager.h index 5ea1366f0..b1b798600 100644 --- a/libpyside/signalmanager.h +++ b/libpyside/signalmanager.h @@ -62,12 +62,17 @@ public: static int qt_metacall(QObject* object, QMetaObject::Call call, int id, void** args); void addGlobalSlot(const char* slot, PyObject* callback); + int addGlobalSlotGetIndex(const char* slot, PyObject* callback); void globalReceiverConnectNotify(QObject *sender, int slotIndex); void globalReceiverDisconnectNotify(QObject *sender, int slotIndex); // Used to register a new signal/slot on QMetaobject of source. static bool registerMetaMethod(QObject* source, const char* signature, QMetaMethod::MethodType type); + static int registerMetaMethodGetIndex(QObject* source, const char* signature, QMetaMethod::MethodType type); + + // used to discovery metaobject + static const QMetaObject* retriveMetaObject(PyObject* self); // Used to discovery if SignalManager was connected with object "destroyed()" signal. bool hasConnectionWith(const QObject *object); |