diff options
author | Renato Filho <renato.filho@openbossa.org> | 2010-05-13 15:50:42 -0300 |
---|---|---|
committer | Renato Filho <renato.filho@openbossa.org> | 2010-05-17 19:53:54 -0300 |
commit | c5fd4d4830cb49c9f8087d7e54335f4c248f76bf (patch) | |
tree | 6a4fd6a9e30f1d5a1b3ead182d768d2f4fc38a79 /libpyside | |
parent | d2a6f35ef914b000ddd7685925075985c76817ac (diff) |
Implemented support to modify slot return type.
Included method type in DynamicQMetaObject metadata.
Moved Signal/Slot objet to libpyside.
Create unittest to signal class.
Implemented disconnection function.
Fixed emit method on signal object
Diffstat (limited to 'libpyside')
-rw-r--r-- | libpyside/CMakeLists.txt | 4 | ||||
-rw-r--r-- | libpyside/dynamicqmetaobject.cpp | 108 | ||||
-rw-r--r-- | libpyside/dynamicqmetaobject.h | 25 | ||||
-rw-r--r-- | libpyside/pyside.cpp | 51 | ||||
-rw-r--r-- | libpyside/pyside.h | 50 | ||||
-rw-r--r-- | libpyside/qsignal.cpp | 413 | ||||
-rw-r--r-- | libpyside/qsignal.h | 29 | ||||
-rw-r--r-- | libpyside/qslot.cpp | 176 |
8 files changed, 821 insertions, 35 deletions
diff --git a/libpyside/CMakeLists.txt b/libpyside/CMakeLists.txt index 23345efbf..0597f1608 100644 --- a/libpyside/CMakeLists.txt +++ b/libpyside/CMakeLists.txt @@ -4,6 +4,9 @@ set(libpyside_SRC dynamicqmetaobject.cpp signalmanager.cpp globalreceiver.cpp +qsignal.cpp +qslot.cpp +pyside.cpp ) include_directories(${CMAKE_CURRENT_SOURCE_DIR} @@ -31,6 +34,7 @@ set(libpyside_HEADERS pysideconversions.h pysidemacros.h signalmanager.h + pyside.h ) # create pkg-config file diff --git a/libpyside/dynamicqmetaobject.cpp b/libpyside/dynamicqmetaobject.cpp index a2e6bef0f..5cf1b9dbe 100644 --- a/libpyside/dynamicqmetaobject.cpp +++ b/libpyside/dynamicqmetaobject.cpp @@ -35,12 +35,15 @@ #include "dynamicqmetaobject.h" #include <QByteArray> #include <QString> +#include <QStringList> #include <QList> #include <QObject> #include <cstring> #include <QDebug> #include <QMetaMethod> +#include "qsignal.h" + #define MAX_SIGNALS_COUNT 50 using namespace PySide; @@ -58,11 +61,32 @@ static int registerString(const QByteArray& s, QList<QByteArray>* strings) return idx; } -static void clearItem(QLinkedList<QByteArray> &l, const QByteArray &value) +MethodData::MethodData(const char *signature, const char *type) + : m_signature(signature), m_type(type) +{ +} + +void MethodData::clear() +{ + m_signature.clear(); + m_type.clear(); +} + +bool MethodData::operator==(const MethodData &other) const +{ + return m_signature == other.signature(); +} + +QByteArray MethodData::signature() const +{ + return m_signature; +} + +QByteArray MethodData::type() const { - QLinkedList<QByteArray>::iterator i = qFind(l.begin(), l.end(), value); - if (i != l.end()) - *i = QByteArray(); + if (m_type == "void") + return QByteArray(""); + return m_type; } DynamicQMetaObject::DynamicQMetaObject(const char *className, const QMetaObject* metaObject) @@ -81,13 +105,13 @@ DynamicQMetaObject::~DynamicQMetaObject() delete[] d.data; } -void DynamicQMetaObject::addSignal(const char* signal) +void DynamicQMetaObject::addSignal(const char *signal, const char *type) { //search for a empty space - QByteArray blank; - QLinkedList<QByteArray>::iterator i = qFind(m_signals.begin(), m_signals.end(), blank); + MethodData blank; + QLinkedList<MethodData>::iterator i = qFind(m_signals.begin(), m_signals.end(), blank); if (i != m_signals.end()) { - *i = QByteArray(signal); + *i = MethodData(signal, type); updateMetaObject(); return; } @@ -97,19 +121,19 @@ void DynamicQMetaObject::addSignal(const char* signal) return; } - m_signals << QByteArray(signal); + m_signals << MethodData(signal, type); updateMetaObject(); } -void DynamicQMetaObject::addSlot(const char* slot) +void DynamicQMetaObject::addSlot(const char *slot, const char *type) { //search for a empty space - QByteArray blank; - QLinkedList<QByteArray>::iterator i = qFind(m_slots.begin(), m_slots.end(), blank); + MethodData blank; + QLinkedList<MethodData>::iterator i = qFind(m_slots.begin(), m_slots.end(), blank); if (i != m_slots.end()) { - *i = QByteArray(slot); + *i = MethodData(slot, type); } else { - m_slots << QByteArray(slot); + m_slots << MethodData(slot, type); } updateMetaObject(); } @@ -117,13 +141,16 @@ void DynamicQMetaObject::addSlot(const char* slot) void DynamicQMetaObject::removeSlot(uint index) { QMetaMethod m = method(index); - if (m_slots.contains(m.signature())) { - clearItem(m_slots, m.signature()); - updateMetaObject(); + foreach(MethodData md, m_slots) { + if (md.signature() == m.signature()) { + md.clear(); + updateMetaObject(); + break; + } } } -DynamicQMetaObject* DynamicQMetaObject::createBasedOn(PyTypeObject *type, const QMetaObject *base) +DynamicQMetaObject* DynamicQMetaObject::createBasedOn(PyObject *pyObj, PyTypeObject *type, const QMetaObject *base) { PyObject *key, *value; Py_ssize_t pos = 0; @@ -133,14 +160,30 @@ DynamicQMetaObject* DynamicQMetaObject::createBasedOn(PyTypeObject *type, const DynamicQMetaObject *mo = new PySide::DynamicQMetaObject(className.toAscii(), base); while (PyDict_Next(type->tp_dict, &pos, &key, &value)) { + + //Register signals + if (value->ob_type == &PySideSignal_Type) { + SignalData *data = reinterpret_cast<SignalData*>(value); + + for(int i=0, i_max=data->signatures_size; i < i_max; i++) { + mo->addSignal(data->signatures[i]); + printf("QObject with signal:[%s][%s]\n", + PyString_AS_STRING(PyObject_Str(key)), data->signatures[i]); + } + } + if (!PyFunction_Check(value)) continue; + //Register Slots if (PyObject_HasAttrString(value, PYSIDE_SLOT_LIST_ATTR)) { PyObject *signature_list = PyObject_GetAttrString(value, PYSIDE_SLOT_LIST_ATTR); for(Py_ssize_t i=0, i_max=PyList_Size(signature_list); i < i_max; i++) { PyObject *signature = PyList_GET_ITEM(signature_list, i); - mo->addSlot(PyString_AsString(signature)); + QString sig(PyString_AsString(signature)); + //slot the slot type and signature + QStringList slotInfo = sig.split(" ", QString::SkipEmptyParts); + mo->addSlot(slotInfo[1].toAscii(), slotInfo[0].toAscii()); } } } @@ -151,9 +194,12 @@ void DynamicQMetaObject::removeSignal(uint index) { //Current Qt implementation does not support runtime remove signal QMetaMethod m = method(index); - if (m_signals.contains(m.signature())) { - clearItem(m_signals, m.signature()); - updateMetaObject(); + foreach(MethodData md, m_signals) { + if (md.signature() == m.signature()) { + md.clear(); + updateMetaObject(); + break; + } } } @@ -198,26 +244,28 @@ void DynamicQMetaObject::updateMetaObject() int index = HEADER_LENGHT; //write signals - QLinkedList<QByteArray>::iterator iSignal = m_signals.begin(); + QLinkedList<MethodData>::iterator iSignal = m_signals.begin(); for(int i=0; i < MAX_SIGNALS_COUNT; i++) { + QByteArray sigType; if (iSignal != m_signals.end()) { - data[index++] = registerString(*iSignal, &strings); // func name + data[index++] = registerString((*iSignal).signature(), &strings); // func name + sigType = (*iSignal).type(); iSignal++; } else { data[index++] = NULL_INDEX; // func name } data[index++] = NULL_INDEX; // arguments - data[index++] = NULL_INDEX; // normalized type + data[index++] = (sigType.size() > 0 ? registerString(sigType, &strings) : NULL_INDEX); // normalized type data[index++] = NULL_INDEX; // tags data[index++] = AccessPublic | MethodSignal; // flags } //write slots - foreach(QByteArray slot, m_slots) { - data[index++] = registerString(slot, &strings); // func name + foreach(MethodData slot, m_slots) { + data[index++] = registerString(slot.signature(), &strings); // func name data[index++] = NULL_INDEX; // arguments - data[index++] = NULL_INDEX; // normalized type + data[index++] = (slot.type().size() > 0 ? registerString(slot.type(), &strings) : NULL_INDEX); // normalized type data[index++] = NULL_INDEX; // tags data[index++] = AccessPublic | MethodSlot; // flags } @@ -225,8 +273,8 @@ void DynamicQMetaObject::updateMetaObject() // create the m_metadata string QByteArray str; - foreach(QByteArray signature, strings) { - str.append(signature); + foreach(QByteArray field, strings) { + str.append(field); str.append(char(0)); } diff --git a/libpyside/dynamicqmetaobject.h b/libpyside/dynamicqmetaobject.h index 9336b63ac..bec8dd3df 100644 --- a/libpyside/dynamicqmetaobject.h +++ b/libpyside/dynamicqmetaobject.h @@ -48,24 +48,39 @@ class QObject; namespace PySide { +class MethodData +{ + public: + MethodData(){} + MethodData(const char *signature, const char *type); + void clear(); + QByteArray signature() const; + QByteArray type() const; + bool operator==(const MethodData &other) const; + + private: + QByteArray m_signature; + QByteArray m_type; +}; + 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 addSignal(const char* signal, const char* type=0); + void addSlot(const char* slot, const char* type=0); void removeSignal(uint idex); void removeSlot(uint index); //Retrieve Python metadata to create QMetaObject (class name, signals, slot) - static DynamicQMetaObject *createBasedOn(PyTypeObject *obj, const QMetaObject* base); + static DynamicQMetaObject *createBasedOn(PyObject *obj, PyTypeObject *type, const QMetaObject* base); private: - QLinkedList<QByteArray> m_signals; - QLinkedList<QByteArray> m_slots; + QLinkedList<MethodData> m_signals; + QLinkedList<MethodData> m_slots; QByteArray m_className; void updateMetaObject(); diff --git a/libpyside/pyside.cpp b/libpyside/pyside.cpp new file mode 100644 index 000000000..02eea7867 --- /dev/null +++ b/libpyside/pyside.cpp @@ -0,0 +1,51 @@ +/* + * This file is part of the Shiboken Python Bindings Generator project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. Please + * review the following information to ensure the GNU Lesser General + * Public License version 2.1 requirements will be met: + * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + * + * As a special exception to the GNU Lesser General Public License + * version 2.1, the object code form of a "work that uses the Library" + * may incorporate material from a header file that is part of the + * Library. You may distribute such object code under terms of your + * choice, provided that the incorporated material (i) does not exceed + * more than 5% of the total size of the Library; and (ii) is limited to + * numerical parameters, data structure layouts, accessors, macros, + * inline functions and templates. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + + +#include "pyside.h" + +extern "C" PyAPI_FUNC(void) init_signal(PyObject* module); +extern "C" PyAPI_FUNC(void) init_slot(PyObject* module); + +namespace PySide +{ + +void init(PyObject *module) +{ + init_signal(module); + init_slot(module); +} + +} //namespace PySide + diff --git a/libpyside/pyside.h b/libpyside/pyside.h new file mode 100644 index 000000000..aaeeb43d2 --- /dev/null +++ b/libpyside/pyside.h @@ -0,0 +1,50 @@ +/* + * This file is part of the Shiboken Python Bindings Generator project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. Please + * review the following information to ensure the GNU Lesser General + * Public License version 2.1 requirements will be met: + * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + * + * As a special exception to the GNU Lesser General Public License + * version 2.1, the object code form of a "work that uses the Library" + * may incorporate material from a header file that is part of the + * Library. You may distribute such object code under terms of your + * choice, provided that the incorporated material (i) does not exceed + * more than 5% of the total size of the Library; and (ii) is limited to + * numerical parameters, data structure layouts, accessors, macros, + * inline functions and templates. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef PYSIDE_H +#define PYSIDE_H + +#include <Python.h> +#include <pysidemacros.h> + +namespace PySide +{ + +PYSIDE_API void init(PyObject *module); + +} //namespace PySide + + +#endif // PYSIDE_H + diff --git a/libpyside/qsignal.cpp b/libpyside/qsignal.cpp new file mode 100644 index 000000000..8fe79ee1e --- /dev/null +++ b/libpyside/qsignal.cpp @@ -0,0 +1,413 @@ +#define protected public + +#include <shiboken.h> +#include <Python.h> +#include <QDebug> + +#include "qsignal.h" +#include "signalmanager.h" + +#define SIGNAL_CLASS_NAME "Signal" + +namespace PySide +{ + +extern "C" +{ + +static int qsignal_init(PyObject*, PyObject*, PyObject*); +static void qsignal_free(void*); +static void qsignal_instance_free(void*); + +//methods +static PyObject* qsignal_instance_connect(PyObject *self, PyObject *args, PyObject *kw); +static PyObject* qsignal_instance_disconnect(PyObject *self, PyObject *args); +static PyObject* qsignal_instance_emit(PyObject *self, PyObject *args); + +//aux +static char* qsignal_build_signature(const char *name, const char *signature); +static const char* qsignal_get_type_name(PyObject *type); +static void qsignal_append_signature(SignalData *self, PyObject *args); +static void qsignal_instance_initialize(PyObject *instance, SignalData *data, PyObject *source); + +PyTypeObject PySideSignal_Type = { + PyObject_HEAD_INIT(0) + 0, /*ob_size*/ + SIGNAL_CLASS_NAME, /*tp_name*/ + sizeof(SignalData), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + SIGNAL_CLASS_NAME, /*tp_doc */ + 0, /*tp_traverse */ + 0, /*tp_clear */ + 0, /*tp_richcompare */ + 0, /*tp_weaklistoffset */ + 0, /*tp_iter */ + 0, /*tp_iternext */ + 0, /*tp_methods */ + 0, /*tp_members */ + 0, /*tp_getset */ + 0, /*tp_base */ + 0, /*tp_dict */ + 0, /*tp_descr_get */ + 0, /*tp_descr_set */ + 0, /*tp_dictoffset */ + (initproc)qsignal_init, /*tp_init */ + 0, /*tp_alloc */ + PyType_GenericNew, /*tp_new */ + qsignal_free, /*tp_free */ + 0, /*tp_is_gc */ + 0, /*tp_bases */ + 0, /*tp_mro */ + 0, /*tp_cache */ + 0, /*tp_subclasses */ + 0, /*tp_weaklist */ + 0, /*tp_del */ +}; + +static PyMethodDef PySideQtSignalInstance_methods[] = { + {"connect", (PyCFunction)qsignal_instance_connect, METH_VARARGS|METH_KEYWORDS}, + {"disconnect", (PyCFunction)qsignal_instance_disconnect, METH_VARARGS}, + {"emit", (PyCFunction)qsignal_instance_emit, METH_VARARGS}, + {NULL} /* Sentinel */ +}; + +PyTypeObject PySideSignalInstance_Type = { + PyObject_HEAD_INIT(0) + 0, /*ob_size*/ + SIGNAL_CLASS_NAME, /*tp_name*/ + sizeof(SignalData), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + SIGNAL_CLASS_NAME"I", /*tp_doc */ + 0, /*tp_traverse */ + 0, /*tp_clear */ + 0, /*tp_richcompare */ + 0, /*tp_weaklistoffset */ + 0, /*tp_iter */ + 0, /*tp_iternext */ + PySideQtSignalInstance_methods, /*tp_methods */ + 0, /*tp_members */ + 0, /*tp_getset */ + &PySideSignal_Type, /*tp_base */ + 0, /*tp_dict */ + 0, /*tp_descr_get */ + 0, /*tp_descr_set */ + 0, /*tp_dictoffset */ + 0, /*tp_init */ + 0, /*tp_alloc */ + PyType_GenericNew, /*tp_new */ + qsignal_instance_free, /*tp_free */ + 0, /*tp_is_gc */ + 0, /*tp_bases */ + 0, /*tp_mro */ + 0, /*tp_cache */ + 0, /*tp_subclasses */ + 0, /*tp_weaklist */ + 0, /*tp_del */ +}; + + +PyAPI_FUNC(void) init_signal(PyObject* module) +{ + if (PyType_Ready(&PySideSignal_Type) < 0) + return; + + Py_INCREF(&PySideSignal_Type); + PyModule_AddObject(module, SIGNAL_CLASS_NAME, ((PyObject*)&PySideSignal_Type)); + + if (PyType_Ready(&PySideSignalInstance_Type) < 0) + return; + + Py_INCREF(&PySideSignalInstance_Type); +} + + +} // extern "C" + +void signal_update_source(PyObject *source) +{ + PyObject *key, *value; + Py_ssize_t pos = 0; + PyTypeObject *obType = source->ob_type; + + while (PyDict_Next(obType->tp_dict, &pos, &key, &value)) { + + if (value->ob_type == &PySideSignal_Type) { + PyObject *signal_instance = (PyObject*)PyObject_New(SignalData, &PySideSignalInstance_Type); + + qsignal_instance_initialize(signal_instance, reinterpret_cast<SignalData*>(value), source); + + PyObject_SetAttr(source, key, signal_instance); + Py_DECREF(signal_instance); + + } + + } +} + +const char* qsignal_get_type_name(PyObject *type) +{ + if (PyType_Check(type)) { + //tp_name return the full name + Shiboken::AutoDecRef type_name(PyObject_GetAttrString(type, "__name__")); + return PyString_AS_STRING((PyObject*)type_name); + } else if (PyString_Check(type)) { + return PyString_AS_STRING(type); + } + return ""; +} + +char* qsignal_build_signature(const char *name, const char *signature) +{ + QString signal; + signal.sprintf("2%s(%s)", name, (signature ? signature : "()")); + return strdup(QMetaObject::normalizedSignature(signal.toAscii())); +} + +void qsignal_append_signature(SignalData *self, PyObject *args) +{ + char *signature = 0; + for(Py_ssize_t i=0, i_max=PySequence_Size(args); i < i_max; i++) { + Shiboken::AutoDecRef arg(PySequence_ITEM(args, i)); + const char *type_name = qsignal_get_type_name(arg); + if (strlen(type_name) > 0) { + if (signature) { + signature = strcat(signature, ","); + signature = strcat(signature, type_name); + } else { + signature = strdup(type_name); + } + } + } + + self->signatures_size++; + if (self->signatures_size > 1) { + self->signatures = (char**) realloc(self->signatures, sizeof(char**) * self->signatures_size); + } else { + self->signatures = (char**) malloc(sizeof(char**)); + } + self->signatures[self->signatures_size -1] = qsignal_build_signature(self->signal_name, signature); + printf("registred signature:[%d][%s]\n", self->signatures_size -1, self->signatures[self->signatures_size -1]); + free(signature); +} + +int qsignal_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + static PyObject *emptyTuple = 0; + static const char *kwlist[] = {"name", 0}; + char* arg_name = 0; + + if (emptyTuple == 0) + emptyTuple = PyTuple_New(0); + + if (!PyArg_ParseTupleAndKeywords(emptyTuple, kwds, + "|s:QtCore."SIGNAL_CLASS_NAME, (char**) kwlist, &arg_name)) + return 0; + + bool tupled_args = false; + SignalData *data = reinterpret_cast<SignalData*>(self); + if (arg_name) + data->signal_name = strdup(arg_name); + + for(Py_ssize_t i=0, i_max=PyTuple_Size(args); i < i_max; i++) { + PyObject *arg = PyTuple_GET_ITEM(args, i); + if (PySequence_Check(arg)) { + tupled_args = true; + qsignal_append_signature(data, arg); + } + } + + if (!tupled_args) + qsignal_append_signature(data, args); + + + return 1; +} + +void qsignal_free(void *self) +{ + PyObject *pySelf = reinterpret_cast<PyObject*>(self); + SignalData *data = reinterpret_cast<SignalData*>(self); + + //keep the data to instance + if (!data->initialized) + qsignal_instance_free(self); + + pySelf->ob_type->tp_free (self); +} + +void qsignal_instance_free(void *self) +{ + PyObject *pySelf = reinterpret_cast<PyObject*>(self); + SignalData *data = reinterpret_cast<SignalData*>(self); + free(data->signatures[0]); + for(int i=1, i_max=data->signatures_size; i < i_max; i++) { + free(data->signatures[i]); + } + free(data->signatures); + free(data->signal_name); + data->initialized = false; + + pySelf->ob_type->tp_free (self); +} + +void qsignal_instance_initialize(PyObject *instance, SignalData *data, PyObject *source) +{ + SignalData *self = reinterpret_cast<SignalData*>(instance); + self->signal_name = data->signal_name; + self->signatures_size = data->signatures_size; + self->signatures = data->signatures; + self->initialized = true; + self->source = source; + data->initialized = true; +} + +PyObject* qsignal_instance_connect(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *slot; + PyObject *type; + static const char *kwlist[] = {"type", 0}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, + "O|O:"SIGNAL_CLASS_NAME, (char**) kwlist, &slot, &type)) + return 0; + + SignalData *source = reinterpret_cast<SignalData*>(self); + Shiboken::AutoDecRef pyArgs(PyList_New(0)); + + bool match = false; + if (slot->ob_type == &PySideSignal_Type) { + SignalData *target = reinterpret_cast<SignalData*>(slot); + for(int s, s_max=source->signatures_size; s < s_max; s++) { + for(int t, t_max=target->signatures_size; t < t_max; t++) { + if (QMetaObject::checkConnectArgs(source->signatures[s], target->signatures[t])) { + PyList_Append(pyArgs, source->source); + Shiboken::AutoDecRef source_signature(PyString_FromString(source->signatures[s])); + PyList_Append(pyArgs, source_signature); + + PyList_Append(pyArgs, target->source); + Shiboken::AutoDecRef target_signature(PyString_FromString(source->signatures[s])); + PyList_Append(pyArgs, target_signature); + match = true; + break; + } + } + if (match) break; + } + } else { + //try the first signature + PyList_Append(pyArgs, source->source); + Shiboken::AutoDecRef signature(PyString_FromString(source->signatures[0])); + PyList_Append(pyArgs, signature); + + PyList_Append(pyArgs, slot); + match = true; + } + + if (match) { + Shiboken::AutoDecRef tupleArgs(PyList_AsTuple(pyArgs)); + Shiboken::AutoDecRef pyMethod(PyObject_GetAttrString(source->source, "connect")); + return PyObject_CallObject(pyMethod, tupleArgs); + } + + return 0; +} + +PyObject* qsignal_instance_disconnect(PyObject *self, PyObject *args) +{ + SignalData *source = reinterpret_cast<SignalData*>(self); + Shiboken::AutoDecRef pyArgs(PyList_New(0)); + + PyObject *slot; + if PyTuple_Check(args) + slot = PyTuple_GET_ITEM(args, 0); + else + slot = args; + + bool match = false; + if (slot->ob_type == &PySideSignal_Type) { + SignalData *target = reinterpret_cast<SignalData*>(slot); + for(int s, s_max=source->signatures_size; s < s_max; s++) { + for(int t, t_max=target->signatures_size; t < t_max; t++) { + if (QMetaObject::checkConnectArgs(source->signatures[s], target->signatures[t])) { + PyList_Append(pyArgs, source->source); + Shiboken::AutoDecRef source_signature(PyString_FromString(source->signatures[s])); + PyList_Append(pyArgs, source_signature); + + PyList_Append(pyArgs, target->source); + Shiboken::AutoDecRef target_signature(PyString_FromString(source->signatures[s])); + PyList_Append(pyArgs, target_signature); + match = true; + break; + } + } + if (match) break; + } + } else { + //try the first signature + PyList_Append(pyArgs, source->source); + Shiboken::AutoDecRef signature(PyString_FromString(source->signatures[0])); + PyList_Append(pyArgs, signature); + + PyList_Append(pyArgs, slot); + match = true; + } + + if (match) { + Shiboken::AutoDecRef tupleArgs(PyList_AsTuple(pyArgs)); + Shiboken::AutoDecRef pyMethod(PyObject_GetAttrString(source->source, "disconnect")); + return PyObject_CallObject(pyMethod, tupleArgs); + } + + return 0; +} + +PyObject* qsignal_instance_emit(PyObject *self, PyObject *args) +{ + SignalData *source = reinterpret_cast<SignalData*>(self); + + Shiboken::AutoDecRef pyArgs(PyList_New(0)); + Shiboken::AutoDecRef source_signature(PyString_FromString(source->signatures[0])); + + 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)); + + Shiboken::AutoDecRef pyMethod(PyObject_GetAttrString(source->source, "emit")); + + Shiboken::AutoDecRef tupleArgs(PyList_AsTuple(pyArgs)); + return PyObject_CallObject(pyMethod, tupleArgs); +} + +} //namespace PySide diff --git a/libpyside/qsignal.h b/libpyside/qsignal.h new file mode 100644 index 000000000..1c91756c9 --- /dev/null +++ b/libpyside/qsignal.h @@ -0,0 +1,29 @@ +#ifndef QSIGNAL_H +#define QSIGNAL_H + +#include <pysidemacros.h> +#include <Python.h> +#include <QObject> + +namespace PySide +{ + +typedef struct { + PyObject_HEAD + bool initialized; + char *signal_name; + char **signatures; + int signatures_size; + PyObject *source; +} SignalData; + +extern "C" +{ + PyAPI_DATA(PyTypeObject) PySideSignal_Type; + PyAPI_DATA(PyTypeObject) PySideSignalInstance_Type; +}; //extern "C" + +PYSIDE_API void signal_update_source(PyObject *source); + +} //namespace PySide +#endif diff --git a/libpyside/qslot.cpp b/libpyside/qslot.cpp new file mode 100644 index 000000000..a2db44e97 --- /dev/null +++ b/libpyside/qslot.cpp @@ -0,0 +1,176 @@ +#include <shiboken.h> +#include <dynamicqmetaobject.h> + +#include <QString> + +#define SLOT_DEC_NAME "Slot" + +typedef struct +{ + PyObject_HEAD + char* slot_name; + char* args; + char* result_type; +} SlotData; + +extern "C" +{ + +static int qslot_init(PyObject *self, PyObject *arg, PyObject *kw); +static PyObject* qslot_call(PyObject *self, PyObject *arg, PyObject *kw); + +// Class Definition ----------------------------------------------- +static PyTypeObject PySideSlot_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "QtCore."SLOT_DEC_NAME, /*tp_name*/ + sizeof(SlotData), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + qslot_call, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + SLOT_DEC_NAME, /*tp_doc */ + 0, /*tp_traverse */ + 0, /*tp_clear */ + 0, /*tp_richcompare */ + 0, /*tp_weaklistoffset */ + 0, /*tp_iter */ + 0, /*tp_iternext */ + 0, /*tp_methods */ + 0, /*tp_members */ + 0, /*tp_getset */ + 0, /*tp_base */ + 0, /*tp_dict */ + 0, /*tp_descr_get */ + 0, /*tp_descr_set */ + 0, /*tp_dictoffset */ + (initproc)qslot_init, /*tp_init */ + 0, /*tp_alloc */ + PyType_GenericNew, /*tp_new */ + 0, /*tp_free */ + 0, /*tp_is_gc */ + 0, /*tp_bases */ + 0, /*tp_mro */ + 0, /*tp_cache */ + 0, /*tp_subclasses */ + 0, /*tp_weaklist */ + 0, /*tp_del */ +}; + +PyAPI_FUNC(void) init_slot(PyObject* module) +{ + if (PyType_Ready(&PySideSlot_Type) < 0) + return; + + Py_INCREF(&PySideSlot_Type); + PyModule_AddObject(module, SLOT_DEC_NAME, ((PyObject*)&PySideSlot_Type)); +} + + +} // extern "C" + +static const char* qslot_get_type_name(PyObject *type) +{ + if (PyType_Check(type)) { + //tp_name return the full name + Shiboken::AutoDecRef type_name(PyObject_GetAttrString(type, "__name__")); + return PyString_AS_STRING((PyObject*)type_name); + } else if (PyString_Check(type)) { + return PyString_AS_STRING(type); + } + return ""; +} + +static int qslot_init(PyObject *self, PyObject *args, PyObject *kw) +{ + static PyObject *emptyTuple = 0; + static const char *kwlist[] = {"name", "result", 0}; + char* arg_name = 0; + PyObject* arg_result = 0; + + if (emptyTuple == 0) + emptyTuple = PyTuple_New(0); + + if (!PyArg_ParseTupleAndKeywords(emptyTuple, kw, "|sO:QtCore."SLOT_DEC_NAME, (char**) kwlist, &arg_name, &arg_result)) + return 0; + + SlotData *data = reinterpret_cast<SlotData*>(self); + for(Py_ssize_t i=0, i_max=PyTuple_Size(args); i < i_max; i++) { + PyObject *arg_type = PyTuple_GET_ITEM(args, i); + const char *type_name = qslot_get_type_name(arg_type); + if (strlen(type_name) > 0) { + if (data->args) { + data->args = strcat(data->args, ","); + data->args = strcat(data->args, type_name); + } else { + data->args = strdup(type_name); + } + } + } + + if (arg_name) + data->slot_name = strdup(arg_name); + + if (arg_result) + data->result_type = strdup(qslot_get_type_name(arg_result)); + else + data->result_type = strdup("void"); + + return 1; +} + +static PyObject* qslot_call(PyObject *self, PyObject *args, PyObject *kw) +{ + PyObject *callback; + callback = PyTuple_GetItem(args, 0); + Py_INCREF(callback); + + if (PyFunction_Check(callback)) { + SlotData *data = reinterpret_cast<SlotData*>(self); + + if (!data->slot_name) { + PyObject *func_name = ((PyFunctionObject*)callback)->func_name; + data->slot_name = strdup(PyString_AS_STRING(func_name)); + } + + QString signature; + signature.sprintf("%s %s(%s)", data->result_type, data->slot_name, data->args); + + PyObject *pySignature = PyString_FromString(QMetaObject::normalizedSignature(signature.toAscii())); + PyObject *signature_list = 0; + if (PyObject_HasAttrString(callback, PYSIDE_SLOT_LIST_ATTR)) { + signature_list = PyObject_GetAttrString(callback, PYSIDE_SLOT_LIST_ATTR); + } else { + signature_list = PyList_New(0); + PyObject_SetAttrString(callback, PYSIDE_SLOT_LIST_ATTR, signature_list); + Py_DECREF(signature_list); + } + + PyList_Append(signature_list, pySignature); + Py_DECREF(pySignature); + + //clear data + free(data->slot_name); + data->slot_name = 0; + free(data->result_type); + data->result_type = 0; + free(data->args); + data->args = 0; + return callback; + } + return callback; +} + |