Signal objects redirect calls for homonymous methods.

This commit is contained in:
Marcelo Lira 2010-10-07 17:25:56 -03:00
commit 7fab5c03a9
4 changed files with 162 additions and 99 deletions

View file

@ -52,6 +52,7 @@ struct SignalData {
char* signalName; char* signalName;
char** signatures; char** signatures;
int signaturesSize; int signaturesSize;
PyObject* homonymousMethod;
}; };
static int signalTpInit(PyObject*, PyObject*, PyObject*); static int signalTpInit(PyObject*, PyObject*, PyObject*);
@ -64,54 +65,57 @@ static PyObject* signalInstanceDisconnect(PyObject*, PyObject*);
static PyObject* signalInstanceEmit(PyObject*, PyObject*); static PyObject* signalInstanceEmit(PyObject*, PyObject*);
static PyObject* signalInstanceGetItem(PyObject*, PyObject*); static PyObject* signalInstanceGetItem(PyObject*, PyObject*);
static PyObject* signalInstanceCall(PyObject* self, PyObject* args, PyObject* kw);
static PyObject* signalCall(PyObject*, PyObject*, PyObject*);
PyTypeObject PySideSignalType = { PyTypeObject PySideSignalType = {
PyObject_HEAD_INIT(0) PyObject_HEAD_INIT(0)
0, /*ob_size*/ /*ob_size*/ 0,
"PySide.QtCore."SIGNAL_CLASS_NAME, /*tp_name*/ /*tp_name*/ "PySide.QtCore."SIGNAL_CLASS_NAME,
sizeof(SignalData), /*tp_basicsize*/ /*tp_basicsize*/ sizeof(SignalData),
0, /*tp_itemsize*/ /*tp_itemsize*/ 0,
0, /*tp_dealloc*/ /*tp_dealloc*/ &Shiboken::deallocWrapper,
0, /*tp_print*/ /*tp_print*/ 0,
0, /*tp_getattr*/ /*tp_getattr*/ 0,
0, /*tp_setattr*/ /*tp_setattr*/ 0,
0, /*tp_compare*/ /*tp_compare*/ 0,
0, /*tp_repr*/ /*tp_repr*/ 0,
0, /*tp_as_number*/ /*tp_as_number*/ 0,
0, /*tp_as_sequence*/ /*tp_as_sequence*/ 0,
0, /*tp_as_mapping*/ /*tp_as_mapping*/ 0,
0, /*tp_hash */ /*tp_hash*/ 0,
0, /*tp_call*/ /*tp_call*/ signalCall,
0, /*tp_str*/ /*tp_str*/ 0,
0, /*tp_getattro*/ /*tp_getattro*/ 0,
0, /*tp_setattro*/ /*tp_setattro*/ 0,
0, /*tp_as_buffer*/ /*tp_as_buffer*/ 0,
Py_TPFLAGS_DEFAULT, /*tp_flags*/ /*tp_flags*/ Py_TPFLAGS_DEFAULT,
SIGNAL_CLASS_NAME, /*tp_doc */ /*tp_doc*/ SIGNAL_CLASS_NAME,
0, /*tp_traverse */ /*tp_traverse*/ 0,
0, /*tp_clear */ /*tp_clear*/ 0,
0, /*tp_richcompare */ /*tp_richcompare*/ 0,
0, /*tp_weaklistoffset */ /*tp_weaklistoffset*/ 0,
0, /*tp_iter */ /*tp_iter*/ 0,
0, /*tp_iternext */ /*tp_iternext*/ 0,
0, /*tp_methods */ /*tp_methods*/ 0,
0, /*tp_members */ /*tp_members*/ 0,
0, /*tp_getset */ /*tp_getset*/ 0,
0, /*tp_base */ /*tp_base*/ 0,
0, /*tp_dict */ /*tp_dict*/ 0,
0, /*tp_descr_get */ /*tp_descr_get*/ 0,
0, /*tp_descr_set */ /*tp_descr_set*/ 0,
0, /*tp_dictoffset */ /*tp_dictoffset*/ 0,
signalTpInit, /*tp_init */ /*tp_init*/ signalTpInit,
0, /*tp_alloc */ /*tp_alloc*/ 0,
PyType_GenericNew, /*tp_new */ /*tp_new*/ PyType_GenericNew,
signalFree, /*tp_free */ /*tp_free*/ signalFree,
0, /*tp_is_gc */ /*tp_is_gc*/ 0,
0, /*tp_bases */ /*tp_bases*/ 0,
0, /*tp_mro */ /*tp_mro*/ 0,
0, /*tp_cache */ /*tp_cache*/ 0,
0, /*tp_subclasses */ /*tp_subclasses*/ 0,
0, /*tp_weaklist */ /*tp_weaklist*/ 0,
0, /*tp_del */ /*tp_del*/ 0,
}; };
static PyMethodDef SignalInstance_methods[] = { static PyMethodDef SignalInstance_methods[] = {
@ -129,52 +133,52 @@ static PyMappingMethods SignalInstance_as_mapping = {
PyTypeObject PySideSignalInstanceType = { PyTypeObject PySideSignalInstanceType = {
PyObject_HEAD_INIT(0) PyObject_HEAD_INIT(0)
0, /*ob_size*/ /*ob_size*/ 0,
"PySide.QtCore."SIGNAL_CLASS_NAME, /*tp_name*/ /*tp_name*/ "PySide.QtCore."SIGNAL_CLASS_NAME,
sizeof(PySideSignalInstanceData),/*tp_basicsize*/ /*tp_basicsize*/ sizeof(PySideSignalInstanceData),
0, /*tp_itemsize*/ /*tp_itemsize*/ 0,
0, /*tp_dealloc*/ /*tp_dealloc*/ 0,
0, /*tp_print*/ /*tp_print*/ 0,
0, /*tp_getattr*/ /*tp_getattr*/ 0,
0, /*tp_setattr*/ /*tp_setattr*/ 0,
0, /*tp_compare*/ /*tp_compare*/ 0,
0, /*tp_repr*/ /*tp_repr*/ 0,
0, /*tp_as_number*/ /*tp_as_number*/ 0,
0, /*tp_as_sequence*/ /*tp_as_sequence*/ 0,
&SignalInstance_as_mapping,/*tp_as_mapping*/ /*tp_as_mapping*/ &SignalInstance_as_mapping,
0, /*tp_hash */ /*tp_hash*/ 0,
0, /*tp_call*/ /*tp_call*/ signalInstanceCall,
0, /*tp_str*/ /*tp_str*/ 0,
0, /*tp_getattro*/ /*tp_getattro*/ 0,
0, /*tp_setattro*/ /*tp_setattro*/ 0,
0, /*tp_as_buffer*/ /*tp_as_buffer*/ 0,
Py_TPFLAGS_DEFAULT, /*tp_flags*/ /*tp_flags*/ Py_TPFLAGS_DEFAULT,
SIGNAL_CLASS_NAME, /*tp_doc */ /*tp_doc*/ SIGNAL_CLASS_NAME,
0, /*tp_traverse */ /*tp_traverse*/ 0,
0, /*tp_clear */ /*tp_clear*/ 0,
0, /*tp_richcompare */ /*tp_richcompare*/ 0,
0, /*tp_weaklistoffset */ /*tp_weaklistoffset*/ 0,
0, /*tp_iter */ /*tp_iter*/ 0,
0, /*tp_iternext */ /*tp_iternext*/ 0,
SignalInstance_methods, /*tp_methods */ /*tp_methods*/ SignalInstance_methods,
0, /*tp_members */ /*tp_members*/ 0,
0, /*tp_getset */ /*tp_getset*/ 0,
0, /*tp_base */ /*tp_base*/ 0,
0, /*tp_dict */ /*tp_dict*/ 0,
0, /*tp_descr_get */ /*tp_descr_get*/ 0,
0, /*tp_descr_set */ /*tp_descr_set*/ 0,
0, /*tp_dictoffset */ /*tp_dictoffset*/ 0,
0, /*tp_init */ /*tp_init*/ 0,
0, /*tp_alloc */ /*tp_alloc*/ 0,
PyType_GenericNew, /*tp_new */ /*tp_new*/ PyType_GenericNew,
signalInstanceFree, /*tp_free */ /*tp_free*/ signalInstanceFree,
0, /*tp_is_gc */ /*tp_is_gc*/ 0,
0, /*tp_bases */ /*tp_bases*/ 0,
0, /*tp_mro */ /*tp_mro*/ 0,
0, /*tp_cache */ /*tp_cache*/ 0,
0, /*tp_subclasses */ /*tp_subclasses*/ 0,
0, /*tp_weaklist */ /*tp_weaklist*/ 0,
0, /*tp_del */ /*tp_del*/ 0,
}; };
int signalTpInit(PyObject* self, PyObject* args, PyObject* kwds) int signalTpInit(PyObject* self, PyObject* args, PyObject* kwds)
@ -224,6 +228,8 @@ void signalFree(void *self)
free(data->signalName); free(data->signalName);
data->initialized = 0; data->initialized = 0;
data->signaturesSize = 0; data->signaturesSize = 0;
Py_XDECREF(data->homonymousMethod);
data->homonymousMethod = 0;
pySelf->ob_type->tp_base->tp_free(self); pySelf->ob_type->tp_base->tp_free(self);
} }
@ -236,8 +242,10 @@ void signalInstanceFree(void* self)
free(data->signalName); free(data->signalName);
free(data->signature); free(data->signature);
Py_XDECREF(data->homonymousMethod);
if (data->next) { if (data->next) {
Py_XDECREF(data->next); Py_DECREF(data->next);
data->next = 0; data->next = 0;
} }
pySelf->ob_type->tp_base->tp_free(self); pySelf->ob_type->tp_base->tp_free(self);
@ -385,6 +393,38 @@ PyObject* signalInstanceDisconnect(PyObject* self, PyObject* args)
return 0; return 0;
} }
PyObject* signalCall(PyObject* self, PyObject* args, PyObject* kw)
{
SignalData* signalData = reinterpret_cast<SignalData*>(self);
if (!signalData->homonymousMethod) {
PyErr_SetString(PyExc_TypeError, "native Qt signal is not callable");
return 0;
}
descrgetfunc getDescriptor = signalData->homonymousMethod->ob_type->tp_descr_get;
Shiboken::AutoDecRef homonymousMethod(getDescriptor(signalData->homonymousMethod, 0, 0));
if (PyCFunction_GET_FLAGS(homonymousMethod.object()) & METH_STATIC)
return PyCFunction_Call(homonymousMethod, args, kw);
ternaryfunc callFunc = signalData->homonymousMethod->ob_type->tp_call;
return callFunc(homonymousMethod, args, kw);
}
PyObject* signalInstanceCall(PyObject* self, PyObject* args, PyObject* kw)
{
PySideSignalInstanceData* signalData = reinterpret_cast<PySideSignalInstanceData*>(self);
if (!signalData->homonymousMethod) {
PyErr_SetString(PyExc_TypeError, "native Qt signal is not callable");
return 0;
}
descrgetfunc getDescriptor = signalData->homonymousMethod->ob_type->tp_descr_get;
Shiboken::AutoDecRef homonymousMethod(getDescriptor(signalData->homonymousMethod, signalData->source, 0));
return PyCFunction_Call(homonymousMethod, args, kw);
}
} // extern "C" } // extern "C"
namespace PySide namespace PySide
@ -503,6 +543,11 @@ void signalInstanceInitialize(PyObject* instance, PyObject* name, SignalData* da
self->source = source; self->source = source;
self->signature = signalBuildSignature(self->signalName, data->signatures[index]); self->signature = signalBuildSignature(self->signalName, data->signatures[index]);
self->homonymousMethod = 0;
if (data->homonymousMethod) {
self->homonymousMethod = data->homonymousMethod;
Py_INCREF(self->homonymousMethod);
}
index++; index++;
if (index < data->signaturesSize) { if (index < data->signaturesSize) {
@ -531,6 +576,7 @@ PyObject* signalNew(const char* name, ...)
self->signaturesSize = 0; self->signaturesSize = 0;
self->signatures = 0; self->signatures = 0;
self->initialized = 0; self->initialized = 0;
self->homonymousMethod = 0;
va_start(listSignatures, name); va_start(listSignatures, name);
sig = va_arg(listSignatures, char*); sig = va_arg(listSignatures, char*);
@ -556,5 +602,15 @@ PyObject* signalBuildQtCompatible(const char* signature)
return ret; return ret;
} }
void addSignalToWrapper(Shiboken::SbkBaseWrapperType* wrapperType, const char* signalName, PyObject* signal)
{
PyObject* typeDict = wrapperType->super.ht_type.tp_dict;
PyObject* homonymousMethod;
if ((homonymousMethod = PyDict_GetItemString(typeDict, signalName))) {
Py_INCREF(homonymousMethod);
reinterpret_cast<SignalData*>(signal)->homonymousMethod = homonymousMethod;
}
PyDict_SetItemString(typeDict, signalName, signal);
}
} //namespace PySide } //namespace PySide

View file

@ -27,6 +27,11 @@
#include <Python.h> #include <Python.h>
#include <QObject> #include <QObject>
namespace Shiboken
{
struct SbkBaseWrapperType;
}
extern "C" extern "C"
{ {
extern PYSIDE_API PyTypeObject PySideSignalInstanceType; extern PYSIDE_API PyTypeObject PySideSignalInstanceType;
@ -37,6 +42,7 @@ extern "C"
char* signalName; char* signalName;
char* signature; char* signature;
PyObject* source; PyObject* source;
PyObject* homonymousMethod;
PyObject* next; PyObject* next;
}; };
}; //extern "C" }; //extern "C"
@ -46,6 +52,7 @@ namespace PySide
PYSIDE_API PyObject* signalNew(const char* name, ...); PYSIDE_API PyObject* signalNew(const char* name, ...);
PYSIDE_API void signalUpdateSource(PyObject* source); PYSIDE_API void signalUpdateSource(PyObject* source);
PYSIDE_API void addSignalToWrapper(Shiboken::SbkBaseWrapperType* wrapperType, const char* signalName, PyObject* signal);
} //namespace PySide } //namespace PySide

View file

@ -67,5 +67,5 @@ target_link_libraries(testbinding
add_dependencies(testbinding pyside QtCore libpyside pysidetest) add_dependencies(testbinding pyside QtCore libpyside pysidetest)
PYSIDE_TEST(homonimoussignalandmethod_test.py) PYSIDE_TEST(homonymoussignalandmethod_test.py)

View file

@ -3,9 +3,9 @@
import unittest import unittest
from testbinding import TestObject from testbinding import TestObject
'''Tests the behaviour of homonimous signals and slots.''' '''Tests the behaviour of homonymous signals and slots.'''
class HomonimousSignalAndMethodTest(unittest.TestCase): class HomonymousSignalAndMethodTest(unittest.TestCase):
def setUp(self): def setUp(self):
self.value = 123 self.value = 123
@ -39,13 +39,13 @@ class HomonimousSignalAndMethodTest(unittest.TestCase):
def testCallingInstanceMethodWithoutArguments(self): def testCallingInstanceMethodWithoutArguments(self):
self.assertRaises(TypeError, TestObject.idValue) self.assertRaises(TypeError, TestObject.idValue)
def testHomonimousSignalAndMethod(self): def testHomonymousSignalAndMethod(self):
self.assertEqual(self.obj.idValue(), self.value) self.assertEqual(self.obj.idValue(), self.value)
def testHomonimousSignalAndStaticMethod(self): def testHomonymousSignalAndStaticMethod(self):
self.assertEqual(TestObject.staticMethodDouble(3), 6) self.assertEqual(TestObject.staticMethodDouble(3), 6)
def testHomonimousSignalAndStaticMethodFromInstance(self): def testHomonymousSignalAndStaticMethodFromInstance(self):
self.assertEqual(self.obj.staticMethodDouble(4), 8) self.assertEqual(self.obj.staticMethodDouble(4), 8)
if __name__ == '__main__': if __name__ == '__main__':