Revert "Gui: fix possible crash when running the garbage collector after creating a shiboken wrapper"

This reverts commit a06533392b.
This commit is contained in:
Uwe
2022-11-09 13:23:47 +01:00
parent c8042bed16
commit 3aac13eacf
-100
View File
@@ -217,106 +217,6 @@ void registerTypes()
// --------------------------------------------------------
namespace Gui {
template<typename qttype>
PyTypeObject *getPyTypeObjectForTypeName();
/*!
* \brief The WrapperManager class
* This is a helper class that records the Python wrappers of a QObject and invalidates
* them when the QObject is about to be destroyed.
* This is to make sure that if the Python wrapper doesn't own the QObject it won't be notified
* if the QObject is destroyed.
* \code
* ui = Gui.UiLoader()
* lineedit = ui.createWidget("QLineEdit")
* lineedit.deleteLater()
* # Make sure this won't crash
* lineedit.show()
* \endcode
*/
class WrapperManager : public QObject
{
std::unordered_map<QObject*, std::list<Py::Object>> wrappers;
public:
static WrapperManager& instance()
{
static WrapperManager singleton;
return singleton;
}
/*!
* \brief addQObject
* \param obj
* \param pyobj
* Add the QObject and its Python wrapper to the list.
*/
void addQObject(QObject* obj, PyObject* pyobj)
{
if (wrappers.find(obj) == wrappers.end()) {
QObject::connect(obj, &QObject::destroyed, this, &WrapperManager::destroyed);
}
auto& pylist = wrappers[obj];
if (std::find_if(pylist.cbegin(), pylist.cend(), [pyobj](const Py::Object& py) { return py.ptr() == pyobj; }) == pylist.end()) {
pylist.emplace_back(pyobj);
}
}
private:
/*!
* \brief destroyed
* \param obj
* The listed QObject is about to be destroyed. Invalidate its Python wrappers now.
*/
void destroyed(QObject* obj = nullptr)
{
if (obj) {
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)
auto key = wrappers.find(obj);
if (key != wrappers.end()) {
Base::PyGILStateLocker lock;
for (const auto& it : key->second) {
auto value = it.ptr();
Shiboken::Object::setValidCpp(reinterpret_cast<SbkObject*>(value), false);
}
wrappers.erase(key);
}
#endif
}
}
void clear()
{
Base::PyGILStateLocker lock;
wrappers.clear();
}
void wrapQApplication()
{
// We have to explicitly hold a reference to the wrapper of the QApplication
// as otherwise it can happen that when running the gc the program crashes
// The code snippet below caused a crash on older versions:
// mw = Gui.getMainWindow()
// mw.style()
// import gc
// gc.collect()
PyTypeObject * type = getPyTypeObjectForTypeName<QApplication>();
if (type) {
auto sbk_type = reinterpret_cast<SbkObjectType*>(type);
std::string typeName = "QApplication";
PyObject* pyobj = Shiboken::Object::newObject(sbk_type, qApp, false, false, typeName.c_str());
addQObject(qApp, pyobj);
}
}
WrapperManager()
{
connect(QApplication::instance(), &QCoreApplication::aboutToQuit,
this, &WrapperManager::clear);
wrapQApplication();
}
~WrapperManager() = default;
};
template<typename qttype>
Py::Object qt_wrapInstance(qttype object, const char* className,
const char* shiboken, const char* pyside,