diff options
Diffstat (limited to 'sources/pyside2/libpyside')
28 files changed, 609 insertions, 1338 deletions
diff --git a/sources/pyside2/libpyside/CMakeLists.txt b/sources/pyside2/libpyside/CMakeLists.txt index 3069b1ca2..ec6713b62 100644 --- a/sources/pyside2/libpyside/CMakeLists.txt +++ b/sources/pyside2/libpyside/CMakeLists.txt @@ -17,6 +17,7 @@ if(${Qt5Quick_FOUND}) endif() endif() +set(QML_PRIVATE_API_SUPPORT 0) if(Qt5Qml_FOUND) # Used for registering custom QQuickItem classes defined in Python code. set(QML_SUPPORT 1) @@ -28,7 +29,6 @@ if(Qt5Qml_FOUND) set(QML_PRIVATE_API_SUPPORT 1) set(QML_INCLUDES ${QML_INCLUDES} ${Qt5Qml_PRIVATE_INCLUDE_DIRS}) else() - set(QML_PRIVATE_API_SUPPORT 0) message(WARNING "QML private API include files could not be found, support for catching QML exceptions inside Python code will not work.") endif() else() @@ -40,14 +40,10 @@ endif() qt5_wrap_cpp(DESTROYLISTENER_MOC "destroylistener.h") -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/signalmanager.cpp.in" - "${CMAKE_CURRENT_BINARY_DIR}/signalmanager.cpp" @ONLY) - set(libpyside_SRC dynamicqmetaobject.cpp destroylistener.cpp - ${CMAKE_CURRENT_BINARY_DIR}/signalmanager.cpp - globalreceiver.cpp + signalmanager.cpp globalreceiverv2.cpp pysideclassinfo.cpp pysidemetafunction.cpp @@ -86,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} @@ -107,6 +104,7 @@ endif() if(QML_SUPPORT) target_compile_definitions(pyside2 PUBLIC PYSIDE_QML_SUPPORT=1) endif() +target_compile_definitions(pyside2 PRIVATE PYSIDE_QML_PRIVATE_API_SUPPORT=${QML_PRIVATE_API_SUPPORT}) if(PYSIDE_QT_CONF_PREFIX) set_property(SOURCE pyside.cpp @@ -122,7 +120,6 @@ endif() set(libpyside_HEADERS destroylistener.h dynamicqmetaobject.h - globalreceiver.h pysideclassinfo.h pysidemacros.h signalmanager.h diff --git a/sources/pyside2/libpyside/PySide2Config-spec.cmake.in b/sources/pyside2/libpyside/PySide2Config-spec.cmake.in index 4281ade5b..afb81f5a6 100644 --- a/sources/pyside2/libpyside/PySide2Config-spec.cmake.in +++ b/sources/pyside2/libpyside/PySide2Config-spec.cmake.in @@ -16,3 +16,4 @@ else() endif() SET(PYSIDE_PYTHONPATH "@PYTHON_SITE_PACKAGES@") SET(PYSIDE_TYPESYSTEMS "@CMAKE_INSTALL_PREFIX@/share/PySide2@pyside2_SUFFIX@/typesystems") +SET(PYSIDE_GLUE "@CMAKE_INSTALL_PREFIX@/share/PySide2@pyside2_SUFFIX@/glue") diff --git a/sources/pyside2/libpyside/destroylistener.cpp b/sources/pyside2/libpyside/destroylistener.cpp index 95e53f709..c6dc54713 100644 --- a/sources/pyside2/libpyside/destroylistener.cpp +++ b/sources/pyside2/libpyside/destroylistener.cpp @@ -40,10 +40,7 @@ #include <sbkpython.h> #include "destroylistener.h" -#include <QObject> #include <shiboken.h> -#include <QDebug> -#include <QMutex> PySide::DestroyListener* PySide::DestroyListener::m_instance = 0; diff --git a/sources/pyside2/libpyside/destroylistener.h b/sources/pyside2/libpyside/destroylistener.h index 0a800451a..b1a0597c5 100644 --- a/sources/pyside2/libpyside/destroylistener.h +++ b/sources/pyside2/libpyside/destroylistener.h @@ -40,10 +40,10 @@ #ifndef PYSIDE_DESTROY_LISTENER #define PYSIDE_DESTROY_LISTENER - -#include <QObject> #include "pysidemacros.h" +#include <QtCore/QObject> + namespace PySide { struct DestroyListenerPrivate; @@ -63,7 +63,7 @@ class PYSIDE_API DestroyListener : public QObject static DestroyListener* m_instance; DestroyListenerPrivate* m_d; DestroyListener(QObject *parent); - ~DestroyListener(); + ~DestroyListener() override; }; }//namespace diff --git a/sources/pyside2/libpyside/dynamicqmetaobject.cpp b/sources/pyside2/libpyside/dynamicqmetaobject.cpp index af2f416c6..b664e149b 100644 --- a/sources/pyside2/libpyside/dynamicqmetaobject.cpp +++ b/sources/pyside2/libpyside/dynamicqmetaobject.cpp @@ -45,546 +45,376 @@ #include "pysideproperty_p.h" #include "pysideslot_p.h" -#include <QByteArray> -#include <QString> -#include <QStringList> -#include <QList> -#include <QLinkedList> -#include <QObject> -#include <cstring> -#include <QDebug> -#include <QMetaMethod> #include <shiboken.h> +#include <QtCore/QByteArray> +#include <QtCore/QObject> +#include <QtCore/QStringList> +#include <QtCore/QTextStream> +#include <QtCore/QVector> +#include <private/qmetaobjectbuilder_p.h> -#define EMPTY_META_METHOD "0()" +#include <cstring> +#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; // when the meta data is not update - int m_methodOffset; - int m_propertyOffset; - int m_dataSize; - int m_emptyMethod; - int m_nullIndex; - - DynamicQMetaObjectPrivate() - : m_updated(false), m_methodOffset(0), m_propertyOffset(0), - m_dataSize(0), m_emptyMethod(-1), m_nullIndex(0) {} - - int createMetaData(QMetaObject* metaObj, QLinkedList<QByteArray> &strings); - void updateMetaObject(QMetaObject* metaObj); - void writeMethodsData(const QList<MethodData>& methods, unsigned int** data, QLinkedList<QByteArray>& strings, int* prtIndex, int nullIndex, int flags); - void writeStringData(char *, QLinkedList<QByteArray> &strings); + 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; + + const QMetaObject *m_baseObject = nullptr; + MetaObjects m_cachedMetaObjects; + bool m_dirty = true; +}; -static int registerString(const QByteArray& s, QLinkedList<QByteArray>& strings) +QMetaObjectBuilder *MetaObjectBuilderPrivate::ensureBuilder() { - int idx = 0; - QLinkedList<QByteArray>::const_iterator it = strings.begin(); - QLinkedList<QByteArray>::const_iterator itEnd = strings.end(); - while (it != itEnd) { - if (strcmp(*it, s) == 0) - return idx; - ++idx; - ++it; + if (!m_builder) { + m_builder = new QMetaObjectBuilder(); + m_builder->setClassName(m_baseObject->className()); + m_builder->setSuperClass(m_baseObject); } - strings.append(s); - return idx; + return m_builder; } -static int blobSize(QLinkedList<QByteArray> &strings) +MetaObjectBuilder::MetaObjectBuilder(const char *className, const QMetaObject *metaObject) : + m_d(new MetaObjectBuilderPrivate) { - int size = strings.size() * sizeof(QByteArrayData); - - QByteArray str; - QByteArray debug_str; - foreach (const QByteArray &field, strings) { - str.append(field); - str.append(char(0)); - - debug_str.append(field); - debug_str.append('|'); - } - //qDebug()<<debug_str; - size += str.size(); - return size; + 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); } -static int aggregateParameterCount(const QList<MethodData> &methods) +MetaObjectBuilder::MetaObjectBuilder(PyTypeObject *type, const QMetaObject *metaObject) + : m_d(new MetaObjectBuilderPrivate) { - int sum = 0; - for (int i = 0; i < methods.size(); ++i) - sum += methods.at(i).parameterCount() * 2 + 1; // nb_param*2 (type and names) +1 for return type - return sum; + 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); + } } -static void writeString(char *out, int i, const QByteArray &str, - const int offsetOfStringdataMember, int &stringdataOffset) +MetaObjectBuilder::~MetaObjectBuilder() { - 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; + qDeleteAll(m_d->m_cachedMetaObjects); + delete m_d->m_builder; + delete m_d; } -static int qvariant_nameToType(const char* name) +int MetaObjectBuilderPrivate::indexOfMethod(QMetaMethod::MethodType mtype, + const QByteArray &signature) const { - 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; + 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; } -/* - Returns true if the type is a QVariant types. -*/ -static bool isVariantType(const char* type) +int MetaObjectBuilder::indexOfMethod(QMetaMethod::MethodType mtype, + const QByteArray &signature) const { - return qvariant_nameToType(type) != 0; + return m_d->indexOfMethod(mtype, signature); } -/*! - Returns true if the type is qreal. -*/ -static bool isQRealType(const char *type) +int MetaObjectBuilderPrivate::indexOfProperty(const QByteArray &name) const { - return strcmp(type, "qreal") == 0; + if (m_builder) { + const int result = m_builder->indexOfProperty(name); + if (result >= 0) + return m_baseObject->propertyCount() + result; + } + return m_baseObject->indexOfProperty(name); } -uint PropertyData::flags() const +int MetaObjectBuilder::indexOfProperty(const QByteArray &name) 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; + return m_d->indexOfProperty(name); } -// 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) +static bool checkMethodSignature(const QByteArray &signature) { + // 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; } -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::addSlot(const QByteArray &signature) { + if (!checkMethodSignature(signature)) + return -1; + m_dirty = true; + return m_baseObject->methodCount() + + ensureBuilder()->addSlot(signature).index(); } -void MethodData::clear() +int MetaObjectBuilder::addSlot(const char *signature) { - m_signature = m_emptySig; - m_rtype.clear(); + return m_d->addSlot(signature); } -bool MethodData::isValid() const +int MetaObjectBuilderPrivate::addSlot(const QByteArray &signature, + const QByteArray &type) { - 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; + if (!checkMethodSignature(signature)) + return -1; + m_dirty = true; + QMetaMethodBuilder methodBuilder = ensureBuilder()->addSlot(signature); + methodBuilder.setReturnType(type); + return m_baseObject->methodCount() + methodBuilder.index(); } -int MethodData::parameterCount() const +int MetaObjectBuilder::addSlot(const char *signature, const char *type) { - return parameterTypes().size(); + return m_d->addSlot(signature, type); } -QByteArray MethodData::name() const +int MetaObjectBuilderPrivate::addSignal(const QByteArray &signature) { - return m_signature.left(qMax(m_signature.indexOf('('), 0)); + if (!checkMethodSignature(signature)) + return -1; + m_dirty = true; + return m_baseObject->methodCount() + + ensureBuilder()->addSignal(signature).index(); } -PropertyData::PropertyData() - : m_cachedNotifyId(0), m_data(0) +int MetaObjectBuilder::addSignal(const char *signature) { + return m_d->addSignal(signature); } -PropertyData::PropertyData(const char* name, int notifyId, PySideProperty* data) - : m_name(name), m_cachedNotifyId(notifyId), m_data(data) +void MetaObjectBuilderPrivate::removeMethod(QMetaMethod::MethodType mtype, + int index) { + 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; } -QByteArray PropertyData::type() const +void MetaObjectBuilder::removeMethod(QMetaMethod::MethodType mtype, int index) { - return QByteArray(PySide::Property::getTypeName(m_data)); + m_d->removeMethod(mtype, index); } - -bool PropertyData::isValid() const +int MetaObjectBuilderPrivate::getPropertyNotifyId(PySideProperty *property) const { - return !m_name.isEmpty(); + int notifyId = -1; + if (property->d->notify) { + if (const char *signalNotify = PySide::Property::getNotifyName(property)) + notifyId = indexOfMethod(QMetaMethod::Signal, signalNotify); + } + return notifyId; } -int PropertyData::cachedNotifyId() const +int MetaObjectBuilderPrivate::addProperty(const QByteArray &propertyName, + PyObject *data) { - return m_cachedNotifyId; -} + int index = indexOfProperty(propertyName); + if (index != -1) + return index; -bool PropertyData::operator==(const PropertyData& other) const -{ - return m_data == other.m_data; + 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; } -bool PropertyData::operator==(const char* name) const +int MetaObjectBuilder::addProperty(const char *property, PyObject *data) { - return m_name == name; + return m_d->addProperty(property, data); } - -DynamicQMetaObject::DynamicQMetaObject(PyTypeObject* type, const QMetaObject* base) - : m_d(new DynamicQMetaObjectPrivate) +void MetaObjectBuilderPrivate::addInfo(const QByteArray &key, + const QByteArray &value) { - d.superdata = base; - d.stringdata = NULL; - d.data = NULL; - d.extradata = NULL; - d.relatedMetaObjects = NULL; - d.static_metacall = NULL; - - 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); + ensureBuilder()->addClassInfo(key, value); + m_dirty = true; } -DynamicQMetaObject::DynamicQMetaObject(const char* className, const QMetaObject* metaObject) - : m_d(new DynamicQMetaObjectPrivate) +void MetaObjectBuilder::addInfo(const char *key, const char *value) { - 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; + m_d->addInfo(key, value); } -DynamicQMetaObject::~DynamicQMetaObject() +void MetaObjectBuilderPrivate::addInfo(const QMap<QByteArray, QByteArray> &info) { - free(reinterpret_cast<char *>(const_cast<QByteArrayData *>(d.stringdata))); - free(const_cast<uint*>(d.data)); - delete m_d; + 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::addMethod(QMetaMethod::MethodType mtype, const char* signature, const char* type) +void MetaObjectBuilder::addInfo(const QMap<QByteArray, QByteArray> &info) { - 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; - else 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(info); } -void DynamicQMetaObject::removeMethod(QMetaMethod::MethodType mtype, uint index) +void MetaObjectBuilderPrivate::removeProperty(int index) { - 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; - } - } + index -= m_baseObject->propertyCount(); + auto builder = ensureBuilder(); + Q_ASSERT(index >= 0 && index < builder->propertyCount()); + builder->removeProperty(index); + m_dirty = true; } -int DynamicQMetaObject::addSignal(const char* signal, const char* type) +void MetaObjectBuilder::removeProperty(int index) { - return addMethod(QMetaMethod::Signal, signal, type); + m_d->removeProperty(index); } -int DynamicQMetaObject::addSlot(const char* slot, const char* type) -{ - return addMethod(QMetaMethod::Slot, slot, type); -} - -void DynamicQMetaObject::removeSlot(uint index) -{ - removeMethod(QMetaMethod::Slot, 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(QMap<QByteArray, QByteArray> info) +const QMetaObject *MetaObjectBuilderPrivate::update() { - QMap<QByteArray, QByteArray>::const_iterator i = info.constBegin(); - while (i != info.constEnd()) { - m_d->m_info[i.key()] = i.value(); - ++i; + 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; } - m_d->m_updated = false; + return m_cachedMetaObjects.back(); } -const QMetaObject* DynamicQMetaObject::update() const +const QMetaObject *MetaObjectBuilder::update() { - if (!m_d->m_updated) { - m_d->updateMetaObject(const_cast<DynamicQMetaObject*>(this)); - m_d->m_updated = true; - } - return this; + return m_d->update(); } -void DynamicQMetaObject::DynamicQMetaObjectPrivate::writeMethodsData(const QList<MethodData>& methods, - unsigned int** data, - QLinkedList<QByteArray>& strings, - int* prtIndex, - int nullIndex, - int flags) -{ - 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; -} - -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. @@ -594,32 +424,35 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type) const PyObject *mro = type->tp_mro; const Py_ssize_t basesCount = PyTuple_GET_SIZE(mro); PyTypeObject *qObjectType = Shiboken::Conversions::getPythonTypeObject("QObject*"); - QVector<PyTypeObject *> basesToCheck; + + std::vector<PyTypeObject *> basesToCheck; + // Prepend the actual type that we are parsing. + basesToCheck.reserve(1u + basesCount); + basesToCheck.push_back(type); + + auto sbkObjTypeF = reinterpret_cast<PyTypeObject *>(SbkObject_TypeF()); + auto baseObjType = reinterpret_cast<PyTypeObject *>(&PyBaseObject_Type); for (Py_ssize_t i = 0; i < basesCount; ++i) { - PyTypeObject *baseType = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, i)); - if (PyType_IsSubtype(baseType, qObjectType) - || baseType == reinterpret_cast<PyTypeObject *>(SbkObject_TypeF()) - || baseType == reinterpret_cast<PyTypeObject *>(&PyBaseObject_Type)) { - continue; - } else { - basesToCheck.append(baseType); + auto baseType = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, i)); + if (baseType != sbkObjTypeF && baseType != baseObjType + && PyType_IsSubtype(baseType, qObjectType) == 0) { + basesToCheck.push_back(baseType); } } - // Prepend the actual type that we are parsing. - basesToCheck.prepend(type); // PYSIDE-315: Handle all signals first, in all involved types. - for (int baseIndex = 0, baseEnd = basesToCheck.size(); baseIndex < baseEnd; ++baseIndex) { - PyTypeObject *baseType = basesToCheck[baseIndex]; + // Leave the properties to be registered after signals because they may depend on + // notify signals. + for (PyTypeObject *baseType : basesToCheck) { PyObject *attrs = baseType->tp_dict; - PyObject *key = 0; - PyObject *value = 0; + PyObject *key = nullptr; + PyObject *value = nullptr; Py_ssize_t pos = 0; while (PyDict_Next(attrs, &pos, &key, &value)) { if (Signal::checkType(value)) { // Register signals. - PySideSignal *data = reinterpret_cast<PySideSignal *>(value); + auto data = reinterpret_cast<PySideSignal *>(value); const char *signalName = Shiboken::String::toCString(key); data->signalName = strdup(signalName); QByteArray sig; @@ -630,8 +463,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); } } } @@ -641,261 +474,41 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type) // PYSIDE-315: Now take care of the rest. // Signals and slots should be separated, unless the types are modified, later. // We check for this using "is_sorted()". Sorting no longer happens at all. - for (int baseIndex = 0, baseEnd = basesToCheck.size(); baseIndex < baseEnd; ++baseIndex) { - PyTypeObject *baseType = basesToCheck[baseIndex]; + for (PyTypeObject *baseType : basesToCheck) { PyObject *attrs = baseType->tp_dict; - PyObject *key = 0; - PyObject *value = 0; + PyObject *key = nullptr; + PyObject *value = nullptr; Py_ssize_t pos = 0; - typedef std::pair<const char *, PyObject *> PropPair; - QVector<PropPair> properties; - while (PyDict_Next(attrs, &pos, &key, &value)) { 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)); + const int index = m_baseObject->indexOfProperty(Shiboken::String::toCString(key)); if (index == -1) - properties << PropPair(Shiboken::String::toCString(key), value); + addProperty(Shiboken::String::toCString(key), value); } else if (PyFunction_Check(value)) { // Register slots. 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); + } + const int index = m_baseObject->indexOfSlot(signature); + if (index == -1) { + if (type.isEmpty() || type == "void") + addSlot(signature); + else + addSlot(signature, type); + } } } } } - - // Register properties - foreach (const PropPair &propPair, properties) - 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, QLinkedList<QByteArray> &strings) -{ - 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, QLinkedList<QByteArray> &strings) -{ - Q_ASSERT(!(reinterpret_cast<quintptr>(out) & (Q_ALIGNOF(QByteArrayData)-1))); - - int offsetOfStringdataMember = strings.size() * sizeof(QByteArrayData); - int stringdataOffset = 0; - int i = 0; - foreach(const QByteArray& str, strings) { - writeString(out, i, str, offsetOfStringdataMember, stringdataOffset); - i++; - } -} - -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); - uint *data = const_cast<uint*>(metaObj->d.data); - int index = 0; - QLinkedList<QByteArray> strings; - m_dataSize = 0; - - // Recompute the size and reallocate memory - // index is set after the last header field. - index = createMetaData(metaObj, strings); - data = const_cast<uint*>(metaObj->d.data); - - registerString(m_className, strings); // register class string - m_nullIndex = registerString("", strings); // register a null string - - // Write class info. - if (m_info.size()) { - 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.size()) { - if (data[5] == 0) - data[5] = index; - - writeMethodsData(m_methods, &data, strings, &index, m_nullIndex, AccessPublic); - } - - // Write signal/slots parameters. - if (m_methods.size()) { - 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 5ecce50c9..1fbe73ea4 100644 --- a/sources/pyside2/libpyside/dynamicqmetaobject.h +++ b/sources/pyside2/libpyside/dynamicqmetaobject.h @@ -40,43 +40,42 @@ #ifndef DYNAMICQMETAOBJECT_H #define DYNAMICQMETAOBJECT_H -#include "pysidemacros.h" #include <sbkpython.h> -#include <QMetaObject> -#include <QMetaMethod> + +#include <QtCore/QMetaObject> +#include <QtCore/QMetaMethod> + +class MetaObjectBuilderPrivate; namespace PySide { -class DynamicQMetaObject : public QMetaObject +class MetaObjectBuilder { + 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); - void addInfo(QMap<QByteArray, QByteArray> info); + 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/dynamicqmetaobject_p.h b/sources/pyside2/libpyside/dynamicqmetaobject_p.h index 219ffc4e3..738b950ba 100644 --- a/sources/pyside2/libpyside/dynamicqmetaobject_p.h +++ b/sources/pyside2/libpyside/dynamicqmetaobject_p.h @@ -41,8 +41,9 @@ #define DYNAMICMETAPROPERTY_P_H #include <sbkpython.h> -#include <QByteArray> -#include <QMetaMethod> + +#include <QtCore/QByteArray> +#include <QtCore/QMetaMethod> #define GLOBAL_RECEIVER_CLASS_NAME "__GlobalReceiver__" diff --git a/sources/pyside2/libpyside/globalreceiver.cpp b/sources/pyside2/libpyside/globalreceiver.cpp deleted file mode 100644 index ee1f6354a..000000000 --- a/sources/pyside2/libpyside/globalreceiver.cpp +++ /dev/null @@ -1,329 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt for Python. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "globalreceiver.h" -#include "dynamicqmetaobject_p.h" -#include "pysideweakref.h" - -#include <QMetaMethod> -#include <QDebug> -#include <QEvent> -#include <QLinkedList> -#include <autodecref.h> -#include <sbkconverter.h> -#include <gilstate.h> - -#include "signalmanager.h" - -#define RECEIVER_DESTROYED_SLOT_NAME "__receiverDestroyed__(QObject*)" - -namespace PySide -{ -class DynamicSlotData -{ - public: - DynamicSlotData(int id, PyObject* callback, GlobalReceiver* parent); - void addRef(const QObject* o); - void decRef(const QObject* o); - void clear(); - int hasRefTo(const QObject* o) const; - int refCount() const; - int id() const; - PyObject* call(PyObject* args); - ~DynamicSlotData(); - static void onCallbackDestroyed(void* data); - - private: - int m_id; - bool m_isMethod; - PyObject* m_callback; - PyObject* m_pythonSelf; - PyObject* m_pyClass; - PyObject* m_weakRef; - GlobalReceiver* m_parent; - QLinkedList<const QObject*> m_refs; -}; - -} - -using namespace PySide; - -DynamicSlotData::DynamicSlotData(int id, PyObject* callback, GlobalReceiver* parent) - : m_id(id), m_pythonSelf(0), m_pyClass(0), m_weakRef(0), m_parent(parent) -{ - Shiboken::GilState gil; - - m_isMethod = PyMethod_Check(callback); - if (m_isMethod) { - //Can not store calback pointe because this will be destroyed at the end of the scope - //To avoid increment intance reference keep the callback information - m_callback = PyMethod_GET_FUNCTION(callback); -#ifdef IS_PY3K - m_pyClass = 0; -#else - m_pyClass = PyMethod_GET_CLASS(callback); -#endif - - m_pythonSelf = PyMethod_GET_SELF(callback); - - //monitor class from method lifetime - m_weakRef = WeakRef::create(m_pythonSelf, DynamicSlotData::onCallbackDestroyed, this); - } else { - m_callback = callback; - Py_INCREF(m_callback); - } -} - -PyObject* DynamicSlotData::call(PyObject* args) -{ - PyObject* callback = m_callback; - - //create a callback based on method data - Shiboken::GilState gil; - if (m_isMethod) -#ifdef IS_PY3K - callback = PyMethod_New(callback, m_pythonSelf); -#else - callback = PyMethod_New(callback, m_pythonSelf, m_pyClass); -#endif - - PyObject* result = PyObject_CallObject(callback, args); - - if (m_isMethod) - Py_DECREF(callback); - - return result; -} - -void DynamicSlotData::addRef(const QObject *o) -{ - m_refs.append(o); -} - -void DynamicSlotData::decRef(const QObject *o) -{ - m_refs.removeOne(o); -} - -int DynamicSlotData::refCount() const -{ - return m_refs.size(); -} - -int DynamicSlotData::id() const -{ - return m_id; -} - -int DynamicSlotData::hasRefTo(const QObject *o) const -{ - return m_refs.count(o); -} - -void DynamicSlotData::clear() -{ - Shiboken::GilState gil; - Py_XDECREF(m_weakRef); - m_weakRef = 0; - m_refs.clear(); -} - -DynamicSlotData::~DynamicSlotData() -{ - Shiboken::GilState gil; - clear(); - if (!m_isMethod) - Py_DECREF(m_callback); -} - -void DynamicSlotData::onCallbackDestroyed(void *data) -{ - Shiboken::GilState gil; - DynamicSlotData* self = reinterpret_cast<DynamicSlotData*>(data); - - //Disconnect all sources - QMetaMethod m = self->m_parent->metaObject()->method(self->m_id); - QByteArray methodName = QByteArray::number(m.methodType()).append(m.methodSignature()); - QLinkedList<const QObject*> sources = self->m_refs; - foreach(const QObject* src, sources) - const_cast<QObject*>(src)->disconnect(self->m_parent, methodName); - self->m_weakRef = 0; -} - -GlobalReceiver::GlobalReceiver() - : m_metaObject(GLOBAL_RECEIVER_CLASS_NAME, &QObject::staticMetaObject) -{ - //slot used to be notifyed of object destrouction - m_metaObject.addSlot(RECEIVER_DESTROYED_SLOT_NAME); - m_metaObject.update(); - setObjectName(QLatin1String("GLOBAL RECEIVER")); -} - -GlobalReceiver::~GlobalReceiver() -{ - while(!m_slotReceivers.empty()) { - DynamicSlotData* data = m_slotReceivers.take(m_slotReceivers.begin().key()); - data->clear(); - delete data; - } -} - -void GlobalReceiver::connectNotify(QObject* source, int slotId) -{ - if (m_slotReceivers.contains(slotId)) { - DynamicSlotData* data = m_slotReceivers[slotId]; - if (!data->hasRefTo(source)) - QObject::connect(source, SIGNAL(destroyed(QObject*)), this, "1" RECEIVER_DESTROYED_SLOT_NAME); - data->addRef(source); - } -} - -void GlobalReceiver::disconnectNotify(QObject* source, int slotId) -{ - if (m_slotReceivers.contains(slotId)) { - DynamicSlotData *data = m_slotReceivers[slotId]; - data->decRef(source); - if (data->refCount() == 0) - removeSlot(slotId); - - if (!hasConnectionWith(source)) - QObject::disconnect(source, SIGNAL(destroyed(QObject*)), this, "1" RECEIVER_DESTROYED_SLOT_NAME); - } -} - -const QMetaObject* GlobalReceiver::metaObject() const -{ - return m_metaObject.update(); -} - -int GlobalReceiver::addSlot(const char* slot, PyObject* callback) -{ - int slotId = m_metaObject.addSlot(slot); - if (!m_slotReceivers.contains(slotId)) - m_slotReceivers[slotId] = new DynamicSlotData(slotId, callback, this); - - bool isShortCircuit = true; - for (int i = 0; slot[i]; ++i) { - if (slot[i] == '(') { - isShortCircuit = false; - break; - } - } - - if (isShortCircuit) - m_shortCircuitSlots << slotId; - - Q_ASSERT(slotId >= QObject::staticMetaObject.methodCount()); - return slotId; -} - -void GlobalReceiver::removeSlot(int slotId) -{ - if (m_slotReceivers.contains(slotId)) { - delete m_slotReceivers.take(slotId); - m_metaObject.removeSlot(slotId); - m_shortCircuitSlots.remove(slotId); - } -} - -bool GlobalReceiver::hasConnectionWith(const QObject *object) -{ - QHash<int, DynamicSlotData*>::iterator i = m_slotReceivers.begin(); - while(i != m_slotReceivers.end()) { - if (i.value()->hasRefTo(object)) { - return true; - } - i++; - } - return false; -} - -int GlobalReceiver::qt_metacall(QMetaObject::Call call, int id, void** args) -{ - Q_ASSERT(call == QMetaObject::InvokeMetaMethod); - Q_ASSERT(id >= QObject::staticMetaObject.methodCount()); - QMetaMethod slot = metaObject()->method(id); - Q_ASSERT(slot.methodType() == QMetaMethod::Slot); - - if (strcmp(slot.methodSignature(), RECEIVER_DESTROYED_SLOT_NAME) == 0) { - QObject *arg = *(QObject**)args[1]; - - //avoid hash changes during the destruction - QHash<int, DynamicSlotData*> copy = m_slotReceivers; - QHash<int, DynamicSlotData*>::iterator i = copy.begin(); - while(i != copy.end()) { - //Remove all refs - int refs = i.value()->hasRefTo(arg); - while(refs) { - disconnectNotify(arg, i.key()); - refs--; - } - i++; - } - return -1; - } - - DynamicSlotData* data = m_slotReceivers.value(id); - if (!data) { - qWarning() << "Unknown global slot, id:" << id; - return -1; - } - - Shiboken::GilState gil; - PyObject* retval = 0; - if (m_shortCircuitSlots.contains(id)) { - retval = data->call(reinterpret_cast<PyObject*>(args[1])); - } else { - QList<QByteArray> paramTypes = slot.parameterTypes(); - Shiboken::AutoDecRef preparedArgs(PyTuple_New(paramTypes.count())); - for (int i = 0, max = paramTypes.count(); i < max; ++i) { - const QByteArray& paramType = paramTypes[i]; - Shiboken::Conversions::SpecificConverter converter(paramType.constData()); - PyTuple_SET_ITEM(preparedArgs.object(), i, converter.toPython(args[i+1])); - } - retval = data->call(preparedArgs); - } - - if (!retval) - PyErr_Print(); - else - Py_DECREF(retval); - - return -1; -} diff --git a/sources/pyside2/libpyside/globalreceiverv2.cpp b/sources/pyside2/libpyside/globalreceiverv2.cpp index 05565e516..43ce50a75 100644 --- a/sources/pyside2/libpyside/globalreceiverv2.cpp +++ b/sources/pyside2/libpyside/globalreceiverv2.cpp @@ -40,15 +40,13 @@ #include "globalreceiverv2.h" #include "dynamicqmetaobject_p.h" #include "pysideweakref.h" +#include "signalmanager.h" -#include <QMetaMethod> -#include <QDebug> -#include <QEvent> -#include <QLinkedList> #include <autodecref.h> #include <gilstate.h> -#include "signalmanager.h" +#include <QtCore/QMetaMethod> +#include <QtCore/QSet> #define RECEIVER_DESTROYED_SLOT_NAME "__receiverDestroyed__(QObject*)" @@ -62,6 +60,7 @@ namespace PySide { class DynamicSlotDataV2 { + Q_DISABLE_COPY(DynamicSlotDataV2) public: DynamicSlotDataV2(PyObject* callback, GlobalReceiverV2* parent); ~DynamicSlotDataV2(); @@ -128,11 +127,11 @@ QByteArray DynamicSlotDataV2::hash() const QByteArray DynamicSlotDataV2::hash(PyObject* callback) { Shiboken::GilState gil; - if (PyMethod_Check(callback)) + if (PyMethod_Check(callback)) { return QByteArray::number((qlonglong)PyObject_Hash(PyMethod_GET_FUNCTION(callback))) + QByteArray::number((qlonglong)PyObject_Hash(PyMethod_GET_SELF(callback))); - else - return QByteArray::number((qlonglong)PyObject_Hash(callback)); + } + return QByteArray::number(qlonglong(PyObject_Hash(callback))); } PyObject* DynamicSlotDataV2::callback() @@ -154,18 +153,15 @@ PyObject* DynamicSlotDataV2::callback() int DynamicSlotDataV2::id(const char* signature) const { - if (m_signatures.contains(signature)) - return m_signatures[signature]; - return -1; + const auto it = m_signatures.constFind(signature); + return it != m_signatures.cend() ? it.value() : -1; } 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; } @@ -189,8 +185,10 @@ DynamicSlotDataV2::~DynamicSlotDataV2() Py_DECREF(m_callback); } -GlobalReceiverV2::GlobalReceiverV2(PyObject *callback, SharedMap map) - : QObject(0), m_metaObject(GLOBAL_RECEIVER_CLASS_NAME, &QObject::staticMetaObject), m_sharedMap(map) +GlobalReceiverV2::GlobalReceiverV2(PyObject *callback, SharedMap map) : + QObject(nullptr), + m_metaObject(GLOBAL_RECEIVER_CLASS_NAME, &QObject::staticMetaObject), + m_sharedMap(std::move(map)) { m_data = new DynamicSlotDataV2(callback, this); m_metaObject.addSlot(RECEIVER_DESTROYED_SLOT_NAME); @@ -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); } @@ -251,7 +249,7 @@ void GlobalReceiverV2::incRef(const QObject* link) void GlobalReceiverV2::decRef(const QObject* link) { - if (m_refs.size() <= 0) + if (m_refs.empty()) return; @@ -268,7 +266,7 @@ void GlobalReceiverV2::decRef(const QObject* link) } } - if (m_refs.size() == 0) + if (m_refs.empty()) Py_BEGIN_ALLOW_THREADS delete this; Py_END_ALLOW_THREADS @@ -285,9 +283,9 @@ int GlobalReceiverV2::refCount(const QObject* link) const void GlobalReceiverV2::notify() { - QSet<const QObject*> objs = QSet<const QObject*>::fromList(m_refs); + const auto objSet = QSet<const QObject*>::fromList(m_refs); Py_BEGIN_ALLOW_THREADS - foreach(const QObject* o, objs) { + for (const QObject *o : objSet) { QMetaObject::disconnect(o, DESTROY_SIGNAL_ID, this, DESTROY_SLOT_ID); QMetaObject::connect(o, DESTROY_SIGNAL_ID, this, DESTROY_SLOT_ID); } @@ -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) @@ -328,9 +326,9 @@ int GlobalReceiverV2::qt_metacall(QMetaObject::Call call, int id, void** args) } if (id == DESTROY_SLOT_ID) { - if (m_refs.size() == 0) + if (m_refs.empty()) return -1; - QObject *obj = *(QObject**)args[1]; + QObject *obj = *reinterpret_cast<QObject**>(args[1]); incRef(); //keep the object live (safe ref) m_refs.removeAll(obj); // remove all refs to this object decRef(); //remove the safe ref diff --git a/sources/pyside2/libpyside/globalreceiverv2.h b/sources/pyside2/libpyside/globalreceiverv2.h index 880719d6f..b92be93a8 100644 --- a/sources/pyside2/libpyside/globalreceiverv2.h +++ b/sources/pyside2/libpyside/globalreceiverv2.h @@ -41,15 +41,14 @@ #define GLOBALRECEIVER_V2_H #include <sbkpython.h> -#include <QObject> -#include <QHash> -#include <QSet> -#include <QSharedPointer> -#include <QLinkedList> -#include <QByteArray> #include "dynamicqmetaobject.h" +#include <QtCore/QByteArray> +#include <QtCore/QObject> +#include <QtCore/QMap> +#include <QtCore/QSharedPointer> + namespace PySide { @@ -78,13 +77,13 @@ public: /** * Destructor **/ - ~GlobalReceiverV2(); + ~GlobalReceiverV2() override; /** * Reimplemented function from QObject **/ - int qt_metacall(QMetaObject::Call call, int id, void** args); - const QMetaObject* metaObject() const; + int qt_metacall(QMetaObject::Call call, int id, void** args) override; + const QMetaObject* metaObject() const override; /** * Add a extra slot to this object @@ -122,22 +121,25 @@ public: int refCount(const QObject* link) const; /** - * Use to retrive the unique hash of this GlobalReceiver object + * Use to retrieve the unique hash of this GlobalReceiver object * * @return a string with a unique id based on GlobalReceiver contents **/ QByteArray hash() const; /** - * Use to retrive the unique hash of the PyObject based on GlobalReceiver rules + * Use to retrieve the unique hash of the PyObject based on GlobalReceiver rules * * @param callback The Python callable object used to calculate the id * @return a string with a unique id based on GlobalReceiver contents **/ 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 b4f7d8771..6e4a3efd4 100644 --- a/sources/pyside2/libpyside/pyside.cpp +++ b/sources/pyside2/libpyside/pyside.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "pyside.h" +#include "pyside_p.h" #include "signalmanager.h" #include "pysideclassinfo_p.h" #include "pysideproperty_p.h" @@ -51,23 +52,24 @@ #include "destroylistener.h" #include <autodecref.h> -#include <qapp_macro.h> #include <basewrapper.h> +#include <bindingmanager.h> +#include <gilstate.h> #include <sbkconverter.h> #include <sbkstring.h> -#include <gilstate.h> -#include <bindingmanager.h> +#include <qapp_macro.h> + +#include <QtCore/QByteArray> +#include <QtCore/QCoreApplication> +#include <QtCore/QDir> +#include <QtCore/QFileInfo> +#include <QtCore/QSharedPointer> +#include <QtCore/QStack> + #include <algorithm> -#include <typeinfo> #include <cstring> #include <cctype> -#include <QByteArray> -#include <QCoreApplication> -#include <QDebug> -#include <QDir> -#include <QFileInfo> -#include <QSharedPointer> -#include <QStack> +#include <typeinfo> static QStack<PySide::CleanupFunction> cleanupFunctionList; static void* qobjectNextAddr; @@ -188,29 +190,21 @@ void destroyQCoreApplication() MakeSingletonQAppWrapper(NULL); } -struct TypeUserData { - TypeUserData(PyTypeObject* type, const QMetaObject* metaobject) : mo(type, metaobject) {} - DynamicQMetaObject mo; - std::size_t cppObjSize; -}; - std::size_t getSizeOfQObject(SbkObjectType* type) { - using namespace Shiboken::ObjectType; - TypeUserData* userData = reinterpret_cast<TypeUserData*>(getTypeUserData(reinterpret_cast<SbkObjectType*>(type))); - return userData->cppObjSize; + return retrieveTypeUserData(type)->cppObjSize; } -void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base, const std::size_t& cppObjSize) +void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base, std::size_t cppObjSize) { //create DynamicMetaObject based on python type - TypeUserData* userData = new TypeUserData(reinterpret_cast<PyTypeObject*>(type), base); - userData->cppObjSize = cppObjSize; + auto userData = + new TypeUserData(reinterpret_cast<PyTypeObject*>(type), base, cppObjSize); userData->mo.update(); 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; @@ -218,6 +212,36 @@ void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base, const s PyObject_SetAttrString(reinterpret_cast<PyObject*>(type), "staticMetaObject", pyMetaObject); } +TypeUserData *retrieveTypeUserData(SbkObjectType *sbkTypeObj) +{ + return reinterpret_cast<TypeUserData *>(Shiboken::ObjectType::getTypeUserData(sbkTypeObj)); +} + +TypeUserData *retrieveTypeUserData(PyTypeObject *pyTypeObj) +{ + return retrieveTypeUserData(reinterpret_cast<SbkObjectType *>(pyTypeObj)); +} + +TypeUserData *retrieveTypeUserData(PyObject *pyObj) +{ + auto pyTypeObj = PyType_Check(pyObj) + ? reinterpret_cast<PyTypeObject *>(pyObj) : Py_TYPE(pyObj); + return retrieveTypeUserData(pyTypeObj); +} + +const QMetaObject *retrieveMetaObject(PyTypeObject *pyTypeObj) +{ + TypeUserData *userData = retrieveTypeUserData(pyTypeObj); + return userData ? userData->mo.update() : nullptr; +} + +const QMetaObject *retrieveMetaObject(PyObject *pyObj) +{ + auto pyTypeObj = PyType_Check(pyObj) + ? reinterpret_cast<PyTypeObject *>(pyObj) : Py_TYPE(pyObj); + return retrieveMetaObject(pyTypeObj); +} + void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base) { initDynamicMetaObject(type, base, 0); @@ -230,25 +254,21 @@ void initQObjectSubType(SbkObjectType *type, PyObject *args, PyObject * /* kwds PyObject* bases = PyTuple_GET_ITEM(args, 1); int numBases = PyTuple_GET_SIZE(bases); - QMetaObject* baseMo = 0; - SbkObjectType* qobjBase = 0; + + TypeUserData *userData = nullptr; for (int i = 0; i < numBases; ++i) { PyTypeObject* base = reinterpret_cast<PyTypeObject*>(PyTuple_GET_ITEM(bases, i)); if (PyType_IsSubtype(base, qObjType)) { - baseMo = reinterpret_cast<QMetaObject*>(Shiboken::ObjectType::getTypeUserData(reinterpret_cast<SbkObjectType*>(base))); - qobjBase = reinterpret_cast<SbkObjectType*>(base); - reinterpret_cast<DynamicQMetaObject*>(baseMo)->update(); + userData = retrieveTypeUserData(base); break; } } - if (!baseMo) { + if (!userData) { qWarning("Sub class of QObject not inheriting QObject!? Crash will happen when using %s.", className.constData()); return; } - - TypeUserData* userData = reinterpret_cast<TypeUserData*>(Shiboken::ObjectType::getTypeUserData(qobjBase)); - initDynamicMetaObject(type, baseMo, userData->cppObjSize); + initDynamicMetaObject(type, userData->mo.update(), userData->cppObjSize); } PyObject* getMetaDataFromQObject(QObject* cppSelf, PyObject* self, PyObject* name) @@ -299,7 +319,7 @@ PyObject* getMetaDataFromQObject(QObject* cppSelf, PyObject* self, PyObject* nam } } } - if (signalList.size() > 0) { + if (!signalList.empty()) { PyObject* pySignal = reinterpret_cast<PyObject*>(Signal::newObjectFromMethod(self, signalList)); PyObject_SetAttr(self, name, pySignal); return pySignal; @@ -366,7 +386,7 @@ PyObject* getWrapperForQObject(QObject* cppSelf, SbkObjectType* sbk_type) // set and check if it's created after the set call QVariant existing = cppSelf->property(invalidatePropertyName); if (!existing.isValid()) { - QSharedPointer<any_t> shared_with_del((any_t*)cppSelf, invalidatePtr); + QSharedPointer<any_t> shared_with_del(reinterpret_cast<any_t*>(cppSelf), invalidatePtr); cppSelf->setProperty(invalidatePropertyName, QVariant::fromValue(shared_with_del)); pyOut = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper(cppSelf)); if (pyOut) { diff --git a/sources/pyside2/libpyside/pyside.h b/sources/pyside2/libpyside/pyside.h index e2e108ed8..b53048eba 100644 --- a/sources/pyside2/libpyside/pyside.h +++ b/sources/pyside2/libpyside/pyside.h @@ -41,16 +41,15 @@ #define PYSIDE_H #include <sbkpython.h> + #include <pysidemacros.h> #ifdef PYSIDE_QML_SUPPORT -# include <qqml.h> +# include <QtQml/qqml.h> #endif -#include <QMetaType> -#include <QHash> -#include <QList> -#include <QLoggingCategory> +#include <QtCore/QMetaType> +#include <QtCore/QHash> struct SbkObjectType; @@ -101,7 +100,8 @@ struct initQtMetaType<T, false> { }; PYSIDE_DEPRECATED(PYSIDE_API void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base)); -PYSIDE_API void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base, const std::size_t& cppObjSize); +PYSIDE_API void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base, + std::size_t cppObjSize); PYSIDE_API void initQObjectSubType(SbkObjectType* type, PyObject* args, PyObject* kwds); /// Return the size in bytes of a type that inherits QObject. diff --git a/sources/pyside2/libpyside/pyside2.pc.in b/sources/pyside2/libpyside/pyside2.pc.in index 37a115989..ecbe0bbc8 100644 --- a/sources/pyside2/libpyside/pyside2.pc.in +++ b/sources/pyside2/libpyside/pyside2.pc.in @@ -3,6 +3,7 @@ exec_prefix=@CMAKE_INSTALL_PREFIX@ libdir=@LIB_INSTALL_DIR@ includedir=@CMAKE_INSTALL_PREFIX@/include/PySide2@pyside2_SUFFIX@ typesystemdir=@CMAKE_INSTALL_PREFIX@/share/PySide2@pyside2_SUFFIX@/typesystems +gluedir=@CMAKE_INSTALL_PREFIX@/share/PySide2@pyside2_SUFFIX@/glue pythonpath=@PYTHON_SITE_PACKAGES@ Name: PySide2@pyside2_SUFFIX@ diff --git a/sources/pyside2/libpyside/globalreceiver.h b/sources/pyside2/libpyside/pyside_p.h index 426d40bfe..1084a40a1 100644 --- a/sources/pyside2/libpyside/globalreceiver.h +++ b/sources/pyside2/libpyside/pyside_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt for Python. @@ -37,44 +37,35 @@ ** ****************************************************************************/ -#ifndef GLOBALRECEIVER_H -#define GLOBALRECEIVER_H +#ifndef PYSIDE_P_H +#define PYSIDE_P_H -#include <sbkpython.h> -#include <QObject> -#include <QHash> -#include <QSet> -#include "dynamicqmetaobject.h" +#include <pysidemacros.h> -namespace PySide -{ +#include <dynamicqmetaobject.h> -class DynamicSlotData; +struct SbkObjectType; -class GlobalReceiver : public QObject +namespace PySide { -public: - GlobalReceiver(); - ~GlobalReceiver(); - int qt_metacall(QMetaObject::Call call, int id, void** args); - const QMetaObject* metaObject() const; - int addSlot(const char* slot, PyObject* callback); - void removeSlot(int slotId); - void connectNotify(QObject* sender, int slotId); - void disconnectNotify(QObject* sender, int slotId); - bool hasConnectionWith(const QObject* object); -protected: - using QObject::connectNotify; - using QObject::disconnectNotify; +// Struct associated with QObject's via Shiboken::Object::getTypeUserData() +struct TypeUserData +{ + explicit TypeUserData(PyTypeObject* type, const QMetaObject* metaobject, std::size_t size) : + mo(type, metaobject), cppObjSize(size) {} -private: - DynamicQMetaObject m_metaObject; - QSet<int> m_shortCircuitSlots; - QHash<int, DynamicSlotData* > m_slotReceivers; + MetaObjectBuilder mo; + std::size_t cppObjSize; }; -} +TypeUserData *retrieveTypeUserData(SbkObjectType *sbkTypeObj); +TypeUserData *retrieveTypeUserData(PyTypeObject *pyTypeObj); +TypeUserData *retrieveTypeUserData(PyObject *pyObj); +// For QML +PYSIDE_API const QMetaObject *retrieveMetaObject(PyTypeObject *pyTypeObj); +PYSIDE_API const QMetaObject *retrieveMetaObject(PyObject *pyObj); -#endif +} //namespace PySide +#endif // PYSIDE_P_H diff --git a/sources/pyside2/libpyside/pysideclassinfo.cpp b/sources/pyside2/libpyside/pysideclassinfo.cpp index 5593825c3..4edf0fa91 100644 --- a/sources/pyside2/libpyside/pysideclassinfo.cpp +++ b/sources/pyside2/libpyside/pysideclassinfo.cpp @@ -38,12 +38,13 @@ ****************************************************************************/ #include <sbkpython.h> + #include "pysideclassinfo.h" +#include "pyside_p.h" #include "pysideclassinfo_p.h" #include "dynamicqmetaobject.h" #include <shiboken.h> -#include <QDebug> #define CLASSINFO_CLASS_NAME "ClassInfo" @@ -74,9 +75,8 @@ static PyType_Spec PySideClassInfoType_spec = { PyTypeObject *PySideClassInfoTypeF(void) { - static PyTypeObject *type = nullptr; - if (!type) - type = (PyTypeObject *)PyType_FromSpec(&PySideClassInfoType_spec); + static PyTypeObject *type = + reinterpret_cast<PyTypeObject *>(PyType_FromSpec(&PySideClassInfoType_spec)); return type; } @@ -97,8 +97,7 @@ PyObject *classCall(PyObject *self, PyObject *args, PyObject * /* kw */) return 0; } - PyObject* klass; - klass = PyTuple_GetItem(args, 0); + PyObject *klass = PyTuple_GetItem(args, 0); bool validClass = false; // This will sometimes segfault if you mistakenly use it on a function declaration @@ -107,10 +106,11 @@ PyObject *classCall(PyObject *self, PyObject *args, PyObject * /* kw */) return 0; } - if (Shiboken::ObjectType::checkType(reinterpret_cast<PyTypeObject*>(klass))) { - PySide::DynamicQMetaObject* mo = reinterpret_cast<PySide::DynamicQMetaObject*>(Shiboken::ObjectType::getTypeUserData(reinterpret_cast<SbkObjectType*>(klass))); - if (mo) { - mo->addInfo(PySide::ClassInfo::getMap(data)); + PyTypeObject *klassType = reinterpret_cast<PyTypeObject*>(klass); + if (Shiboken::ObjectType::checkType(klassType)) { + 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/pysideclassinfo.h b/sources/pyside2/libpyside/pysideclassinfo.h index 910dd9f82..ff60b91c3 100644 --- a/sources/pyside2/libpyside/pysideclassinfo.h +++ b/sources/pyside2/libpyside/pysideclassinfo.h @@ -41,9 +41,11 @@ #define PYSIDE_CLASSINFO_H #include <pysidemacros.h> + #include <sbkpython.h> -#include <QMap> -#include <QByteArray> + +#include <QtCore/QMap> +#include <QtCore/QByteArray> extern "C" { diff --git a/sources/pyside2/libpyside/pysidemetafunction.cpp b/sources/pyside2/libpyside/pysidemetafunction.cpp index a9fbbc7fc..4cdc7ec16 100644 --- a/sources/pyside2/libpyside/pysidemetafunction.cpp +++ b/sources/pyside2/libpyside/pysidemetafunction.cpp @@ -36,14 +36,13 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#include <sbkpython.h> + #include "pysidemetafunction.h" #include "pysidemetafunction_p.h" #include <shiboken.h> -#include <QObject> -#include <QMetaMethod> -#include <QDebug> + +#include <QtCore/QMetaMethod> extern "C" { diff --git a/sources/pyside2/libpyside/pysidemetafunction.h b/sources/pyside2/libpyside/pysidemetafunction.h index 020f02d49..1085ecb5e 100644 --- a/sources/pyside2/libpyside/pysidemetafunction.h +++ b/sources/pyside2/libpyside/pysidemetafunction.h @@ -40,13 +40,12 @@ #ifndef PYSIDE_METAFUNCTION_H #define PYSIDE_METAFUNCTION_H -#include <QObject> -#include <QString> -#include <QStringList> - #include <pysidemacros.h> + #include <sbkpython.h> +#include <QtCore/QObject> + extern "C" { extern PYSIDE_API PyTypeObject *PySideMetaFunctionTypeF(void); diff --git a/sources/pyside2/libpyside/pysidemetafunction_p.h b/sources/pyside2/libpyside/pysidemetafunction_p.h index c3b8fe0c7..442e05ea7 100644 --- a/sources/pyside2/libpyside/pysidemetafunction_p.h +++ b/sources/pyside2/libpyside/pysidemetafunction_p.h @@ -41,8 +41,8 @@ #define PYSIDE_METAFUNCTION_P_H #include <sbkpython.h> -#include <QList> -#include <QByteArray> + +#include <QtCore/QtGlobal> QT_BEGIN_NAMESPACE class QObject; diff --git a/sources/pyside2/libpyside/pysideproperty.cpp b/sources/pyside2/libpyside/pysideproperty.cpp index 279e09ec1..091b0c447 100644 --- a/sources/pyside2/libpyside/pysideproperty.cpp +++ b/sources/pyside2/libpyside/pysideproperty.cpp @@ -45,8 +45,6 @@ #include "pysidesignal_p.h" #include <shiboken.h> -#include <QDebug> - #define QPROPERTY_CLASS_NAME "Property" @@ -173,7 +171,8 @@ int qpropertyTpInit(PyObject* self, PyObject* args, PyObject* kwds) "designable", "scriptable", "stored", "user", "constant", "final", 0}; if (!PyArg_ParseTupleAndKeywords(args, kwds, - "O|OOOOsObbbbbb:QtCore.QProperty", (char**) kwlist, + "O|OOOOsObbbbbb:QtCore.QProperty", + const_cast<char**>(kwlist), /*OO*/ &type, &(pData->fget), /*OOO*/ &(pData->fset), &(pData->freset), &(pData->fdel), /*s*/ &(pData->doc), @@ -197,14 +196,13 @@ int qpropertyTpInit(PyObject* self, PyObject* args, PyObject* kwds) Py_XINCREF(pData->fdel); Py_XINCREF(pData->notify); return 1; - } else { - pData->fget = 0; - pData->fset = 0; - pData->freset = 0; - pData->fdel = 0; - pData->notify = 0; - return -1; } + pData->fget = nullptr; + pData->fset = nullptr; + pData->freset = nullptr; + pData->fdel = nullptr; + pData->notify = nullptr; + return -1; } void qpropertyDeAlloc(PyObject* self) @@ -225,10 +223,9 @@ PyObject *qPropertyCall(PyObject *self, PyObject *args, PyObject * /* kw */) Py_INCREF(self); return self; - } else { - PyErr_SetString(PyExc_TypeError, "Invalid property usage."); - return 0; } + PyErr_SetString(PyExc_TypeError, "Invalid property usage."); + return nullptr; } PyObject* qPropertySetter(PyObject* self, PyObject* callback) @@ -242,10 +239,9 @@ PyObject* qPropertySetter(PyObject* self, PyObject* callback) Py_INCREF(callback); return callback; - } else { - PyErr_SetString(PyExc_TypeError, "Invalid property setter agument."); - return 0; } + PyErr_SetString(PyExc_TypeError, "Invalid property setter agument."); + return nullptr; } PyObject* qPropertyGetter(PyObject* self, PyObject* callback) @@ -259,10 +255,9 @@ PyObject* qPropertyGetter(PyObject* self, PyObject* callback) Py_INCREF(callback); return callback; - } else { - PyErr_SetString(PyExc_TypeError, "Invalid property getter agument."); - return 0; } + PyErr_SetString(PyExc_TypeError, "Invalid property getter agument."); + return nullptr; } static int qpropertyTraverse(PyObject* self, visitproc visit, void* arg) diff --git a/sources/pyside2/libpyside/pysideproperty.h b/sources/pyside2/libpyside/pysideproperty.h index d77416abe..0ea5e84d6 100644 --- a/sources/pyside2/libpyside/pysideproperty.h +++ b/sources/pyside2/libpyside/pysideproperty.h @@ -41,8 +41,10 @@ #define PYSIDE_PROPERTY_H #include <pysidemacros.h> + #include <sbkpython.h> -#include <QObject> + +#include <QtCore/QMetaObject> extern "C" { diff --git a/sources/pyside2/libpyside/pysideqflags.cpp b/sources/pyside2/libpyside/pysideqflags.cpp index 684628e57..cb57031b0 100644 --- a/sources/pyside2/libpyside/pysideqflags.cpp +++ b/sources/pyside2/libpyside/pysideqflags.cpp @@ -38,8 +38,9 @@ ****************************************************************************/ #include "pysideqflags.h" -#include <sbkenum.h> + #include <autodecref.h> +#include <sbkenum.h> extern "C" { struct SbkConverter; @@ -174,13 +175,8 @@ namespace QFlags newspec->itemsize = SbkNewQFlagsType_spec.itemsize; newspec->flags = SbkNewQFlagsType_spec.flags; int idx = -1; -#ifdef IS_PY3K -# define SLOT slot -#else -# define SLOT slot_ -#endif - while (numberMethods[++idx].SLOT) { - assert(SbkNewQFlagsType_slots[idx].SLOT == numberMethods[idx].SLOT); + while (numberMethods[++idx].slot) { + assert(SbkNewQFlagsType_slots[idx].slot == numberMethods[idx].slot); SbkNewQFlagsType_slots[idx].pfunc = numberMethods[idx].pfunc; } newspec->slots = SbkNewQFlagsType_spec.slots; diff --git a/sources/pyside2/libpyside/pysidesignal.cpp b/sources/pyside2/libpyside/pysidesignal.cpp index c3dc65968..e7fd389a8 100644 --- a/sources/pyside2/libpyside/pysidesignal.cpp +++ b/sources/pyside2/libpyside/pysidesignal.cpp @@ -43,7 +43,12 @@ #include "signalmanager.h" #include <shiboken.h> -#include <QDebug> + +#include <QtCore/QObject> +#include <QtCore/QMetaMethod> +#include <QtCore/QMetaObject> + +#include <utility> #define SIGNAL_CLASS_NAME "Signal" #define SIGNAL_INSTANCE_NAME "SignalInstance" @@ -54,14 +59,15 @@ namespace Signal { //aux class SignalSignature { public: - SignalSignature() : m_attributes(QMetaMethod::Compatibility) {} - SignalSignature(QByteArray parameterTypes) : m_parameterTypes(parameterTypes), - m_attributes(QMetaMethod::Compatibility) {} - SignalSignature(QByteArray parameterTypes, QMetaMethod::Attributes attributes) : - m_parameterTypes(parameterTypes), + SignalSignature() = default; + explicit SignalSignature(QByteArray parameterTypes) : + m_parameterTypes(std::move(parameterTypes)) {} + explicit SignalSignature(QByteArray parameterTypes, QMetaMethod::Attributes attributes) : + m_parameterTypes(std::move(parameterTypes)), m_attributes(attributes) {} + QByteArray m_parameterTypes; - QMetaMethod::Attributes m_attributes; + QMetaMethod::Attributes m_attributes = QMetaMethod::Compatibility; }; static char* buildSignature(const char*, const char*); @@ -412,8 +418,7 @@ PyObject* signalInstanceConnect(PyObject* self, PyObject* args, PyObject* kwds) PyObject* result = PyObject_CallObject(pyMethod, tupleArgs); if (result == Py_True || result == Py_False) return result; - else - Py_XDECREF(result); + Py_XDECREF(result); } if (!PyErr_Occurred()) // PYSIDE-79: inverse the logic. A Null return needs an error. PyErr_Format(PyExc_RuntimeError, "Failed to connect signal %s.", source->d->signature); @@ -661,9 +666,10 @@ char* getTypeName(PyObject* type) typeName = strdup("PyObject"); } return typeName; - } else if (type == Py_None) { // Must be checked before as Shiboken::String::check accepts Py_None + } + if (type == Py_None) // Must be checked before as Shiboken::String::check accepts Py_None return strdup("void"); - } else if (Shiboken::String::check(type)) { + if (Shiboken::String::check(type)) { const char *result = Shiboken::String::toCString(type); if (!strcmp(result, "qreal")) result = sizeof(qreal) == sizeof(double) ? "double" : "float"; @@ -778,7 +784,7 @@ PySideSignalInstance* newObjectFromMethod(PyObject* source, const QList<QMetaMet { PySideSignalInstance* root = 0; PySideSignalInstance* previous = 0; - foreach (const QMetaMethod &m, methodList) { + for (const QMetaMethod &m : methodList) { PySideSignalInstance* item = PyObject_New(PySideSignalInstance, PySideSignalInstanceTypeF()); if (!root) root = item; @@ -835,7 +841,7 @@ template<typename T> static typename T::value_type join(T t, const char* sep) { typename T::value_type res; - if (!t.size()) + if (t.isEmpty()) return res; typename T::const_iterator it = t.begin(); @@ -894,7 +900,7 @@ void registerSignals(SbkObjectType* pyObj, const QMetaObject* metaObject) self->signaturesSize = 0; self->signatures = 0; self->signatureAttributes = 0; - self->initialized = 0; + self->initialized = false; self->homonymousMethod = 0; // Empty signatures comes first! So they will be the default signal signature @@ -949,9 +955,9 @@ QStringList getArgsFromSignature(const char* signature, bool* isShortCircuit) if (isShortCircuit) *isShortCircuit = !qsignature.contains(QLatin1Char('(')); - if (qsignature.contains(QLatin1String("()")) || qsignature.contains(QLatin1String("(void)"))) { + if (qsignature.contains(QLatin1String("()")) || qsignature.contains(QLatin1String("(void)"))) return result; - } else if (qsignature.contains(QLatin1Char('('))) { + if (qsignature.contains(QLatin1Char('('))) { static QRegExp regex(QLatin1String(".+\\((.*)\\)")); //get args types QString types = qsignature; @@ -1047,9 +1053,8 @@ QString codeCallbackName(PyObject* callback, const QString& funcName) PyObject* self = PyMethod_GET_SELF(callback); PyObject* func = PyMethod_GET_FUNCTION(callback); return funcName + QString::number(quint64(self), 16) + QString::number(quint64(func), 16); - } else { - return funcName + QString::number(quint64(callback), 16); } + return funcName + QString::number(quint64(callback), 16); } } //namespace Signal diff --git a/sources/pyside2/libpyside/pysidesignal.h b/sources/pyside2/libpyside/pysidesignal.h index abbefbb1a..a2d58a27c 100644 --- a/sources/pyside2/libpyside/pysidesignal.h +++ b/sources/pyside2/libpyside/pysidesignal.h @@ -40,14 +40,19 @@ #ifndef PYSIDE_SIGNAL_H #define PYSIDE_SIGNAL_H -#include <QObject> -#include <QString> -#include <QStringList> - #include <pysidemacros.h> + #include <sbkpython.h> #include <basewrapper.h> +#include <QtCore/QList> +#include <QtCore/QMetaMethod> + +QT_BEGIN_NAMESPACE +struct QMetaObject; +class QObject; +QT_END_NAMESPACE + extern "C" { extern PYSIDE_API PyTypeObject *PySideSignalTypeF(void); diff --git a/sources/pyside2/libpyside/pysideslot.cpp b/sources/pyside2/libpyside/pysideslot.cpp index 6ae664c42..6f6658cf8 100644 --- a/sources/pyside2/libpyside/pysideslot.cpp +++ b/sources/pyside2/libpyside/pysideslot.cpp @@ -42,8 +42,9 @@ #include "pysideslot_p.h" #include <shiboken.h> -#include <QString> -#include <QMetaObject> + +#include <QtCore/QMetaObject> +#include <QtCore/QString> #define SLOT_DEC_NAME "Slot" @@ -96,8 +97,10 @@ int slotTpInit(PyObject *self, PyObject *args, PyObject *kw) if (emptyTuple == 0) emptyTuple = PyTuple_New(0); - if (!PyArg_ParseTupleAndKeywords(emptyTuple, kw, "|sO:QtCore." SLOT_DEC_NAME, (char**) kwlist, &argName, &argResult)) + if (!PyArg_ParseTupleAndKeywords(emptyTuple, kw, "|sO:QtCore." SLOT_DEC_NAME, + const_cast<char**>(kwlist), &argName, &argResult)) { return 0; + } PySideSlot *data = reinterpret_cast<PySideSlot*>(self); for(Py_ssize_t i = 0, i_max = PyTuple_Size(args); i < i_max; i++) { diff --git a/sources/pyside2/libpyside/pysideweakref.cpp b/sources/pyside2/libpyside/pysideweakref.cpp index 6c38d39c4..6b5073db8 100644 --- a/sources/pyside2/libpyside/pysideweakref.cpp +++ b/sources/pyside2/libpyside/pysideweakref.cpp @@ -65,7 +65,7 @@ static PyType_Spec PySideCallableObjectType_spec = { }; -static PyTypeObject *PySideCallableObjectTypeF(void) +static PyTypeObject *PySideCallableObjectTypeF() { static PyTypeObject *type = (PyTypeObject *)PyType_FromSpec(&PySideCallableObjectType_spec); diff --git a/sources/pyside2/libpyside/signalmanager.cpp.in b/sources/pyside2/libpyside/signalmanager.cpp index c67bc6369..8925ffd35 100644 --- a/sources/pyside2/libpyside/signalmanager.cpp.in +++ b/sources/pyside2/libpyside/signalmanager.cpp @@ -43,25 +43,25 @@ #include "pysideproperty.h" #include "pysideproperty_p.h" #include "pyside.h" +#include "pyside_p.h" #include "dynamicqmetaobject.h" #include "pysidemetafunction_p.h" -#include <QtCore> -#include <QHash> -#include <QStringList> -#include <QMetaMethod> #include <autodecref.h> -#include <gilstate.h> -#include <QDebug> -#include <limits> -#include <algorithm> #include <basewrapper.h> #include <bindingmanager.h> +#include <gilstate.h> #include <sbkconverter.h> #include <sbkstring.h> +#include <QtCore/QDebug> +#include <QtCore/QHash> + +#include <algorithm> +#include <limits> + // These private headers are needed to throw JavaScript exceptions -#if @QML_PRIVATE_API_SUPPORT@ +#if PYSIDE_QML_PRIVATE_API_SUPPORT #include <private/qv4engine_p.h> #include <private/qv4context_p.h> #include <private/qqmldata_p.h> @@ -76,7 +76,6 @@ #define PYSIDE_SLOT '1' #define PYSIDE_SIGNAL '2' #include "globalreceiverv2.h" -#include "globalreceiver.h" #define PYTHON_TYPE "PyObject" @@ -91,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); @@ -101,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); @@ -142,11 +141,16 @@ PyObjectWrapper::~PyObjectWrapper() Py_XDECREF(m_me); } -PyObjectWrapper& PyObjectWrapper::operator=(const PySide::PyObjectWrapper& other) +void PyObjectWrapper::reset(PyObject *o) { - Py_XINCREF(other.m_me); + Py_XINCREF(o); Py_XDECREF(m_me); - m_me = other.m_me; + m_me = o; +} + +PyObjectWrapper& PyObjectWrapper::operator=(const PySide::PyObjectWrapper& other) +{ + reset(other.m_me); return *this; } @@ -205,10 +209,9 @@ QDataStream &operator>>(QDataStream& in, PyObjectWrapper& myObj) in >> repr; Shiboken::AutoDecRef pyCode(PyBytes_FromStringAndSize(repr.data(), repr.size())); Shiboken::AutoDecRef value(PyObject_CallFunctionObjArgs(eval_func, pyCode.object(), 0)); - if (!value.object()) { - value = Py_None; - } - myObj = PyObjectWrapper(value); + if (!value.object()) + value.reset(Py_None); + myObj.reset(value); return in; } @@ -220,9 +223,6 @@ struct SignalManager::SignalManagerPrivate { SharedMap m_globalReceivers; - //Deprecated - GlobalReceiver m_globalReceiver; - SignalManagerPrivate() { m_globalReceivers = SharedMap( new QMap<QByteArray, GlobalReceiverV2*>() ); @@ -304,44 +304,21 @@ SignalManager& SignalManager::instance() return me; } -QObject* SignalManager::globalReceiver() -{ - return &m_d->m_globalReceiver; -} - -void SignalManager::globalReceiverConnectNotify(QObject* source, int slotIndex) -{ - m_d->m_globalReceiver.connectNotify(source, slotIndex); -} - -void SignalManager::globalReceiverDisconnectNotify(QObject* source, int slotIndex) -{ - m_d->m_globalReceiver.disconnectNotify(source, slotIndex); -} - -void SignalManager::addGlobalSlot(const char* slot, PyObject* callback) -{ - addGlobalSlotGetIndex(slot, callback); -} - -int SignalManager::addGlobalSlotGetIndex(const char* slot, PyObject* callback) -{ - return m_d->m_globalReceiver.addSlot(slot, callback); -} - QObject* SignalManager::globalReceiver(QObject *sender, PyObject *callback) { SharedMap globalReceivers = m_d->m_globalReceivers; QByteArray hash = GlobalReceiverV2::hash(callback); GlobalReceiverV2* gr = 0; - if (!globalReceivers->contains(hash)) { - gr = (*globalReceivers)[hash] = new GlobalReceiverV2(callback, globalReceivers); + auto it = globalReceivers->find(hash); + if (it == globalReceivers->end()) { + gr = new GlobalReceiverV2(callback, globalReceivers); + globalReceivers->insert(hash, gr); if (sender) { gr->incRef(sender); // create a link reference gr->decRef(); // remove extra reference } } else { - gr = (*globalReceivers)[hash]; + gr = it.value(); if (sender) gr->incRef(sender); } @@ -465,7 +442,7 @@ int SignalManager::qt_metacall(QObject* object, QMetaObject::Call call, int id, if (PyErr_Occurred()) { -#if @QML_PRIVATE_API_SUPPORT@ +#if PYSIDE_QML_PRIVATE_API_SUPPORT // This JS engine grabber based off of Qt 5.5's `qjsEngine` function QQmlData *data = QQmlData::get(object, false); @@ -572,9 +549,26 @@ 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) { - Q_ASSERT(source); + if (!source) { + qWarning("SignalManager::registerMetaMethodGetIndex(\"%s\") called with source=nullptr.", + signature); + return -1; + } const QMetaObject* metaObject = source->metaObject(); int methodIndex = metaObject->indexOfMethod(signature); // Create the dynamic signal is needed @@ -584,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 @@ -599,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) @@ -612,32 +604,16 @@ int SignalManager::registerMetaMethodGetIndex(QObject* source, const char* signa return methodIndex; } -bool SignalManager::hasConnectionWith(const QObject *object) -{ - return m_d->m_globalReceiver.hasConnectionWith(object); -} - -const QMetaObject* SignalManager::retriveMetaObject(PyObject *self) +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 = reinterpret_cast<DynamicQMetaObject*>(Shiboken::Object::getTypeUserData(reinterpret_cast<SbkObject*>(self))); - } + MetaObjectBuilder *builder = metaBuilderFromDict(reinterpret_cast<SbkObject*>(self)->ob_dict); + if (!builder) + builder = &(retrieveTypeUserData(self)->mo); - mo->update(); - return mo; + return builder->update(); } namespace { diff --git a/sources/pyside2/libpyside/signalmanager.h b/sources/pyside2/libpyside/signalmanager.h index 5948a7df1..229ddb91d 100644 --- a/sources/pyside2/libpyside/signalmanager.h +++ b/sources/pyside2/libpyside/signalmanager.h @@ -41,10 +41,12 @@ #define SIGNALMANAGER_H #include "pysidemacros.h" + #include <sbkpython.h> -#include <Qt> -#include <QStringList> -#include <QMetaMethod> + +#include <QtCore/QMetaMethod> + +QT_FORWARD_DECLARE_CLASS(QDataStream) namespace PySide { @@ -53,12 +55,19 @@ namespace PySide class PYSIDE_API PyObjectWrapper { public: + PyObjectWrapper(PyObjectWrapper&&) = delete; + PyObjectWrapper& operator=(PyObjectWrapper &&) = delete; + PyObjectWrapper(); - PyObjectWrapper(PyObject* me); + explicit PyObjectWrapper(PyObject* me); PyObjectWrapper(const PyObjectWrapper &other); + PyObjectWrapper& operator=(const PyObjectWrapper &other); + + void reset(PyObject *o); + ~PyObjectWrapper(); operator PyObject*() const; - PyObjectWrapper& operator=(const PyObjectWrapper &other); + private: PyObject* m_me; }; @@ -68,6 +77,7 @@ PYSIDE_API QDataStream &operator>>(QDataStream& in, PyObjectWrapper& myObj); class PYSIDE_API SignalManager { + Q_DISABLE_COPY(SignalManager) public: static SignalManager& instance(); @@ -84,7 +94,7 @@ public: static int registerMetaMethodGetIndex(QObject* source, const char* signature, QMetaMethod::MethodType type); // used to discovery metaobject - static const QMetaObject* retriveMetaObject(PyObject* self); + static const QMetaObject* retrieveMetaObject(PyObject* self); // Used to discovery if SignalManager was connected with object "destroyed()" signal. int countConnectionsWith(const QObject *object); @@ -95,24 +105,12 @@ public: // Utility function to call a python method usign args received in qt_metacall static int callPythonMetaMethod(const QMetaMethod& method, void** args, PyObject* obj, bool isShortCuit); - PYSIDE_DEPRECATED(QObject* globalReceiver()); - PYSIDE_DEPRECATED(void addGlobalSlot(const char* slot, PyObject* callback)); - PYSIDE_DEPRECATED(int addGlobalSlotGetIndex(const char* slot, PyObject* callback)); - - PYSIDE_DEPRECATED(void globalReceiverConnectNotify(QObject *sender, int slotIndex)); - PYSIDE_DEPRECATED(void globalReceiverDisconnectNotify(QObject *sender, int slotIndex)); - PYSIDE_DEPRECATED(bool hasConnectionWith(const QObject *object)); - private: struct SignalManagerPrivate; SignalManagerPrivate* m_d; SignalManager(); ~SignalManager(); - - // disable copy - SignalManager(const SignalManager&); - SignalManager operator=(const SignalManager&); }; } |