aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sources/pyside2/PySide2/glue/qtcore.cpp4
-rw-r--r--sources/pyside2/libpyside/pyside.cpp20
-rw-r--r--sources/pyside2/libpyside/pyside.h1
-rw-r--r--sources/pyside2/tests/QtWidgets/CMakeLists.txt1
-rw-r--r--sources/pyside2/tests/QtWidgets/bug_750.py2
-rw-r--r--sources/pyside2/tests/QtWidgets/qapplication_singleton_test.py39
-rw-r--r--sources/pyside2/tests/pysidetest/qapp_like_a_macro_test.py15
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp4
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.cpp4
-rw-r--r--sources/shiboken2/libshiboken/qapp_macro.cpp198
-rw-r--r--sources/shiboken2/libshiboken/qapp_macro.h3
11 files changed, 55 insertions, 236 deletions
diff --git a/sources/pyside2/PySide2/glue/qtcore.cpp b/sources/pyside2/PySide2/glue/qtcore.cpp
index d99a150ad..e54fa1846 100644
--- a/sources/pyside2/PySide2/glue/qtcore.cpp
+++ b/sources/pyside2/PySide2/glue/qtcore.cpp
@@ -1430,8 +1430,8 @@ if (qApp) {
// this will keep app live after python exit (extra ref)
}
// PYSIDE-571: make sure that we return the singleton "None"
-if (pyApp == Py_None)
- Py_DECREF(MakeSingletonQAppWrapper(nullptr)); // here qApp and instance() diverge
+if (Py_TYPE(pyApp) == Py_TYPE(Py_None))
+ Py_DECREF(MakeQAppWrapper(nullptr));
%PYARG_0 = pyApp;
Py_XINCREF(%PYARG_0);
// @snippet qcoreapplication-instance
diff --git a/sources/pyside2/libpyside/pyside.cpp b/sources/pyside2/libpyside/pyside.cpp
index eeb4de037..d22958398 100644
--- a/sources/pyside2/libpyside/pyside.cpp
+++ b/sources/pyside2/libpyside/pyside.cpp
@@ -94,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)
@@ -214,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)
@@ -299,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);
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/tests/QtWidgets/CMakeLists.txt b/sources/pyside2/tests/QtWidgets/CMakeLists.txt
index 6d8645918..6682136ea 100644
--- a/sources/pyside2/tests/QtWidgets/CMakeLists.txt
+++ b/sources/pyside2/tests/QtWidgets/CMakeLists.txt
@@ -87,7 +87,6 @@ PYSIDE_TEST(qapp_issue_585.py)
PYSIDE_TEST(qapp_test.py)
PYSIDE_TEST(qapplication_test.py)
PYSIDE_TEST(qapplication_exit_segfault_test.py)
-PYSIDE_TEST(qapplication_singleton_test.py)
PYSIDE_TEST(qbrush_test.py)
PYSIDE_TEST(qdynamic_signal.py)
# TODO: This passes, but requires manual button clicking (at least on mac)
diff --git a/sources/pyside2/tests/QtWidgets/bug_750.py b/sources/pyside2/tests/QtWidgets/bug_750.py
index 42b6c9843..78d333efd 100644
--- a/sources/pyside2/tests/QtWidgets/bug_750.py
+++ b/sources/pyside2/tests/QtWidgets/bug_750.py
@@ -36,7 +36,7 @@ from helper.usesqapplication import UsesQApplication
from PySide2.QtCore import QTimer
from PySide2.QtGui import QPainter, QFont, QFontInfo
-from PySide2.QtWidgets import QWidget, qApp
+from PySide2.QtWidgets import QWidget
class MyWidget(QWidget):
def paintEvent(self, e):
diff --git a/sources/pyside2/tests/QtWidgets/qapplication_singleton_test.py b/sources/pyside2/tests/QtWidgets/qapplication_singleton_test.py
deleted file mode 100644
index e79e303f0..000000000
--- a/sources/pyside2/tests/QtWidgets/qapplication_singleton_test.py
+++ /dev/null
@@ -1,39 +0,0 @@
-#############################################################################
-##
-## Copyright (C) 2016 The Qt Company Ltd.
-## Contact: https://www.qt.io/licensing/
-##
-## This file is part of the test suite of Qt for Python.
-##
-## $QT_BEGIN_LICENSE:GPL-EXCEPT$
-## 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 General Public License Usage
-## Alternatively, this file may be used under the terms of the GNU
-## General Public License version 3 as published by the Free Software
-## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-## 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-3.0.html.
-##
-## $QT_END_LICENSE$
-##
-#############################################################################
-
-import unittest
-
-from PySide2.QtWidgets import QApplication
-
-class TestSingleton(unittest.TestCase):
- def testBasic(self):
- a = QApplication([])
- self.assertRaises(RuntimeError, QApplication, [])
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/sources/pyside2/tests/pysidetest/qapp_like_a_macro_test.py b/sources/pyside2/tests/pysidetest/qapp_like_a_macro_test.py
index 43f455ea9..2cc18c9c9 100644
--- a/sources/pyside2/tests/pysidetest/qapp_like_a_macro_test.py
+++ b/sources/pyside2/tests/pysidetest/qapp_like_a_macro_test.py
@@ -32,6 +32,8 @@ import PySide2
# This test tests the new "macro" feature of qApp.
# It also uses the qApp variable to finish the instance and start over.
+# Note: this test makes qapplication_singleton_test.py obsolete.
+
class qAppMacroTest(unittest.TestCase):
_test_1093_is_first = True
@@ -44,13 +46,8 @@ class qAppMacroTest(unittest.TestCase):
QtWidgets = QtGui = QtCore
# qApp is in the builtins
self.assertEqual(bool(qApp), False)
- # and also in certain PySide modules
- QtCore.qApp, QtGui.qApp, QtWidgets.qApp
- # and they are all the same
- self.assertTrue(qApp is QtCore.qApp is QtGui.qApp is QtWidgets.qApp)
- # and the type is NoneType, but it is not None (cannot work)
- self.assertTrue(type(qApp) is type(None))
- self.assertTrue(qApp is not None)
+ # and the type is None
+ self.assertTrue(qApp is None)
# now we create an application for all cases
classes = (QtCore.QCoreApplication,
QtGui.QGuiApplication,
@@ -63,9 +60,7 @@ class qAppMacroTest(unittest.TestCase):
QtCore.QCoreApplication([])
with self.assertRaises(RuntimeError):
QtCore.QCoreApplication([])
- self.assertEqual(QtCore.QCoreApplication.instance(), QtCore.qApp)
- # and they are again all the same
- self.assertTrue(qApp is QtCore.qApp is QtGui.qApp is QtWidgets.qApp)
+ self.assertEqual(QtCore.QCoreApplication.instance(), qApp)
def test_1093(self):
# Test that without creating a QApplication staticMetaObject still exists.
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
index f9020420f..5697a24e0 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
@@ -5818,10 +5818,6 @@ bool CppGenerator::finishGeneration()
s << INDENT << "FinishSignatureInitialization(module, " << moduleName()
<< "_SignatureStrings);\n";
- if (usePySideExtensions()) {
- // initialize the qApp module.
- s << INDENT << "NotifyModuleForQApp(module, qApp);\n";
- }
s << Qt::endl;
s << "SBK_MODULE_INIT_FUNCTION_END\n";
diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp
index 71efe12c0..29ee1b185 100644
--- a/sources/shiboken2/libshiboken/basewrapper.cpp
+++ b/sources/shiboken2/libshiboken/basewrapper.cpp
@@ -426,7 +426,7 @@ void SbkDeallocQAppWrapper(PyObject *pyObj)
{
SbkDeallocWrapper(pyObj);
// PYSIDE-571: make sure to create a singleton deleted qApp.
- MakeSingletonQAppWrapper(nullptr);
+ Py_DECREF(MakeQAppWrapper(nullptr));
}
void SbkDeallocWrapperWithPrivateDtor(PyObject *self)
@@ -612,7 +612,7 @@ PyObject *SbkQAppTpNew(PyTypeObject *subtype, PyObject *, PyObject *)
subtype->tp_free = PyObject_Del;
}
#endif
- auto self = reinterpret_cast<SbkObject *>(MakeSingletonQAppWrapper(subtype));
+ auto self = reinterpret_cast<SbkObject *>(MakeQAppWrapper(subtype));
return self == nullptr ? nullptr : _setupNew(self, subtype);
}
diff --git a/sources/shiboken2/libshiboken/qapp_macro.cpp b/sources/shiboken2/libshiboken/qapp_macro.cpp
index 979638d17..3ef3a51c6 100644
--- a/sources/shiboken2/libshiboken/qapp_macro.cpp
+++ b/sources/shiboken2/libshiboken/qapp_macro.cpp
@@ -51,200 +51,50 @@ extern "C"
//
// qApp is a macro in Qt5. In Python, we simulate that a little by a
// variable that monitors Q*Application.instance().
-// This variable is also able to destroy the app by deleting qApp.
+// This variable is also able to destroy the app by qApp.shutdown().
//
-static const char *mod_names[3] = {"PySide2.QtCore", "PySide2.QtGui", "PySide2.QtWidgets"};
-
-static int
-qApp_module_index(PyObject *module)
-{
- const char *name = PyModule_GetName(module);
- 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)
-#define PYTHON_IS_PYTHON2 (!PYTHON_IS_PYTHON3)
-#define Py_NONE_TYPE Py_TYPE(Py_None)
-
-#if PYTHON_IS_PYTHON3
-# define BRACE_OPEN {
-# define BRACE_CLOSE }
-#else
-# define BRACE_OPEN
-# define BRACE_CLOSE
-#endif
-
-static SbkObject _Py_ChameleonQAppWrapper_Struct = {
- BRACE_OPEN
- _PyObject_EXTRA_INIT
- 1, Py_NONE_TYPE
- BRACE_CLOSE
-};
static PyObject *qApp_var = nullptr;
-static PyObject *qApp_content = reinterpret_cast<PyObject *>(&_Py_ChameleonQAppWrapper_Struct);
-static PyObject *qApp_moduledicts[5] = {nullptr, nullptr, nullptr, nullptr, nullptr};
+static PyObject *qApp_content = nullptr;
-static int
-reset_qApp_var(void)
+static PyObject *
+monitor_qApp_var(PyObject *qApp)
{
- PyObject **mod_ptr;
+ static bool init_done;
+ static PyObject *builtins = PyEval_GetBuiltins();
- for (mod_ptr = qApp_moduledicts; *mod_ptr != nullptr; mod_ptr++) {
- // We respect whatever the user may have set.
- PyObject *existing = PyDict_GetItem(*mod_ptr, qApp_var);
- if (existing == nullptr || Py_TYPE(existing) == Py_NONE_TYPE) {
- if (PyDict_SetItem(*mod_ptr, qApp_var, qApp_content) < 0)
- return -1;
- }
+ if (!init_done) {
+ qApp_var = Py_BuildValue("s", "qApp");
+ if (qApp_var == nullptr)
+ return nullptr;
+ // This is a borrowed reference
+ Py_INCREF(builtins);
+ init_done = true;
}
- return 0;
-}
-static bool app_created = false;
+ if (PyDict_SetItem(builtins, qApp_var, qApp) < 0)
+ return nullptr;
+ qApp_content = qApp;
+ Py_INCREF(qApp);
+ return qApp;
+}
PyObject *
-MakeSingletonQAppWrapper(PyTypeObject *type)
+MakeQAppWrapper(PyTypeObject *type)
{
if (type == nullptr)
- type = Py_NONE_TYPE;
- if (!(type == Py_NONE_TYPE || Py_TYPE(qApp_content) == Py_NONE_TYPE)) {
+ type = Py_TYPE(Py_None);
+ if (!(type == Py_TYPE(Py_None) || Py_TYPE(qApp_content) == Py_TYPE(Py_None))) {
const char *res_name = PepType_GetNameStr(Py_TYPE(qApp_content));
const char *type_name = PepType_GetNameStr(type);
PyErr_Format(PyExc_RuntimeError, "Please destroy the %s singleton before"
" creating a new %s instance.", res_name, type_name);
return nullptr;
}
- if (reset_qApp_var() < 0)
- return nullptr;
- if (type == Py_NONE_TYPE) {
- // PYSIDE-1093: Ignore None when no instance has ever been created.
- if (!app_created)
- Py_RETURN_NONE;
- Py_TYPE(qApp_content) = Py_NONE_TYPE;
- } else {
- PyObject_Init(qApp_content, type);
- app_created = true;
- }
- Py_INCREF(qApp_content);
- return qApp_content;
-}
-
-// PYSIDE-1158: Be clear that the QApp none has the type of None but is a
-// different thing.
-
-static PyObject *
-none_repr(PyObject *op)
-{
- if (op == qApp_content)
- return PyUnicode_FromString("noApp");
- return PyUnicode_FromString("None");
-}
-
-static void
-none_dealloc(PyObject *ignore)
-{
- if (ignore == qApp_content)
- return;
- /* This should never get called, but we also don't want to SEGV if
- * we accidentally decref None out of existence.
- */
- Py_FatalError("deallocating None");
+ PyObject *self = type != Py_TYPE(Py_None) ? PyObject_New(PyObject, type) : Py_None;
+ return monitor_qApp_var(self);
}
-#if PYTHON_IS_PYTHON2
-
-// Install support in Py_NONE_TYPE for Python 2: 'bool(qApp) == False'.
-static int
-none_bool(PyObject *v)
-{
- return 0;
-}
-
-static PyNumberMethods none_as_number = {
- nullptr, /* nb_add */
- nullptr, /* nb_subtract */
- nullptr, /* nb_multiply */
- nullptr, /* nb_divide */
- nullptr, /* nb_remainder */
- nullptr, /* nb_divmod */
- nullptr, /* nb_power */
- nullptr, /* nb_negative */
- nullptr, /* nb_positive */
- nullptr, /* nb_absolute */
- reinterpret_cast<inquiry>(none_bool), /* nb_nonzero */
-};
-
-#endif
-
-static int
-setup_qApp_var(PyObject *module)
-{
- int module_index;
- static int init_done = 0;
-
- if (!init_done) {
- Py_NONE_TYPE->tp_repr = &none_repr;
- Py_NONE_TYPE->tp_dealloc = &none_dealloc;
-#if PYTHON_IS_PYTHON2
- Py_NONE_TYPE->tp_as_number = &none_as_number;
-#endif
- qApp_var = Py_BuildValue("s", "qApp");
- if (qApp_var == nullptr)
- return -1;
- // This is a borrowed reference
- qApp_moduledicts[0] = PyEval_GetBuiltins();
- Py_INCREF(qApp_moduledicts[0]);
- init_done = 1;
- }
-
- // Initialize qApp. We insert it into __dict__ for "import *" and also
- // into __builtins__, to let it appear like a real macro.
- module_index = qApp_module_index(module);
- if (module_index) {
- // This line gets a borrowed reference
- qApp_moduledicts[module_index] = PyModule_GetDict(module);
- Py_INCREF(qApp_moduledicts[module_index]);
- if (reset_qApp_var() < 0)
- return -1;
- }
- return 0;
-}
-
-void
-NotifyModuleForQApp(PyObject *module, void *qApp)
-{
- /*
- * PYSIDE-571: Check if an QApplication instance exists before the import.
- * This happens in scriptableapplication and application_test.py .
- *
- * Crucial Observation
- * ===================
- *
- * A Q*Application object from C++ does not have a wrapper or constructor
- * like instances created by Python. It makes no sense to support
- * deletion or special features like qApp resurrection.
- *
- * Therefore, the implementation is very simple and just redirects the
- * qApp_contents variable and assigns the instance, instead of vice-versa.
- */
-
- // 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.
-
- // PYSIDE-1135 again:
- // The problem of late initialization is not worth the effort.
- // We simply don't create the qApp variable when we are embedded.
- if (qApp == nullptr)
- setup_qApp_var(module);
-}
-
-
} //extern "C"
// end of module
diff --git a/sources/shiboken2/libshiboken/qapp_macro.h b/sources/shiboken2/libshiboken/qapp_macro.h
index be45241de..9abd17c17 100644
--- a/sources/shiboken2/libshiboken/qapp_macro.h
+++ b/sources/shiboken2/libshiboken/qapp_macro.h
@@ -45,8 +45,7 @@
extern "C"
{
-LIBSHIBOKEN_API PyObject *MakeSingletonQAppWrapper(PyTypeObject *type);
-LIBSHIBOKEN_API void NotifyModuleForQApp(PyObject *module, void *qApp);
+LIBSHIBOKEN_API PyObject *MakeQAppWrapper(PyTypeObject *type);
} // extern "C"