diff options
-rw-r--r-- | PySide/QtCore/typesystem_core.xml | 8 | ||||
-rw-r--r-- | libpyside/dynamicqmetaobject.cpp | 7 | ||||
-rw-r--r-- | libpyside/pyside.cpp | 6 | ||||
-rw-r--r-- | libpyside/qsignal.cpp | 449 | ||||
-rw-r--r-- | libpyside/qsignal.h | 29 | ||||
-rw-r--r-- | libpyside/qsignal_p.h | 40 | ||||
-rw-r--r-- | libpyside/qslot.cpp | 12 |
7 files changed, 293 insertions, 258 deletions
diff --git a/PySide/QtCore/typesystem_core.xml b/PySide/QtCore/typesystem_core.xml index 37decba1f..d6fe524bb 100644 --- a/PySide/QtCore/typesystem_core.xml +++ b/PySide/QtCore/typesystem_core.xml @@ -1793,7 +1793,7 @@ <!-- Second argument is a PySide.QtCore.Signal. See bug #362. --> <add-function signature="singleShot(int, PyObject*)" static="yes"> <inject-code class="target" position="beginning"> - if (!PyObject_TypeCheck(%2, &PySide::SignalInstance_Type)) + if (!PyObject_TypeCheck(%2, &PySideSignalInstanceType)) goto Sbk%TYPEFunc_%FUNCTION_NAME_TypeError; // %FUNCTION_NAME() - disable generation of c++ function call @@ -1803,7 +1803,7 @@ QTimer* timer = Converter<QTimer*>::toCpp(pyTimer); timer->setSingleShot(true); timer->connect(timer, SIGNAL(timeout()), timer, SLOT(deleteLater())); - PySide::SignalInstanceData* signalInstance = reinterpret_cast<PySide::SignalInstanceData*>(%2); + PySideSignalInstanceData* signalInstance = reinterpret_cast<PySideSignalInstanceData*>(%2); Shiboken::AutoDecRef signalSignature(PyString_FromFormat("2%s", signalInstance->signature)); Shiboken::AutoDecRef result( PyObject_CallMethod(pyTimer, @@ -2498,9 +2498,9 @@ // since it refers to a name very tied to the generator implementation. // Check bug #362 for more information on this // http://bugs.openbossa.org/show_bug.cgi?id=362 - if (!PyObject_TypeCheck(%1, &PySide::SignalInstance_Type)) + if (!PyObject_TypeCheck(%1, &PySideSignalInstanceType)) goto Sbk%TYPEFunc_%FUNCTION_NAME_TypeError; - PySide::SignalInstanceData* signalInstance = reinterpret_cast<PySide::SignalInstanceData*>(%1); + PySideSignalInstanceData* signalInstance = reinterpret_cast<PySideSignalInstanceData*>(%1); QObject* sender = %CONVERTTOCPP[QObject*](signalInstance->source); %PYARG_0 = %CONVERTTOPYTHON[QSignalTransition*](%CPPSELF->%FUNCTION_NAME(sender, signalInstance->signature, %2)); </inject-code> diff --git a/libpyside/dynamicqmetaobject.cpp b/libpyside/dynamicqmetaobject.cpp index db0611208..8bb1a6eab 100644 --- a/libpyside/dynamicqmetaobject.cpp +++ b/libpyside/dynamicqmetaobject.cpp @@ -33,6 +33,7 @@ #include <QMetaMethod> #include "qsignal.h" +#include "qsignal_p.h" #include "qproperty.h" #include "qproperty_p.h" @@ -393,14 +394,14 @@ DynamicQMetaObject* DynamicQMetaObject::createBasedOn(PyObject* pyObj, PyTypeObj } //Register signals - if (value->ob_type == &Signal_Type) { + if (value->ob_type == &PySideSignalType) { PyObject *attr = PyObject_GetAttr(pyObj, key); - SignalInstanceData *data = reinterpret_cast<SignalInstanceData*>(attr); + PySideSignalInstanceData *data = reinterpret_cast<PySideSignalInstanceData*>(attr); while(data) { int index = base->indexOfSignal(data->signature); if (index == -1) mo->addSignal(data->signature); - data = reinterpret_cast<SignalInstanceData*>(data->next); + data = reinterpret_cast<PySideSignalInstanceData*>(data->next); } } diff --git a/libpyside/pyside.cpp b/libpyside/pyside.cpp index ebc17cf5f..3cc1fd4c7 100644 --- a/libpyside/pyside.cpp +++ b/libpyside/pyside.cpp @@ -26,13 +26,13 @@ #include "qproperty_p.h" #include "qproperty.h" #include "qsignal.h" +#include "qsignal_p.h" #include <basewrapper.h> #include <conversions.h> #include <algorithm> #include <cctype> #include <QStack> -extern "C" void init_signal(PyObject* module); extern "C" void init_slot(PyObject* module); static QStack<PySide::CleanupFunction> cleanupFunctionList; @@ -42,7 +42,7 @@ namespace PySide void init(PyObject *module) { - init_signal(module); + initSignalSupport(module); init_slot(module); initQProperty(module); // Init signal manager, so it will register some meta types used by QVariant. @@ -75,7 +75,7 @@ bool fillQtProperties(PyObject* qObj, const QMetaObject* metaObj, PyObject* kwds propName.append("()"); if (metaObj->indexOfSignal(propName) != -1) { propName.prepend('2'); - PySide::signal_connect(qObj, propName, value); + PySide::signalConnect(qObj, propName, value); } else { PyErr_Format(PyExc_AttributeError, "'%s' is not a Qt property or a signal", propName.constData()); return false; diff --git a/libpyside/qsignal.cpp b/libpyside/qsignal.cpp index 76fc45046..46cb1b694 100644 --- a/libpyside/qsignal.cpp +++ b/libpyside/qsignal.cpp @@ -25,45 +25,46 @@ #include <QDebug> #include "qsignal.h" +#include "qsignal_p.h" #include "signalmanager.h" #define SIGNAL_CLASS_NAME "Signal" #define QT_SIGNAL_SENTINEL "2" +struct SignalData; + namespace PySide { + //aux + static char* signalBuildSignature(const char*, const char*); + static void signalAppendSignature(SignalData*, char*); + static void signalInstanceInitialize(PyObject*, PyObject*, SignalData*, PyObject *, int); + static char* signalParseSignature(PyObject*); + static PyObject* signalBuildQtCompatible(const char*); +} extern "C" { -char* get_type_name(PyObject*); - -typedef struct { +struct SignalData { PyObject_HEAD bool initialized; char* signalName; char** signatures; int signaturesSize; -} SignalData; +}; -static int signal_init(PyObject*, PyObject*, PyObject*); -static void signal_free(void*); -static void signal_instance_free(void*); +static int signalTpInit(PyObject*, PyObject*, PyObject*); +static void signalFree(void*); +static void signalInstanceFree(void*); //methods -static PyObject* signal_instance_connect(PyObject*, PyObject*, PyObject*); -static PyObject* signal_instance_disconnect(PyObject*, PyObject*); -static PyObject* signal_instance_emit(PyObject*, PyObject*); -static PyObject* signal_instance_get_item(PyObject*, PyObject*); - -//aux -static char* signal_build_signature(const char*, const char*); -static void signal_append_signature(SignalData*, char*); -static void signal_instance_initialize(PyObject*, PyObject*, SignalData*, PyObject *, int); -static char* signal_parse_signature(PyObject*); -static PyObject* signal_build_qt_compatible(const char*); - -PyTypeObject Signal_Type = { +static PyObject* signalInstanceConnect(PyObject*, PyObject*, PyObject*); +static PyObject* signalInstanceDisconnect(PyObject*, PyObject*); +static PyObject* signalInstanceEmit(PyObject*, PyObject*); +static PyObject* signalInstanceGetItem(PyObject*, PyObject*); + +PyTypeObject PySideSignalType = { PyObject_HEAD_INIT(0) 0, /*ob_size*/ "PySide.QtCore."SIGNAL_CLASS_NAME, /*tp_name*/ @@ -100,10 +101,10 @@ PyTypeObject Signal_Type = { 0, /*tp_descr_get */ 0, /*tp_descr_set */ 0, /*tp_dictoffset */ - signal_init, /*tp_init */ + signalTpInit, /*tp_init */ 0, /*tp_alloc */ PyType_GenericNew, /*tp_new */ - signal_free, /*tp_free */ + signalFree, /*tp_free */ 0, /*tp_is_gc */ 0, /*tp_bases */ 0, /*tp_mro */ @@ -114,23 +115,23 @@ PyTypeObject Signal_Type = { }; static PyMethodDef SignalInstance_methods[] = { - {"connect", (PyCFunction)signal_instance_connect, METH_VARARGS|METH_KEYWORDS, 0}, - {"disconnect", signal_instance_disconnect, METH_VARARGS, 0}, - {"emit", signal_instance_emit, METH_VARARGS, 0}, + {"connect", (PyCFunction)signalInstanceConnect, METH_VARARGS|METH_KEYWORDS, 0}, + {"disconnect", signalInstanceDisconnect, METH_VARARGS, 0}, + {"emit", signalInstanceEmit, METH_VARARGS, 0}, {0} /* Sentinel */ }; static PyMappingMethods SignalInstance_as_mapping = { 0, - signal_instance_get_item, + signalInstanceGetItem, 0 }; -PyTypeObject SignalInstance_Type = { +PyTypeObject PySideSignalInstanceType = { PyObject_HEAD_INIT(0) 0, /*ob_size*/ "PySide.QtCore."SIGNAL_CLASS_NAME, /*tp_name*/ - sizeof(SignalInstanceData),/*tp_basicsize*/ + sizeof(PySideSignalInstanceData),/*tp_basicsize*/ 0, /*tp_itemsize*/ 0, /*tp_dealloc*/ 0, /*tp_print*/ @@ -166,7 +167,7 @@ PyTypeObject SignalInstance_Type = { 0, /*tp_init */ 0, /*tp_alloc */ PyType_GenericNew, /*tp_new */ - signal_instance_free, /*tp_free */ + signalInstanceFree, /*tp_free */ 0, /*tp_is_gc */ 0, /*tp_bases */ 0, /*tp_mro */ @@ -176,137 +177,7 @@ PyTypeObject SignalInstance_Type = { 0, /*tp_del */ }; - -void init_signal(PyObject* module) -{ - if (PyType_Ready(&Signal_Type) < 0) - return; - - Py_INCREF(&Signal_Type); - PyModule_AddObject(module, SIGNAL_CLASS_NAME, ((PyObject*)&Signal_Type)); - - if (PyType_Ready(&SignalInstance_Type) < 0) - return; - - Py_INCREF(&SignalInstance_Type); -} - - -} // extern "C" - - -PyObject* signal_instance_get_item(PyObject* self, PyObject* key) -{ - SignalInstanceData* data = reinterpret_cast<SignalInstanceData*>(self); - char* sigKey = signal_parse_signature(key); - char* sig = signal_build_signature(data->signalName, sigKey); - free(sigKey); - const char* sigName = data->signalName; - - while(data) { - if (strcmp(data->signature, sig) == 0) { - free(sig); - PyObject *result = reinterpret_cast<PyObject*>(data); - Py_INCREF(result); - return result; - } - data = reinterpret_cast<SignalInstanceData*>(data->next); - } - PyErr_Format(PyExc_IndexError, "Signature %s not found for signal: %s", sig, sigName); - free(sig); - - return 0; -} - -void signalUpdateSource(PyObject* source) -{ - Shiboken::AutoDecRef attrs(PyObject_Dir(source)); - - for(int i = 0, iMax = PyList_GET_SIZE(attrs.object()); i < iMax; ++i) { - PyObject *attrName = PyList_GET_ITEM(attrs.object(), i); - Shiboken::AutoDecRef attr(PyObject_GetAttr(reinterpret_cast<PyObject*>(source->ob_type), attrName)); - if (!attr.isNull() && attr->ob_type == &Signal_Type) { - Shiboken::AutoDecRef signalInstance((PyObject*)PyObject_New(SignalInstanceData, &SignalInstance_Type)); - signal_instance_initialize(signalInstance, attrName, reinterpret_cast<SignalData*>(attr.object()), source, 0); - PyObject_SetAttr(source, attrName, signalInstance); - } - } -} - -char* get_type_name(PyObject* type) -{ - if (PyType_Check(type)) { - char *typeName = NULL; - if (type->ob_type == &Shiboken::SbkBaseWrapperType_Type) { - Shiboken::SbkBaseWrapperType *objType = reinterpret_cast<Shiboken::SbkBaseWrapperType*>(type); - Q_ASSERT(objType->original_name); - typeName = strdup(objType->original_name); - } else { - // Translate python types to Qt names - PyTypeObject *objType = reinterpret_cast<PyTypeObject*>(type); - if ((objType == &PyString_Type) || (objType == &PyUnicode_Type)) - typeName = strdup("QString"); - else if (objType == &PyInt_Type) - typeName = strdup("int"); - else if (objType == &PyLong_Type) - typeName = strdup("long"); - else if (objType == &PyFloat_Type) - typeName = strdup("qreal"); - else if (objType == &PyBool_Type) - typeName = strdup("bool"); - else - typeName = strdup("PyObject"); - } - return typeName; - } else if (PyString_Check(type)) { - return strdup(PyString_AS_STRING(type)); - } - return 0; -} - -char* signal_build_signature(const char *name, const char *signature) -{ - QString signal; - signal.sprintf("%s(%s)", name, signature); - return strdup(QMetaObject::normalizedSignature(signal.toAscii())); -} - -char* signal_parse_signature(PyObject *args) -{ - char *signature = 0; - if (args && (PyString_Check(args) || (!PySequence_Check(args) && (args != Py_None)))) - return get_type_name(args); - - for(Py_ssize_t i = 0, i_max = PySequence_Size(args); i < i_max; i++) { - Shiboken::AutoDecRef arg(PySequence_ITEM(args, i)); - char* typeName = get_type_name(arg); - if (typeName) { - if (signature) { - signature = reinterpret_cast<char*>(realloc(signature, (strlen(signature) + 1 + strlen(typeName)) * sizeof(char*))); - signature = strcat(signature, ","); - signature = strcat(signature, typeName); - free(typeName); - } else { - signature = typeName; - } - } - } - return signature; -} - -void signal_append_signature(SignalData* self, char* signature) -{ - self->signaturesSize++; - - if (self->signaturesSize > 1) { - self->signatures = (char**) realloc(self->signatures, sizeof(char**) * self->signaturesSize); - } else { - self->signatures = (char**) malloc(sizeof(char**)); - } - self->signatures[self->signaturesSize-1] = signature; -} - -int signal_init(PyObject* self, PyObject* args, PyObject* kwds) +int signalTpInit(PyObject* self, PyObject* args, PyObject* kwds) { static PyObject *emptyTuple = 0; static const char *kwlist[] = {"name", 0}; @@ -316,7 +187,7 @@ int signal_init(PyObject* self, PyObject* args, PyObject* kwds) emptyTuple = PyTuple_New(0); if (!PyArg_ParseTupleAndKeywords(emptyTuple, kwds, - "|s:QtCore."SIGNAL_CLASS_NAME, (char**) kwlist, &argName)) + "|s:QtCore."SIGNAL_CLASS_NAME, (char**) kwlist, &argName)) return 0; bool tupledArgs = false; @@ -329,17 +200,17 @@ int signal_init(PyObject* self, PyObject* args, PyObject* kwds) PyObject *arg = PyTuple_GET_ITEM(args, i); if (PySequence_Check(arg) && !PyString_Check(arg)) { tupledArgs = true; - signal_append_signature(data, signal_parse_signature(arg)); + PySide::signalAppendSignature(data, PySide::signalParseSignature(arg)); } } if (!tupledArgs) - signal_append_signature(data, signal_parse_signature(args)); + PySide::signalAppendSignature(data, PySide::signalParseSignature(args)); return 1; } -void signal_free(void *self) +void signalFree(void *self) { PyObject *pySelf = reinterpret_cast<PyObject*>(self); SignalData *data = reinterpret_cast<SignalData*>(self); @@ -357,10 +228,10 @@ void signal_free(void *self) pySelf->ob_type->tp_base->tp_free(self); } -void signal_instance_free(void* self) +void signalInstanceFree(void* self) { PyObject *pySelf = reinterpret_cast<PyObject*>(self); - SignalInstanceData *data = reinterpret_cast<SignalInstanceData*>(self); + PySideSignalInstanceData *data = reinterpret_cast<PySideSignalInstanceData*>(self); free(data->signalName); free(data->signature); @@ -372,66 +243,47 @@ void signal_instance_free(void* self) pySelf->ob_type->tp_base->tp_free(self); } -void signal_instance_initialize(PyObject* instance, PyObject* name, SignalData* data, PyObject* source, int index) -{ - SignalInstanceData *self = reinterpret_cast<SignalInstanceData*>(instance); - self->next = 0; - if (data->signalName) - self->signalName = strdup(data->signalName); - else - self->signalName = strdup(PyString_AsString(name)); - - self->source = source; - self->signature = signal_build_signature(self->signalName, data->signatures[index]); - index++; - - if (index < data->signaturesSize) { - self->next = reinterpret_cast<PyObject*>(PyObject_New(SignalInstanceData, &SignalInstance_Type)); - signal_instance_initialize(self->next, name, data, source, index); - } -} - -PyObject* signal_instance_connect(PyObject* self, PyObject* args, PyObject* kwds) +PyObject* signalInstanceConnect(PyObject* self, PyObject* args, PyObject* kwds) { PyObject *slot = 0; PyObject *type = 0; static const char *kwlist[] = {"slot", "type", 0}; if (!PyArg_ParseTupleAndKeywords(args, kwds, - "O|O:"SIGNAL_CLASS_NAME, (char**) kwlist, &slot, &type)) + "O|O:"SIGNAL_CLASS_NAME, (char**) kwlist, &slot, &type)) return 0; - SignalInstanceData *source = reinterpret_cast<SignalInstanceData*>(self); + PySideSignalInstanceData *source = reinterpret_cast<PySideSignalInstanceData*>(self); Shiboken::AutoDecRef pyArgs(PyList_New(0)); bool match = false; - if (slot->ob_type == &SignalInstance_Type) { - SignalInstanceData *sourceWalk = source; - SignalInstanceData *targetWalk; + if (slot->ob_type == &PySideSignalInstanceType) { + PySideSignalInstanceData *sourceWalk = source; + PySideSignalInstanceData *targetWalk; //find best match while(sourceWalk && !match) { - targetWalk = reinterpret_cast<SignalInstanceData*>(slot); + targetWalk = reinterpret_cast<PySideSignalInstanceData*>(slot); while(targetWalk && !match) { if (QMetaObject::checkConnectArgs(sourceWalk->signature, targetWalk->signature)) { PyList_Append(pyArgs, sourceWalk->source); - Shiboken::AutoDecRef sourceSignature(signal_build_qt_compatible(sourceWalk->signature)); + Shiboken::AutoDecRef sourceSignature(PySide::signalBuildQtCompatible(sourceWalk->signature)); PyList_Append(pyArgs, sourceSignature); PyList_Append(pyArgs, targetWalk->source); - Shiboken::AutoDecRef targetSignature(signal_build_qt_compatible(targetWalk->signature)); + Shiboken::AutoDecRef targetSignature(PySide::signalBuildQtCompatible(targetWalk->signature)); PyList_Append(pyArgs, targetSignature); match = true; } - targetWalk = reinterpret_cast<SignalInstanceData*>(targetWalk->next); + targetWalk = reinterpret_cast<PySideSignalInstanceData*>(targetWalk->next); } - sourceWalk = reinterpret_cast<SignalInstanceData*>(sourceWalk->next); + sourceWalk = reinterpret_cast<PySideSignalInstanceData*>(sourceWalk->next); } } else { //try the first signature PyList_Append(pyArgs, source->source); - Shiboken::AutoDecRef signature(signal_build_qt_compatible(source->signature)); + Shiboken::AutoDecRef signature(PySide::signalBuildQtCompatible(source->signature)); PyList_Append(pyArgs, signature); PyList_Append(pyArgs, slot); @@ -450,20 +302,49 @@ PyObject* signal_instance_connect(PyObject* self, PyObject* args, PyObject* kwds return 0; } -bool signal_connect(PyObject* source, const char* signal, PyObject* callback) +PyObject* signalInstanceEmit(PyObject* self, PyObject* args) { - Shiboken::AutoDecRef pyMethod(PyObject_GetAttrString(source, "connect")); - if (pyMethod.isNull()) - return false; + PySideSignalInstanceData *source = reinterpret_cast<PySideSignalInstanceData*>(self); - Shiboken::AutoDecRef pySignature(PyString_FromString(signal)); - Shiboken::AutoDecRef pyArgs(PyTuple_Pack(3, source, pySignature.object(), callback)); - return PyObject_CallObject(pyMethod, pyArgs); + Shiboken::AutoDecRef pyArgs(PyList_New(0)); + Shiboken::AutoDecRef sourceSignature(PySide::signalBuildQtCompatible(source->signature)); + + PyList_Append(pyArgs, sourceSignature); + for(Py_ssize_t i = 0, max = PyTuple_Size(args); i < max; i++) + PyList_Append(pyArgs, PyTuple_GetItem(args, i)); + + Shiboken::AutoDecRef pyMethod(PyObject_GetAttrString(source->source, "emit")); + + Shiboken::AutoDecRef tupleArgs(PyList_AsTuple(pyArgs)); + return PyObject_CallObject(pyMethod, tupleArgs); } -PyObject* signal_instance_disconnect(PyObject* self, PyObject* args) +PyObject* signalInstanceGetItem(PyObject* self, PyObject* key) { - SignalInstanceData *source = reinterpret_cast<SignalInstanceData*>(self); + PySideSignalInstanceData* data = reinterpret_cast<PySideSignalInstanceData*>(self); + char* sigKey = PySide::signalParseSignature(key); + char* sig = PySide::signalBuildSignature(data->signalName, sigKey); + free(sigKey); + const char* sigName = data->signalName; + + while(data) { + if (strcmp(data->signature, sig) == 0) { + free(sig); + PyObject *result = reinterpret_cast<PyObject*>(data); + Py_INCREF(result); + return result; + } + data = reinterpret_cast<PySideSignalInstanceData*>(data->next); + } + PyErr_Format(PyExc_IndexError, "Signature %s not found for signal: %s", sig, sigName); + free(sig); + + return 0; +} + +PyObject* signalInstanceDisconnect(PyObject* self, PyObject* args) +{ + PySideSignalInstanceData *source = reinterpret_cast<PySideSignalInstanceData*>(self); Shiboken::AutoDecRef pyArgs(PyList_New(0)); PyObject *slot; @@ -473,22 +354,22 @@ PyObject* signal_instance_disconnect(PyObject* self, PyObject* args) slot = args; bool match = false; - if (slot->ob_type == &SignalInstance_Type) { - SignalInstanceData *target = reinterpret_cast<SignalInstanceData*>(slot); + if (slot->ob_type == &PySideSignalInstanceType) { + PySideSignalInstanceData *target = reinterpret_cast<PySideSignalInstanceData*>(slot); if (QMetaObject::checkConnectArgs(source->signature, target->signature)) { PyList_Append(pyArgs, source->source); - Shiboken::AutoDecRef source_signature(signal_build_qt_compatible(source->signature)); + Shiboken::AutoDecRef source_signature(PySide::signalBuildQtCompatible(source->signature)); PyList_Append(pyArgs, source_signature); PyList_Append(pyArgs, target->source); - Shiboken::AutoDecRef target_signature(signal_build_qt_compatible(target->signature)); + Shiboken::AutoDecRef target_signature(PySide::signalBuildQtCompatible(target->signature)); PyList_Append(pyArgs, target_signature); match = true; } } else { //try the first signature PyList_Append(pyArgs, source->source); - Shiboken::AutoDecRef signature(signal_build_qt_compatible(source->signature)); + Shiboken::AutoDecRef signature(PySide::signalBuildQtCompatible(source->signature)); PyList_Append(pyArgs, signature); PyList_Append(pyArgs, slot); @@ -504,28 +385,148 @@ PyObject* signal_instance_disconnect(PyObject* self, PyObject* args) return 0; } -PyObject* signal_instance_emit(PyObject* self, PyObject* args) +} // extern "C" + +namespace PySide { - SignalInstanceData *source = reinterpret_cast<SignalInstanceData*>(self); - Shiboken::AutoDecRef pyArgs(PyList_New(0)); - Shiboken::AutoDecRef source_signature(signal_build_qt_compatible(source->signature)); +void initSignalSupport(PyObject* module) +{ + if (PyType_Ready(&PySideSignalType) < 0) + return; - PyList_Append(pyArgs, source_signature); - for(Py_ssize_t i=0, i_max=PyTuple_Size(args); i < i_max; i++) - PyList_Append(pyArgs, PyTuple_GetItem(args, i)); + Py_INCREF(&PySideSignalType); + PyModule_AddObject(module, SIGNAL_CLASS_NAME, ((PyObject*)&PySideSignalType)); - Shiboken::AutoDecRef pyMethod(PyObject_GetAttrString(source->source, "emit")); + if (PyType_Ready(&PySideSignalInstanceType) < 0) + return; - Shiboken::AutoDecRef tupleArgs(PyList_AsTuple(pyArgs)); - return PyObject_CallObject(pyMethod, tupleArgs); + Py_INCREF(&PySideSignalInstanceType); +} + +void signalUpdateSource(PyObject* source) +{ + Shiboken::AutoDecRef attrs(PyObject_Dir(source)); + + for(int i = 0, iMax = PyList_GET_SIZE(attrs.object()); i < iMax; ++i) { + PyObject *attrName = PyList_GET_ITEM(attrs.object(), i); + Shiboken::AutoDecRef attr(PyObject_GetAttr(reinterpret_cast<PyObject*>(source->ob_type), attrName)); + if (!attr.isNull() && attr->ob_type == &PySideSignalType) { + Shiboken::AutoDecRef signalInstance((PyObject*)PyObject_New(PySideSignalInstanceData, &PySideSignalInstanceType)); + signalInstanceInitialize(signalInstance, attrName, reinterpret_cast<SignalData*>(attr.object()), source, 0); + PyObject_SetAttr(source, attrName, signalInstance); + } + } +} + +char* getTypeName(PyObject* type) +{ + if (PyType_Check(type)) { + char *typeName = NULL; + if (type->ob_type == &Shiboken::SbkBaseWrapperType_Type) { + Shiboken::SbkBaseWrapperType *objType = reinterpret_cast<Shiboken::SbkBaseWrapperType*>(type); + Q_ASSERT(objType->original_name); + typeName = strdup(objType->original_name); + } else { + // Translate python types to Qt names + PyTypeObject *objType = reinterpret_cast<PyTypeObject*>(type); + if ((objType == &PyString_Type) || (objType == &PyUnicode_Type)) + typeName = strdup("QString"); + else if (objType == &PyInt_Type) + typeName = strdup("int"); + else if (objType == &PyLong_Type) + typeName = strdup("long"); + else if (objType == &PyFloat_Type) + typeName = strdup("qreal"); + else if (objType == &PyBool_Type) + typeName = strdup("bool"); + else + typeName = strdup("PyObject"); + } + return typeName; + } else if (PyString_Check(type)) { + return strdup(PyString_AS_STRING(type)); + } + return 0; +} + +char* signalBuildSignature(const char *name, const char *signature) +{ + QString signal; + signal.sprintf("%s(%s)", name, signature); + return strdup(QMetaObject::normalizedSignature(signal.toAscii())); +} + +char* signalParseSignature(PyObject *args) +{ + char *signature = 0; + if (args && (PyString_Check(args) || (!PySequence_Check(args) && (args != Py_None)))) + return getTypeName(args); + + for(Py_ssize_t i = 0, i_max = PySequence_Size(args); i < i_max; i++) { + Shiboken::AutoDecRef arg(PySequence_ITEM(args, i)); + char* typeName = getTypeName(arg); + if (typeName) { + if (signature) { + signature = reinterpret_cast<char*>(realloc(signature, (strlen(signature) + 1 + strlen(typeName)) * sizeof(char*))); + signature = strcat(signature, ","); + signature = strcat(signature, typeName); + free(typeName); + } else { + signature = typeName; + } + } + } + return signature; +} + +void signalAppendSignature(SignalData* self, char* signature) +{ + self->signaturesSize++; + + if (self->signaturesSize > 1) { + self->signatures = (char**) realloc(self->signatures, sizeof(char**) * self->signaturesSize); + } else { + self->signatures = (char**) malloc(sizeof(char**)); + } + self->signatures[self->signaturesSize-1] = signature; +} + +void signalInstanceInitialize(PyObject* instance, PyObject* name, SignalData* data, PyObject* source, int index) +{ + PySideSignalInstanceData *self = reinterpret_cast<PySideSignalInstanceData*>(instance); + self->next = 0; + if (data->signalName) + self->signalName = strdup(data->signalName); + else + self->signalName = strdup(PyString_AsString(name)); + + self->source = source; + self->signature = signalBuildSignature(self->signalName, data->signatures[index]); + index++; + + if (index < data->signaturesSize) { + self->next = reinterpret_cast<PyObject*>(PyObject_New(PySideSignalInstanceData, &PySideSignalInstanceType)); + signalInstanceInitialize(self->next, name, data, source, index); + } +} + +bool signalConnect(PyObject* source, const char* signal, PyObject* callback) +{ + Shiboken::AutoDecRef pyMethod(PyObject_GetAttrString(source, "connect")); + if (pyMethod.isNull()) + return false; + + Shiboken::AutoDecRef pySignature(PyString_FromString(signal)); + Shiboken::AutoDecRef pyArgs(PyTuple_Pack(3, source, pySignature.object(), callback)); + return PyObject_CallObject(pyMethod, pyArgs); } PyObject* signalNew(const char* name, ...) { va_list listSignatures; char* sig = 0; - SignalData* self = PyObject_New(SignalData, &Signal_Type); + SignalData* self = PyObject_New(SignalData, &PySideSignalType); self->signalName = strdup(name); self->signaturesSize = 0; self->signatures = 0; @@ -535,7 +536,7 @@ PyObject* signalNew(const char* name, ...) sig = va_arg(listSignatures, char*); while(sig != NULL) { - signal_append_signature(self, strdup(sig)); + signalAppendSignature(self, strdup(sig)); sig = va_arg(listSignatures, char*); } @@ -545,7 +546,7 @@ PyObject* signalNew(const char* name, ...) } -PyObject* signal_build_qt_compatible(const char* signature) +PyObject* signalBuildQtCompatible(const char* signature) { char* qtSignature; qtSignature = reinterpret_cast<char*>(malloc(strlen(signature)+2)); diff --git a/libpyside/qsignal.h b/libpyside/qsignal.h index 54fa8f03a..617749608 100644 --- a/libpyside/qsignal.h +++ b/libpyside/qsignal.h @@ -27,28 +27,25 @@ #include <Python.h> #include <QObject> -namespace PySide -{ - -struct SignalInstanceData -{ - PyObject_HEAD - char* signalName; - char* signature; - PyObject* source; - PyObject* next; -}; - - extern "C" { - extern PYSIDE_API PyTypeObject Signal_Type; - extern PYSIDE_API PyTypeObject SignalInstance_Type; + extern PYSIDE_API PyTypeObject PySideSignalInstanceType; + + struct PySideSignalInstanceData + { + PyObject_HEAD + char* signalName; + char* signature; + PyObject* source; + PyObject* next; + }; }; //extern "C" +namespace PySide +{ + PYSIDE_API PyObject* signalNew(const char* name, ...); PYSIDE_API void signalUpdateSource(PyObject* source); -PYSIDE_API bool signal_connect(PyObject* source, const char* signal, PyObject* callback); } //namespace PySide diff --git a/libpyside/qsignal_p.h b/libpyside/qsignal_p.h new file mode 100644 index 000000000..7858011e8 --- /dev/null +++ b/libpyside/qsignal_p.h @@ -0,0 +1,40 @@ +/* + * This file is part of the PySide project. + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef PYSIDE_QSIGNAL_P_H +#define PYSIDE_QSIGNAL_P_H + +#include <Python.h> + +extern "C" +{ + extern PyTypeObject PySideSignalType; +}; //extern "C" + +namespace PySide +{ + bool signalConnect(PyObject* source, const char* signal, PyObject* callback); + char* getTypeName(PyObject*); + void initSignalSupport(PyObject* module); +} //namespace PySide + +#endif diff --git a/libpyside/qslot.cpp b/libpyside/qslot.cpp index 273de2721..762f85f28 100644 --- a/libpyside/qslot.cpp +++ b/libpyside/qslot.cpp @@ -21,9 +21,9 @@ */ #include <shiboken.h> -#include "dynamicqmetaobject_p.h" - #include <QString> +#include "dynamicqmetaobject_p.h" +#include "qsignal_p.h" #define SLOT_DEC_NAME "Slot" @@ -41,10 +41,6 @@ extern "C" static int slot_init(PyObject*, PyObject*, PyObject*); static PyObject* slot_call(PyObject*, PyObject*, PyObject*); -//external qsignal.cpp -extern char* get_type_name(PyObject*); - - // Class Definition ----------------------------------------------- static PyTypeObject Slot_Type = { PyObject_HEAD_INIT(NULL) @@ -124,7 +120,7 @@ int slot_init(PyObject *self, PyObject *args, PyObject *kw) SlotData *data = reinterpret_cast<SlotData*>(self); for(Py_ssize_t i = 0, i_max = PyTuple_Size(args); i < i_max; i++) { PyObject *argType = PyTuple_GET_ITEM(args, i); - char *typeName = get_type_name(argType); + char *typeName = PySide::getTypeName(argType); if (typeName) { if (data->args) { data->args = reinterpret_cast<char*>(realloc(data->args, (strlen(data->args) + 1 + strlen(typeName)) * sizeof(char*))); @@ -141,7 +137,7 @@ int slot_init(PyObject *self, PyObject *args, PyObject *kw) data->slotName = strdup(argName); if (argResult) - data->resultType = get_type_name(argResult); + data->resultType = PySide::getTypeName(argResult); else data->resultType = strdup("void"); |