aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrenato <renato.filho@openbossa.org>2009-12-30 11:45:09 -0300
committerHugo Lima <hugo.lima@openbossa.org>2010-01-04 18:59:39 -0200
commit359c973b425db0c27675add1a330734bbd7d8dbd (patch)
treef94fb1b9d80cc2596dc911be006ba0c2584769c9
parent0d6a8f3978188f3e343c364806e0bb6e6ac1e643 (diff)
Implement disconnect function for Python callback.
Reviewed by Hugo Parente <hugo.lima@openbossa.org>
-rw-r--r--PySide/QtCore/glue/qobject_connect.cpp44
-rw-r--r--PySide/QtCore/typesystem_core.xml15
-rw-r--r--libpyside/dynamicqmetaobject.cpp15
-rw-r--r--libpyside/dynamicqmetaobject.h4
-rw-r--r--libpyside/globalreceiver.cpp92
-rw-r--r--libpyside/globalreceiver.h6
-rw-r--r--libpyside/signalmanager.cpp10
-rw-r--r--libpyside/signalmanager.h3
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;