diff options
author | renato <renato.filho@openbossa.org> | 2009-12-30 11:45:09 -0300 |
---|---|---|
committer | Hugo Lima <hugo.lima@openbossa.org> | 2010-01-04 18:59:39 -0200 |
commit | 359c973b425db0c27675add1a330734bbd7d8dbd (patch) | |
tree | f94fb1b9d80cc2596dc911be006ba0c2584769c9 | |
parent | 0d6a8f3978188f3e343c364806e0bb6e6ac1e643 (diff) |
Implement disconnect function for Python callback.
Reviewed by Hugo Parente <hugo.lima@openbossa.org>
-rw-r--r-- | PySide/QtCore/glue/qobject_connect.cpp | 44 | ||||
-rw-r--r-- | PySide/QtCore/typesystem_core.xml | 15 | ||||
-rw-r--r-- | libpyside/dynamicqmetaobject.cpp | 15 | ||||
-rw-r--r-- | libpyside/dynamicqmetaobject.h | 4 | ||||
-rw-r--r-- | libpyside/globalreceiver.cpp | 92 | ||||
-rw-r--r-- | libpyside/globalreceiver.h | 6 | ||||
-rw-r--r-- | libpyside/signalmanager.cpp | 10 | ||||
-rw-r--r-- | libpyside/signalmanager.h | 3 |
8 files changed, 175 insertions, 14 deletions
diff --git a/PySide/QtCore/glue/qobject_connect.cpp b/PySide/QtCore/glue/qobject_connect.cpp index 846ab5012..96177322f 100644 --- a/PySide/QtCore/glue/qobject_connect.cpp +++ b/PySide/QtCore/glue/qobject_connect.cpp @@ -80,5 +80,47 @@ static bool qobjectConnectCallback(QObject* source, const char* signal, PyObject } slotIndex = metaObject->indexOfSlot(slot); } - return QMetaObject::connect(source, signalIndex, receiver, slotIndex, type); + if (QMetaObject::connect(source, signalIndex, receiver, slotIndex, type)) { + if (usingGlobalReceiver) + signalManager.globalReceiverConnectNotify(slotIndex); + + return true; + } + return false; +} + + +static bool qobjectDisconnectCallback(QObject* source, const char* signal, PyObject* callback) +{ + if (!PySide::checkSignal(signal)) + return false; + + PySide::SignalManager& signalManager = PySide::SignalManager::instance(); + + // Extract receiver from callback + bool usingGlobalReceiver; + QObject* receiver = 0; + PyObject* self; + if (PyMethod_Check(callback)) { + self = PyMethod_GET_SELF(callback); + if (SbkQObject_Check(self)) + receiver = SbkQObject_cptr(self); + } + usingGlobalReceiver = !receiver; + if (usingGlobalReceiver) + receiver = signalManager.globalReceiver(); + + const QMetaObject* metaObject = receiver->metaObject(); + const QByteArray callbackSig = PySide::getCallbackSignature(signal, callback, usingGlobalReceiver).toAscii(); + QByteArray qtSlotName(callbackSig); + qtSlotName = qtSlotName.prepend('1'); + + if (QObject::disconnect(source, signal, receiver, qtSlotName.constData())) { + if (usingGlobalReceiver) { + int slotIndex = metaObject->indexOfSlot(callbackSig.constData()); + signalManager.globalReceiverDisconnectNotify(slotIndex); + } + return true; + } + return false; } diff --git a/PySide/QtCore/typesystem_core.xml b/PySide/QtCore/typesystem_core.xml index 642b994f6..22cf6acbf 100644 --- a/PySide/QtCore/typesystem_core.xml +++ b/PySide/QtCore/typesystem_core.xml @@ -1346,9 +1346,18 @@ %PYARG_0 = %CONVERTTOPYTHON[bool](PySide::SignalManager::instance().emitSignal(%CPPSELF, %1, %PYARG_2)); </inject-code> </add-function> -<!-- <modify-function signature="disconnect(const QObject*, const char*)" remove="all"/> --> -<!-- <modify-function signature="disconnect(const char*, const QObject*, const char*)" remove="all"/> --> -<!-- <modify-function signature="disconnect(const QObject*, const char*, const QObject*, const char *)" remove="all"/> --> + <add-function signature="disconnect(const char *, PyCallable*)" return-type="bool"> + <inject-code class="target" position="beginning"> + // %FUNCTION_NAME() - disable generation of function call. + %PYARG_0 = %CONVERTTOPYTHON[bool](qobjectDisconnectCallback(%CPPSELF, %1, %2)); + </inject-code> + </add-function> + <add-function signature="disconnect(const QObject*, const char*, PyCallable*)" return-type="bool"> + <inject-code class="target" position="beginning"> + // %FUNCTION_NAME() - disable generation of function call. + %PYARG_0 = %CONVERTTOPYTHON[bool](qobjectDisconnectCallback(%1, %2, %3)); + </inject-code> + </add-function> <inject-code class="native" position="beginning"> static bool qobjectInheritsInternal(PyTypeObject *objType, const char *class_name) diff --git a/libpyside/dynamicqmetaobject.cpp b/libpyside/dynamicqmetaobject.cpp index 40e74ce67..083f1d666 100644 --- a/libpyside/dynamicqmetaobject.cpp +++ b/libpyside/dynamicqmetaobject.cpp @@ -39,6 +39,7 @@ #include <QObject> #include <cstring> #include <QDebug> +#include <QMetaMethod> using namespace PySide; @@ -83,6 +84,20 @@ void DynamicQMetaObject::addSlot(const char* slot) updateMetaObject(); } +void DynamicQMetaObject::removeSlot(uint index) +{ + QMetaMethod m = method(index); + if (m_slots.removeAll(m.signature())) + updateMetaObject(); +} + +void DynamicQMetaObject::removeSignal(uint index) +{ + QMetaMethod m = method(index); + if (m_signals.removeAll(m.signature())) + updateMetaObject(); +} + void DynamicQMetaObject::updateMetaObject() { // these values are from moc source code, generator.cpp:66 diff --git a/libpyside/dynamicqmetaobject.h b/libpyside/dynamicqmetaobject.h index 572d3b444..557ebe146 100644 --- a/libpyside/dynamicqmetaobject.h +++ b/libpyside/dynamicqmetaobject.h @@ -50,9 +50,13 @@ class PYSIDE_API DynamicQMetaObject : public QMetaObject public: DynamicQMetaObject(const char* className, const QMetaObject* metaObject); ~DynamicQMetaObject(); + void addSignal(const char* signal); void addSlot(const char* slot); + void removeSignal(uint idex); + void removeSlot(uint index); + private: QLinkedList<QByteArray> m_signals; QLinkedList<QByteArray> m_slots; diff --git a/libpyside/globalreceiver.cpp b/libpyside/globalreceiver.cpp index 0d6ce7cf2..333268081 100644 --- a/libpyside/globalreceiver.cpp +++ b/libpyside/globalreceiver.cpp @@ -39,16 +39,87 @@ #include <autodecref.h> #include "typeresolver.h" + +namespace PySide +{ + +class DynamicSlotData +{ + public: + DynamicSlotData(PyObject *callback); + void incRef(); + void decRef(); + int refCount() const; + PyObject *callback() const; + ~DynamicSlotData(); + + private: + int m_refCount; + PyObject *m_callback; +}; + +} + using namespace PySide; -GlobalReceiver::GlobalReceiver() : m_metaObject("GlobalReceiver", &QObject::staticMetaObject) +DynamicSlotData::DynamicSlotData(PyObject *callback) + : m_refCount(0) +{ + m_callback = callback; + Py_INCREF(callback); +} + +void DynamicSlotData::incRef() +{ + m_refCount++; +} + +void DynamicSlotData::decRef() +{ + m_refCount--; +} + +int DynamicSlotData::refCount() const +{ + return m_refCount; +} + +PyObject *DynamicSlotData::callback() const +{ + return m_callback; +} + +DynamicSlotData::~DynamicSlotData() +{ + Py_XDECREF(m_callback); +} + + +GlobalReceiver::GlobalReceiver() + : m_metaObject("GlobalReceiver", &QObject::staticMetaObject) { } GlobalReceiver::~GlobalReceiver() { - foreach(PyObject* obj, m_slotReceivers) - Py_DECREF(obj); + foreach(DynamicSlotData* data, m_slotReceivers) + delete data; +} + +void GlobalReceiver::connectNotify(int slotId) +{ + if (m_slotReceivers.contains(slotId)) + m_slotReceivers[slotId]->incRef(); +} + +void GlobalReceiver::disconnectNotify(int slotId) +{ + if (m_slotReceivers.contains(slotId)) { + DynamicSlotData *data = m_slotReceivers[slotId]; + data->decRef(); + if (data->refCount() == 0) + removeSlot(slotId); + } } const QMetaObject* GlobalReceiver::metaObject() const @@ -60,8 +131,9 @@ void GlobalReceiver::addSlot(const char* slot, PyObject* callback) { m_metaObject.addSlot(slot); int slotId = m_metaObject.indexOfSlot(slot); - Py_INCREF(callback); - m_slotReceivers[slotId] = callback; + if (!m_slotReceivers.contains(slotId)) { + m_slotReceivers[slotId] = new DynamicSlotData(callback); + } bool isShortCircuit = true; for (int i = 0; slot[i]; ++i) { @@ -78,8 +150,9 @@ void GlobalReceiver::addSlot(const char* slot, PyObject* callback) void GlobalReceiver::removeSlot(int slotId) { - PyObject* obj = m_slotReceivers.take(slotId); - Py_XDECREF(obj); + delete m_slotReceivers.take(slotId); + m_metaObject.removeSlot(slotId); + m_shortCircuitSlots.remove(slotId); } int GlobalReceiver::qt_metacall(QMetaObject::Call call, int id, void** args) @@ -89,14 +162,15 @@ int GlobalReceiver::qt_metacall(QMetaObject::Call call, int id, void** args) QMetaMethod slot = m_metaObject.method(id); Q_ASSERT(slot.methodType() == QMetaMethod::Slot); - PyObject* callback = m_slotReceivers.value(id); - if (!callback) { + DynamicSlotData* data = m_slotReceivers.value(id); + if (!data) { qWarning() << "Unknown global slot, id:" << id; return -1; } int numArgs; PyObject* retval = 0; + PyObject* callback = data->callback(); if (m_shortCircuitSlots.contains(id)) { retval = PyObject_CallObject(callback, reinterpret_cast<PyObject*>(args[1])); } else { diff --git a/libpyside/globalreceiver.h b/libpyside/globalreceiver.h index e1e230b7b..9243f9d3f 100644 --- a/libpyside/globalreceiver.h +++ b/libpyside/globalreceiver.h @@ -44,6 +44,8 @@ namespace PySide { +class DynamicSlotData; + class GlobalReceiver : public QObject { public: @@ -53,10 +55,12 @@ public: const QMetaObject* metaObject() const; void addSlot(const char* slot, PyObject* callback); void removeSlot(int slotId); + void connectNotify(int slotId); + void disconnectNotify(int slotId); private: DynamicQMetaObject m_metaObject; - QHash<int, PyObject* > m_slotReceivers; QSet<int> m_shortCircuitSlots; + QHash<int, DynamicSlotData* > m_slotReceivers; }; } diff --git a/libpyside/signalmanager.cpp b/libpyside/signalmanager.cpp index c8b55e77f..99b2e5ae4 100644 --- a/libpyside/signalmanager.cpp +++ b/libpyside/signalmanager.cpp @@ -164,6 +164,16 @@ QObject* SignalManager::globalReceiver() return &m_d->m_globalReceiver; } +void SignalManager::globalReceiverConnectNotify(int slotIndex) +{ + m_d->m_globalReceiver.connectNotify(slotIndex); +} + +void SignalManager::globalReceiverDisconnectNotify(int slotIndex) +{ + m_d->m_globalReceiver.disconnectNotify(slotIndex); +} + void SignalManager::addGlobalSlot(const char* slot, PyObject* callback) { m_d->m_globalReceiver.addSlot(slot, callback); diff --git a/libpyside/signalmanager.h b/libpyside/signalmanager.h index 870aecdfe..60888ee0c 100644 --- a/libpyside/signalmanager.h +++ b/libpyside/signalmanager.h @@ -59,6 +59,9 @@ public: static int qt_metacall(QObject* object, QMetaObject::Call call, int id, void** args); void addGlobalSlot(const char* slot, PyObject* callback); + + void globalReceiverConnectNotify(int slotIndex); + void globalReceiverDisconnectNotify(int slotIndex); private: struct SignalManagerPrivate; SignalManagerPrivate* m_d; |