diff options
author | Hugo Lima <hugo.lima@openbossa.org> | 2009-12-15 19:24:30 -0200 |
---|---|---|
committer | Hugo Lima <hugo.lima@openbossa.org> | 2009-12-16 15:02:42 -0200 |
commit | c8e908097207d8852e17e99585ae88a17e3af144 (patch) | |
tree | d9aaf4d99ad3711654c98ef5ae6af8da2d4b9e9f | |
parent | d90b6ba47409c7cc461bb6c200f8e41b9a917088 (diff) |
Initial port of signal slots infrastructure from PySide to the Shiboken version.
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | PySide/QtCore/CMakeLists.txt | 2 | ||||
-rw-r--r-- | PySide/QtCore/typesystem_core.xml | 29 | ||||
-rw-r--r-- | libpyside/CMakeLists.txt | 21 | ||||
-rw-r--r-- | libpyside/abstractqobjectconnection.cpp | 57 | ||||
-rw-r--r-- | libpyside/abstractqobjectconnection.h | 91 | ||||
-rw-r--r-- | libpyside/proxyslot.cpp | 88 | ||||
-rw-r--r-- | libpyside/proxyslot.h | 81 | ||||
-rw-r--r-- | libpyside/pysidemacros.h | 52 | ||||
-rw-r--r-- | libpyside/signalmanager.cpp | 172 | ||||
-rw-r--r-- | libpyside/signalmanager.h | 70 | ||||
-rw-r--r-- | libpyside/signalsignalconnection.cpp | 43 | ||||
-rw-r--r-- | libpyside/signalsignalconnection.h | 50 | ||||
-rw-r--r-- | libpyside/signalslotconnection.cpp | 84 | ||||
-rw-r--r-- | libpyside/signalslotconnection.h | 58 | ||||
-rw-r--r-- | libpyside/typeresolver.cpp | 118 | ||||
-rw-r--r-- | libpyside/typeresolver.h | 118 |
17 files changed, 1135 insertions, 2 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index fb6958134..cb78ea0e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,10 +59,11 @@ if (NOT SITE_PACKAGE) message(FATAL_ERROR "Could not detect Python module installation directory.") endif (NOT SITE_PACKAGE) -set(GENERATOR_EXTRA_FLAGS --generatorSet=shiboken --enable-parent-ctor-heuristic) +set(GENERATOR_EXTRA_FLAGS --generatorSet=shiboken --enable-parent-ctor-heuristic --enable-pyside-extensions) enable_testing() +add_subdirectory(libpyside) # project directories add_subdirectory(${BINDING_NAME}) add_subdirectory(tests) diff --git a/PySide/QtCore/CMakeLists.txt b/PySide/QtCore/CMakeLists.txt index 03bef4792..3bdec2010 100644 --- a/PySide/QtCore/CMakeLists.txt +++ b/PySide/QtCore/CMakeLists.txt @@ -104,11 +104,13 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/${BINDING_NAME}/QtCore/ ${QT_INCLUDE_DIR} ${SHIBOKEN_INCLUDE_DIR} + ${libpyside_SOURCE_DIR} ${PYTHON_INCLUDE_PATH} ) add_library(QtCore MODULE ${QtCore_SRC}) set_property(TARGET QtCore PROPERTY PREFIX "") target_link_libraries(QtCore + pyside ${PYTHON_LIBRARIES} ${SHIBOKEN_LIBRARY} ${QT_QTCORE_LIBRARY} diff --git a/PySide/QtCore/typesystem_core.xml b/PySide/QtCore/typesystem_core.xml index 7a5b880dd..88a054537 100644 --- a/PySide/QtCore/typesystem_core.xml +++ b/PySide/QtCore/typesystem_core.xml @@ -1255,6 +1255,7 @@ <extra-includes> <include file-name="QThread" location="global"/> <include file-name="QCoreApplication" location="global"/> + <include file-name="signalmanager.h" location="local" /> </extra-includes> <modify-function signature="deleteLater()"> @@ -1291,7 +1292,33 @@ </modify-function> <modify-function signature="thread() const" remove="all"/> <modify-function signature="connect(const QObject*, const char*, const char *, Qt::ConnectionType) const" remove="all"/> - <modify-function signature="connect(const QObject*, const char*, const QObject*, const char *, Qt::ConnectionType)" remove="all"/> + <modify-function signature="connect(const QObject*, const char*, const QObject*, const char *, Qt::ConnectionType)"> + <inject-code class="target" position="beginning"> + %PYARG_0 = %CONVERTTOPYTHON[bool](PySide::SignalManager::instance().connect(%1, %2, %3, %4, %5)); + </inject-code> + </modify-function> + <add-function signature="connect(const QObject*, const char*, PyCallable*, Qt::ConnectionType)" return-type="bool"> + <modify-argument index="4"> + <replace-default-expression with="Qt::AutoConnection" /> + </modify-argument> + <inject-code class="target" position="beginning"> + %PYARG_0 = %CONVERTTOPYTHON[bool](PySide::SignalManager::instance().connect(%1, %2, %PYARG_3, %4)); + </inject-code> + </add-function> + <!-- static version --> + <add-function signature="connect(const char*, PyCallable*, Qt::ConnectionType)" return-type="bool"> + <modify-argument index="3"> + <replace-default-expression with="Qt::AutoConnection" /> + </modify-argument> + <inject-code class="target" position="beginning"> + %PYARG_0 = %CONVERTTOPYTHON[bool](PySide::SignalManager::instance().connect(%CPPSELF, %1, %PYARG_2, %3)); + </inject-code> + </add-function> + <add-function signature="emit(const char*, PySequence*)" return-type="bool"> + <inject-code class="target" position="beginning"> + %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"/> diff --git a/libpyside/CMakeLists.txt b/libpyside/CMakeLists.txt new file mode 100644 index 000000000..ad1ebffce --- /dev/null +++ b/libpyside/CMakeLists.txt @@ -0,0 +1,21 @@ +project(libpyside) + +set(libpyside_SRC +typeresolver.cpp +proxyslot.cpp +abstractqobjectconnection.cpp +signalmanager.cpp +signalsignalconnection.cpp +signalslotconnection.cpp +) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR} + ${SHIBOKEN_INCLUDE_DIR} + ${PYTHON_INCLUDE_PATH} + ) + +add_library(pyside SHARED ${libpyside_SRC}) +target_link_libraries(pyside + ${PYTHON_LIBRARIES} + ${SHIBOKEN_LIBRARY} +) diff --git a/libpyside/abstractqobjectconnection.cpp b/libpyside/abstractqobjectconnection.cpp new file mode 100644 index 000000000..0f5a1b63a --- /dev/null +++ b/libpyside/abstractqobjectconnection.cpp @@ -0,0 +1,57 @@ +/* +* 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 "abstractqobjectconnection.h" +#include "typeresolver.h" +#include "signalmanager.h" + +using namespace PySide; + +AbstractQObjectConnection::AbstractQObjectConnection(QObject* source, const char* signal, Qt::ConnectionType connectionType) + : m_source(source), m_connectionType(connectionType), m_slotIndex(-1) +{ + m_signalArgs = getArgsFromSignature(signal); + m_signalIndex = source->metaObject()->indexOfSignal(signal); +} + +void AbstractQObjectConnection::trigger(void** args) +{ + int numArgs = m_signalArgs.count(); + PyObject* pyArgs = PyTuple_New(numArgs); + for (int i = 0; i < numArgs; ++i) { + PyObject* arg = TypeResolver::get(m_signalArgs[i])->toPython(args[i+1]); + PyTuple_SET_ITEM(pyArgs, i, arg); + } + trigger(pyArgs); +} diff --git a/libpyside/abstractqobjectconnection.h b/libpyside/abstractqobjectconnection.h new file mode 100644 index 000000000..5ba43194c --- /dev/null +++ b/libpyside/abstractqobjectconnection.h @@ -0,0 +1,91 @@ +/* +* 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 ABSTRACTQOBJECTCONNECTION_H +#define ABSTRACTQOBJECTCONNECTION_H +#include <Python.h> +#include <Qt> +#include <QStringList> + +class QObject; + +namespace PySide +{ +class AbstractQObjectConnection +{ +public: + AbstractQObjectConnection(QObject* source, const char* signal, Qt::ConnectionType connectionType); + virtual ~AbstractQObjectConnection() {} + + QObject* source() const + { + return m_source; + } + void setSignalIndex(int signalIndex) + { + m_signalIndex = signalIndex; + } + + int signalIndex() const + { + return m_signalIndex; + } + + void setSlotIndex(int slotIndex) + { + m_slotIndex = slotIndex; + } + + int slotIndex() const + { + return m_slotIndex; + } + + Qt::ConnectionType type() const + { + return m_connectionType; + } + + void trigger(void** args); + virtual void trigger(PyObject* args) = 0; +private: + QObject* m_source; + QStringList m_signalArgs; + Qt::ConnectionType m_connectionType; + int m_signalIndex; + int m_slotIndex; +}; +} + +#endif diff --git a/libpyside/proxyslot.cpp b/libpyside/proxyslot.cpp new file mode 100644 index 000000000..59467056f --- /dev/null +++ b/libpyside/proxyslot.cpp @@ -0,0 +1,88 @@ +/* +* 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 <Python.h> +#include <QDebug> +#include "proxyslot.h" +#include "abstractqobjectconnection.h" +#include "signalmanager.h" + +using namespace PySide; + +ProxySlot::ProxySlot(QObject* signalSource) : m_signalSource(signalSource) +{ + m_nextSlotIndex = m_signalSource->metaObject()->methodCount()-1; +} + +bool ProxySlot::connect(AbstractQObjectConnection* connection) +{ + QObject* source = connection->source(); + attachAbstractConnection(connection); + int slotIndex = connection->slotIndex(); + int signalIndex = connection->signalIndex(); + + qDebug() << "conectando" << signalIndex << "em" << slotIndex; + if (signalIndex >= 0) { + return QMetaObject::connect(source, signalIndex, this, slotIndex, connection->type()); + } else { // dynamic signals! + // TODO: Register dynamic signal + } + return true; + +} + +void ProxySlot::attachAbstractConnection(AbstractQObjectConnection* connection) +{ + m_nextSlotIndex++; + m_connections[m_nextSlotIndex] = connection; + connection->setSlotIndex(m_nextSlotIndex); +} + +int ProxySlot::qt_metacall(QMetaObject::Call callType, int slotIndex, void** args) +{ + // 2 is the index of deleteLater slot + if (slotIndex == 2) { + deleteLater(); + SignalManager::instance().removeProxySlot(m_signalSource); + } + + if (m_connections.contains(slotIndex)) { +// thread_locker lock; + m_connections[slotIndex]->trigger(args); + return -1; + } + + return QObject::qt_metacall(callType, slotIndex, args); +} + diff --git a/libpyside/proxyslot.h b/libpyside/proxyslot.h new file mode 100644 index 000000000..8e45eff6f --- /dev/null +++ b/libpyside/proxyslot.h @@ -0,0 +1,81 @@ +/* +* 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 <QObject> +#include <QHash> + +namespace PySide +{ + +class AbstractQObjectConnection; + +class ProxySlot : public QObject +{ +public: + ProxySlot(QObject* signalSource); + bool connect(AbstractQObjectConnection* connection); +protected: + /** + * Qt's meta-object system uses the qt_metacall() function to access the + * meta-information for a particular QObject object (its signals, slots, + * properties, etc.). + * + * About the implemmentation + * + * The call may indicate access to the meta-object of the QObject base + * class, we need to take care of this use case. + * If the QObject::qt_metacall() call returns -1, this means that the + * metacall has been handled by QObject and that there is nothing to do. + * In that case, we return immediately. Similarly, if the metacall isn't + * a slot invocation, we follow QObject's convention and return an + * identifier that can be handled by a subclass. + * + * If all goes well, we invoke the specified slot and return -1 to + * indicate that the metacall has been processed. + * + * \see \link http://doc.trolltech.com/qq/qq16-dynamicqobject.html + */ + int qt_metacall(QMetaObject::Call call, int id, void **args); + +private: + QObject* m_signalSource; + int m_nextSlotIndex; + // slot_index => connection_info, used by qt_metacall + // to recover the connection_info + QHash<int, AbstractQObjectConnection*> m_connections; + + void attachAbstractConnection(AbstractQObjectConnection* connection); +}; + +}
\ No newline at end of file diff --git a/libpyside/pysidemacros.h b/libpyside/pysidemacros.h new file mode 100644 index 000000000..c9e1e11de --- /dev/null +++ b/libpyside/pysidemacros.h @@ -0,0 +1,52 @@ +/* +* 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 PYSIDEMACROS_H +#define PYSIDEMACROS_H + +#if defined _WIN32 || defined __CYGWIN__ + #if PYSIDE_BUILD + #define PYSIDE_API __declspec(dllexport) + #else + #define PYSIDE_API __declspec(dllimport) + #endif +#else + #if __GNUC__ >= 4 + #define PYSIDE_API __attribute__ ((visibility("default"))) + #else + #define PYSIDE_API + #endif +#endif + +#endif diff --git a/libpyside/signalmanager.cpp b/libpyside/signalmanager.cpp new file mode 100644 index 000000000..711465549 --- /dev/null +++ b/libpyside/signalmanager.cpp @@ -0,0 +1,172 @@ +/* +* 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 "signalmanager.h" +#include "proxyslot.h" +#include <QHash> +#include <QStringList> +#include <QDebug> + +#if QSLOT_CODE != 1 || QSIGNAL_CODE != 2 +#error QSLOT_CODE and/or QSIGNAL_CODE changed! change the hardcoded stuff to the correct value! +#endif +#define PYSIDE_SLOT '1' +#define PYSIDE_SIGNAL '2' +#include "typeresolver.h" +#include "signalslotconnection.h" + +using namespace PySide; + +static bool checkSignal(const char* signal) +{ + if (signal[0] != PYSIDE_SIGNAL) { + PyErr_SetString(PyExc_TypeError, "Use the function PySide.QtCore.SIGNAL on signals"); + return false; + } + return true; +} + +QStringList PySide::getArgsFromSignature(const char* signature) +{ + QString qsignature(signature); + QStringList result; + QRegExp splitRegex("\\s*,\\s*"); + + if (qsignature.contains("()") || qsignature.contains("(void)")) { + return result; + } else if (qsignature.contains('(')) { + //get args types + QString types = qsignature.replace(QRegExp(".+\\((.*)\\)"), "\\1"); + result = types.split(splitRegex); + } + return result; +} + +struct SignalManager::SignalManagerPrivate +{ + QHash<QObject*, ProxySlot*> m_proxies; + + ProxySlot* findProxy(QObject* signalSource) + { + ProxySlot* proxy = m_proxies.value(signalSource); + if (!proxy) { + proxy = new ProxySlot(signalSource); + m_proxies[signalSource] = proxy; + QObject::connect(signalSource, SIGNAL(destroyed()), proxy, SLOT(deleteLater())); + } + return proxy; + } +}; + +SignalManager::SignalManager() : m_d(new SignalManagerPrivate) +{ +} + +SignalManager::~SignalManager() +{ + delete m_d; +} + +SignalManager& SignalManager::instance() +{ + static SignalManager me; + return me; +} + +bool SignalManager::connect(QObject* source, const char* signal, PyObject* callback, Qt::ConnectionType type) +{ + if (!checkSignal(signal)) + return false; + signal++; + + ProxySlot* proxy = m_d->findProxy(source); + AbstractQObjectConnection* connection = new SignalSlotConnection(source, signal, callback, type); + return proxy->connect(connection); +} + +bool SignalManager::connect(QObject* source, const char* signal, QObject* receiver, const char* slot, Qt::ConnectionType type) +{ + if (!checkSignal(signal)) + return false; + + if (!QMetaObject::checkConnectArgs(signal, slot)) + return false; + int signal_index = source->metaObject()->indexOfSignal(signal); + int slot_index = receiver->metaObject()->indexOfSlot(slot); + + bool retval; + if (signal_index != -1 && slot_index != -1) { + // C++ -> C++ connection + retval = QMetaObject::connect(source, signal_index, + receiver, slot_index, type); + } else { + // We have a python slot or signal + ProxySlot* proxy = m_d->findProxy(source); + AbstractQObjectConnection* connection = 0; + retval = proxy->connect(connection); + } + return retval; + +} + +bool SignalManager::emitSignal(QObject* source, const char* signal, PyObject* args) +{ + if (checkSignal(signal)) + return false; + + int argsGiven = PySequence_Size(args); + + //search native signal + int signalIndex = source->metaObject()->indexOfSignal(signal+1); + if (signalIndex == -1) { + // dynamic signal + qDebug() << "Dynamic signal not implemented yet!"; + } else { + // a C++ signal + QStringList argTypes = getArgsFromSignature(signal); + void* signalArgs[argsGiven+1]; + + for (int i = 0; i < argsGiven; i++) + signalArgs[i] = TypeResolver::get(argTypes[i])->toCpp(PySequence_GetItem(args, i)); + + QMetaObject::activate(source, signalIndex, signalArgs); + return true; + } + return false; +} + +void PySide::SignalManager::removeProxySlot(QObject* signalSource) +{ + m_d->m_proxies.remove(signalSource); +} diff --git a/libpyside/signalmanager.h b/libpyside/signalmanager.h new file mode 100644 index 000000000..515ac6153 --- /dev/null +++ b/libpyside/signalmanager.h @@ -0,0 +1,70 @@ +/* +* 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 SIGNALMANAGER_H +#define SIGNALMANAGER_H + +#include "pysidemacros.h" +#include <Python.h> +#include <Qt> +#include <QStringList> + +class QObject; + +namespace PySide +{ + +QStringList getArgsFromSignature(const char* signature); + +class PYSIDE_API SignalManager +{ +public: + static SignalManager& instance(); + bool connect(QObject* source, const char* signal, PyObject* callback, Qt::ConnectionType type = Qt::AutoConnection); + bool connect(QObject* source, const char* signal, QObject* receiver, const char* slot, Qt::ConnectionType type = Qt::AutoConnection); + bool emitSignal(QObject* source, const char* signal, PyObject* args); + void removeProxySlot(QObject* signalSource); +private: + struct SignalManagerPrivate; + SignalManagerPrivate* m_d; + SignalManager(); + ~SignalManager(); + + // disable copy + SignalManager(const SignalManager&); + SignalManager operator=(const SignalManager&); +}; + +} +#endif diff --git a/libpyside/signalsignalconnection.cpp b/libpyside/signalsignalconnection.cpp new file mode 100644 index 000000000..2797a0778 --- /dev/null +++ b/libpyside/signalsignalconnection.cpp @@ -0,0 +1,43 @@ +/* +* 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 "signalsignalconnection.h" + +using namespace PySide; + +void SignalSignalConnection::trigger(PyObject* args) +{ + +} + diff --git a/libpyside/signalsignalconnection.h b/libpyside/signalsignalconnection.h new file mode 100644 index 000000000..c5896cc21 --- /dev/null +++ b/libpyside/signalsignalconnection.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 SIGNALSIGNALCONNECTION_H +#define SIGNALSIGNALCONNECTION_H +#include "abstractqobjectconnection.h" + +namespace PySide +{ + +class SignalSignalConnection : public AbstractQObjectConnection +{ +public: + virtual void trigger(PyObject* args); +}; + +} + +#endif diff --git a/libpyside/signalslotconnection.cpp b/libpyside/signalslotconnection.cpp new file mode 100644 index 000000000..8f7ddf17c --- /dev/null +++ b/libpyside/signalslotconnection.cpp @@ -0,0 +1,84 @@ +/* +* 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 "signalslotconnection.h" +#include <QDebug> + +using namespace PySide; + +SignalSlotConnection::SignalSlotConnection(QObject* source, const char* signal, PyObject* callback, Qt::ConnectionType connectionType) + : AbstractQObjectConnection(source, signal, connectionType), m_receiver(0) +{ + if (PyMethod_Check(callback)) { + m_function = PyMethod_GET_FUNCTION(callback); + if (PyObject* self = PyMethod_GET_SELF(callback)) + m_receiver = self; + } else { + m_function = callback; + } + Py_INCREF(m_function); + PyCodeObject* objCode = reinterpret_cast<PyCodeObject*>(PyFunction_GET_CODE(m_function)); + m_numSlotArgs = objCode->co_flags & CO_VARARGS ? -1 : objCode->co_argcount; +} + +SignalSlotConnection::~SignalSlotConnection() +{ + Py_DECREF(m_function); +} + +void SignalSlotConnection::trigger(PyObject* args) +{ + int useSelf = m_receiver ? 1 : 0; + int numArgs = PySequence_Size(args); + PyObject* preparedArgs = PyTuple_New(numArgs + useSelf); + if (m_receiver) + PyTuple_SetItem(preparedArgs, 0, m_receiver); + for (int i = 0; i < numArgs; ++i) + PyTuple_SET_ITEM(preparedArgs, i + useSelf, PyTuple_GET_ITEM(args, i)); + + qDebug() << "num args: " << m_numSlotArgs; + // sliceamento +// if (m_num_slot_args != -1 && m_num_slot_args < python::len(args)) { +// args = python::list(args.slice(0, m_num_slot_args)); +// } + qDebug() << "Receiver" << m_receiver; + qDebug() << "numargs" << numArgs; + PyObject* retval = PyObject_CallObject(m_function, preparedArgs); + if (retval) { + Py_DECREF(retval); + } else { + qWarning(qPrintable(QString("Error calling slot ")+ + PyString_AS_STRING(reinterpret_cast<PyCodeObject*>(PyFunction_GET_CODE(m_function))->co_name))); + } +} diff --git a/libpyside/signalslotconnection.h b/libpyside/signalslotconnection.h new file mode 100644 index 000000000..4c9015c98 --- /dev/null +++ b/libpyside/signalslotconnection.h @@ -0,0 +1,58 @@ +/* +* 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 SIGNALSLOTCONNECTION_H +#define SIGNALSLOTCONNECTION_H + +#include "abstractqobjectconnection.h" + +class QObject; + +namespace PySide +{ + +class SignalSlotConnection : public AbstractQObjectConnection +{ +public: + SignalSlotConnection(QObject* source, const char* signal, PyObject* callback, Qt::ConnectionType connectionType); + ~SignalSlotConnection(); + void trigger(PyObject* args); +private: + PyObject* m_receiver; + PyObject* m_function; + int m_numSlotArgs; +}; + +} +#endif diff --git a/libpyside/typeresolver.cpp b/libpyside/typeresolver.cpp new file mode 100644 index 000000000..d4c704ab9 --- /dev/null +++ b/libpyside/typeresolver.cpp @@ -0,0 +1,118 @@ +/* +* 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 "typeresolver.h" +#include <QHash> +#include <cstdlib> +#include <QDebug> + +using namespace PySide; + +static QHash<QLatin1String, TypeResolver*> typeResolverMap; + +struct TypeResolver::TypeResolverPrivate +{ + const char* typeName; // maybe this is not needed anymore + CppToPythonFunc cppToPython; + PythonToCppFunc pythonToCpp; + DeleteObjectFunc deleteObject; +}; + +static void deinitTypeResolver() +{ + qDeleteAll(typeResolverMap); + typeResolverMap.clear(); +} + +static void registerTypeResolver(TypeResolver* resolver) +{ + static bool initied = false; + if (!initied) { + Q_ASSERT(typeResolverMap.isEmpty()); + initied = true; + std::atexit(deinitTypeResolver); + TypeResolver::createValueTypeResolver<double>("double"); + TypeResolver::createValueTypeResolver<float>("float"); + TypeResolver::createValueTypeResolver<qreal>("qreal"); + TypeResolver::createValueTypeResolver<bool>("bool"); + TypeResolver::createValueTypeResolver<int>("int"); + TypeResolver::createValueTypeResolver<qint64>("qint64"); + } + Q_ASSERT(!typeResolverMap.contains(QLatin1String(resolver->typeName()))); + typeResolverMap[QLatin1String(resolver->typeName())] = resolver; +} + +TypeResolver::TypeResolver(const char* typeName, TypeResolver::CppToPythonFunc cppToPy, TypeResolver::PythonToCppFunc pyToCpp, TypeResolver::DeleteObjectFunc deleter) +{ + m_d = new TypeResolverPrivate; + m_d->typeName = typeName; + m_d->cppToPython = cppToPy; + m_d->pythonToCpp = pyToCpp; + m_d->deleteObject = deleter; + + registerTypeResolver(this); +} + +TypeResolver::~TypeResolver() +{ + delete m_d; +} + +PySide::TypeResolver* TypeResolver::get(const QString& typeName) +{ + QByteArray data = typeName.toAscii(); + return get(data.constData()); +} + +PySide::TypeResolver* TypeResolver::get(const char* typeName) +{ + Q_ASSERT(typeResolverMap.contains(QLatin1String(typeName))); + return typeResolverMap.value(QLatin1String(typeName)); +} + +const char* TypeResolver::typeName() const +{ + return m_d->typeName; +} + +void* TypeResolver::toCpp(PyObject* pyObj) +{ + return m_d->pythonToCpp(pyObj); +} + +PyObject* TypeResolver::toPython(void* cppObj) +{ + return m_d->cppToPython(cppObj); +} + diff --git a/libpyside/typeresolver.h b/libpyside/typeresolver.h new file mode 100644 index 000000000..b3af959c4 --- /dev/null +++ b/libpyside/typeresolver.h @@ -0,0 +1,118 @@ +/* +* 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 TYPERESOLVER_H +#define TYPERESOLVER_H + +#include "pysidemacros.h" +#include "conversions.h" +#include <Python.h> +#include <QGenericArgument> + +namespace PySide +{ + +/* value type convertion functions */ +template <class T> +inline PyObject* objectToPython(void* p) +{ + return Shiboken::SbkBaseWrapper_New(reinterpret_cast<Shiboken::SbkBaseWrapperType*>(Shiboken::SbkType<T>()), p); +} + +template <> +inline PyObject* objectToPython<int>(void* p) +{ + return PyInt_FromLong(*reinterpret_cast<int*>(p)); +} + +template <class T> +inline void* pythonToValueType(PyObject* pyobj) +{ + return new T(Shiboken::Converter<T>::toCpp(pyobj)); +} + +template <class T> +inline void* pythonToObjectType(PyObject* pyobj) +{ + // TODO: Check if we could just check if this type is a shibotype and use the ptr + // buuuuut.... what if it's a primitive type!? + return Shiboken::Converter<T*>::toCpp(pyobj); +} + +template <class T> +inline void objectDeleter(void *data) +{ + delete reinterpret_cast<T*>(data); +} + +class PYSIDE_API TypeResolver +{ +public: + typedef PyObject* (*CppToPythonFunc)(void*); + typedef void* (*PythonToCppFunc)(PyObject*); + typedef void (*DeleteObjectFunc)(void*); + + ~TypeResolver(); + + template<typename T> + static TypeResolver* createValueTypeResolver(const char* typeName) + { + return new TypeResolver(typeName, &objectToPython<T>, &pythonToValueType<T>, &objectDeleter<T>); + } + + template<typename T> + static TypeResolver* createObjectTypeResolver(const char* typeName) + { + return new TypeResolver(typeName, &objectToPython<T>, &pythonToObjectType<T>, &objectDeleter<T>); + } + + static TypeResolver* get(const char* typeName); + static TypeResolver* get(const QString& typeName); + + const char* typeName() const; + PyObject* toPython(void* cppObj); + void* toCpp(PyObject* pyObj); +private: + struct TypeResolverPrivate; + TypeResolverPrivate* m_d; + + // disable object copy + TypeResolver(const TypeResolver&); + TypeResolver& operator=(const TypeResolver&); + + TypeResolver(const char* typeName, CppToPythonFunc cppToPy, PythonToCppFunc pyToCpp, DeleteObjectFunc deleter); +}; +} + +#endif |