Implement disconnect function for Python callback.
Reviewed by Hugo Parente <hugo.lima@openbossa.org>
This commit is contained in:
parent
0d6a8f3978
commit
359c973b42
8 changed files with 175 additions and 14 deletions
|
|
@ -80,5 +80,47 @@ static bool qobjectConnectCallback(QObject* source, const char* signal, PyObject
|
||||||
}
|
}
|
||||||
slotIndex = metaObject->indexOfSlot(slot);
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1346,9 +1346,18 @@
|
||||||
%PYARG_0 = %CONVERTTOPYTHON[bool](PySide::SignalManager::instance().emitSignal(%CPPSELF, %1, %PYARG_2));
|
%PYARG_0 = %CONVERTTOPYTHON[bool](PySide::SignalManager::instance().emitSignal(%CPPSELF, %1, %PYARG_2));
|
||||||
</inject-code>
|
</inject-code>
|
||||||
</add-function>
|
</add-function>
|
||||||
<!-- <modify-function signature="disconnect(const QObject*, const char*)" remove="all"/> -->
|
<add-function signature="disconnect(const char *, PyCallable*)" return-type="bool">
|
||||||
<!-- <modify-function signature="disconnect(const char*, const QObject*, const char*)" remove="all"/> -->
|
<inject-code class="target" position="beginning">
|
||||||
<!-- <modify-function signature="disconnect(const QObject*, const char*, const QObject*, const char *)" remove="all"/> -->
|
// %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">
|
<inject-code class="native" position="beginning">
|
||||||
static bool
|
static bool
|
||||||
qobjectInheritsInternal(PyTypeObject *objType, const char *class_name)
|
qobjectInheritsInternal(PyTypeObject *objType, const char *class_name)
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QMetaMethod>
|
||||||
|
|
||||||
using namespace PySide;
|
using namespace PySide;
|
||||||
|
|
||||||
|
|
@ -83,6 +84,20 @@ void DynamicQMetaObject::addSlot(const char* slot)
|
||||||
updateMetaObject();
|
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()
|
void DynamicQMetaObject::updateMetaObject()
|
||||||
{
|
{
|
||||||
// these values are from moc source code, generator.cpp:66
|
// these values are from moc source code, generator.cpp:66
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,13 @@ class PYSIDE_API DynamicQMetaObject : public QMetaObject
|
||||||
public:
|
public:
|
||||||
DynamicQMetaObject(const char* className, const QMetaObject* metaObject);
|
DynamicQMetaObject(const char* className, const QMetaObject* metaObject);
|
||||||
~DynamicQMetaObject();
|
~DynamicQMetaObject();
|
||||||
|
|
||||||
void addSignal(const char* signal);
|
void addSignal(const char* signal);
|
||||||
void addSlot(const char* slot);
|
void addSlot(const char* slot);
|
||||||
|
|
||||||
|
void removeSignal(uint idex);
|
||||||
|
void removeSlot(uint index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QLinkedList<QByteArray> m_signals;
|
QLinkedList<QByteArray> m_signals;
|
||||||
QLinkedList<QByteArray> m_slots;
|
QLinkedList<QByteArray> m_slots;
|
||||||
|
|
|
||||||
|
|
@ -39,16 +39,87 @@
|
||||||
#include <autodecref.h>
|
#include <autodecref.h>
|
||||||
#include "typeresolver.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;
|
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()
|
GlobalReceiver::~GlobalReceiver()
|
||||||
{
|
{
|
||||||
foreach(PyObject* obj, m_slotReceivers)
|
foreach(DynamicSlotData* data, m_slotReceivers)
|
||||||
Py_DECREF(obj);
|
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
|
const QMetaObject* GlobalReceiver::metaObject() const
|
||||||
|
|
@ -60,8 +131,9 @@ void GlobalReceiver::addSlot(const char* slot, PyObject* callback)
|
||||||
{
|
{
|
||||||
m_metaObject.addSlot(slot);
|
m_metaObject.addSlot(slot);
|
||||||
int slotId = m_metaObject.indexOfSlot(slot);
|
int slotId = m_metaObject.indexOfSlot(slot);
|
||||||
Py_INCREF(callback);
|
if (!m_slotReceivers.contains(slotId)) {
|
||||||
m_slotReceivers[slotId] = callback;
|
m_slotReceivers[slotId] = new DynamicSlotData(callback);
|
||||||
|
}
|
||||||
|
|
||||||
bool isShortCircuit = true;
|
bool isShortCircuit = true;
|
||||||
for (int i = 0; slot[i]; ++i) {
|
for (int i = 0; slot[i]; ++i) {
|
||||||
|
|
@ -78,8 +150,9 @@ void GlobalReceiver::addSlot(const char* slot, PyObject* callback)
|
||||||
|
|
||||||
void GlobalReceiver::removeSlot(int slotId)
|
void GlobalReceiver::removeSlot(int slotId)
|
||||||
{
|
{
|
||||||
PyObject* obj = m_slotReceivers.take(slotId);
|
delete m_slotReceivers.take(slotId);
|
||||||
Py_XDECREF(obj);
|
m_metaObject.removeSlot(slotId);
|
||||||
|
m_shortCircuitSlots.remove(slotId);
|
||||||
}
|
}
|
||||||
|
|
||||||
int GlobalReceiver::qt_metacall(QMetaObject::Call call, int id, void** args)
|
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);
|
QMetaMethod slot = m_metaObject.method(id);
|
||||||
Q_ASSERT(slot.methodType() == QMetaMethod::Slot);
|
Q_ASSERT(slot.methodType() == QMetaMethod::Slot);
|
||||||
|
|
||||||
PyObject* callback = m_slotReceivers.value(id);
|
DynamicSlotData* data = m_slotReceivers.value(id);
|
||||||
if (!callback) {
|
if (!data) {
|
||||||
qWarning() << "Unknown global slot, id:" << id;
|
qWarning() << "Unknown global slot, id:" << id;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int numArgs;
|
int numArgs;
|
||||||
PyObject* retval = 0;
|
PyObject* retval = 0;
|
||||||
|
PyObject* callback = data->callback();
|
||||||
if (m_shortCircuitSlots.contains(id)) {
|
if (m_shortCircuitSlots.contains(id)) {
|
||||||
retval = PyObject_CallObject(callback, reinterpret_cast<PyObject*>(args[1]));
|
retval = PyObject_CallObject(callback, reinterpret_cast<PyObject*>(args[1]));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,8 @@
|
||||||
namespace PySide
|
namespace PySide
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class DynamicSlotData;
|
||||||
|
|
||||||
class GlobalReceiver : public QObject
|
class GlobalReceiver : public QObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -53,10 +55,12 @@ public:
|
||||||
const QMetaObject* metaObject() const;
|
const QMetaObject* metaObject() const;
|
||||||
void addSlot(const char* slot, PyObject* callback);
|
void addSlot(const char* slot, PyObject* callback);
|
||||||
void removeSlot(int slotId);
|
void removeSlot(int slotId);
|
||||||
|
void connectNotify(int slotId);
|
||||||
|
void disconnectNotify(int slotId);
|
||||||
private:
|
private:
|
||||||
DynamicQMetaObject m_metaObject;
|
DynamicQMetaObject m_metaObject;
|
||||||
QHash<int, PyObject* > m_slotReceivers;
|
|
||||||
QSet<int> m_shortCircuitSlots;
|
QSet<int> m_shortCircuitSlots;
|
||||||
|
QHash<int, DynamicSlotData* > m_slotReceivers;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -164,6 +164,16 @@ QObject* SignalManager::globalReceiver()
|
||||||
return &m_d->m_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)
|
void SignalManager::addGlobalSlot(const char* slot, PyObject* callback)
|
||||||
{
|
{
|
||||||
m_d->m_globalReceiver.addSlot(slot, callback);
|
m_d->m_globalReceiver.addSlot(slot, callback);
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,9 @@ public:
|
||||||
|
|
||||||
static int qt_metacall(QObject* object, QMetaObject::Call call, int id, void** args);
|
static int qt_metacall(QObject* object, QMetaObject::Call call, int id, void** args);
|
||||||
void addGlobalSlot(const char* slot, PyObject* callback);
|
void addGlobalSlot(const char* slot, PyObject* callback);
|
||||||
|
|
||||||
|
void globalReceiverConnectNotify(int slotIndex);
|
||||||
|
void globalReceiverDisconnectNotify(int slotIndex);
|
||||||
private:
|
private:
|
||||||
struct SignalManagerPrivate;
|
struct SignalManagerPrivate;
|
||||||
SignalManagerPrivate* m_d;
|
SignalManagerPrivate* m_d;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue