diff options
Diffstat (limited to 'sources/pyside2/libpyside/pyside.cpp')
-rw-r--r-- | sources/pyside2/libpyside/pyside.cpp | 616 |
1 files changed, 0 insertions, 616 deletions
diff --git a/sources/pyside2/libpyside/pyside.cpp b/sources/pyside2/libpyside/pyside.cpp deleted file mode 100644 index 4995f35dd..000000000 --- a/sources/pyside2/libpyside/pyside.cpp +++ /dev/null @@ -1,616 +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 "pyside.h" -#include "pyside_p.h" -#include "signalmanager.h" -#include "pysideclassinfo_p.h" -#include "pysideproperty_p.h" -#include "pysideproperty.h" -#include "pysidesignal.h" -#include "pysidesignal_p.h" -#include "pysidestaticstrings.h" -#include "pysideslot_p.h" -#include "pysidemetafunction_p.h" -#include "pysidemetafunction.h" -#include "dynamicqmetaobject.h" - -#include <autodecref.h> -#include <basewrapper.h> -#include <bindingmanager.h> -#include <gilstate.h> -#include <sbkconverter.h> -#include <sbkstring.h> -#include <sbkstaticstrings.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 <cstring> -#include <cctype> -#include <typeinfo> - -static QStack<PySide::CleanupFunction> cleanupFunctionList; -static void *qobjectNextAddr; - -QT_BEGIN_NAMESPACE -extern bool qRegisterResourceData(int, const unsigned char *, const unsigned char *, - const unsigned char *); -QT_END_NAMESPACE - -namespace PySide -{ - -void init(PyObject *module) -{ - qobjectNextAddr = 0; - ClassInfo::init(module); - Signal::init(module); - Slot::init(module); - Property::init(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) -{ - QByteArray propName(Shiboken::String::toCString(name)); - propName[0] = std::toupper(propName[0]); - propName.prepend("set"); - - Shiboken::AutoDecRef propSetter(PyObject_GetAttrString(qObj, propName.constData())); - if (!propSetter.isNull()) { - *accept = true; - Shiboken::AutoDecRef args(PyTuple_Pack(1, value)); - Shiboken::AutoDecRef retval(PyObject_CallObject(propSetter, args)); - if (retval.isNull()) - return false; - } else { - PyErr_Clear(); - Shiboken::AutoDecRef attr(PyObject_GenericGetAttr(qObj, name)); - if (PySide::Property::checkType(attr)) { - *accept = true; - if (PySide::Property::setValue(reinterpret_cast<PySideProperty *>(attr.object()), qObj, value) < 0) - return false; - } - } - return true; -} - -bool fillQtProperties(PyObject *qObj, const QMetaObject *metaObj, PyObject *kwds, const char **blackList, unsigned int blackListSize) -{ - - PyObject *key, *value; - Py_ssize_t pos = 0; - - while (PyDict_Next(kwds, &pos, &key, &value)) { - if (!blackListSize || !std::binary_search(blackList, blackList + blackListSize, std::string(Shiboken::String::toCString(key)))) { - QByteArray propName(Shiboken::String::toCString(key)); - bool accept = false; - if (metaObj->indexOfProperty(propName) != -1) { - if (!_setProperty(qObj, key, value, &accept)) - return false; - } else { - propName.append("()"); - if (metaObj->indexOfSignal(propName) != -1) { - accept = true; - propName.prepend('2'); - if (!PySide::Signal::connect(qObj, propName, value)) - return false; - } - } - if (!accept) { - // PYSIDE-1019: Allow any existing attribute in the constructor. - if (!_setProperty(qObj, key, value, &accept)) - return false; - } - if (!accept) { - PyErr_Format(PyExc_AttributeError, "'%s' is not a Qt property or a signal", - propName.constData()); - return false; - } - } - } - return true; -} - -void registerCleanupFunction(CleanupFunction func) -{ - cleanupFunctionList.push(func); -} - -void runCleanupFunctions() -{ - while (!cleanupFunctionList.isEmpty()) { - CleanupFunction f = cleanupFunctionList.pop(); - f(); - } -} - -static void destructionVisitor(SbkObject *pyObj, void *data) -{ - auto realData = reinterpret_cast<void **>(data); - auto pyQApp = reinterpret_cast<SbkObject *>(realData[0]); - auto pyQObjectType = reinterpret_cast<PyTypeObject *>(realData[1]); - - if (pyObj != pyQApp && PyObject_TypeCheck(pyObj, pyQObjectType)) { - if (Shiboken::Object::hasOwnership(pyObj) && Shiboken::Object::isValid(pyObj, false)) { - Shiboken::Object::setValidCpp(pyObj, false); - - Py_BEGIN_ALLOW_THREADS - Shiboken::callCppDestructor<QObject>(Shiboken::Object::cppPointer(pyObj, pyQObjectType)); - Py_END_ALLOW_THREADS - } - } - -}; - -void destroyQCoreApplication() -{ - QCoreApplication *app = QCoreApplication::instance(); - if (!app) - return; - SignalManager::instance().clear(); - - Shiboken::BindingManager &bm = Shiboken::BindingManager::instance(); - SbkObject *pyQApp = bm.retrieveWrapper(app); - PyTypeObject *pyQObjectType = Shiboken::Conversions::getPythonTypeObject("QObject*"); - assert(pyQObjectType); - - void *data[2] = {pyQApp, pyQObjectType}; - bm.visitAllPyObjects(&destructionVisitor, &data); - - // in the end destroy app - // Allow threads because the destructor calls - // QThreadPool::globalInstance().waitForDone() which may deadlock on the GIL - // if there is a worker working with python objects. - Py_BEGIN_ALLOW_THREADS - delete app; - Py_END_ALLOW_THREADS - // PYSIDE-571: make sure to create a singleton deleted qApp. - Py_DECREF(MakeQAppWrapper(nullptr)); -} - -std::size_t getSizeOfQObject(SbkObjectType *type) -{ - return retrieveTypeUserData(type)->cppObjSize; -} - -void initDynamicMetaObject(SbkObjectType *type, const QMetaObject *base, std::size_t cppObjSize) -{ - //create DynamicMetaObject based on python type - 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 = const_cast<QMetaObject *>(userData->mo.update()); - static SbkConverter *converter = Shiboken::Conversions::getConverter("QMetaObject"); - if (!converter) - return; - Shiboken::AutoDecRef pyMetaObject(Shiboken::Conversions::pointerToPython(converter, metaObjectPtr)); - PyObject_SetAttr(reinterpret_cast<PyObject *>(type), - PySide::PyName::qtStaticMetaObject(), 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 initQObjectSubType(SbkObjectType *type, PyObject *args, PyObject * /* kwds */) -{ - PyTypeObject *qObjType = Shiboken::Conversions::getPythonTypeObject("QObject*"); - QByteArray className(Shiboken::String::toCString(PyTuple_GET_ITEM(args, 0))); - - PyObject *bases = PyTuple_GET_ITEM(args, 1); - int numBases = PyTuple_GET_SIZE(bases); - - TypeUserData *userData = nullptr; - - for (int i = 0; i < numBases; ++i) { - auto base = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(bases, i)); - if (PyType_IsSubtype(base, qObjType)) { - userData = retrieveTypeUserData(base); - break; - } - } - if (!userData) { - qWarning("Sub class of QObject not inheriting QObject!? Crash will happen when using %s.", className.constData()); - return; - } - 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); - if (!Shiboken::Object::isValid(reinterpret_cast<SbkObject *>(self), false)) - return attr; - - if (attr && Property::checkType(attr)) { - PyObject *value = Property::getValue(reinterpret_cast<PySideProperty *>(attr), self); - Py_DECREF(attr); - if (!value) - return 0; - attr = value; - } - - //mutate native signals to signal instance type - if (attr && PyObject_TypeCheck(attr, PySideSignalTypeF())) { - PyObject *signal = reinterpret_cast<PyObject *>(Signal::initialize(reinterpret_cast<PySideSignal *>(attr), name, self)); - PyObject_SetAttr(self, name, reinterpret_cast<PyObject *>(signal)); - return signal; - } - - //search on metaobject (avoid internal attributes started with '__') - if (!attr) { - const char *cname = Shiboken::String::toCString(name); - uint cnameLen = qstrlen(cname); - if (std::strncmp("__", cname, 2)) { - const QMetaObject *metaObject = cppSelf->metaObject(); - //signal - QList<QMetaMethod> signalList; - for(int i=0, i_max = metaObject->methodCount(); i < i_max; i++) { - QMetaMethod method = metaObject->method(i); - const QByteArray methSig_ = method.methodSignature(); - const char *methSig = methSig_.constData(); - bool methMacth = !std::strncmp(cname, methSig, cnameLen) && methSig[cnameLen] == '('; - if (methMacth) { - if (method.methodType() == QMetaMethod::Signal) { - signalList.append(method); - } else { - PySideMetaFunction *func = MetaFunction::newObject(cppSelf, i); - if (func) { - PyObject *result = reinterpret_cast<PyObject *>(func); - PyObject_SetAttr(self, name, result); - return result; - } - } - } - } - if (!signalList.empty()) { - PyObject *pySignal = reinterpret_cast<PyObject *>(Signal::newObjectFromMethod(self, signalList)); - PyObject_SetAttr(self, name, pySignal); - return pySignal; - } - } - } - return attr; -} - -bool inherits(PyTypeObject *objType, const char *class_name) -{ - if (strcmp(objType->tp_name, class_name) == 0) - return true; - - PyTypeObject *base = objType->tp_base; - if (base == 0) - return false; - - return inherits(base, class_name); -} - -void *nextQObjectMemoryAddr() -{ - return qobjectNextAddr; -} - -void setNextQObjectMemoryAddr(void *addr) -{ - qobjectNextAddr = addr; -} - -} // namespace PySide - -// A QSharedPointer is used with a deletion function to invalidate a pointer -// when the property value is cleared. This should be a QSharedPointer with -// a void *pointer, but that isn't allowed -typedef char any_t; -Q_DECLARE_METATYPE(QSharedPointer<any_t>); - -namespace PySide -{ - -static void invalidatePtr(any_t *object) -{ - Shiboken::GilState state; - - SbkObject *wrapper = Shiboken::BindingManager::instance().retrieveWrapper(object); - if (wrapper != NULL) - Shiboken::BindingManager::instance().releaseWrapper(wrapper); -} - -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)); - if (pyOut) { - Py_INCREF(pyOut); - return pyOut; - } - - // Setting the property will trigger an QEvent notification, which may call into - // code that creates the wrapper so only set the property if it isn't already - // 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(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) { - Py_INCREF(pyOut); - return pyOut; - } - } - - pyOut = Shiboken::Object::newObject(sbk_type, cppSelf, false, false, typeName(cppSelf)); - - return pyOut; -} - -#ifdef PYSIDE_QML_SUPPORT -static QuickRegisterItemFunction quickRegisterItem; - -QuickRegisterItemFunction getQuickRegisterItemFunction() -{ - return quickRegisterItem; -} - -void setQuickRegisterItemFunction(QuickRegisterItemFunction function) -{ - quickRegisterItem = function; -} -#endif // PYSIDE_QML_SUPPORT - -// Inspired by Shiboken::String::toCString; -QString pyStringToQString(PyObject *str) { - if (str == Py_None) - return QString(); - - if (PyUnicode_Check(str)) { - const char *unicodeBuffer = _PepUnicode_AsString(str); - if (unicodeBuffer) - return QString::fromUtf8(unicodeBuffer); - } - if (PyBytes_Check(str)) { - const char *asciiBuffer = PyBytes_AS_STRING(str); - if (asciiBuffer) - return QString::fromLatin1(asciiBuffer); - } - return QString(); -} - -static const unsigned char qt_resource_name[] = { - // qt - 0x0,0x2, - 0x0,0x0,0x7,0x84, - 0x0,0x71, - 0x0,0x74, - // etc - 0x0,0x3, - 0x0,0x0,0x6c,0xa3, - 0x0,0x65, - 0x0,0x74,0x0,0x63, - // qt.conf - 0x0,0x7, - 0x8,0x74,0xa6,0xa6, - 0x0,0x71, - 0x0,0x74,0x0,0x2e,0x0,0x63,0x0,0x6f,0x0,0x6e,0x0,0x66 -}; - -static const unsigned char qt_resource_struct[] = { - // : - 0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1, - // :/qt - 0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x2, - // :/qt/etc - 0x0,0x0,0x0,0xa,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x3, - // :/qt/etc/qt.conf - 0x0,0x0,0x0,0x16,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0 -}; - -bool registerInternalQtConf() -{ - // Guard to ensure single registration. -#ifdef PYSIDE_QT_CONF_PREFIX - static bool registrationAttempted = false; -#else - static bool registrationAttempted = true; -#endif - static bool isRegistered = false; - if (registrationAttempted) - return isRegistered; - registrationAttempted = true; - - // Support PyInstaller case when a qt.conf file might be provided next to the generated - // PyInstaller executable. - // This will disable the internal qt.conf which points to the PySide2 subdirectory (due to the - // subdirectory not existing anymore). - QString executablePath = - QString::fromWCharArray(Py_GetProgramFullPath()); - QString appDirPath = QFileInfo(executablePath).absolutePath(); - QString maybeQtConfPath = QDir(appDirPath).filePath(QStringLiteral("qt.conf")); - bool executableQtConfAvailable = QFileInfo::exists(maybeQtConfPath); - maybeQtConfPath = QDir::toNativeSeparators(maybeQtConfPath); - - // Allow disabling the usage of the internal qt.conf. This is necessary for tests to work, - // because tests are executed before the package is installed, and thus the Prefix specified - // in qt.conf would point to a not yet existing location. - bool disableInternalQtConf = - qEnvironmentVariableIntValue("PYSIDE_DISABLE_INTERNAL_QT_CONF") > 0 ? true : false; - if (disableInternalQtConf || executableQtConfAvailable) { - registrationAttempted = true; - return false; - } - - PyObject *pysideModule = PyImport_ImportModule("PySide2"); - if (!pysideModule) - return false; - - // 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_GetAttr(pysideModule, Shiboken::PyMagicName::file()); - Py_DECREF(pysideModule); - if (!pysideInitFilePath) - return false; - - QString initPath = pyStringToQString(pysideInitFilePath); - Py_DECREF(pysideInitFilePath); - if (initPath.isEmpty()) - return false; - - // pysideDir - absolute path to the directory containing the init file, which also contains - // the rest of the PySide2 modules. - // prefixPath - absolute path to the directory containing the installed Qt (prefix). - QDir pysideDir = QFileInfo(QDir::fromNativeSeparators(initPath)).absoluteDir(); - QString setupPrefix; -#ifdef PYSIDE_QT_CONF_PREFIX - setupPrefix = QStringLiteral(PYSIDE_QT_CONF_PREFIX); -#endif - const QString prefixPathStr = pysideDir.absoluteFilePath(setupPrefix); -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - const QByteArray prefixPath = prefixPathStr.toLocal8Bit(); -#else - // PYSIDE-972, QSettings used by QtCore uses Latin1 - const QByteArray prefixPath = prefixPathStr.toLatin1(); -#endif - - // rccData needs to be static, otherwise when it goes out of scope, the Qt resource system - // will point to invalid memory. - static QByteArray rccData = QByteArrayLiteral("[Paths]\nPrefix = ") + prefixPath -#ifdef Q_OS_WIN - // LibraryExecutables needs to point to Prefix instead of ./bin because we don't - // currently conform to the Qt default directory layout on Windows. This is necessary - // for QtWebEngineCore to find the location of QtWebEngineProcess.exe. - + QByteArray("\nLibraryExecutables = ") + prefixPath -#endif - ; - rccData.append('\n'); - - // The RCC data structure expects a 4-byte size value representing the actual data. - int size = rccData.size(); - - for (int i = 0; i < 4; ++i) { - rccData.prepend((size & 0xff)); - size >>= 8; - } - - const int version = 0x01; - isRegistered = qRegisterResourceData(version, qt_resource_struct, qt_resource_name, - reinterpret_cast<const unsigned char *>( - rccData.constData())); - - return isRegistered; -} - - - -} //namespace PySide - |