diff options
Diffstat (limited to 'sources/pyside2/libpyside')
18 files changed, 290 insertions, 69 deletions
diff --git a/sources/pyside2/libpyside/CMakeLists.txt b/sources/pyside2/libpyside/CMakeLists.txt index 7b8adfc84..7493a453a 100644 --- a/sources/pyside2/libpyside/CMakeLists.txt +++ b/sources/pyside2/libpyside/CMakeLists.txt @@ -53,6 +53,7 @@ set(libpyside_SRC pysideqflags.cpp pysideweakref.cpp pyside.cpp + pysidestaticstrings.cpp ${DESTROYLISTENER_MOC} ) @@ -130,6 +131,7 @@ set(libpyside_HEADERS pysidemacros.h signalmanager.h pyside.h + pysidestaticstrings.h pysidemetafunction.h pysidesignal.h pysideproperty.h diff --git a/sources/pyside2/libpyside/dynamicqmetaobject.cpp b/sources/pyside2/libpyside/dynamicqmetaobject.cpp index 857d242a2..dae9e2059 100644 --- a/sources/pyside2/libpyside/dynamicqmetaobject.cpp +++ b/sources/pyside2/libpyside/dynamicqmetaobject.cpp @@ -140,7 +140,8 @@ MetaObjectBuilder::MetaObjectBuilder(PyTypeObject *type, const QMetaObject *meta MetaObjectBuilder::~MetaObjectBuilder() { - qDeleteAll(m_d->m_cachedMetaObjects); + for (auto *metaObject : m_d->m_cachedMetaObjects) + free(const_cast<QMetaObject*>(metaObject)); delete m_d->m_builder; delete m_d; } @@ -413,6 +414,10 @@ const QMetaObject *MetaObjectBuilderPrivate::update() if (!m_builder) return m_baseObject; if (m_cachedMetaObjects.empty() || m_dirty) { + // PYSIDE-803: The dirty branch needs to be protected by the GIL. + // This was moved from SignalManager::retrieveMetaObject to here, + // which is only the update in "return builder->update()". + Shiboken::GilState gil; m_cachedMetaObjects.push_back(m_builder->toMetaObject()); checkMethodOrder(m_cachedMetaObjects.back()); m_dirty = false; @@ -464,7 +469,8 @@ void MetaObjectBuilderPrivate::parsePythonType(PyTypeObject *type) if (Signal::checkType(value)) { // Register signals. auto data = reinterpret_cast<PySideSignal *>(value); - data->data->signalName = Shiboken::String::toCString(key); + if (data->data->signalName.isEmpty()) + data->data->signalName = Shiboken::String::toCString(key); for (const auto &s : data->data->signatures) { const auto sig = data->data->signalName + '(' + s.signature + ')'; if (m_baseObject->indexOfSignal(sig) == -1) { diff --git a/sources/pyside2/libpyside/dynamicqmetaobject_p.h b/sources/pyside2/libpyside/dynamicqmetaobject_p.h index 534be5825..9199630b7 100644 --- a/sources/pyside2/libpyside/dynamicqmetaobject_p.h +++ b/sources/pyside2/libpyside/dynamicqmetaobject_p.h @@ -45,8 +45,6 @@ #include <QtCore/QByteArray> #include <QtCore/QMetaMethod> -#define GLOBAL_RECEIVER_CLASS_NAME "__GlobalReceiver__" - struct PySideProperty; namespace PySide { diff --git a/sources/pyside2/libpyside/globalreceiverv2.cpp b/sources/pyside2/libpyside/globalreceiverv2.cpp index 84ec92687..0377f7697 100644 --- a/sources/pyside2/libpyside/globalreceiverv2.cpp +++ b/sources/pyside2/libpyside/globalreceiverv2.cpp @@ -187,7 +187,7 @@ DynamicSlotDataV2::~DynamicSlotDataV2() GlobalReceiverV2::GlobalReceiverV2(PyObject *callback, SharedMap map) : QObject(nullptr), - m_metaObject(GLOBAL_RECEIVER_CLASS_NAME, &QObject::staticMetaObject), + m_metaObject("__GlobalReceiver__", &QObject::staticMetaObject), m_sharedMap(std::move(map)) { m_data = new DynamicSlotDataV2(callback, this); diff --git a/sources/pyside2/libpyside/pyside.cpp b/sources/pyside2/libpyside/pyside.cpp index 9ee20f461..e2b8708ce 100644 --- a/sources/pyside2/libpyside/pyside.cpp +++ b/sources/pyside2/libpyside/pyside.cpp @@ -45,6 +45,7 @@ #include "pysideproperty.h" #include "pysidesignal.h" #include "pysidesignal_p.h" +#include "pysidestaticstrings.h" #include "pysideslot_p.h" #include "pysidemetafunction_p.h" #include "pysidemetafunction.h" @@ -57,6 +58,7 @@ #include <gilstate.h> #include <sbkconverter.h> #include <sbkstring.h> +#include <sbkstaticstrings.h> #include <qapp_macro.h> #include <QtCore/QByteArray> @@ -92,6 +94,7 @@ void init(PyObject *module) MetaFunction::init(module); // Init signal manager, so it will register some meta types used by QVariant. SignalManager::instance(); + initQApp(); } static bool _setProperty(PyObject *qObj, PyObject *name, PyObject *value, bool *accept) @@ -147,7 +150,8 @@ bool fillQtProperties(PyObject *qObj, const QMetaObject *metaObj, PyObject *kwds return false; } if (!accept) { - PyErr_Format(PyExc_AttributeError, "'%S' is not a Qt property or a signal", key); + PyErr_Format(PyExc_AttributeError, "'%s' is not a Qt property or a signal", + propName.constData()); return false; } } @@ -211,7 +215,7 @@ void destroyQCoreApplication() delete app; Py_END_ALLOW_THREADS // PYSIDE-571: make sure to create a singleton deleted qApp. - MakeSingletonQAppWrapper(NULL); + Py_DECREF(MakeQAppWrapper(nullptr)); } std::size_t getSizeOfQObject(SbkObjectType *type) @@ -233,7 +237,8 @@ void initDynamicMetaObject(SbkObjectType *type, const QMetaObject *base, std::si if (!converter) return; Shiboken::AutoDecRef pyMetaObject(Shiboken::Conversions::pointerToPython(converter, metaObjectPtr)); - PyObject_SetAttrString(reinterpret_cast<PyObject *>(type), "staticMetaObject", pyMetaObject); + PyObject_SetAttr(reinterpret_cast<PyObject *>(type), + PySide::PyName::qtStaticMetaObject(), pyMetaObject); } TypeUserData *retrieveTypeUserData(SbkObjectType *sbkTypeObj) @@ -295,6 +300,23 @@ void initQObjectSubType(SbkObjectType *type, PyObject *args, PyObject * /* kwds initDynamicMetaObject(type, userData->mo.update(), userData->cppObjSize); } +void initQApp() +{ + /* + * qApp will not be initialized when embedding is active. + * That means that qApp exists already when PySide is initialized. + * We could solve that by creating a qApp variable, but in embedded + * mode, we also have the effect that the first assignment to qApp + * is persistent! Therefore, we can never be sure to have created + * qApp late enough to get the right type for the instance. + * + * I would appreciate very much if someone could explain or even fix + * this issue. It exists only when a pre-existing application exists. + */ + if (!qApp) + Py_DECREF(MakeQAppWrapper(nullptr)); +} + PyObject *getMetaDataFromQObject(QObject *cppSelf, PyObject *self, PyObject *name) { PyObject *attr = PyObject_GenericGetAttr(self, name); @@ -306,7 +328,6 @@ PyObject *getMetaDataFromQObject(QObject *cppSelf, PyObject *self, PyObject *nam Py_DECREF(attr); if (!value) return 0; - Py_INCREF(value); attr = value; } @@ -397,6 +418,24 @@ static void invalidatePtr(any_t *object) static const char invalidatePropertyName[] = "_PySideInvalidatePtr"; +// PYSIDE-1214, when creating new wrappers for classes inheriting QObject but +// not exposed to Python, try to find the best-matching (most-derived) Qt +// class by walking up the meta objects. +static const char *typeName(QObject *cppSelf) +{ + const char *typeName = typeid(*cppSelf).name(); + if (!Shiboken::Conversions::getConverter(typeName)) { + for (auto metaObject = cppSelf->metaObject(); metaObject; metaObject = metaObject->superClass()) { + const char *name = metaObject->className(); + if (Shiboken::Conversions::getConverter(name)) { + typeName = name; + break; + } + } + } + return typeName; +} + PyObject *getWrapperForQObject(QObject *cppSelf, SbkObjectType *sbk_type) { PyObject *pyOut = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper(cppSelf)); @@ -419,8 +458,7 @@ PyObject *getWrapperForQObject(QObject *cppSelf, SbkObjectType *sbk_type) } } - const char *typeName = typeid(*cppSelf).name(); - pyOut = Shiboken::Object::newObject(sbk_type, cppSelf, false, false, typeName); + pyOut = Shiboken::Object::newObject(sbk_type, cppSelf, false, false, typeName(cppSelf)); return pyOut; } @@ -539,7 +577,7 @@ bool registerInternalQtConf() // Querying __file__ should be done only for modules that have finished their initialization. // Thus querying for the top-level PySide2 package works for us whenever any Qt-wrapped module // is loaded. - PyObject *pysideInitFilePath = PyObject_GetAttrString(pysideModule, "__file__"); + PyObject *pysideInitFilePath = PyObject_GetAttr(pysideModule, Shiboken::PyMagicName::file()); Py_DECREF(pysideModule); if (!pysideInitFilePath) return false; diff --git a/sources/pyside2/libpyside/pyside.h b/sources/pyside2/libpyside/pyside.h index 1529d79c9..ae400e1fe 100644 --- a/sources/pyside2/libpyside/pyside.h +++ b/sources/pyside2/libpyside/pyside.h @@ -103,6 +103,7 @@ PYSIDE_DEPRECATED(PYSIDE_API void initDynamicMetaObject(SbkObjectType *type, con PYSIDE_API void initDynamicMetaObject(SbkObjectType *type, const QMetaObject *base, std::size_t cppObjSize); PYSIDE_API void initQObjectSubType(SbkObjectType *type, PyObject *args, PyObject *kwds); +PYSIDE_API void initQApp(); /// Return the size in bytes of a type that inherits QObject. PYSIDE_API std::size_t getSizeOfQObject(SbkObjectType *type); diff --git a/sources/pyside2/libpyside/pysideclassinfo.cpp b/sources/pyside2/libpyside/pysideclassinfo.cpp index fe5ca8765..375a31b57 100644 --- a/sources/pyside2/libpyside/pysideclassinfo.cpp +++ b/sources/pyside2/libpyside/pysideclassinfo.cpp @@ -60,11 +60,11 @@ static PyType_Slot PySideClassInfoType_slots[] = { {Py_tp_init, (void *)classInfoTpInit}, {Py_tp_new, (void *)classInfoTpNew}, {Py_tp_free, (void *)classInfoFree}, - {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_dealloc, (void *)Sbk_object_dealloc}, {0, 0} }; static PyType_Spec PySideClassInfoType_spec = { - "PySide2.QtCore.ClassInfo", + "2:PySide2.QtCore.ClassInfo", sizeof(PySideClassInfo), 0, Py_TPFLAGS_DEFAULT, @@ -75,7 +75,7 @@ static PyType_Spec PySideClassInfoType_spec = { PyTypeObject *PySideClassInfoTypeF(void) { static PyTypeObject *type = - reinterpret_cast<PyTypeObject *>(PyType_FromSpec(&PySideClassInfoType_spec)); + reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(&PySideClassInfoType_spec)); return type; } diff --git a/sources/pyside2/libpyside/pysideclassinfo_p.h b/sources/pyside2/libpyside/pysideclassinfo_p.h index c0038a71a..021aa58e9 100644 --- a/sources/pyside2/libpyside/pysideclassinfo_p.h +++ b/sources/pyside2/libpyside/pysideclassinfo_p.h @@ -44,8 +44,6 @@ #include <QMetaObject> #include "pysideclassinfo.h" -#define __INFO_ATTR_NAME__ "__classInfo__" // not used! ??? - struct PySideClassInfo; extern "C" diff --git a/sources/pyside2/libpyside/pysidemetafunction.cpp b/sources/pyside2/libpyside/pysidemetafunction.cpp index e0e0c439b..f4b95385a 100644 --- a/sources/pyside2/libpyside/pysidemetafunction.cpp +++ b/sources/pyside2/libpyside/pysidemetafunction.cpp @@ -62,11 +62,11 @@ static PyType_Slot PySideMetaFunctionType_slots[] = { {Py_tp_call, (void *)functionCall}, {Py_tp_new, (void *)PyType_GenericNew}, {Py_tp_free, (void *)functionFree}, - {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_dealloc, (void *)Sbk_object_dealloc}, {0, 0} }; static PyType_Spec PySideMetaFunctionType_spec = { - "PySide2.QtCore.MetaFunction", + "2:PySide2.QtCore.MetaFunction", sizeof(PySideMetaFunction), 0, Py_TPFLAGS_DEFAULT, @@ -76,9 +76,8 @@ static PyType_Spec PySideMetaFunctionType_spec = { PyTypeObject *PySideMetaFunctionTypeF(void) { - static PyTypeObject *type = nullptr; - if (!type) - type = (PyTypeObject *)PyType_FromSpec(&PySideMetaFunctionType_spec); + static PyTypeObject *type = reinterpret_cast<PyTypeObject *>( + SbkType_FromSpec(&PySideMetaFunctionType_spec)); return type; } diff --git a/sources/pyside2/libpyside/pysideproperty.cpp b/sources/pyside2/libpyside/pysideproperty.cpp index d9d15eb3b..77dc6f3fc 100644 --- a/sources/pyside2/libpyside/pysideproperty.cpp +++ b/sources/pyside2/libpyside/pysideproperty.cpp @@ -61,6 +61,9 @@ static PyObject *qPropertyGetter(PyObject *, PyObject *); static int qpropertyTraverse(PyObject *self, visitproc visit, void *arg); static int qpropertyClear(PyObject *self); +// Attributes +static PyObject *qPropertyDocGet(PyObject *, void *); + static PyMethodDef PySidePropertyMethods[] = { {"setter", (PyCFunction)qPropertySetter, METH_O, 0}, {"write", (PyCFunction)qPropertySetter, METH_O, 0}, @@ -69,6 +72,11 @@ static PyMethodDef PySidePropertyMethods[] = { {0, 0, 0, 0} }; +static PyGetSetDef PySidePropertyType_getset[] = { + {"__doc__", qPropertyDocGet, nullptr, nullptr, nullptr}, + {nullptr, nullptr, nullptr, nullptr, nullptr} +}; + static PyType_Slot PySidePropertyType_slots[] = { {Py_tp_dealloc, (void *)qpropertyDeAlloc}, {Py_tp_call, (void *)qPropertyCall}, @@ -77,11 +85,12 @@ static PyType_Slot PySidePropertyType_slots[] = { {Py_tp_methods, (void *)PySidePropertyMethods}, {Py_tp_init, (void *)qpropertyTpInit}, {Py_tp_new, (void *)qpropertyTpNew}, + {Py_tp_getset, PySidePropertyType_getset}, {0, 0} }; -// Dotted modulename is crucial for PyType_FromSpec to work. Is this name right? +// Dotted modulename is crucial for SbkType_FromSpec to work. Is this name right? static PyType_Spec PySidePropertyType_spec = { - "PySide2.QtCore.Property", + "2:PySide2.QtCore.Property", sizeof(PySideProperty), 0, Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE, @@ -91,9 +100,8 @@ static PyType_Spec PySidePropertyType_spec = { PyTypeObject *PySidePropertyTypeF(void) { - static PyTypeObject *type = nullptr; - if (!type) - type = (PyTypeObject *)PyType_FromSpec(&PySidePropertyType_spec); + static PyTypeObject *type = reinterpret_cast<PyTypeObject *>( + SbkType_FromSpec(&PySidePropertyType_spec)); return type; } @@ -177,12 +185,10 @@ int qpropertyTpInit(PyObject *self, PyObject *args, PyObject *kwds) return -1; } - if (doc) { + if (doc) pData->doc = doc; - free(doc); - } else { + else pData->doc.clear(); - } pData->typeName = PySide::Signal::getTypeName(type); @@ -210,6 +216,11 @@ int qpropertyTpInit(PyObject *self, PyObject *args, PyObject *kwds) void qpropertyDeAlloc(PyObject *self) { qpropertyClear(self); + if (PepRuntime_38_flag) { + // PYSIDE-939: Handling references correctly. + // This was not needed before Python 3.8 (Python issue 35810) + Py_DECREF(Py_TYPE(self)); + } Py_TYPE(self)->tp_free(self); } @@ -262,6 +273,24 @@ PyObject *qPropertyGetter(PyObject *self, PyObject *callback) return nullptr; } +static PyObject *qPropertyDocGet(PyObject *self, void *) +{ + auto data = reinterpret_cast<PySideProperty *>(self); + PySidePropertyPrivate *pData = data->d; + + QByteArray doc(pData->doc); + if (!doc.isEmpty()) { +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_FromString(doc); +#else + return PyString_FromString(doc); +#endif + } + Py_INCREF(Py_None); + return Py_None; +} + + static int qpropertyTraverse(PyObject *self, visitproc visit, void *arg) { PySidePropertyPrivate *data = reinterpret_cast<PySideProperty *>(self)->d; diff --git a/sources/pyside2/libpyside/pysideqflags.cpp b/sources/pyside2/libpyside/pysideqflags.cpp index fd0ed005f..d7e6b4f4c 100644 --- a/sources/pyside2/libpyside/pysideqflags.cpp +++ b/sources/pyside2/libpyside/pysideqflags.cpp @@ -86,6 +86,11 @@ extern "C" { return PyLong_AsLong(number); } + static PyObject *qflag_int(PyObject *self) + { + return PyLong_FromLong(reinterpret_cast<PySideQFlagsObject*>(self)->ob_value); + } + PyObject *PySideQFlagsRichCompare(PyObject *self, PyObject *other, int op) { int result = 0; @@ -146,13 +151,14 @@ namespace QFlags {Py_nb_and, 0}, {Py_nb_xor, 0}, {Py_nb_or, 0}, - {Py_nb_int, 0}, + {Py_nb_int, reinterpret_cast<void*>(qflag_int)}, + {Py_nb_index, reinterpret_cast<void*>(qflag_int)}, #ifndef IS_PY3K {Py_nb_long, 0}, #endif {Py_tp_new, (void *)PySideQFlagsNew}, {Py_tp_richcompare, (void *)PySideQFlagsRichCompare}, - {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_dealloc, (void *)Sbk_object_dealloc}, {0, 0} }; static PyType_Spec SbkNewQFlagsType_spec = { @@ -168,7 +174,7 @@ namespace QFlags char qualname[200]; // PYSIDE-747: Here we insert now the full class name. strcpy(qualname, name); - // Careful: PyType_FromSpec does not allocate the string. + // Careful: SbkType_FromSpec does not allocate the string. PyType_Spec *newspec = new PyType_Spec; newspec->name = strdup(qualname); newspec->basicsize = SbkNewQFlagsType_spec.basicsize; @@ -180,7 +186,7 @@ namespace QFlags SbkNewQFlagsType_slots[idx].pfunc = numberMethods[idx].pfunc; } newspec->slots = SbkNewQFlagsType_spec.slots; - PyTypeObject *type = (PyTypeObject *)PyType_FromSpec(newspec); + PyTypeObject *type = (PyTypeObject *)SbkType_FromSpec(newspec); Py_TYPE(type) = &PyType_Type; PySideQFlagsType *flagsType = reinterpret_cast<PySideQFlagsType *>(type); diff --git a/sources/pyside2/libpyside/pysidesignal.cpp b/sources/pyside2/libpyside/pysidesignal.cpp index a09c17a24..0fa33254c 100644 --- a/sources/pyside2/libpyside/pysidesignal.cpp +++ b/sources/pyside2/libpyside/pysidesignal.cpp @@ -40,6 +40,7 @@ #include <sbkpython.h> #include "pysidesignal.h" #include "pysidesignal_p.h" +#include "pysidestaticstrings.h" #include "signalmanager.h" #include <shiboken.h> @@ -53,6 +54,7 @@ #include <utility> #define QT_SIGNAL_SENTINEL '2' +#define PyEnumMeta_Check(x) (strcmp(Py_TYPE(arg)->tp_name, "EnumMeta") == 0) namespace PySide { namespace Signal { @@ -109,13 +111,13 @@ static PyType_Slot PySideMetaSignalType_slots[] = { {Py_tp_methods, (void *)MetaSignal_methods}, {Py_tp_base, (void *)&PyType_Type}, {Py_tp_free, (void *)PyObject_GC_Del}, - {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_dealloc, (void *)Sbk_object_dealloc}, {0, 0} }; static PyType_Spec PySideMetaSignalType_spec = { - "PySide2.QtCore.MetaSignal", + "2:PySide2.QtCore.MetaSignal", 0, - // sizeof(PyHeapTypeObject) is filled in by PyType_FromSpecWithBases + // sizeof(PyHeapTypeObject) is filled in by SbkType_FromSpecWithBases // which calls PyType_Ready which calls inherit_special. 0, Py_TPFLAGS_DEFAULT, @@ -128,7 +130,7 @@ PyTypeObject *PySideMetaSignalTypeF(void) static PyTypeObject *type = nullptr; if (!type) { PyObject *bases = Py_BuildValue("(O)", &PyType_Type); - type = (PyTypeObject *)PyType_FromSpecWithBases(&PySideMetaSignalType_spec, bases); + type = (PyTypeObject *)SbkType_FromSpecWithBases(&PySideMetaSignalType_spec, bases); Py_XDECREF(bases); } return type; @@ -141,11 +143,11 @@ static PyType_Slot PySideSignalType_slots[] = { {Py_tp_init, (void *)signalTpInit}, {Py_tp_new, (void *)PyType_GenericNew}, {Py_tp_free, (void *)signalFree}, - {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_dealloc, (void *)Sbk_object_dealloc}, {0, 0} }; static PyType_Spec PySideSignalType_spec = { - "PySide2.QtCore.Signal", + "2:PySide2.QtCore.Signal", sizeof(PySideSignal), 0, Py_TPFLAGS_DEFAULT, @@ -157,7 +159,7 @@ PyTypeObject *PySideSignalTypeF(void) { static PyTypeObject *type = nullptr; if (!type) { - type = (PyTypeObject *)PyType_FromSpec(&PySideSignalType_spec); + type = reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(&PySideSignalType_spec)); PyTypeObject *hold = Py_TYPE(type); Py_TYPE(type) = PySideMetaSignalTypeF(); Py_INCREF(Py_TYPE(type)); @@ -180,11 +182,11 @@ static PyType_Slot PySideSignalInstanceType_slots[] = { {Py_tp_methods, (void *)SignalInstance_methods}, {Py_tp_new, (void *)PyType_GenericNew}, {Py_tp_free, (void *)signalInstanceFree}, - {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_dealloc, (void *)Sbk_object_dealloc}, {0, 0} }; static PyType_Spec PySideSignalInstanceType_spec = { - "PySide2.QtCore.SignalInstance", + "2:PySide2.QtCore.SignalInstance", sizeof(PySideSignalInstance), 0, Py_TPFLAGS_DEFAULT, @@ -195,7 +197,7 @@ static PyType_Spec PySideSignalInstanceType_spec = { PyTypeObject *PySideSignalInstanceTypeF(void) { static PyTypeObject *type = - (PyTypeObject *)PyType_FromSpec(&PySideSignalInstanceType_spec); + reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(&PySideSignalInstanceType_spec)); return type; } @@ -240,7 +242,7 @@ int signalTpInit(PyObject *self, PyObject *args, PyObject *kwds) for (Py_ssize_t i = 0, i_max = PyTuple_Size(args); i < i_max; i++) { PyObject *arg = PyTuple_GET_ITEM(args, i); - if (PySequence_Check(arg) && !Shiboken::String::check(arg)) { + if (PySequence_Check(arg) && !Shiboken::String::check(arg) && !PyEnumMeta_Check(arg)) { tupledArgs = true; const auto sig = PySide::Signal::parseSignature(arg); PySide::Signal::appendSignature( @@ -412,7 +414,8 @@ PyObject *signalInstanceConnect(PyObject *self, PyObject *args, PyObject *kwds) if (match) { Shiboken::AutoDecRef tupleArgs(PyList_AsTuple(pyArgs)); - Shiboken::AutoDecRef pyMethod(PyObject_GetAttrString(source->d->source, "connect")); + Shiboken::AutoDecRef pyMethod(PyObject_GetAttr(source->d->source, + PySide::PyName::qtConnect())); if (pyMethod.isNull()) { // PYSIDE-79: check if pyMethod exists. PyErr_SetString(PyExc_RuntimeError, "method 'connect' vanished!"); return 0; @@ -465,7 +468,8 @@ PyObject *signalInstanceEmit(PyObject *self, PyObject *args) for (Py_ssize_t i = 0, max = PyTuple_Size(args); i < max; i++) PyList_Append(pyArgs, PyTuple_GetItem(args, i)); - Shiboken::AutoDecRef pyMethod(PyObject_GetAttrString(source->d->source, "emit")); + Shiboken::AutoDecRef pyMethod(PyObject_GetAttr(source->d->source, + PySide::PyName::qtEmit())); Shiboken::AutoDecRef tupleArgs(PyList_AsTuple(pyArgs)); return PyObject_CallObject(pyMethod, tupleArgs); @@ -530,7 +534,8 @@ PyObject *signalInstanceDisconnect(PyObject *self, PyObject *args) if (match) { Shiboken::AutoDecRef tupleArgs(PyList_AsTuple(pyArgs)); - Shiboken::AutoDecRef pyMethod(PyObject_GetAttrString(source->d->source, "disconnect")); + Shiboken::AutoDecRef pyMethod(PyObject_GetAttr(source->d->source, + PySide::PyName::qtDisconnect())); PyObject *result = PyObject_CallObject(pyMethod, tupleArgs); if (!result || result == Py_True) return result; @@ -615,7 +620,7 @@ void init(PyObject *module) { if (SbkSpecial_Type_Ready(module, PySideMetaSignalTypeF(), MetaSignal_SignatureStrings) < 0) return; - Py_INCREF(PySideSignalTypeF()); + Py_INCREF(PySideMetaSignalTypeF()); PyModule_AddObject(module, "MetaSignal", reinterpret_cast<PyObject *>(PySideMetaSignalTypeF())); if (SbkSpecial_Type_Ready(module, PySideSignalTypeF(), Signal_SignatureStrings) < 0) @@ -756,7 +761,8 @@ void instanceInitialize(PySideSignalInstance *self, PyObject *name, PySideSignal bool connect(PyObject *source, const char *signal, PyObject *callback) { - Shiboken::AutoDecRef pyMethod(PyObject_GetAttrString(source, "connect")); + Shiboken::AutoDecRef pyMethod(PyObject_GetAttr(source, + PySide::PyName::qtConnect())); if (pyMethod.isNull()) return false; diff --git a/sources/pyside2/libpyside/pysideslot.cpp b/sources/pyside2/libpyside/pysideslot.cpp index 204253aa2..e60115450 100644 --- a/sources/pyside2/libpyside/pysideslot.cpp +++ b/sources/pyside2/libpyside/pysideslot.cpp @@ -71,11 +71,11 @@ static PyType_Slot PySideSlotType_slots[] = { {Py_tp_call, (void *)slotCall}, {Py_tp_init, (void *)slotTpInit}, {Py_tp_new, (void *)PyType_GenericNew}, - {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_dealloc, (void *)Sbk_object_dealloc}, {0, 0} }; static PyType_Spec PySideSlotType_spec = { - "PySide2.QtCore.Slot", + "2:PySide2.QtCore.Slot", sizeof(PySideSlot), 0, Py_TPFLAGS_DEFAULT, @@ -85,9 +85,8 @@ static PyType_Spec PySideSlotType_spec = { static PyTypeObject *PySideSlotTypeF(void) { - static PyTypeObject *type = nullptr; - if (!type) - type = (PyTypeObject *)PyType_FromSpec(&PySideSlotType_spec); + static PyTypeObject *type = reinterpret_cast<PyTypeObject *>( + SbkType_FromSpec(&PySideSlotType_spec)); return type; } diff --git a/sources/pyside2/libpyside/pysidestaticstrings.cpp b/sources/pyside2/libpyside/pysidestaticstrings.cpp new file mode 100644 index 000000000..82e233621 --- /dev/null +++ b/sources/pyside2/libpyside/pysidestaticstrings.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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 "pysidestaticstrings.h" +#include <sbkstring.h> + +#define STATIC_STRING_IMPL(funcName, value) \ +PyObject *funcName() \ +{ \ + static PyObject *const s = Shiboken::String::createStaticString(value); \ + return s; \ +} + +namespace PySide +{ +namespace PyName +{ +STATIC_STRING_IMPL(qtStaticMetaObject, "staticMetaObject") +STATIC_STRING_IMPL(qtConnect, "connect") +STATIC_STRING_IMPL(qtDisconnect, "disconnect") +STATIC_STRING_IMPL(qtEmit, "emit") +} // namespace PyName +} // namespace PySide diff --git a/sources/pyside2/libpyside/pysidestaticstrings.h b/sources/pyside2/libpyside/pysidestaticstrings.h new file mode 100644 index 000000000..1d5700c51 --- /dev/null +++ b/sources/pyside2/libpyside/pysidestaticstrings.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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$ +** +****************************************************************************/ + +#ifndef PYSIDESTRINGS_H +#define PYSIDESTRINGS_H + +#include <sbkpython.h> + +namespace PySide +{ +namespace PyName +{ +PyObject *qtStaticMetaObject(); +PyObject *qtConnect(); +PyObject *qtDisconnect(); +PyObject *qtEmit(); +} // namespace PyName +} // namespace PySide + +#endif // PYSIDESTRINGS_H diff --git a/sources/pyside2/libpyside/pysideweakref.cpp b/sources/pyside2/libpyside/pysideweakref.cpp index 2b27f9545..cd90634bd 100644 --- a/sources/pyside2/libpyside/pysideweakref.cpp +++ b/sources/pyside2/libpyside/pysideweakref.cpp @@ -53,11 +53,11 @@ static PyObject *CallableObject_call(PyObject *callable_object, PyObject *args, static PyType_Slot PySideCallableObjectType_slots[] = { {Py_tp_call, (void *)CallableObject_call}, - {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_dealloc, (void *)Sbk_object_dealloc}, {0, 0} }; static PyType_Spec PySideCallableObjectType_spec = { - const_cast<char *>("PySide.Callable"), + "1:PySide.Callable", sizeof(PySideCallableObject), 0, Py_TPFLAGS_DEFAULT, @@ -68,7 +68,7 @@ static PyType_Spec PySideCallableObjectType_spec = { static PyTypeObject *PySideCallableObjectTypeF() { static PyTypeObject *type = - (PyTypeObject *)PyType_FromSpec(&PySideCallableObjectType_spec); + reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(&PySideCallableObjectType_spec)); return type; } @@ -94,7 +94,8 @@ PyObject *create(PyObject *obj, PySideWeakRefFunction func, void *userData) PyType_Ready(PySideCallableObjectTypeF()); } - PySideCallableObject *callable = PyObject_New(PySideCallableObject, PySideCallableObjectTypeF()); + PyTypeObject *type = PySideCallableObjectTypeF(); + PySideCallableObject *callable = PyObject_New(PySideCallableObject, type); if (!callable || PyErr_Occurred()) return 0; diff --git a/sources/pyside2/libpyside/signalmanager.cpp b/sources/pyside2/libpyside/signalmanager.cpp index 0895cc682..8e8cc9f02 100644 --- a/sources/pyside2/libpyside/signalmanager.cpp +++ b/sources/pyside2/libpyside/signalmanager.cpp @@ -53,6 +53,7 @@ #include <gilstate.h> #include <sbkconverter.h> #include <sbkstring.h> +#include <sbkstaticstrings.h> #include <QtCore/QDebug> #include <QtCore/QHash> @@ -77,8 +78,6 @@ #define PYSIDE_SIGNAL '2' #include "globalreceiverv2.h" -#define PYTHON_TYPE "PyObject" - namespace { static PyObject *metaObjectAttr = 0; @@ -115,18 +114,24 @@ namespace PySide { PyObjectWrapper::PyObjectWrapper() :m_me(Py_None) { + // PYSIDE-813: When PYSIDE-164 was solved by adding some thread allowance, + // this code was no longer protected. It was hard to find this connection. + // See the website https://bugreports.qt.io/browse/PYSIDE-813 for details. + Shiboken::GilState gil; Py_XINCREF(m_me); } PyObjectWrapper::PyObjectWrapper(PyObject *me) : m_me(me) { + Shiboken::GilState gil; Py_XINCREF(m_me); } PyObjectWrapper::PyObjectWrapper(const PyObjectWrapper &other) : m_me(other.m_me) { + Shiboken::GilState gil; Py_XINCREF(m_me); } @@ -143,6 +148,7 @@ PyObjectWrapper::~PyObjectWrapper() void PyObjectWrapper::reset(PyObject *o) { + Shiboken::GilState gil; Py_XINCREF(o); Py_XDECREF(m_me); m_me = o; @@ -171,7 +177,7 @@ QDataStream &operator<<(QDataStream &out, const PyObjectWrapper &myObj) Shiboken::GilState gil; if (!reduce_func) { Shiboken::AutoDecRef pickleModule(PyImport_ImportModule("pickle")); - reduce_func = PyObject_GetAttrString(pickleModule, "dumps"); + reduce_func = PyObject_GetAttr(pickleModule, Shiboken::PyName::dumps()); } Shiboken::AutoDecRef repr(PyObject_CallFunctionObjArgs(reduce_func, (PyObject *)myObj, NULL)); if (repr.object()) { @@ -202,7 +208,7 @@ QDataStream &operator>>(QDataStream &in, PyObjectWrapper &myObj) Shiboken::GilState gil; if (!eval_func) { Shiboken::AutoDecRef pickleModule(PyImport_ImportModule("pickle")); - eval_func = PyObject_GetAttrString(pickleModule, "loads"); + eval_func = PyObject_GetAttr(pickleModule, Shiboken::PyName::loads()); } QByteArray repr; @@ -268,15 +274,15 @@ SignalManager::SignalManager() : m_d(new SignalManagerPrivate) using namespace Shiboken; // Register PyObject type to use in queued signal and slot connections - qRegisterMetaType<PyObjectWrapper>(PYTHON_TYPE); - qRegisterMetaTypeStreamOperators<PyObjectWrapper>(PYTHON_TYPE); + qRegisterMetaType<PyObjectWrapper>("PyObject"); + qRegisterMetaTypeStreamOperators<PyObjectWrapper>("PyObject"); qRegisterMetaTypeStreamOperators<PyObjectWrapper>("PyObjectWrapper"); qRegisterMetaTypeStreamOperators<PyObjectWrapper>("PySide::PyObjectWrapper"); SbkConverter *converter = Shiboken::Conversions::createConverter(&PyBaseObject_Type, nullptr); Shiboken::Conversions::setCppPointerToPythonFunction(converter, PyObject_PTR_CppToPython_PyObject); Shiboken::Conversions::setPythonToCppPointerFunctions(converter, PyObject_PythonToCpp_PyObject_PTR, is_PyObject_PythonToCpp_PyObject_PTR_Convertible); - Shiboken::Conversions::registerConverterName(converter, PYTHON_TYPE); + Shiboken::Conversions::registerConverterName(converter, "PyObject"); Shiboken::Conversions::registerConverterName(converter, "object"); Shiboken::Conversions::registerConverterName(converter, "PyObjectWrapper"); Shiboken::Conversions::registerConverterName(converter, "PySide::PyObjectWrapper"); @@ -551,10 +557,19 @@ bool SignalManager::registerMetaMethod(QObject *source, const char *signature, Q static MetaObjectBuilder *metaBuilderFromDict(PyObject *dict) { + // PYSIDE-803: The dict in this function is the ob_dict of an SbkObject. + // The "metaObjectAttr" entry is only handled in this file. There is no + // way in this function to involve the interpreter. Therefore, we need + // no GIL. + // Note that "SignalManager::registerMetaMethodGetIndex" has write actions + // that might involve the interpreter, but in that context the GIL is held. if (!dict || !PyDict_Contains(dict, metaObjectAttr)) return nullptr; - PyObject *pyBuilder = PyDict_GetItem(dict, metaObjectAttr); + // PYSIDE-813: The above assumption is not true in debug mode: + // PyDict_GetItem would touch PyThreadState_GET and the global error state. + // PyDict_GetItemWithError instead can work without GIL. + PyObject *pyBuilder = PyDict_GetItemWithError(dict, metaObjectAttr); #ifdef IS_PY3K return reinterpret_cast<MetaObjectBuilder *>(PyCapsule_GetPointer(pyBuilder, nullptr)); #else @@ -606,7 +621,14 @@ int SignalManager::registerMetaMethodGetIndex(QObject *source, const char *signa const QMetaObject *SignalManager::retrieveMetaObject(PyObject *self) { - Shiboken::GilState gil; + // PYSIDE-803: Avoid the GIL in SignalManager::retrieveMetaObject + // This function had the GIL. We do not use the GIL unless we have to. + // metaBuilderFromDict accesses a Python dict, but in that context there + // is no way to reach the interpreter, see "metaBuilderFromDict". + // + // The update function is MetaObjectBuilderPrivate::update in + // dynamicmetaobject.c . That function now uses the GIL when the + // m_dirty flag is set. Q_ASSERT(self); MetaObjectBuilder *builder = metaBuilderFromDict(reinterpret_cast<SbkObject *>(self)->ob_dict); diff --git a/sources/pyside2/libpyside/signalmanager.h b/sources/pyside2/libpyside/signalmanager.h index 229ddb91d..fe077bd1a 100644 --- a/sources/pyside2/libpyside/signalmanager.h +++ b/sources/pyside2/libpyside/signalmanager.h @@ -43,6 +43,7 @@ #include "pysidemacros.h" #include <sbkpython.h> +#include <shibokenmacros.h> #include <QtCore/QMetaMethod> |