diff --git a/CMakeLists.txt b/CMakeLists.txt index 9aff656..12efdf8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ LIST(APPEND CMAKE_PREFIX_PATH ${QT_ROOT}/lib/cmake) FILE(GLOB_RECURSE PYTHON_ROOT ${DEPENDENCIES_DIR}/Python*/pyconfig.h.in) GET_FILENAME_COMPONENT(PYTHON_ROOT ${PYTHON_ROOT} DIRECTORY) -FILE(GLOB_RECURSE SIP_ROOT ${DEPENDENCIES_DIR}/sip*/siplib/sip.h) +FILE(GLOB_RECURSE SIP_ROOT ${DEPENDENCIES_DIR}/sip-*/siplib/sip.h) GET_FILENAME_COMPONENT(SIP_ROOT ${SIP_ROOT} DIRECTORY) # need to install python diff --git a/src/runner/CMakeLists.txt b/src/runner/CMakeLists.txt index 8750dd7..0b5194d 100644 --- a/src/runner/CMakeLists.txt +++ b/src/runner/CMakeLists.txt @@ -13,6 +13,7 @@ FILE(GLOB ${PROJ_NAME}_HDRS *.h) SET(CMAKE_INCLUDE_CURRENT_DIR ON) SET(CMAKE_AUTOMOC ON) SET(CMAKE_AUTOUIC ON) +ADD_DEFINITIONS(-DQT_NO_KEYWORDS) FIND_PACKAGE(Qt5Widgets REQUIRED) #QT5_WRAP_UI(${PROJ_NAME}_UIHDRS ${${PROJ_NAME}_FORMS}) FIND_PACKAGE(Qt5LinguistTools) diff --git a/src/runner/proxypluginwrappers.h b/src/runner/proxypluginwrappers.h index 974fa7a..61a8bae 100644 --- a/src/runner/proxypluginwrappers.h +++ b/src/runner/proxypluginwrappers.h @@ -202,7 +202,7 @@ public: virtual QIcon icon() const; virtual void setParentWidget(QWidget *parent); -public slots: +public Q_SLOTS: virtual void display() const; }; diff --git a/src/runner/pythonrunner.cpp b/src/runner/pythonrunner.cpp index ac68828..df606a3 100644 --- a/src/runner/pythonrunner.cpp +++ b/src/runner/pythonrunner.cpp @@ -48,7 +48,7 @@ private: private: std::map m_PythonObjects; const MOBase::IOrganizer *m_MOInfo; - char *m_PythonHome; + wchar_t *m_PythonHome; }; @@ -69,13 +69,14 @@ using namespace MOBase; namespace bpy = boost::python; +static sipWrapperType sipWrapper_Type; struct QString_to_python_str { static PyObject *convert(const QString &str) { // It's safer to explicitly convert to unicode as if we don't, this can return either str or unicode without it being easy to know which to expect bpy::object pyStr = bpy::object(str.toUtf8().constData()); - if (PyString_Check(pyStr.ptr())) + if (SIPBytes_Check(pyStr.ptr())) pyStr = pyStr.attr("decode")("utf-8"); return bpy::incref(pyStr.ptr()); } @@ -97,14 +98,14 @@ struct QString_from_python_str } static void *convertible(PyObject *objPtr) { - return PyString_Check(objPtr) || PyUnicode_Check(objPtr) ? objPtr : nullptr; + return SIPBytes_Check(objPtr) || PyUnicode_Check(objPtr) ? objPtr : nullptr; } static void construct(PyObject *objPtr, bpy::converter::rvalue_from_python_stage1_data *data) { // Ensure the string uses 8-bit characters PyObject *strPtr = PyUnicode_Check(objPtr) ? PyUnicode_AsUTF8String(objPtr) : objPtr; // Extract the character data from the python string - const char* value = PyString_AsString(strPtr); + const char* value = SIPBytes_AsString(strPtr); // Deallocate local copy if one was made if (strPtr != objPtr) Py_DecRef(strPtr); @@ -225,7 +226,7 @@ struct QVariant_to_python_obj { static PyObject *convert(const QVariant &var) { switch (var.type()) { - case QVariant::Int: return PyLong_FromLong(var.toInt()); + case QVariant::Int: return SIPLong_FromLong(var.toInt()); case QVariant::UInt: return PyLong_FromUnsignedLong(var.toUInt()); case QVariant::Bool: return PyBool_FromLong(var.toBool()); case QVariant::String: return bpy::incref(bpy::object(var.toString()).ptr()); @@ -251,7 +252,7 @@ struct QVariant_from_python_obj } static void *convertible(PyObject *objPtr) { - if (!PyString_Check(objPtr) && !PyInt_Check(objPtr) && + if (!SIPBytes_Check(objPtr) && !PyLong_Check(objPtr) && !PyBool_Check(objPtr) && !PyList_Check(objPtr)) { return nullptr; } @@ -268,17 +269,17 @@ struct QVariant_from_python_obj } static void construct(PyObject *objPtr, bpy::converter::rvalue_from_python_stage1_data *data) { - // PyBools will also return true for PyInt_Check but not the other way around, so the order + // PyBools will also return true for SIPLong_Check but not the other way around, so the order // here is relevant if (PyList_Check(objPtr)) { constructVariant(bpy::extract(objPtr)(), data); } else if (PyDict_Check(objPtr)) { constructVariant(bpy::extract(objPtr)(), data); - } else if (PyString_Check(objPtr) || PyUnicode_Check(objPtr)) { + } else if (SIPBytes_Check(objPtr) || PyUnicode_Check(objPtr)) { constructVariant(bpy::extract(objPtr)(), data); } else if (PyBool_Check(objPtr)) { constructVariant(bpy::extract(objPtr)(), data); - } else if (PyInt_Check(objPtr)) { + } else if (SIPLong_Check(objPtr)) { //QVariant doesn't have long. It has int or long long. Given that on m/s, //long is 32 bits for 32- and 64- bit code... constructVariant(bpy::extract(objPtr)(), data); @@ -399,11 +400,11 @@ struct QFlags_from_python_obj } static void* convertible(PyObject *objPtr) { - return PyInt_Check(objPtr) ? objPtr : nullptr; + return SIPLong_Check(objPtr) ? objPtr : nullptr; } static void construct(PyObject *objPtr, bpy::converter::rvalue_from_python_stage1_data *data) { - int intVersion = (int)PyInt_AsLong(objPtr); + int intVersion = (int)SIPLong_AsLong(objPtr); T tVersion = (T)intVersion; void *storage = ((bpy::converter::rvalue_from_python_storage> *)data)->storage.bytes; new (storage) QFlags(tVersion); @@ -558,7 +559,22 @@ struct QClass_converters static void *QClass_from_PyQt(PyObject *objPtr) { - if (!PyObject_TypeCheck(objPtr, sipAPI()->api_simplewrapper_type)) { + // This would transfer responsibility for deconstructing the object to C++, but Boost assumes l-value converters (such as this) don't do that + // Instead, this should be called within the wrappers for functions which return deletable pointers. + //sipAPI()->api_transfer_to(objPtr, 0); + /*if (PyObject_TypeCheck(objPtr, sipAPI()->api_wrapper_type)) { + sipWrapper *wrapper; + wrapper = reinterpret_cast(objPtr); + return wrapper->super.data; + } else if (PyObject_TypeCheck(objPtr, sipAPI()->api_simplewrapper_type)) {*/ + sipSimpleWrapper *wrapper; + wrapper = reinterpret_cast(objPtr); + return wrapper->data; + /*} else if (PyObject_TypeCheck(objPtr, sipAPI()->api_wrappertype_type)) { + sipWrapper *wrapper; + wrapper = reinterpret_cast(objPtr); + return wrapper->super.data; + } else { if (std::is_same_v) { // QStringLists aren't wrapped by PyQt - regular Python string/unicode lists are used instead @@ -566,17 +582,13 @@ struct QClass_converters if (extractor.check()) return new QStringList(extractor()); } - PyErr_SetString(PyExc_TypeError, "type not wrapped"); - bpy::throw_error_already_set(); - } - - // This would transfer responsibility for deconstructing the object to C++, but Boost assumes l-value converters (such as this) don't do that - // Instead, this should be called within the wrappers for functions which return deletable pointers. - //sipAPI()->api_transfer_to(objPtr, 0); - - sipSimpleWrapper *wrapper = reinterpret_cast(objPtr); - return wrapper->data; + if (!std::is_same_v) { + PyErr_SetString(PyExc_TypeError, "type not wrapped"); + bpy::throw_error_already_set(); + } + }*/ } + QClass_converters() { bpy::converter::registry::insert(&QClass_from_PyQt, bpy::type_id()); @@ -658,7 +670,7 @@ int getArgCount(PyObject *object) { if (funcCode) { PyObject *argCount = PyObject_GetAttrString(funcCode, "co_argcount"); if(argCount) { - result = PyInt_AsLong(argCount); + result = SIPLong_AsLong(argCount); Py_DECREF(argCount); } Py_DECREF(funcCode); @@ -1203,7 +1215,7 @@ BOOST_PYTHON_MODULE(mobase) PythonRunner::PythonRunner(const MOBase::IOrganizer *moInfo) : m_MOInfo(moInfo) { - m_PythonHome = new char[MAX_PATH + 1]; + m_PythonHome = new wchar_t[MAX_PATH + 1]; } static const char *argv0 = "ModOrganizer.exe"; @@ -1215,16 +1227,17 @@ bool PythonRunner::initPython(const QString &pythonPath) if (!pythonPath.isEmpty() && !QFile::exists(pythonPath + "/python.exe")) { return false; } - strncpy(m_PythonHome, pythonPath.toUtf8().constData(), MAX_PATH); + pythonPath.toWCharArray(m_PythonHome); if (!pythonPath.isEmpty()) { Py_SetPythonHome(m_PythonHome); } - char argBuffer[MAX_PATH]; - strcpy(argBuffer, argv0); + wchar_t argBuffer[MAX_PATH]; + const size_t cSize = strlen(argv0) + 1; + mbstowcs(argBuffer, argv0, MAX_PATH); Py_SetProgramName(argBuffer); - PyImport_AppendInittab("mobase", &initmobase); + PyImport_AppendInittab("mobase", &PyInit_mobase); Py_OptimizeFlag = 2; Py_NoSiteFlag = 1; Py_InitializeEx(0); @@ -1233,15 +1246,15 @@ bool PythonRunner::initPython(const QString &pythonPath) return false; } - PySys_SetArgv(0, (char**)&argBuffer); + PySys_SetArgv(0, (wchar_t**)&argBuffer); bpy::object mainModule = bpy::import("__main__"); bpy::object mainNamespace = mainModule.attr("__dict__"); mainNamespace["sys"] = bpy::import("sys"); initPath(mainNamespace); bpy::import("site"); - mainNamespace["cStringIO"] = bpy::import("cStringIO"); - bpy::exec("s_ErrIO = cStringIO.StringIO()\n" + mainNamespace["io"] = bpy::import("io"); + bpy::exec("s_ErrIO = io.StringIO()\n" "sys.stderr = s_ErrIO", mainNamespace); return true; @@ -1277,11 +1290,7 @@ void PythonRunner::initPath(bpy::object &moduleNamespace) { static QString paths[] = { m_MOInfo->pluginDataPath(), - QCoreApplication::applicationDirPath(), - QCoreApplication::applicationDirPath() + "/python27.zip", - QCoreApplication::applicationDirPath() + "/python27.zip/Lib", - QCoreApplication::applicationDirPath() + "/python27.zip/DLLs", - QCoreApplication::applicationDirPath() + "/python27.zip/Lib/site-packages", + QCoreApplication::applicationDirPath() }; for (int i = 0; i < sizeof(paths) / sizeof(QString); ++i) { diff --git a/src/runner/sipapiaccess.h b/src/runner/sipapiaccess.h index c9c95d0..c99dd8c 100644 --- a/src/runner/sipapiaccess.h +++ b/src/runner/sipapiaccess.h @@ -7,7 +7,35 @@ static const sipAPIDef *sipAPI() { static const sipAPIDef *sipApi = nullptr; if (sipApi == nullptr) { +#if defined(SIP_USE_PYCAPSULE) sipApi = (const sipAPIDef *)PyCapsule_Import("sip._C_API", 0); +#else + PyObject *sip_module; + PyObject *sip_module_dict; + PyObject *c_api; + + /* Import the SIP module. */ + sip_module = PyImport_ImportModule("sip"); + + if (sip_module == NULL) + return NULL; + + /* Get the module's dictionary. */ + sip_module_dict = PyModule_GetDict(sip_module); + + /* Get the "_C_API" attribute. */ + c_api = PyDict_GetItemString(sip_module_dict, "_C_API"); + + if (c_api == NULL) + return NULL; + + /* Sanity check that it is the right type. */ + if (!PyCObject_Check(c_api)) + return NULL; + + /* Get the actual pointer from the object. */ + sipApi = (const sipAPIDef *)PyCObject_AsVoidPtr(c_api); +#endif } return sipApi; diff --git a/src/runner/uibasewrappers.h b/src/runner/uibasewrappers.h index c1c2e9c..3b71894 100644 --- a/src/runner/uibasewrappers.h +++ b/src/runner/uibasewrappers.h @@ -105,7 +105,7 @@ private: Q_DISABLE_COPY(ModRepositoryBridgeWrapper) -private slots: +private Q_SLOTS: void filesAvailable(int modID, QVariant userData, const QList &resultData) {