diff options
author | Christian Tismer <tismer@stackless.com> | 2019-12-22 17:38:00 +0100 |
---|---|---|
committer | Christian Tismer <tismer@stackless.com> | 2020-01-02 11:12:52 +0100 |
commit | c0ce6747df8a28ebab37a2ef5cda7d0db4e51793 (patch) | |
tree | 0b8ae19b96fd33bd4737e7778016ac2086312daf | |
parent | 0b6dd91fbd02e4de1f653e2a8cd6e892628dac0c (diff) |
qApp: make sure to create the right instance when embedding
qApp has special treatment for the embedded case where some
Q*Application instance might exist before initialization happens.
In order to get these cases right, it was necessary to try to import
all three modules in question and do the initialization with the highest
existing module index.
Change-Id: Ifd27129ce166dee20e9424b1ee04a0d66cba79cc
Fixes: PYSIDE-1164
Task-number: PYSIDE-1135
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
-rw-r--r-- | sources/shiboken2/libshiboken/qapp_macro.cpp | 70 |
1 files changed, 47 insertions, 23 deletions
diff --git a/sources/shiboken2/libshiboken/qapp_macro.cpp b/sources/shiboken2/libshiboken/qapp_macro.cpp index c2018bd6f..f92cc7087 100644 --- a/sources/shiboken2/libshiboken/qapp_macro.cpp +++ b/sources/shiboken2/libshiboken/qapp_macro.cpp @@ -53,19 +53,17 @@ extern "C" // variable that monitors Q*Application.instance(). // This variable is also able to destroy the app by deleting qApp. // +static const char *mod_names[3] = {"PySide2.QtCore", "PySide2.QtGui", "PySide2.QtWidgets"}; +static const char *app_names[3] = {"QCoreApplication", "QGuiApplication", "QApplication"}; + static int qApp_module_index(PyObject *module) { const char *name = PyModule_GetName(module); - int ret = 0; - - if (strcmp(name, "PySide2.QtCore") == 0) - ret = 1; - else if (strcmp(name, "PySide2.QtGui") == 0) - ret = 2; - else if (strcmp(name, "PySide2.QtWidgets") == 0) - ret = 3; - return ret; + for (int idx = 0; idx < 3; idx++) + if (strcmp(name, mod_names[idx]) == 0) + return idx + 1; + return 0; } #define PYTHON_IS_PYTHON3 (PY_VERSION_HEX >= 0x03000000) @@ -109,6 +107,8 @@ reset_qApp_var(void) return 0; } +static bool app_created = false; + /* * Note: * The PYSIDE-585 problem was that shutdown is called one more often @@ -120,7 +120,6 @@ reset_qApp_var(void) PyObject * MakeSingletonQAppWrapper(PyTypeObject *type) { - static bool app_created = false; if (type == nullptr) type = Py_NONE_TYPE; if (!(type == Py_NONE_TYPE || Py_TYPE(qApp_content) == Py_NONE_TYPE)) { @@ -245,20 +244,45 @@ NotifyModuleForQApp(PyObject *module, void *qApp) * Therefore, the implementation is very simple and just redirects the * qApp_contents variable and assigns the instance, instead of vice-versa. */ - PyObject *coreDict = qApp_moduledicts[1]; - if (coreDict == nullptr) { - // PYSIDE-1135: Make sure that at least QtCore gets imported. - // That problem exists when a derived instance is created in C++. - qApp_moduledicts[1] = Py_None; // anything != nullptr during import - coreDict = PyImport_ImportModule("PySide2.QtCore"); - qApp_moduledicts[1] = coreDict; - } - if (qApp != nullptr && coreDict != nullptr && coreDict != Py_None) { - PyObject *coreApp = PyDict_GetItemString(coreDict, "QCoreApplication"); - if (coreApp != nullptr) { - qApp_content = PyObject_CallMethod(coreApp, "instance", ""); - reset_qApp_var(); + + // PYSIDE-1135: Make sure that at least QtCore gets imported. + // That problem exists when a derived instance is created in C++. + // PYSIDE-1164: Use the highest Q*Application module possible, + // because in embedded mode the instance() seems to be sticky. + static bool oneshot_active = false; + if (qApp == nullptr || app_created || oneshot_active) + return; + + // qApp exists without an application created. + // We assume that we are embedded, and we simply try to import all three modules. + oneshot_active = true; + int mod_found = 0; + const char *mod_name, *app_name; + const char *thismod_name = PyModule_GetName(module); + + // First go through all three modules, import and set qApp_moduledicts. + for (int idx = 0; idx < 3; idx++) { + // only import if it is not already the module + PyObject *mod = strcmp(thismod_name, mod_names[idx]) == 0 ? module + : PyImport_ImportModule(mod_names[idx]); + if (mod != nullptr) { + mod_found = idx + 1; + qApp_moduledicts[mod_found] = PyModule_GetDict(mod); + mod_name = PyModule_GetName(mod); + app_name = app_names[idx]; + continue; } + PyErr_Clear(); + } + + // Then take the highest module and call instance() on it. + if (mod_found) { + PyObject *mod_dict = qApp_moduledicts[mod_found]; + PyObject *app_class = PyDict_GetItemString(mod_dict, app_name); + qApp_content = PyObject_CallMethod(app_class, const_cast<char *>("instance"), + const_cast<char *>("")); + app_created = true; + reset_qApp_var(); } } |