! * \brief addQObject * \param obj * \param pyobj * Connects destruction event of a QObject with invalidation of its PythonWrapper via a helper * QObject. */
| 409 | * QObject. |
| 410 | */ |
| 411 | void addQObject(QObject* obj, PyObject* pyobj) |
| 412 | { |
| 413 | // static array to contain created connections so they can be safely disconnected later |
| 414 | static std::map<QObject*, QMetaObject::Connection> connections = {}; |
| 415 | |
| 416 | const auto PyW_uniqueName = QString::number(reinterpret_cast<quintptr>(pyobj)); |
| 417 | auto PyW_invalidator = findChild<QObject*>(PyW_uniqueName, Qt::FindDirectChildrenOnly); |
| 418 | |
| 419 | if (!PyW_invalidator) { |
| 420 | PyW_invalidator = new QObject(this); |
| 421 | PyW_invalidator->setObjectName(PyW_uniqueName); |
| 422 | |
| 423 | Py_INCREF(pyobj); |
| 424 | } |
| 425 | else if (connections.contains(PyW_invalidator)) { |
| 426 | disconnect(connections[PyW_invalidator]); |
| 427 | connections.erase(PyW_invalidator); |
| 428 | } |
| 429 | |
| 430 | auto destroyedFun = [pyobj]() { |
| 431 | Base::PyGILStateLocker lock; |
| 432 | |
| 433 | if (auto sbkPtr = reinterpret_cast<SbkObject*>(pyobj); sbkPtr) { |
| 434 | Shiboken::Object::setValidCpp(sbkPtr, false); |
| 435 | } |
| 436 | else { |
| 437 | Base::Console().developerError( |
| 438 | "WrapperManager", |
| 439 | "A QObject has just been destroyed after its Pythonic wrapper.\n" |
| 440 | ); |
| 441 | } |
| 442 | |
| 443 | Py_DECREF(pyobj); |
| 444 | }; |
| 445 | |
| 446 | connections[PyW_invalidator] |
| 447 | = connect(PyW_invalidator, &QObject::destroyed, this, destroyedFun); |
| 448 | connect(obj, &QObject::destroyed, PyW_invalidator, &QObject::deleteLater); |
| 449 | } |
| 450 | |
| 451 | private: |
| 452 | void wrapQApplication() |
no test coverage detected