aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside2/libpyside
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2018-10-02 15:28:19 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2018-10-22 15:05:03 +0000
commitd1d08a134d2b22b91150a70a1ec23f576bb38398 (patch)
tree49d415e560b782a2faf78b5f03e69fb6960ea026 /sources/pyside2/libpyside
parent3d6fc64570024d6af11597bb2ee4d431600ec6e1 (diff)
libpyside: Port DynamicQMetaObject to QMetaObjectBuilder
Qt 5 introduces a new class QMetaObjectBuilder for generating dynamic meta objects for use cases like QML. It provides an API to add methods, properties and info and a factory method toMetaObject() to obtain a QMetaObject snapshot reflecting the changes. Replace the DynamicQMetaObject aggregated by TypeUserData by a class MetaObjectBuilder wrapping a QMetaObjectBuilder with dirty-handling. The code to create the binary data of the QMetaObject can then be removed. For plain Qt objects, the wrapped base meta object will be returned (which fixes the bug). Task-number: PYSIDE-784 Change-Id: Id8a54570aff36c75fe0f3bf2d297a12d02cd773a Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'sources/pyside2/libpyside')
-rw-r--r--sources/pyside2/libpyside/CMakeLists.txt3
-rw-r--r--sources/pyside2/libpyside/dynamicqmetaobject.cpp908
-rw-r--r--sources/pyside2/libpyside/dynamicqmetaobject.h38
-rw-r--r--sources/pyside2/libpyside/globalreceiverv2.cpp10
-rw-r--r--sources/pyside2/libpyside/globalreceiverv2.h5
-rw-r--r--sources/pyside2/libpyside/pyside.cpp11
-rw-r--r--sources/pyside2/libpyside/pyside_p.h6
-rw-r--r--sources/pyside2/libpyside/pysideclassinfo.cpp5
-rw-r--r--sources/pyside2/libpyside/signalmanager.cpp44
9 files changed, 337 insertions, 693 deletions
diff --git a/sources/pyside2/libpyside/CMakeLists.txt b/sources/pyside2/libpyside/CMakeLists.txt
index 101b32e4a..ec6713b62 100644
--- a/sources/pyside2/libpyside/CMakeLists.txt
+++ b/sources/pyside2/libpyside/CMakeLists.txt
@@ -82,7 +82,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}
${SHIBOKEN_INCLUDE_DIR}
${SHIBOKEN_PYTHON_INCLUDE_DIR}
${QML_INCLUDES}
- ${Qt5Core_INCLUDE_DIRS})
+ ${Qt5Core_INCLUDE_DIRS}
+ ${Qt5Core_PRIVATE_INCLUDE_DIRS})
add_library(pyside2 SHARED ${libpyside_SRC} ${other_files})
target_link_libraries(pyside2
${SHIBOKEN_PYTHON_LIBRARIES}
diff --git a/sources/pyside2/libpyside/dynamicqmetaobject.cpp b/sources/pyside2/libpyside/dynamicqmetaobject.cpp
index 525e24f4a..5cbfa70f9 100644
--- a/sources/pyside2/libpyside/dynamicqmetaobject.cpp
+++ b/sources/pyside2/libpyside/dynamicqmetaobject.cpp
@@ -50,521 +50,371 @@
#include <QtCore/QByteArray>
#include <QtCore/QObject>
#include <QtCore/QStringList>
+#include <QtCore/QTextStream>
#include <QtCore/QVector>
+#include <private/qmetaobjectbuilder_p.h>
#include <cstring>
-
-#define EMPTY_META_METHOD "0()"
+#include <vector>
using namespace PySide;
-enum PropertyFlags {
- Invalid = 0x00000000,
- Readable = 0x00000001,
- Writable = 0x00000002,
- Resettable = 0x00000004,
- EnumOrFlag = 0x00000008,
- StdCppSet = 0x00000100,
-// Override = 0x00000200,
- Constant = 0x00000400,
- Final = 0x00000800,
- Designable = 0x00001000,
- ResolveDesignable = 0x00002000,
- Scriptable = 0x00004000,
- ResolveScriptable = 0x00008000,
- Stored = 0x00010000,
- ResolveStored = 0x00020000,
- Editable = 0x00040000,
- ResolveEditable = 0x00080000,
- User = 0x00100000,
- ResolveUser = 0x00200000,
- Notify = 0x00400000
-};
-
-// 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
-};
-
-enum MetaDataFlags {
- IsUnresolvedType = 0x80000000,
- TypeNameIndexMask = 0x7FFFFFFF
-};
-
-class DynamicQMetaObject::DynamicQMetaObjectPrivate
+// MetaObjectBuilder: Provides the QMetaObject's returned by
+// QObject::metaObject() for PySide2 objects. There are several
+// scenarios to consider:
+// 1) A plain Qt class (say QTimer) is instantiated. In that case,
+// return the base meta object until a modification is made by
+// adding methods, properties or class info (cf qmetaobject_test.py).
+// In that case, instantiate a QMetaObjectBuilder inheriting the
+// base meta meta object, add the method and return the result
+// of QMetaObjectBuilder::toMetaObject() (with dirty handling should
+// further modifications be made).
+// 2) A Python class inheriting a Qt class is instantiated. For this,
+// instantiate a QMetaObjectBuilder and add the methods/properties
+// found by inspecting the Python class.
+
+class MetaObjectBuilderPrivate
{
public:
- QList<MethodData> m_methods;
- QList<PropertyData> m_properties;
-
- QMap<QByteArray, QByteArray> m_info;
- QByteArray m_className;
-
- bool m_updated = false; // when the meta data is not update
- int m_methodOffset = 0;
- int m_propertyOffset = 0;
- int m_dataSize = 0;
- int m_emptyMethod = -1;
- int m_nullIndex = 0;
-
- int createMetaData(QMetaObject* metaObj);
- void updateMetaObject(QMetaObject* metaObj);
- void writeMethodsData(const QList<MethodData>& methods, unsigned int** data,
- QByteArrayList& strings, int* prtIndex,
- int nullIndex, int flags);
- void writeStringData(char *, const QByteArrayList& strings) const;
+ using MetaObjects = std::vector<const QMetaObject *>;
+
+ QMetaObjectBuilder *ensureBuilder();
+ void parsePythonType(PyTypeObject *type);
+ int indexOfMethod(QMetaMethod::MethodType mtype,
+ const QByteArray &signature) const;
+ int indexOfProperty(const QByteArray &name) const;
+ int addSlot(const QByteArray &signature);
+ int addSlot(const QByteArray &signature, const QByteArray &type);
+ int addSignal(const QByteArray &signature);
+ void removeMethod(QMetaMethod::MethodType mtype, int index);
int getPropertyNotifyId(PySideProperty *property) const;
-};
+ int addProperty(const QByteArray &property, PyObject *data);
+ void addInfo(const QByteArray &key, const QByteArray &value);
+ void addInfo(const QMap<QByteArray, QByteArray> &info);
+ void removeProperty(int index);
+ const QMetaObject *update();
-bool sortMethodSignalSlot(const MethodData &m1, const MethodData &m2)
-{
- if (m1.methodType() == QMetaMethod::Signal)
- return m2.methodType() == QMetaMethod::Slot;
- return false;
-}
+ QMetaObjectBuilder *m_builder = nullptr;
-static int registerString(const QByteArray& s, QByteArrayList& strings)
-{
- int idx = strings.indexOf(s);
- if (idx == -1) {
- idx = strings.size();
- strings.append(s);
- }
- return idx;
-}
-
-static int blobSize(const QByteArrayList &strings)
-{
- int size = strings.size() * int(sizeof(QByteArrayData));
- for (const QByteArray &field : strings)
- size += field.size() + 1;
- return size;
-}
-
-static int aggregateParameterCount(const QList<MethodData> &methods)
-{
- int sum = 0;
- for (const auto &method : methods)
- sum += method.parameterCount() * 2 + 1; // nb_param*2 (type and names) +1 for return type
- return sum;
-}
+ const QMetaObject *m_baseObject = nullptr;
+ MetaObjects m_cachedMetaObjects;
+ bool m_dirty = true;
+};
-static void writeString(char *out, int i, const QByteArray &str,
- const int offsetOfStringdataMember, int &stringdataOffset)
+QMetaObjectBuilder *MetaObjectBuilderPrivate::ensureBuilder()
{
- int size = str.size();
- qptrdiff offset = offsetOfStringdataMember + stringdataOffset
- - i * sizeof(QByteArrayData);
- const QByteArrayData data =
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset);
-
- memcpy(out + i * sizeof(QByteArrayData), &data, sizeof(QByteArrayData));
-
- memcpy(out + offsetOfStringdataMember + stringdataOffset, str.constData(), size);
- out[offsetOfStringdataMember + stringdataOffset + size] = '\0';
-
- stringdataOffset += size + 1;
+ if (!m_builder) {
+ m_builder = new QMetaObjectBuilder();
+ m_builder->setClassName(m_baseObject->className());
+ m_builder->setSuperClass(m_baseObject);
+ }
+ return m_builder;
}
-static int qvariant_nameToType(const char* name)
+MetaObjectBuilder::MetaObjectBuilder(const char *className, const QMetaObject *metaObject) :
+ m_d(new MetaObjectBuilderPrivate)
{
- if (!name)
- return 0;
-
- if (strcmp(name, "QVariant") == 0)
- return 0xffffffff;
- if (strcmp(name, "QCString") == 0)
- return QMetaType::QByteArray;
- if (strcmp(name, "Q_LLONG") == 0)
- return QMetaType::LongLong;
- if (strcmp(name, "Q_ULLONG") == 0)
- return QMetaType::ULongLong;
- if (strcmp(name, "QIconSet") == 0)
- return QMetaType::QIcon;
-
- uint tp = QMetaType::type(name);
- return tp < QMetaType::User ? tp : 0;
+ m_d->m_baseObject = metaObject;
+ m_d->m_builder = new QMetaObjectBuilder();
+ m_d->m_builder->setClassName(className);
+ m_d->m_builder->setSuperClass(metaObject);
+ m_d->m_builder->setClassName(className);
}
-/*
- Returns true if the type is a QVariant types.
-*/
-static bool isVariantType(const char* type)
+MetaObjectBuilder::MetaObjectBuilder(PyTypeObject *type, const QMetaObject *metaObject)
+ : m_d(new MetaObjectBuilderPrivate)
{
- return qvariant_nameToType(type) != 0;
+ m_d->m_baseObject = metaObject;
+ const char *className = type->tp_name;
+ if (const char *lastDot = strrchr(type->tp_name, '.'))
+ className = lastDot + 1;
+ // Different names indicate a Python class inheriting a Qt class.
+ // Parse the type.
+ if (strcmp(className, metaObject->className()) != 0) {
+ m_d->m_builder = new QMetaObjectBuilder();
+ m_d->m_builder->setClassName(className);
+ m_d->m_builder->setSuperClass(metaObject);
+ m_d->parsePythonType(type);
+ }
}
-/*!
- Returns true if the type is qreal.
-*/
-static bool isQRealType(const char *type)
+MetaObjectBuilder::~MetaObjectBuilder()
{
- return strcmp(type, "qreal") == 0;
+ qDeleteAll(m_d->m_cachedMetaObjects);
+ delete m_d->m_builder;
+ delete m_d;
}
-uint PropertyData::flags() const
+int MetaObjectBuilderPrivate::indexOfMethod(QMetaMethod::MethodType mtype,
+ const QByteArray &signature) const
{
- const QByteArray btype(type());
- const char* typeName = btype.data();
- uint flags = Invalid;
- if (!isVariantType(typeName))
- flags |= EnumOrFlag;
- else if (!isQRealType(typeName))
- flags |= qvariant_nameToType(typeName) << 24;
-
- if (PySide::Property::isReadable(m_data))
- flags |= Readable;
-
- if (PySide::Property::isWritable(m_data))
- flags |= Writable;
-
- if (PySide::Property::hasReset(m_data))
- flags |= Resettable;
-
- if (PySide::Property::isDesignable(m_data))
- flags |= Designable;
- else
- flags |= ResolveDesignable;
-
- if (PySide::Property::isScriptable(m_data))
- flags |= Scriptable;
- else
- flags |= ResolveScriptable;
-
- if (PySide::Property::isStored(m_data))
- flags |= Stored;
- else
- flags |= ResolveStored;
-
- //EDITABLE
- flags |= ResolveEditable;
-
- if (PySide::Property::isUser(m_data))
- flags |= User;
- else
- flags |= ResolveUser;
-
- if (m_cachedNotifyId != -1)
- flags |= Notify;
-
- if (PySide::Property::isConstant(m_data))
- flags |= Constant;
-
- if (PySide::Property::isFinal(m_data))
- flags |= Final;
-
- return flags;
+ int result = -1;
+ if (m_builder) {
+ switch (mtype) {
+ case QMetaMethod::Signal:
+ result = m_builder->indexOfSignal(signature);
+ break;
+ case QMetaMethod::Slot:
+ result = m_builder->indexOfSlot(signature);
+ break;
+ case QMetaMethod::Constructor:
+ result = m_builder->indexOfConstructor(signature);
+ break;
+ case QMetaMethod::Method:
+ result = m_builder->indexOfMethod(signature);
+ break;
+ }
+ if (result >= 0)
+ return result + m_baseObject->methodCount();
+ }
+ switch (mtype) {
+ case QMetaMethod::Signal:
+ result = m_baseObject->indexOfSignal(signature);
+ break;
+ case QMetaMethod::Slot:
+ result = m_baseObject->indexOfSlot(signature);
+ break;
+ case QMetaMethod::Constructor:
+ result = m_baseObject->indexOfConstructor(signature);
+ break;
+ case QMetaMethod::Method:
+ result = m_baseObject->indexOfMethod(signature);
+ break;
+ }
+ return result;
}
-// const QByteArray with EMPTY_META_METHOD, used to save some memory
-const QByteArray MethodData::m_emptySig(EMPTY_META_METHOD);
-
-MethodData::MethodData()
- : m_signature(m_emptySig)
+int MetaObjectBuilder::indexOfMethod(QMetaMethod::MethodType mtype,
+ const QByteArray &signature) const
{
+ return m_d->indexOfMethod(mtype, signature);
}
-MethodData::MethodData(QMetaMethod::MethodType mtype, const QByteArray& signature, const QByteArray& rtype)
- : m_signature(QMetaObject::normalizedSignature(signature.constData()))
- , m_rtype(QMetaObject::normalizedSignature(rtype.constData()))
- , m_mtype(mtype)
+int MetaObjectBuilderPrivate::indexOfProperty(const QByteArray &name) const
{
+ if (m_builder) {
+ const int result = m_builder->indexOfProperty(name);
+ if (result >= 0)
+ return m_baseObject->propertyCount() + result;
+ }
+ return m_baseObject->indexOfProperty(name);
}
-void MethodData::clear()
+int MetaObjectBuilder::indexOfProperty(const QByteArray &name) const
{
- m_signature = m_emptySig;
- m_rtype.clear();
+ return m_d->indexOfProperty(name);
}
-bool MethodData::isValid() const
+static bool checkMethodSignature(const QByteArray &signature)
{
- return m_signature != m_emptySig;
-}
-
-QList<QByteArray> MethodData::parameterTypes() const
-{
- const char *signature = m_signature.constData();
- QList<QByteArray> list;
- while (*signature && *signature != '(')
- ++signature;
- while (*signature && *signature != ')' && *++signature != ')') {
- const char *begin = signature;
- int level = 0;
- while (*signature && (level > 0 || *signature != ',') && *signature != ')') {
- if (*signature == '<')
- ++level;
- else if (*signature == '>')
- --level;
- ++signature;
- }
- list += QByteArray(begin, signature - begin);
- }
- return list;
+ // Common mistake not to add parentheses to the signature.
+ const int openParen = signature.indexOf('(');
+ const int closingParen = signature.lastIndexOf(')');
+ const bool ok = openParen != -1 && closingParen != -1 && openParen < closingParen;
+ if (!ok) {
+ const QByteArray message =
+ "MetaObjectBuilder::addMethod: Invalid method signature provided for \""
+ + signature + '"';
+ PyErr_WarnEx(PyExc_RuntimeWarning, message.constData(), 0);
+ }
+ return ok;
}
-int MethodData::parameterCount() const
+int MetaObjectBuilderPrivate::addSlot(const QByteArray &signature)
{
- return parameterTypes().size();
+ if (!checkMethodSignature(signature))
+ return -1;
+ m_dirty = true;
+ return m_baseObject->methodCount()
+ + ensureBuilder()->addSlot(signature).index();
}
-QByteArray MethodData::name() const
+int MetaObjectBuilder::addSlot(const char *signature)
{
- return m_signature.left(qMax(m_signature.indexOf('('), 0));
+ return m_d->addSlot(signature);
}
-PropertyData::PropertyData()
- : m_cachedNotifyId(0), m_data(0)
+int MetaObjectBuilderPrivate::addSlot(const QByteArray &signature,
+ const QByteArray &type)
{
+ if (!checkMethodSignature(signature))
+ return -1;
+ m_dirty = true;
+ QMetaMethodBuilder methodBuilder = ensureBuilder()->addSlot(signature);
+ methodBuilder.setReturnType(type);
+ return m_baseObject->methodCount() + methodBuilder.index();
}
-PropertyData::PropertyData(const char* name, int notifyId, PySideProperty* data)
- : m_name(name), m_cachedNotifyId(notifyId), m_data(data)
+int MetaObjectBuilder::addSlot(const char *signature, const char *type)
{
+ return m_d->addSlot(signature, type);
}
-QByteArray PropertyData::type() const
+int MetaObjectBuilderPrivate::addSignal(const QByteArray &signature)
{
- return QByteArray(PySide::Property::getTypeName(m_data));
+ if (!checkMethodSignature(signature))
+ return -1;
+ m_dirty = true;
+ return m_baseObject->methodCount()
+ + ensureBuilder()->addSignal(signature).index();
}
-
-bool PropertyData::isValid() const
+int MetaObjectBuilder::addSignal(const char *signature)
{
- return !m_name.isEmpty();
+ return m_d->addSignal(signature);
}
-int PropertyData::cachedNotifyId() const
+void MetaObjectBuilderPrivate::removeMethod(QMetaMethod::MethodType mtype,
+ int index)
{
- return m_cachedNotifyId;
+ index -= m_baseObject->methodCount();
+ auto builder = ensureBuilder();
+ Q_ASSERT(index >= 0 && index < builder->methodCount());
+ switch (mtype) {
+ case QMetaMethod::Constructor:
+ builder->removeConstructor(index);
+ break;
+ default:
+ builder->removeMethod(index);
+ break;
+ }
+ m_dirty = true;
}
-bool PropertyData::operator==(const PropertyData& other) const
+void MetaObjectBuilder::removeMethod(QMetaMethod::MethodType mtype, int index)
{
- return m_data == other.m_data;
+ m_d->removeMethod(mtype, index);
}
-bool PropertyData::operator==(const char* name) const
+int MetaObjectBuilderPrivate::getPropertyNotifyId(PySideProperty *property) const
{
- return m_name == name;
+ int notifyId = -1;
+ if (property->d->notify) {
+ if (const char *signalNotify = PySide::Property::getNotifyName(property))
+ notifyId = indexOfMethod(QMetaMethod::Signal, signalNotify);
+ }
+ return notifyId;
}
-
-DynamicQMetaObject::DynamicQMetaObject(PyTypeObject* type, const QMetaObject* base)
- : m_d(new DynamicQMetaObjectPrivate)
+int MetaObjectBuilderPrivate::addProperty(const QByteArray &propertyName,
+ PyObject *data)
{
- d.superdata = base;
- d.stringdata = NULL;
- d.data = NULL;
- d.extradata = NULL;
- d.relatedMetaObjects = NULL;
- d.static_metacall = NULL;
+ int index = indexOfProperty(propertyName);
+ if (index != -1)
+ return index;
- m_d->m_className = QByteArray(type->tp_name).split('.').last();
- m_d->m_methodOffset = base->methodCount() - 1;
- m_d->m_propertyOffset = base->propertyCount() - 1;
- parsePythonType(type);
+ PySideProperty *property = reinterpret_cast<PySideProperty *>(data);
+ int propertyNotifyId = getPropertyNotifyId(property);
+ if (propertyNotifyId >= 0)
+ propertyNotifyId -= m_baseObject->methodCount();
+ auto newProperty =
+ ensureBuilder()->addProperty(propertyName, property->d->typeName,
+ propertyNotifyId);
+ index = newProperty.index() + m_baseObject->propertyCount();
+ m_dirty = true;
+ return index;
}
-DynamicQMetaObject::DynamicQMetaObject(const char* className, const QMetaObject* metaObject)
- : m_d(new DynamicQMetaObjectPrivate)
+int MetaObjectBuilder::addProperty(const char *property, PyObject *data)
{
- d.superdata = metaObject;
- d.stringdata = 0;
- d.data = 0;
- d.extradata = 0;
- d.relatedMetaObjects = NULL;
- d.static_metacall = NULL;
-
- m_d->m_className = className;
- m_d->m_methodOffset = metaObject->methodCount() - 1;
- m_d->m_propertyOffset = metaObject->propertyCount() - 1;
+ return m_d->addProperty(property, data);
}
-DynamicQMetaObject::~DynamicQMetaObject()
+void MetaObjectBuilderPrivate::addInfo(const QByteArray &key,
+ const QByteArray &value)
{
- free(reinterpret_cast<char *>(const_cast<QByteArrayData *>(d.stringdata)));
- free(const_cast<uint*>(d.data));
- delete m_d;
+ ensureBuilder()->addClassInfo(key, value);
+ m_dirty = true;
}
-int DynamicQMetaObject::addMethod(QMetaMethod::MethodType mtype, const char* signature, const char* type)
+void MetaObjectBuilder::addInfo(const char *key, const char *value)
{
- int index = -1;
- int counter = 0;
-
- QList<MethodData>::iterator it = m_d->m_methods.begin();
- for (; it != m_d->m_methods.end(); ++it) {
- if ((it->signature() == signature) && (it->methodType() == mtype))
- return m_d->m_methodOffset + counter;
- if (!it->isValid())
- index = counter;
- counter++;
- }
-
- // Common mistake not to add parentheses to the signature.
- if ((strchr(signature, ')') == 0) || ((strchr(signature, '(') == 0))) {
- const QString message =
- QLatin1String("DynamicQMetaObject::addMethod: Invalid method signature "
- "provided for ") + QLatin1String(signature);
- const QByteArray messageLatin = message.toLatin1();
- PyErr_WarnEx(PyExc_RuntimeWarning, messageLatin.constData(), 0);
- return -1;
- }
-
- //has blank method
- if (index != -1) {
- m_d->m_methods[index] = MethodData(mtype, signature, type);
- index++;
- } else {
- m_d->m_methods << MethodData(mtype, signature, type);
- index = m_d->m_methods.size();
- }
-
- m_d->m_updated = false;
- return m_d->m_methodOffset + index;
+ m_d->addInfo(key, value);
}
-void DynamicQMetaObject::removeMethod(QMetaMethod::MethodType mtype, uint index)
+void MetaObjectBuilderPrivate::addInfo(const QMap<QByteArray, QByteArray> &info)
{
- const char* methodSig = method(index).methodSignature();
- QList<MethodData>::iterator it = m_d->m_methods.begin();
- for (; it != m_d->m_methods.end(); ++it) {
- if ((it->signature() == methodSig) && (it->methodType() == mtype)){
- it->clear();
- m_d->m_updated = false;
- break;
- }
- }
+ auto builder = ensureBuilder();
+ for (auto i = info.constBegin(), end = info.constEnd(); i != end; ++i)
+ builder->addClassInfo(i.key(), i.value());
+ m_dirty = true;
}
-int DynamicQMetaObject::addSignal(const char* signal, const char* type)
+void MetaObjectBuilder::addInfo(const QMap<QByteArray, QByteArray> &info)
{
- return addMethod(QMetaMethod::Signal, signal, type);
+ m_d->addInfo(info);
}
-int DynamicQMetaObject::addSlot(const char* slot, const char* type)
+void MetaObjectBuilderPrivate::removeProperty(int index)
{
- return addMethod(QMetaMethod::Slot, slot, type);
+ index -= m_baseObject->propertyCount();
+ auto builder = ensureBuilder();
+ Q_ASSERT(index >= 0 && index < builder->propertyCount());
+ builder->removeProperty(index);
+ m_dirty = true;
}
-void DynamicQMetaObject::removeSlot(uint index)
+void MetaObjectBuilder::removeProperty(int index)
{
- removeMethod(QMetaMethod::Slot, index);
+ m_d->removeProperty(index);
}
-void DynamicQMetaObject::removeSignal(uint index)
-{
- removeMethod(QMetaMethod::Signal, index);
-}
+// PYSIDE-315: Instead of sorting the items and maybe breaking indices, we
+// ensure that the signals and slots are sorted by the improved
+// parsePythonType() (signals must go before slots). The order can only
+// become distorted if the class is modified after creation. In that
+// case, we give a warning.
-int DynamicQMetaObject::addProperty(const char* propertyName, PyObject* data)
+static QString msgMethodSortOrder(const QMetaObject *mo, int offendingIndex)
{
- int index = m_d->m_properties.indexOf(propertyName);
- if (index != -1)
- return m_d->m_propertyOffset + index;
-
- // retrieve notifyId
- PySideProperty *property = reinterpret_cast<PySideProperty *>(data);
- const int notifyId = m_d->getPropertyNotifyId(property);
-
- //search for a empty space
- PropertyData blank;
- index = m_d->m_properties.indexOf(blank);
- if (index != -1) {
- m_d->m_properties[index] = PropertyData(propertyName, notifyId, property);
- } else {
- m_d->m_properties << PropertyData(propertyName, notifyId, property);
- index = m_d->m_properties.size();
+ QString result;
+ QTextStream str(&result);
+ str << "\n\n*** Sort Warning ***\nSignals and slots in QMetaObject '"
+ << mo->className()
+ << "' are not ordered correctly, this may lead to issues.\n";
+ const int methodOffset = mo->methodOffset();
+ for (int m = methodOffset, methodCount = mo->methodCount(); m < methodCount; ++m) {
+ const auto method = mo->method(m);
+ str << (m - methodOffset + 1) << (m > offendingIndex ? '!' : ' ')
+ << (method.methodType() == QMetaMethod::Signal ? " Signal " : " Slot ")
+ << method.methodSignature() << '\n';
}
- m_d->m_updated = false;
- return m_d->m_propertyOffset + index;
+ return result;
}
-int DynamicQMetaObject::DynamicQMetaObjectPrivate::getPropertyNotifyId(PySideProperty *property) const
+static void checkMethodOrder(const QMetaObject *metaObject)
{
- int notifyId = -1;
- if (property->d->notify) {
- const char *signalNotify = PySide::Property::getNotifyName(property);
- if (signalNotify) {
- const MethodData signalObject(QMetaMethod::Signal, signalNotify, "");
- notifyId = m_methods.indexOf(signalObject);
+ const int lastMethod = metaObject->methodCount() - 1;
+ for (int m = metaObject->methodOffset(); m < lastMethod; ++m) {
+ if (metaObject->method(m).methodType() == QMetaMethod::Slot
+ && metaObject->method(m + 1).methodType() == QMetaMethod::Signal) {
+ const auto message = msgMethodSortOrder(metaObject, m);
+ PyErr_WarnEx(PyExc_RuntimeWarning, qPrintable(message), 0);
+ // Prevent a warning from being turned into an error. We cannot easily unwind.
+ PyErr_Clear();
+ break;
}
}
- return notifyId;
-}
-
-void DynamicQMetaObject::addInfo(const char* key, const char* value)
-{
- m_d->m_info[key] = value;
-}
-
-void DynamicQMetaObject::addInfo(const QMap<QByteArray, QByteArray> &info)
-{
- QMap<QByteArray, QByteArray>::const_iterator i = info.constBegin();
- while (i != info.constEnd()) {
- m_d->m_info[i.key()] = i.value();
- ++i;
- }
- m_d->m_updated = false;
}
-const QMetaObject* DynamicQMetaObject::update() const
+const QMetaObject *MetaObjectBuilderPrivate::update()
{
- if (!m_d->m_updated) {
- m_d->updateMetaObject(const_cast<DynamicQMetaObject*>(this));
- m_d->m_updated = true;
+ if (!m_builder)
+ return m_baseObject;
+ if (m_cachedMetaObjects.empty() || m_dirty) {
+ m_cachedMetaObjects.push_back(m_builder->toMetaObject());
+ checkMethodOrder(m_cachedMetaObjects.back());
+ m_dirty = false;
}
- return this;
+ return m_cachedMetaObjects.back();
}
-void DynamicQMetaObject::DynamicQMetaObjectPrivate::writeMethodsData(const QList<MethodData>& methods,
- unsigned int** data,
- QByteArrayList& strings,
- int* prtIndex,
- int nullIndex,
- int flags)
+const QMetaObject *MetaObjectBuilder::update()
{
- int index = *prtIndex;
- int paramsIndex = index + methods.count() * 5;
-
- QList<MethodData>::const_iterator it = methods.begin();
-
- if (m_emptyMethod == -1)
- m_emptyMethod = registerString(EMPTY_META_METHOD, strings);
-
- for (; it != methods.end(); ++it) {
- int name_idx = 0;
- int argc = it->parameterCount();
- if (it->signature() != EMPTY_META_METHOD)
- name_idx = registerString(it->name(), strings);
- else
- name_idx = m_emptyMethod; // func name
-
- (*data)[index++] = name_idx;
- (*data)[index++] = argc; // argc (previously: arg name)
- (*data)[index++] = paramsIndex; //parameter index
- (*data)[index++] = nullIndex; // tags
- (*data)[index++] = flags | (it->methodType() == QMetaMethod::Signal ? MethodSignal : MethodSlot);
-
- if (it->methodType() == QMetaMethod::Signal)
- (*data)[13] += 1; //signal count
-
- paramsIndex += 1 + argc * 2;
- }
- *prtIndex = index;
+ return m_d->update();
}
-void DynamicQMetaObject::parsePythonType(PyTypeObject *type)
+void MetaObjectBuilderPrivate::parsePythonType(PyTypeObject *type)
{
// Get all non-QObject-derived base types in method resolution order, filtering out the types
// that can't have signals, slots or properties.
@@ -609,8 +459,8 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type)
if (data->signatures[i])
sig += data->signatures[i];
sig += ')';
- if (d.superdata->indexOfSignal(sig) == -1)
- addSignal(sig, "void");
+ if (m_baseObject->indexOfSignal(sig) == -1)
+ m_builder->addSignal(sig);
}
}
}
@@ -634,7 +484,7 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type)
if (Property::checkType(value)) {
// Leave the properties to be registered after signals because they may depend on
// notify signals.
- int index = d.superdata->indexOfProperty(Shiboken::String::toCString(key));
+ int index = m_baseObject->indexOfProperty(Shiboken::String::toCString(key));
if (index == -1)
properties << PropPair(Shiboken::String::toCString(key), value);
} else if (PyFunction_Check(value)) {
@@ -642,13 +492,23 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type)
if (PyObject_HasAttr(value, slotAttrName)) {
PyObject *signatureList = PyObject_GetAttr(value, slotAttrName);
for (Py_ssize_t i = 0, i_max = PyList_Size(signatureList); i < i_max; ++i) {
- PyObject *signature = PyList_GET_ITEM(signatureList, i);
- QByteArray sig(Shiboken::String::toCString(signature));
+ PyObject *pySignature = PyList_GET_ITEM(signatureList, i);
+ QByteArray signature(Shiboken::String::toCString(pySignature));
// Split the slot type and its signature.
- QList<QByteArray> slotInfo = sig.split(' ');
- int index = d.superdata->indexOfSlot(slotInfo[1]);
- if (index == -1)
- addSlot(slotInfo[1], slotInfo[0]);
+ QByteArray type;
+ const int spacePos = signature.indexOf(' ');
+ if (spacePos != -1) {
+ type = signature.left(spacePos);
+ signature.remove(0, spacePos + 1);
+ }
+ int index = m_baseObject->indexOfSlot(signature);
+ if (index == -1) {
+ if (type.isEmpty() || type == "void") {
+ addSlot(signature);
+ } else {
+ addSlot(signature, type);
+ }
+ }
}
}
}
@@ -659,219 +519,3 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type)
addProperty(propPair.first, propPair.second);
}
}
-
-/*!
- Allocate the meta data table.
- Returns the index in the table corresponding to the header fields count.
-*/
-int DynamicQMetaObject::DynamicQMetaObjectPrivate::createMetaData(QMetaObject* metaObj)
-{
- const int n_methods = m_methods.size();
- const int n_properties = m_properties.size();
- const int n_info = m_info.size();
-
- int header[] = {7, // revision (Used by moc, qmetaobjectbuilder and qdbus)
- 0, // class name index in m_metadata
- n_info, 0, // classinfo and classinfo index
- n_methods, 0, // method count and method list index
- n_properties, 0, // prop count and prop indexes
- 0, 0, // enum count and enum index
- 0, 0, // constructors (since revision 2)
- 0, // flags (since revision 3)
- 0}; // signal count (since revision 4)
-
- const int HEADER_LENGHT = sizeof(header)/sizeof(int);
-
- m_dataSize = HEADER_LENGHT;
- m_dataSize += n_info*2; //class info: name, value
- m_dataSize += n_methods*5; //method: name, argc, parameters, tag, flags
- m_dataSize += n_properties*4; //property: name, type, flags
- m_dataSize += 1; //eod
-
- m_dataSize += aggregateParameterCount(m_methods); // types and parameter names
-
- uint* data = reinterpret_cast<uint*>(realloc(const_cast<uint*>(metaObj->d.data), m_dataSize * sizeof(uint)));
-
- Q_ASSERT(data);
- std::memcpy(data, header, sizeof(header));
-
- metaObj->d.data = data;
-
- return HEADER_LENGHT;
-}
-
-// Writes strings to string data struct.
-// The struct consists of an array of QByteArrayData, followed by a char array
-// containing the actual strings. This format must match the one produced by
-// moc (see generator.cpp).
-void DynamicQMetaObject::DynamicQMetaObjectPrivate::writeStringData(char *out,
- const QByteArrayList& strings) const
-{
- Q_ASSERT(!(reinterpret_cast<quintptr>(out) & (Q_ALIGNOF(QByteArrayData)-1)));
-
- const int size = strings.size();
- const int offsetOfStringdataMember = size * int(sizeof(QByteArrayData));
- int stringdataOffset = 0;
- for (int i = 0; i < size; ++i)
- writeString(out, i, strings.at(i), offsetOfStringdataMember, stringdataOffset);
-}
-
-QList<MethodData>::iterator is_sorted_until(QList<MethodData>::iterator first,
- QList<MethodData>::iterator last,
- bool comp(const MethodData &m1, const MethodData &m2))
-{
- if (first != last) {
- QList<MethodData>::iterator next = first;
- while (++next != last) {
- if (comp(*next, *first))
- return next;
- ++first;
- }
- }
- return last;
-}
-
-bool is_sorted(QList<MethodData>::iterator first, QList<MethodData>::iterator last,
- bool comp(const MethodData &m1, const MethodData &m2))
-{
- return is_sorted_until(first, last, comp) == last;
-}
-
-void DynamicQMetaObject::DynamicQMetaObjectPrivate::updateMetaObject(QMetaObject* metaObj)
-{
- Q_ASSERT(!m_updated);
- m_dataSize = 0;
-
- // Recompute the size and reallocate memory
- // index is set after the last header field.
- int index = createMetaData(metaObj);
- uint *data = const_cast<uint*>(metaObj->d.data);
-
- QByteArrayList strings;
- strings.append(m_className); // register class string
- m_nullIndex = registerString(QByteArrayLiteral(""), strings); // register a null string
-
- // Write class info.
- if (!m_info.isEmpty()) {
- if (data[3] == 0)
- data[3] = index;
-
- QMap<QByteArray, QByteArray>::const_iterator i = m_info.constBegin(); //TODO: info is a hash this can fail
- while (i != m_info.constEnd()) {
- int valueIndex = registerString(i.value(), strings);
- int keyIndex = registerString(i.key(), strings);
- data[index++] = keyIndex;
- data[index++] = valueIndex;
- i++;
- }
- }
-
- // Write methods first, then properties, to be consistent with moc.
- // Write signals/slots (signals must be written first, see indexOfMethodRelative in
- // qmetaobject.cpp).
-
- QList<MethodData>::iterator it;
- // PYSIDE-315: Instead of sorting the items and maybe breaking indices,
- // we ensure that the signals and slots are sorted by the improved parsePythonType().
- // The order can only become distorted if the class is modified after creation.
- // In that case, we give a warning.
- if (!is_sorted(m_methods.begin(), m_methods.end(), sortMethodSignalSlot)) {
- const char *metaObjectName = this->m_className.data();
- PyObject *txt = PyBytes_FromFormat("\n\n*** Sort Warning ***\n"
- "Signals and slots in QMetaObject '%s' are not ordered correctly, "
- "this may lead to issues.\n", metaObjectName);
- it = m_methods.begin();
- QList<MethodData>::iterator end = m_methods.end();
- QList<MethodData>::iterator until = is_sorted_until(m_methods.begin(), m_methods.end(),
- sortMethodSignalSlot);
- for (; it != end; ++it) {
- PyObject *atxt = PyBytes_FromFormat("%d%s %s %s\n", it - m_methods.begin() + 1,
- until >= it + 1 ? " " : "!",
- it->methodType() == QMetaMethod::Signal ? "Signal" : "Slot ",
- it->signature().data() );
- PyBytes_ConcatAndDel(&txt, atxt);
- }
- PyErr_WarnEx(PyExc_RuntimeWarning, PyBytes_AsString(txt), 0);
- Py_DECREF(txt);
- // Prevent a warning from being turned into an error. We cannot easily unwind.
- PyErr_Clear();
- }
-
- if (!m_methods.empty()) {
- if (data[5] == 0)
- data[5] = index;
-
- writeMethodsData(m_methods, &data, strings, &index, m_nullIndex, AccessPublic);
- }
-
- // Write signal/slots parameters.
- if (!m_methods.empty()) {
- for (it = m_methods.begin(); it != m_methods.end(); ++it) {
- QList<QByteArray> paramTypeNames = it->parameterTypes();
- int paramCount = paramTypeNames.size();
- for (int i = -1; i < paramCount; ++i) {
- const QByteArray &typeName = (i < 0) ? it->returnType() : paramTypeNames.at(i);
- int typeInfo;
- if (QtPrivate::isBuiltinType(typeName))
- typeInfo = QMetaType::type(typeName);
- else
- typeInfo = IsUnresolvedType | registerString(typeName, strings);
- data[index++] = typeInfo;
- }
-
- // Parameter names (use a null string)
- for (int i = 0; i < paramCount; ++i) {
- data[index++] = m_nullIndex;
- }
- }
- }
-
- // Write properties.
- if (m_properties.size()) {
- if (data[7] == 0)
- data[7] = index;
-
- QList<PropertyData>::const_iterator i = m_properties.constBegin();
- while (i != m_properties.constEnd()) {
- if (i->isValid()) {
- data[index++] = registerString(i->name(), strings); // name
- } else
- data[index++] = m_nullIndex;
-
- // Find out the property type index.
- int typeInfo = m_nullIndex;
- if (i->isValid()) {
- const QByteArray &typeName = i->type();
- if (QtPrivate::isBuiltinType(typeName))
- typeInfo = QMetaType::type(typeName);
- else
- typeInfo = IsUnresolvedType | registerString(typeName, strings);
- }
- data[index++] = typeInfo; // normalized type
-
- data[index++] = i->flags();
- i++;
- }
-
- // Write properties notify.
- i = m_properties.constBegin();
- while (i != m_properties.constEnd()) {
- // Recompute notifyId, because sorting the methods might have changed the relative
- // index.
- const int notifyId = getPropertyNotifyId(i->data());
- data[index++] = notifyId >= 0 ? static_cast<uint>(notifyId) : 0; //signal notify index
- i++;
- }
- }
-
- data[index++] = 0; // the end
-
- // Create the m_metadata string.
- int size = blobSize(strings);
- char *blob =
- reinterpret_cast<char *>(realloc(reinterpret_cast<char *>(const_cast<QByteArrayData *>(metaObj->d.stringdata)), size));
- writeStringData(blob, strings);
-
- metaObj->d.stringdata = reinterpret_cast<const QByteArrayData *>(blob);
- metaObj->d.data = data;
-}
diff --git a/sources/pyside2/libpyside/dynamicqmetaobject.h b/sources/pyside2/libpyside/dynamicqmetaobject.h
index e68c7dd50..1fbe73ea4 100644
--- a/sources/pyside2/libpyside/dynamicqmetaobject.h
+++ b/sources/pyside2/libpyside/dynamicqmetaobject.h
@@ -45,39 +45,37 @@
#include <QtCore/QMetaObject>
#include <QtCore/QMetaMethod>
+class MetaObjectBuilderPrivate;
+
namespace PySide
{
-class DynamicQMetaObject : public QMetaObject
+class MetaObjectBuilder
{
- Q_DISABLE_COPY(DynamicQMetaObject)
+ Q_DISABLE_COPY(MetaObjectBuilder)
public:
- DynamicQMetaObject(const char* className, const QMetaObject* metaObject);
- DynamicQMetaObject(PyTypeObject* type, const QMetaObject* metaobject);
- ~DynamicQMetaObject();
+ MetaObjectBuilder(const char *className, const QMetaObject *metaObject);
+ MetaObjectBuilder(PyTypeObject *type, const QMetaObject *metaObject);
+ ~MetaObjectBuilder();
- int addMethod(QMetaMethod::MethodType mtype, const char* signature, const char* type);
- void removeMethod(QMetaMethod::MethodType mtype, uint index);
- int addSignal(const char* signal, const char* type = 0);
- int addSlot(const char* slot, const char* type = 0);
- int addProperty(const char* property, PyObject* data);
- void addInfo(const char* key, const char* value);
+ int indexOfMethod(QMetaMethod::MethodType mtype, const QByteArray &signature) const;
+ int indexOfProperty(const QByteArray &name) const;
+ int addSlot(const char *signature);
+ int addSlot(const char *signature, const char *type);
+ int addSignal(const char *signature);
+ void removeMethod(QMetaMethod::MethodType mtype, int index);
+ int addProperty(const char *property, PyObject *data);
+ void addInfo(const char *key, const char *value);
void addInfo(const QMap<QByteArray, QByteArray> &info);
- void removeSignal(uint idex);
- void removeSlot(uint index);
- void removeProperty(uint index);
+ void removeProperty(int index);
- const QMetaObject* update() const;
+ const QMetaObject *update();
private:
- class DynamicQMetaObjectPrivate;
- DynamicQMetaObjectPrivate* m_d;
-
- void parsePythonType(PyTypeObject *type);
+ MetaObjectBuilderPrivate *m_d;
};
-
}
#endif
diff --git a/sources/pyside2/libpyside/globalreceiverv2.cpp b/sources/pyside2/libpyside/globalreceiverv2.cpp
index a1a695759..43ce50a75 100644
--- a/sources/pyside2/libpyside/globalreceiverv2.cpp
+++ b/sources/pyside2/libpyside/globalreceiverv2.cpp
@@ -160,10 +160,8 @@ int DynamicSlotDataV2::id(const char* signature) const
int DynamicSlotDataV2::addSlot(const char* signature)
{
int index = id(signature);
- if (index == -1) {
- DynamicQMetaObject *dmo = const_cast<DynamicQMetaObject*>(reinterpret_cast<const DynamicQMetaObject*>(m_parent->metaObject()));
- index = m_signatures[signature] = dmo->addSlot(signature);
- }
+ if (index == -1)
+ index = m_signatures[signature] = m_parent->metaObjectBuilder().addSlot(signature);
return index;
}
@@ -202,7 +200,7 @@ GlobalReceiverV2::GlobalReceiverV2(PyObject *callback, SharedMap map) :
DESTROY_SIGNAL_ID = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
if (DESTROY_SLOT_ID == 0)
- DESTROY_SLOT_ID = m_metaObject.indexOfSlot(RECEIVER_DESTROYED_SLOT_NAME);
+ DESTROY_SLOT_ID = m_metaObject.indexOfMethod(QMetaMethod::Slot, RECEIVER_DESTROYED_SLOT_NAME);
}
@@ -306,7 +304,7 @@ QByteArray GlobalReceiverV2::hash(PyObject* callback)
const QMetaObject* GlobalReceiverV2::metaObject() const
{
- return m_metaObject.update();
+ return const_cast<GlobalReceiverV2 *>(this)->m_metaObject.update();
}
int GlobalReceiverV2::qt_metacall(QMetaObject::Call call, int id, void** args)
diff --git a/sources/pyside2/libpyside/globalreceiverv2.h b/sources/pyside2/libpyside/globalreceiverv2.h
index b12823a84..b92be93a8 100644
--- a/sources/pyside2/libpyside/globalreceiverv2.h
+++ b/sources/pyside2/libpyside/globalreceiverv2.h
@@ -135,8 +135,11 @@ public:
**/
static QByteArray hash(PyObject* callback);
+ const MetaObjectBuilder &metaObjectBuilder() const { return m_metaObject; }
+ MetaObjectBuilder &metaObjectBuilder() { return m_metaObject; }
+
private:
- DynamicQMetaObject m_metaObject;
+ MetaObjectBuilder m_metaObject;
DynamicSlotDataV2 *m_data;
QList<const QObject*> m_refs;
SharedMap m_sharedMap;
diff --git a/sources/pyside2/libpyside/pyside.cpp b/sources/pyside2/libpyside/pyside.cpp
index 856e5b92c..6e4a3efd4 100644
--- a/sources/pyside2/libpyside/pyside.cpp
+++ b/sources/pyside2/libpyside/pyside.cpp
@@ -204,7 +204,7 @@ void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base, std::si
Shiboken::ObjectType::setTypeUserData(type, userData, Shiboken::callCppDestructor<TypeUserData>);
//initialize staticQMetaObject property
- void* metaObjectPtr = &userData->mo;
+ void *metaObjectPtr = const_cast<QMetaObject *>(userData->mo.update());
static SbkConverter* converter = Shiboken::Conversions::getConverter("QMetaObject");
if (!converter)
return;
@@ -229,13 +229,13 @@ TypeUserData *retrieveTypeUserData(PyObject *pyObj)
return retrieveTypeUserData(pyTypeObj);
}
-DynamicQMetaObject *retrieveMetaObject(PyTypeObject *pyTypeObj)
+const QMetaObject *retrieveMetaObject(PyTypeObject *pyTypeObj)
{
TypeUserData *userData = retrieveTypeUserData(pyTypeObj);
- return userData ? &(userData->mo) : nullptr;
+ return userData ? userData->mo.update() : nullptr;
}
-DynamicQMetaObject *retrieveMetaObject(PyObject *pyObj)
+const QMetaObject *retrieveMetaObject(PyObject *pyObj)
{
auto pyTypeObj = PyType_Check(pyObj)
? reinterpret_cast<PyTypeObject *>(pyObj) : Py_TYPE(pyObj);
@@ -268,8 +268,7 @@ void initQObjectSubType(SbkObjectType *type, PyObject *args, PyObject * /* kwds
qWarning("Sub class of QObject not inheriting QObject!? Crash will happen when using %s.", className.constData());
return;
}
- userData->mo.update();
- initDynamicMetaObject(type, &userData->mo, userData->cppObjSize);
+ initDynamicMetaObject(type, userData->mo.update(), userData->cppObjSize);
}
PyObject* getMetaDataFromQObject(QObject* cppSelf, PyObject* self, PyObject* name)
diff --git a/sources/pyside2/libpyside/pyside_p.h b/sources/pyside2/libpyside/pyside_p.h
index 66a37fc7a..1084a40a1 100644
--- a/sources/pyside2/libpyside/pyside_p.h
+++ b/sources/pyside2/libpyside/pyside_p.h
@@ -55,7 +55,7 @@ struct TypeUserData
explicit TypeUserData(PyTypeObject* type, const QMetaObject* metaobject, std::size_t size) :
mo(type, metaobject), cppObjSize(size) {}
- DynamicQMetaObject mo;
+ MetaObjectBuilder mo;
std::size_t cppObjSize;
};
@@ -63,8 +63,8 @@ TypeUserData *retrieveTypeUserData(SbkObjectType *sbkTypeObj);
TypeUserData *retrieveTypeUserData(PyTypeObject *pyTypeObj);
TypeUserData *retrieveTypeUserData(PyObject *pyObj);
// For QML
-PYSIDE_API DynamicQMetaObject *retrieveMetaObject(PyTypeObject *pyTypeObj);
-PYSIDE_API DynamicQMetaObject *retrieveMetaObject(PyObject *pyObj);
+PYSIDE_API const QMetaObject *retrieveMetaObject(PyTypeObject *pyTypeObj);
+PYSIDE_API const QMetaObject *retrieveMetaObject(PyObject *pyObj);
} //namespace PySide
diff --git a/sources/pyside2/libpyside/pysideclassinfo.cpp b/sources/pyside2/libpyside/pysideclassinfo.cpp
index 88b2b89f5..88292024f 100644
--- a/sources/pyside2/libpyside/pysideclassinfo.cpp
+++ b/sources/pyside2/libpyside/pysideclassinfo.cpp
@@ -108,8 +108,9 @@ PyObject *classCall(PyObject *self, PyObject *args, PyObject * /* kw */)
PyTypeObject *klassType = reinterpret_cast<PyTypeObject*>(klass);
if (Shiboken::ObjectType::checkType(klassType)) {
- if (PySide::DynamicQMetaObject *mo = PySide::retrieveMetaObject(klassType)) {
- mo->addInfo(PySide::ClassInfo::getMap(data));
+ if (auto userData = PySide::retrieveTypeUserData(klassType)) {
+ PySide::MetaObjectBuilder &mo = userData->mo;
+ mo.addInfo(PySide::ClassInfo::getMap(data));
pData->m_alreadyWrapped = true;
validClass = true;
}
diff --git a/sources/pyside2/libpyside/signalmanager.cpp b/sources/pyside2/libpyside/signalmanager.cpp
index f505fde5a..8925ffd35 100644
--- a/sources/pyside2/libpyside/signalmanager.cpp
+++ b/sources/pyside2/libpyside/signalmanager.cpp
@@ -90,7 +90,7 @@ namespace {
static void destroyMetaObject(PyObject* obj)
{
void* ptr = PyCapsule_GetPointer(obj, 0);
- PySide::DynamicQMetaObject* meta = reinterpret_cast<PySide::DynamicQMetaObject*>(ptr);
+ auto meta = reinterpret_cast<PySide::MetaObjectBuilder*>(ptr);
SbkObject* wrapper = Shiboken::BindingManager::instance().retrieveWrapper(meta);
if (wrapper)
Shiboken::BindingManager::instance().releaseWrapper(wrapper);
@@ -100,7 +100,7 @@ namespace {
#else
static void destroyMetaObject(void* obj)
{
- PySide::DynamicQMetaObject* meta = reinterpret_cast<PySide::DynamicQMetaObject*>(obj);
+ auto meta = reinterpret_cast<PySide::MetaObjectBuilder*>(obj);
SbkObject* wrapper = Shiboken::BindingManager::instance().retrieveWrapper(meta);
if (wrapper)
Shiboken::BindingManager::instance().releaseWrapper(wrapper);
@@ -549,6 +549,19 @@ bool SignalManager::registerMetaMethod(QObject* source, const char* signature, Q
return (ret != -1);
}
+static MetaObjectBuilder *metaBuilderFromDict(PyObject* dict)
+{
+ if (!dict || !PyDict_Contains(dict, metaObjectAttr))
+ return nullptr;
+
+ PyObject *pyBuilder = PyDict_GetItem(dict, metaObjectAttr);
+#ifdef IS_PY3K
+ return reinterpret_cast<MetaObjectBuilder *>(PyCapsule_GetPointer(pyBuilder, nullptr));
+#else
+ return reinterpret_cast<MetaObjectBuilder *>(PyCObject_AsVoidPtr(pyBuilder));
+#endif
+}
+
int SignalManager::registerMetaMethodGetIndex(QObject* source, const char* signature, QMetaMethod::MethodType type)
{
if (!source) {
@@ -565,13 +578,13 @@ int SignalManager::registerMetaMethodGetIndex(QObject* source, const char* signa
qWarning() << "Invalid Signal signature:" << signature;
return -1;
} else {
- DynamicQMetaObject *dmo = 0;
PyObject *pySelf = reinterpret_cast<PyObject*>(self);
PyObject* dict = self->ob_dict;
+ MetaObjectBuilder *dmo = metaBuilderFromDict(dict);
// Create a instance meta object
- if (!dict || !PyDict_Contains(dict, metaObjectAttr)) {
- dmo = new DynamicQMetaObject(Py_TYPE(pySelf), metaObject);
+ if (!dmo) {
+ dmo = new MetaObjectBuilder(Py_TYPE(pySelf), metaObject);
#ifdef IS_PY3K
PyObject* pyDmo = PyCapsule_New(dmo, 0, destroyMetaObject);
#else
@@ -580,8 +593,6 @@ int SignalManager::registerMetaMethodGetIndex(QObject* source, const char* signa
PyObject_SetAttr(pySelf, metaObjectAttr, pyDmo);
Py_DECREF(pyDmo);
- } else {
- dmo = reinterpret_cast<DynamicQMetaObject*>(const_cast<QMetaObject*>(metaObject));
}
if (type == QMetaMethod::Signal)
@@ -596,24 +607,13 @@ int SignalManager::registerMetaMethodGetIndex(QObject* source, const char* signa
const QMetaObject* SignalManager::retrieveMetaObject(PyObject *self)
{
Shiboken::GilState gil;
- DynamicQMetaObject *mo = 0;
Q_ASSERT(self);
- PyObject* dict = reinterpret_cast<SbkObject*>(self)->ob_dict;
- if (dict && PyDict_Contains(dict, metaObjectAttr)) {
- PyObject *pyMo = PyDict_GetItem(dict, metaObjectAttr);
-
-#ifdef IS_PY3K
- mo = reinterpret_cast<DynamicQMetaObject*>(PyCapsule_GetPointer(pyMo, 0));
-#else
- mo = reinterpret_cast<DynamicQMetaObject*>(PyCObject_AsVoidPtr(pyMo));
-#endif
- } else {
- mo = PySide::retrieveMetaObject(self);
- }
+ MetaObjectBuilder *builder = metaBuilderFromDict(reinterpret_cast<SbkObject*>(self)->ob_dict);
+ if (!builder)
+ builder = &(retrieveTypeUserData(self)->mo);
- mo->update();
- return mo;
+ return builder->update();
}
namespace {