aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/libshiboken
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2017-10-27 14:20:36 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2017-10-27 14:20:36 +0200
commit25f899e276c00b8d7f334819d6cd7927ed67093a (patch)
treed2a063aab76e0435eb862ca5d2b541a5e718f062 /sources/shiboken2/libshiboken
parent4725008aeea407ae55cfd66de802dd9e06412efc (diff)
parente30e0c161b2b4d50484314bf006e9e5e8ff6b380 (diff)
Merge remote-tracking branch 'origin/5.6' into 5.9
Diffstat (limited to 'sources/shiboken2/libshiboken')
-rw-r--r--sources/shiboken2/libshiboken/CMakeLists.txt2
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.cpp46
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.h3
-rw-r--r--sources/shiboken2/libshiboken/helper.cpp9
-rw-r--r--sources/shiboken2/libshiboken/helper.h2
-rw-r--r--sources/shiboken2/libshiboken/qapp_macro.cpp184
-rw-r--r--sources/shiboken2/libshiboken/qapp_macro.h53
7 files changed, 289 insertions, 10 deletions
diff --git a/sources/shiboken2/libshiboken/CMakeLists.txt b/sources/shiboken2/libshiboken/CMakeLists.txt
index 5cdd0c935..ac59e80cd 100644
--- a/sources/shiboken2/libshiboken/CMakeLists.txt
+++ b/sources/shiboken2/libshiboken/CMakeLists.txt
@@ -48,6 +48,7 @@ threadstatesaver.cpp
typeresolver.cpp
shibokenbuffer.cpp
signature.cpp
+qapp_macro.cpp
)
get_numpy_location()
@@ -91,6 +92,7 @@ install(FILES
shibokenbuffer.h
sbkpython.h
signature.h
+ qapp_macro.h
"${CMAKE_CURRENT_BINARY_DIR}/sbkversion.h"
DESTINATION include/shiboken2${shiboken2_SUFFIX})
install(TARGETS libshiboken EXPORT shiboken2
diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp
index 3c17f8bf8..d90904dec 100644
--- a/sources/shiboken2/libshiboken/basewrapper.cpp
+++ b/sources/shiboken2/libshiboken/basewrapper.cpp
@@ -52,6 +52,7 @@
#include <algorithm>
#include "threadstatesaver.h"
#include "signature.h"
+#include "qapp_macro.h"
namespace {
void _destroyParentInfo(SbkObject* obj, bool keepReference);
@@ -243,7 +244,9 @@ static void SbkDeallocWrapperCommon(PyObject* pyObj, bool canDelete)
// be invoked and it trying to delete this object while it is still in
// progress from the first time around, resulting in a double delete and a
// crash.
- PyObject_GC_UnTrack(pyObj);
+ // PYSIDE-571: Some objects do not use GC, so check this!
+ if (PyObject_IS_GC(pyObj))
+ PyObject_GC_UnTrack(pyObj);
// Check that Python is still initialized as sometimes this is called by a static destructor
// after Python interpeter is shutdown.
@@ -278,6 +281,13 @@ void SbkDeallocWrapper(PyObject* pyObj)
SbkDeallocWrapperCommon(pyObj, true);
}
+void SbkDeallocQAppWrapper(PyObject* pyObj)
+{
+ SbkDeallocWrapper(pyObj);
+ // PYSIDE-571: make sure to create a singleton deleted qApp.
+ MakeSingletonQAppWrapper(NULL);
+}
+
void SbkDeallocWrapperWithPrivateDtor(PyObject* self)
{
SbkDeallocWrapperCommon(self, false);
@@ -375,9 +385,8 @@ PyObject* SbkObjectTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* k
return reinterpret_cast<PyObject*>(newType);
}
-PyObject* SbkObjectTpNew(PyTypeObject* subtype, PyObject*, PyObject*)
+static PyObject *_setupNew(SbkObject *self, PyTypeObject *subtype)
{
- SbkObject* self = PyObject_GC_New(SbkObject, subtype);
Py_INCREF(reinterpret_cast<PyObject*>(subtype));
SbkObjectPrivate* d = new SbkObjectPrivate;
@@ -394,10 +403,35 @@ PyObject* SbkObjectTpNew(PyTypeObject* subtype, PyObject*, PyObject*)
self->ob_dict = 0;
self->weakreflist = 0;
self->d = d;
- PyObject_GC_Track(reinterpret_cast<PyObject*>(self));
return reinterpret_cast<PyObject*>(self);
}
+PyObject* SbkObjectTpNew(PyTypeObject *subtype, PyObject *, PyObject *)
+{
+ SbkObject *self = PyObject_GC_New(SbkObject, subtype);
+ PyObject *res = _setupNew(self, subtype);
+ PyObject_GC_Track(reinterpret_cast<PyObject*>(self));
+ return res;
+}
+
+PyObject* SbkQAppTpNew(PyTypeObject* subtype, PyObject *, PyObject *)
+{
+ // PYSIDE-571:
+ // For qApp, we need to create a singleton Python object.
+ // We cannot track this with the GC, because it is a static variable!
+
+ // Python2 has a weird handling of flags in derived classes that Python3
+ // does not have. Observed with bug_307.py.
+ // But it could theoretically also happen with Python3.
+ // Therefore we enforce that there is no GC flag, ever!
+ if (PyType_HasFeature(subtype, Py_TPFLAGS_HAVE_GC)) {
+ subtype->tp_flags &= ~Py_TPFLAGS_HAVE_GC;
+ subtype->tp_free = PyObject_Del;
+ }
+ SbkObject* self = reinterpret_cast<SbkObject*>(MakeSingletonQAppWrapper(subtype));
+ return self == 0 ? 0 : _setupNew(self, subtype);
+}
+
} //extern "C"
@@ -1370,7 +1404,9 @@ void deallocData(SbkObject* self, bool cleanup)
}
delete self->d; // PYSIDE-205: always delete d.
Py_XDECREF(self->ob_dict);
- Py_TYPE(self)->tp_free(self);
+ // PYSIDE-571: qApp is no longer allocated.
+ if (PyObject_IS_GC((PyObject*)self))
+ Py_TYPE(self)->tp_free(self);
}
void setTypeUserData(SbkObject* wrapper, void* userData, DeleteUserDataFunc d_func)
diff --git a/sources/shiboken2/libshiboken/basewrapper.h b/sources/shiboken2/libshiboken/basewrapper.h
index a230c1337..bd2d6820f 100644
--- a/sources/shiboken2/libshiboken/basewrapper.h
+++ b/sources/shiboken2/libshiboken/basewrapper.h
@@ -66,6 +66,7 @@ struct LIBSHIBOKEN_API SbkObject
/// Dealloc the python object \p pyObj and the C++ object represented by it.
LIBSHIBOKEN_API void SbkDeallocWrapper(PyObject* pyObj);
+LIBSHIBOKEN_API void SbkDeallocQAppWrapper(PyObject* pyObj);
LIBSHIBOKEN_API void SbkDeallocWrapperWithPrivateDtor(PyObject* self);
struct SbkObjectType;
@@ -105,6 +106,8 @@ struct LIBSHIBOKEN_API SbkObjectType
};
LIBSHIBOKEN_API PyObject* SbkObjectTpNew(PyTypeObject* subtype, PyObject*, PyObject*);
+// the special case of a switchable singleton
+LIBSHIBOKEN_API PyObject* SbkQAppTpNew(PyTypeObject *subtype, PyObject *args, PyObject *kwds);
} // extern "C"
diff --git a/sources/shiboken2/libshiboken/helper.cpp b/sources/shiboken2/libshiboken/helper.cpp
index 2249bf458..5792db5be 100644
--- a/sources/shiboken2/libshiboken/helper.cpp
+++ b/sources/shiboken2/libshiboken/helper.cpp
@@ -43,9 +43,10 @@
namespace Shiboken
{
-bool sequenceToArgcArgv(PyObject* argList, int* argc, char*** argv, const char* defaultAppName)
+// PySide-510: Changed from PySequence to PyList, which is correct.
+bool listToArgcArgv(PyObject* argList, int* argc, char*** argv, const char* defaultAppName)
{
- if (!PySequence_Check(argList))
+ if (!PyList_Check(argList))
return false;
if (!defaultAppName)
@@ -55,7 +56,7 @@ bool sequenceToArgcArgv(PyObject* argList, int* argc, char*** argv, const char*
Shiboken::AutoDecRef args(PySequence_Fast(argList, 0));
int numArgs = int(PySequence_Fast_GET_SIZE(argList));
for (int i = 0; i < numArgs; ++i) {
- PyObject* item = PySequence_Fast_GET_ITEM(args.object(), i);
+ PyObject* item = PyList_GET_ITEM(args.object(), i);
if (!PyBytes_Check(item) && !PyUnicode_Check(item))
return false;
}
@@ -74,7 +75,7 @@ bool sequenceToArgcArgv(PyObject* argList, int* argc, char*** argv, const char*
(*argv)[0] = strdup(appName ? Shiboken::String::toCString(appName) : defaultAppName);
} else {
for (int i = 0; i < numArgs; ++i) {
- PyObject* item = PySequence_Fast_GET_ITEM(args.object(), i);
+ PyObject* item = PyList_GET_ITEM(args.object(), i);
char* string = 0;
if (Shiboken::String::check(item)) {
string = strdup(Shiboken::String::toCString(item));
diff --git a/sources/shiboken2/libshiboken/helper.h b/sources/shiboken2/libshiboken/helper.h
index f2061b667..33d97c62c 100644
--- a/sources/shiboken2/libshiboken/helper.h
+++ b/sources/shiboken2/libshiboken/helper.h
@@ -101,7 +101,7 @@ inline PyObject* makeTuple(const A& a, const B& b, const C& c, const D& d, const
* \note The argv array is allocated using new operator and each item is allocated using malloc.
* \returns True on sucess, false otherwise.
*/
-LIBSHIBOKEN_API bool sequenceToArgcArgv(PyObject* argList, int* argc, char*** argv, const char* defaultAppName = 0);
+LIBSHIBOKEN_API bool listToArgcArgv(PyObject* argList, int* argc, char*** argv, const char* defaultAppName = 0);
/**
* Convert a python sequence into a heap-allocated array of ints.
diff --git a/sources/shiboken2/libshiboken/qapp_macro.cpp b/sources/shiboken2/libshiboken/qapp_macro.cpp
new file mode 100644
index 000000000..b31e98d06
--- /dev/null
+++ b/sources/shiboken2/libshiboken/qapp_macro.cpp
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $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 "basewrapper.h"
+
+extern "C"
+{
+
+#include "qapp_macro.h"
+
+////////////////////////////////////////////////////////////////////////////
+//
+// Support for the qApp macro.
+//
+// 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.
+//
+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;
+}
+
+#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 = NULL;
+static PyObject *qApp_content = (PyObject *)&_Py_ChameleonQAppWrapper_Struct;
+static PyObject *qApp_moduledicts[5] = {0, 0, 0, 0, 0};
+static int qApp_var_ref = 0;
+static int qApp_content_ref = 0;
+
+static int
+reset_qApp_var()
+{
+ PyObject **mod_ptr;
+
+ for (mod_ptr = qApp_moduledicts; *mod_ptr != NULL; mod_ptr++) {
+ // We respect whatever the user may have set.
+ if (PyDict_GetItem(*mod_ptr, qApp_var) == NULL)
+ if (PyDict_SetItem(*mod_ptr, qApp_var, qApp_content) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+
+PyObject *
+MakeSingletonQAppWrapper(PyTypeObject *type)
+{
+ if (type == NULL)
+ type = Py_NONE_TYPE;
+ if (!(type == Py_NONE_TYPE || Py_TYPE(qApp_content) == Py_NONE_TYPE)) {
+ const char *res_name = strrchr(Py_TYPE(qApp_content)->tp_name, '.')+1;
+ const char *type_name = strrchr(type->tp_name, '.')+1;
+ PyErr_Format(PyExc_RuntimeError, "Please destroy the %s singleton before"
+ " creating a new %s instance.", res_name, type_name);
+ return NULL;
+ }
+ if (reset_qApp_var() < 0)
+ return NULL;
+ // always know the max of the refs
+ if (Py_REFCNT(qApp_var) > qApp_var_ref)
+ qApp_var_ref = Py_REFCNT(qApp_var);
+ if (Py_REFCNT(qApp_content) > qApp_content_ref)
+ qApp_content_ref = Py_REFCNT(qApp_content);
+
+ if (Py_TYPE(qApp_content) != Py_NONE_TYPE)
+ Py_REFCNT(qApp_var) = 1; // fuse is armed...
+ if (type == Py_NONE_TYPE) {
+ // Debug mode showed that we need to do more than just remove the
+ // reference. To keep everything in the right order, it is easiest
+ // to do a full shutdown, using QtCore.__moduleShutdown().
+ PyObject *__moduleShutdown = PyDict_GetItemString(qApp_moduledicts[1],
+ "__moduleShutdown");
+ if (__moduleShutdown != NULL) {
+ Py_DECREF(PyObject_CallFunction(__moduleShutdown, (char *)"()"));
+ }
+ // restore the "None-state"
+ Py_TYPE(qApp_content) = Py_NONE_TYPE;
+ Py_REFCNT(qApp_var) = qApp_var_ref;
+ Py_REFCNT(qApp_content) = qApp_content_ref;
+ }
+ else
+ (void)PyObject_INIT(qApp_content, type);
+ Py_INCREF(qApp_content);
+ return qApp_content;
+}
+
+static int
+setup_qApp_var(PyObject *module)
+{
+ int module_index;
+ static int init_done = 0;
+
+ if (!init_done) {
+ qApp_var = Py_BuildValue("s", "qApp");
+ if (qApp_var == NULL)
+ return -1;
+ qApp_moduledicts[0] = PyEval_GetBuiltins();
+ 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) {
+ qApp_moduledicts[module_index] = PyModule_GetDict(module);
+ if (reset_qApp_var() < 0)
+ return -1;
+ }
+ return 0;
+}
+
+void
+NotifyModuleForQApp(PyObject *module)
+{
+ 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
new file mode 100644
index 000000000..98f0ec629
--- /dev/null
+++ b/sources/shiboken2/libshiboken/qapp_macro.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $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 QAPP_MACRO_H
+#define QAPP_MACRO_H
+
+#include "sbkpython.h"
+
+extern "C"
+{
+
+LIBSHIBOKEN_API PyObject *MakeSingletonQAppWrapper(PyTypeObject *type);
+LIBSHIBOKEN_API void NotifyModuleForQApp(PyObject *module);
+
+} // extern "C"
+
+#endif // QAPP_MACRO_H