diff options
-rw-r--r-- | libpyside/CMakeLists.txt | 5 | ||||
-rw-r--r-- | libpyside/abstractqobjectconnection.cpp | 3 | ||||
-rw-r--r-- | libpyside/dynamicqmetaobject.cpp | 155 | ||||
-rw-r--r-- | libpyside/dynamicqmetaobject.h | 72 | ||||
-rw-r--r-- | libpyside/proxyslot.cpp | 2 | ||||
-rw-r--r-- | libpyside/proxyslot.h | 11 | ||||
-rw-r--r-- | libpyside/signalmanager.cpp | 39 | ||||
-rw-r--r-- | libpyside/signalmanager.h | 3 | ||||
-rw-r--r-- | libpyside/signalslotconnection.cpp | 17 |
9 files changed, 275 insertions, 32 deletions
diff --git a/libpyside/CMakeLists.txt b/libpyside/CMakeLists.txt index ad1ebffce..2c2aa4d68 100644 --- a/libpyside/CMakeLists.txt +++ b/libpyside/CMakeLists.txt @@ -1,12 +1,13 @@ project(libpyside) set(libpyside_SRC -typeresolver.cpp -proxyslot.cpp abstractqobjectconnection.cpp +dynamicqmetaobject.cpp +proxyslot.cpp signalmanager.cpp signalsignalconnection.cpp signalslotconnection.cpp +typeresolver.cpp ) include_directories(${CMAKE_CURRENT_SOURCE_DIR} diff --git a/libpyside/abstractqobjectconnection.cpp b/libpyside/abstractqobjectconnection.cpp index 0f5a1b63a..65d47486e 100644 --- a/libpyside/abstractqobjectconnection.cpp +++ b/libpyside/abstractqobjectconnection.cpp @@ -35,6 +35,7 @@ #include "abstractqobjectconnection.h" #include "typeresolver.h" #include "signalmanager.h" +#include <QDebug> using namespace PySide; @@ -50,7 +51,7 @@ 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]); + PyObject* arg = TypeResolver::get(m_signalArgs[i])->toPython(args[i]); PyTuple_SET_ITEM(pyArgs, i, arg); } trigger(pyArgs); diff --git a/libpyside/dynamicqmetaobject.cpp b/libpyside/dynamicqmetaobject.cpp new file mode 100644 index 000000000..47baf6c82 --- /dev/null +++ b/libpyside/dynamicqmetaobject.cpp @@ -0,0 +1,155 @@ +/* +* 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 "dynamicqmetaobject.h" +#include <QByteArray> +#include <QString> +#include <QList> +#include <QObject> +#include <cstring> + +using namespace PySide; + +static int registerString(const QByteArray& s, QList<QByteArray>* strings) +{ + int idx = 0; + for (int i = 0; i < strings->count(); ++i) { + const QString &str = strings->at(i); + if (str == s) + return idx; + idx += str.length() + 1; + } + strings->append(s); + return idx; +} + +DynamicQMetaObject::DynamicQMetaObject(const QObject* object) : m_originalMetaObject(object->metaObject()) +{ + m_metaObject.d.superdata = m_originalMetaObject; + m_metaObject.d.stringdata = 0; + m_metaObject.d.data = 0; + m_metaObject.d.extradata = 0; + m_stringData = 0; + m_data = 0; + updateMetaObject(); +} + +DynamicQMetaObject::~DynamicQMetaObject() +{ + delete[] m_stringData; + delete[] m_data; +} + +void DynamicQMetaObject::addSignal(const char* signal) +{ + m_signals << QByteArray(signal); + updateMetaObject(); +} + +void DynamicQMetaObject::addSlot(const char* slot) +{ + m_signals << QByteArray(slot); + updateMetaObject(); +} + +void DynamicQMetaObject::updateMetaObject() +{ + // these values are from moc source code, generator.cpp:66 + enum MethodFlags { + AccessPrivate = 0x00, + AccessProtected = 0x01, + AccessPublic = 0x02, + MethodMethod = 0x00, + MethodSignal = 0x04, + MethodSlot = 0x08, + MethodConstructor = 0x0c, + MethodCompatibility = 0x10, + MethodCloned = 0x20, + MethodScriptable = 0x40 + }; + + uint n_signals = m_signals.count(); + uint n_methods = n_signals + m_slots.count(); + int header[] = {2, // revision + 0, // class name index in m_metadata + 0, 0, // classinfo and classinfo index, not used by us + n_methods, 0, // method count and method list index + 0, 0, // prop count and prop indexes + 0, 0 // enum count and enum index + }; + + const int HEADER_LENGHT = sizeof(header)/sizeof(int); + header[5] = HEADER_LENGHT; + // header size + 5 indexes per method + an ending zero + delete[] m_data; + m_data = new uint[HEADER_LENGHT + n_methods*5 + 1]; + std::memcpy(m_data, header, sizeof(header)); + + QList<QByteArray> strings; + registerString(m_originalMetaObject->className(), &strings); // register class string + const int NULL_INDEX = registerString("", &strings); // register a null string + int index = HEADER_LENGHT; + + //write signals + foreach(QByteArray signal, m_signals) { + m_data[index++] = registerString(signal, &strings); // func name + m_data[index++] = NULL_INDEX; // arguments + m_data[index++] = NULL_INDEX; // normalized type + m_data[index++] = NULL_INDEX; // tags + m_data[index++] = AccessPublic | MethodSignal; // flags + } + //write slots + foreach(QByteArray slot, m_slots) { + m_data[index++] = registerString(slot, &strings); // func name + m_data[index++] = NULL_INDEX; // arguments + m_data[index++] = NULL_INDEX; // normalized type + m_data[index++] = NULL_INDEX; // tags + m_data[index++] = AccessPublic | MethodSlot; // flags + } + m_data[index++] = 0; // the end + + // create the m_metadata string + QByteArray str; + foreach(QByteArray signature, strings) { + str.append(signature); + str.append(char(0)); + } + delete[] m_stringData; + m_stringData = new char[str.count()]; + std::copy(str.begin(), str.end(), m_stringData); + + // create metaobject + m_metaObject.d.stringdata = m_stringData; + m_metaObject.d.data = m_data; +} diff --git a/libpyside/dynamicqmetaobject.h b/libpyside/dynamicqmetaobject.h new file mode 100644 index 000000000..a7fb3b6f2 --- /dev/null +++ b/libpyside/dynamicqmetaobject.h @@ -0,0 +1,72 @@ +/* +* 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 DYNAMICQMETAOBJECT_H +#define DYNAMICQMETAOBJECT_H + +#include <QMetaObject> +#include <QLinkedList> +#include <QByteArray> + +class QObject; + +namespace PySide +{ + +class DynamicQMetaObject +{ +public: + DynamicQMetaObject(const QObject* object); + ~DynamicQMetaObject(); + void addSignal(const char* signal); + void addSlot(const char* slot); + + const QMetaObject* metaObject() const + { + return &m_metaObject; + } +private: + const QMetaObject* m_originalMetaObject; + QMetaObject m_metaObject; + + QLinkedList<QByteArray> m_signals; + QLinkedList<QByteArray> m_slots; + unsigned int* m_data; + char* m_stringData; + + void updateMetaObject(); +}; + +} +#endif diff --git a/libpyside/proxyslot.cpp b/libpyside/proxyslot.cpp index 59467056f..885232574 100644 --- a/libpyside/proxyslot.cpp +++ b/libpyside/proxyslot.cpp @@ -40,7 +40,7 @@ using namespace PySide; -ProxySlot::ProxySlot(QObject* signalSource) : m_signalSource(signalSource) +ProxySlot::ProxySlot(const QObject* signalSource) : m_metaObject(signalSource), m_signalSource(signalSource) { m_nextSlotIndex = m_signalSource->metaObject()->methodCount()-1; } diff --git a/libpyside/proxyslot.h b/libpyside/proxyslot.h index 8e45eff6f..c2334f799 100644 --- a/libpyside/proxyslot.h +++ b/libpyside/proxyslot.h @@ -34,6 +34,7 @@ #include <QObject> #include <QHash> +#include "dynamicqmetaobject.h" namespace PySide { @@ -43,8 +44,13 @@ class AbstractQObjectConnection; class ProxySlot : public QObject { public: - ProxySlot(QObject* signalSource); + ProxySlot(const QObject* signalSource); bool connect(AbstractQObjectConnection* connection); + DynamicQMetaObject* dynamicQMetaObject() + { + return &m_metaObject; + } + protected: /** * Qt's meta-object system uses the qt_metacall() function to access the @@ -69,7 +75,8 @@ protected: int qt_metacall(QMetaObject::Call call, int id, void **args); private: - QObject* m_signalSource; + DynamicQMetaObject m_metaObject; + const QObject* m_signalSource; int m_nextSlotIndex; // slot_index => connection_info, used by qt_metacall // to recover the connection_info diff --git a/libpyside/signalmanager.cpp b/libpyside/signalmanager.cpp index 711465549..e9f9b7c2b 100644 --- a/libpyside/signalmanager.cpp +++ b/libpyside/signalmanager.cpp @@ -75,11 +75,16 @@ QStringList PySide::getArgsFromSignature(const char* signature) struct SignalManager::SignalManagerPrivate { - QHash<QObject*, ProxySlot*> m_proxies; + QHash<const QObject*, ProxySlot*> m_proxies; - ProxySlot* findProxy(QObject* signalSource) + ProxySlot* findProxy(const QObject* signalSource) const { - ProxySlot* proxy = m_proxies.value(signalSource); + return m_proxies.value(signalSource); + } + + ProxySlot* getProxy(const QObject* signalSource) + { + ProxySlot* proxy = findProxy(signalSource); if (!proxy) { proxy = new ProxySlot(signalSource); m_proxies[signalSource] = proxy; @@ -110,7 +115,9 @@ bool SignalManager::connect(QObject* source, const char* signal, PyObject* callb return false; signal++; - ProxySlot* proxy = m_d->findProxy(source); + ProxySlot* proxy = m_d->getProxy(source); + if (source->metaObject()->indexOfSignal(signal) == -1) + proxy->dynamicQMetaObject()->addSignal(signal); AbstractQObjectConnection* connection = new SignalSlotConnection(source, signal, callback, type); return proxy->connect(connection); } @@ -132,7 +139,7 @@ bool SignalManager::connect(QObject* source, const char* signal, QObject* receiv receiver, slot_index, type); } else { // We have a python slot or signal - ProxySlot* proxy = m_d->findProxy(source); + ProxySlot* proxy = m_d->getProxy(source); AbstractQObjectConnection* connection = 0; retval = proxy->connect(connection); } @@ -142,18 +149,14 @@ bool SignalManager::connect(QObject* source, const char* signal, QObject* receiv bool SignalManager::emitSignal(QObject* source, const char* signal, PyObject* args) { - if (checkSignal(signal)) + if (!checkSignal(signal)) return false; + signal++; 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 + int signalIndex = source->metaObject()->indexOfSignal(signal); + if (signalIndex != -1) { QStringList argTypes = getArgsFromSignature(signal); void* signalArgs[argsGiven+1]; @@ -166,7 +169,15 @@ bool SignalManager::emitSignal(QObject* source, const char* signal, PyObject* ar return false; } -void PySide::SignalManager::removeProxySlot(QObject* signalSource) +void PySide::SignalManager::removeProxySlot(const QObject* signalSource) { m_d->m_proxies.remove(signalSource); } + +const QMetaObject* PySide::SignalManager::getMetaObject(const QObject* object) const +{ + ProxySlot* proxy = m_d->findProxy(object); + if (proxy) + return proxy->dynamicQMetaObject()->metaObject(); + return 0; +} diff --git a/libpyside/signalmanager.h b/libpyside/signalmanager.h index 515ac6153..4e6fe6d9f 100644 --- a/libpyside/signalmanager.h +++ b/libpyside/signalmanager.h @@ -54,7 +54,8 @@ public: 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); + void removeProxySlot(const QObject* signalSource); + const QMetaObject* getMetaObject(const QObject* object) const; private: struct SignalManagerPrivate; SignalManagerPrivate* m_d; diff --git a/libpyside/signalslotconnection.cpp b/libpyside/signalslotconnection.cpp index 8f7ddf17c..f6391682e 100644 --- a/libpyside/signalslotconnection.cpp +++ b/libpyside/signalslotconnection.cpp @@ -59,21 +59,15 @@ SignalSlotConnection::~SignalSlotConnection() void SignalSlotConnection::trigger(PyObject* args) { - int useSelf = m_receiver ? 1 : 0; - int numArgs = PySequence_Size(args); - PyObject* preparedArgs = PyTuple_New(numArgs + useSelf); + Q_ASSERT(PySequence_Size(args) >= m_numSlotArgs); + const int useSelf = m_receiver ? 1 : 0; + + PyObject* preparedArgs = PyTuple_New(m_numSlotArgs); if (m_receiver) PyTuple_SetItem(preparedArgs, 0, m_receiver); - for (int i = 0; i < numArgs; ++i) + for (int i = 0; i < m_numSlotArgs; ++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); @@ -81,4 +75,5 @@ void SignalSlotConnection::trigger(PyObject* args) qWarning(qPrintable(QString("Error calling slot ")+ PyString_AS_STRING(reinterpret_cast<PyCodeObject*>(PyFunction_GET_CODE(m_function))->co_name))); } + Py_DECREF(preparedArgs); } |