@@ -170,17 +170,20 @@ PythonQt::PythonQt(int flags)
170170 }
171171 Py_INCREF (&PythonQtSlotFunction_Type);
172172
173- // add our own python object types for qt objects
174- if (PyType_Ready (&PythonQtInstanceWrapper_Type) < 0 ) {
175- std::cerr << " could not initialize PythonQtInstanceWrapper_Type" << " , in " << __FILE__ << " :" << __LINE__ << std::endl;
176- }
177- Py_INCREF (&PythonQtInstanceWrapper_Type);
178-
179- // add our own python object types for qt objects
173+ // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
174+ PythonQtClassWrapper_Type.tp_base = &PyType_Type;
175+ // add our own python object types for classes
180176 if (PyType_Ready (&PythonQtClassWrapper_Type) < 0 ) {
181177 std::cerr << " could not initialize PythonQtClassWrapper_Type" << " , in " << __FILE__ << " :" << __LINE__ << std::endl;
182178 }
183179 Py_INCREF (&PythonQtClassWrapper_Type);
180+
181+ // add our own python object types for CPP instances
182+ if (PyType_Ready (&PythonQtInstanceWrapper_Type) < 0 ) {
183+ PythonQt::handleError ();
184+ std::cerr << " could not initialize PythonQtInstanceWrapper_Type" << " , in " << __FILE__ << " :" << __LINE__ << std::endl;
185+ }
186+ Py_INCREF (&PythonQtInstanceWrapper_Type);
184187
185188 // add our own python object types for redirection of stdout
186189 if (PyType_Ready (&PythonQtStdOutRedirectType) < 0 ) {
@@ -274,16 +277,8 @@ void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* p
274277 while (m) {
275278 PythonQtClassInfo* info = _knownQtClasses.value (m->className ());
276279 if (!info) {
277- info = new PythonQtClassInfo (m );
280+ info = createPythonQtClassInfo (m, NULL , package );
278281 _knownQtClasses.insert (m->className (), info);
279- PythonQtObjectPtr pack = packageByName (package);
280- PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper (info);
281- PyModule_AddObject (pack, m->className (), pyobj);
282- if (package && strncmp (package," Qt" ,2 )==0 ) {
283- // put all qt objects into Qt as well
284- PythonQtObjectPtr pack = packageByName (" Qt" );
285- PyModule_AddObject (pack, m->className (), pyobj);
286- }
287282 }
288283 if (first) {
289284 first = false ;
@@ -295,6 +290,21 @@ void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* p
295290 }
296291}
297292
293+ PythonQtClassInfo* PythonQtPrivate::createPythonQtClassInfo (const QMetaObject* meta, const char * cppClassName, const char * package)
294+ {
295+ PythonQtClassInfo* info = new PythonQtClassInfo (meta, cppClassName);
296+ PythonQtObjectPtr pack = packageByName (package);
297+ PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper (info, package);
298+ PyModule_AddObject (pack, meta?meta->className ():cppClassName, pyobj);
299+ if (package && strncmp (package," Qt" ,2 )==0 ) {
300+ // put all qt objects into Qt as well
301+ PythonQtObjectPtr pack = packageByName (" Qt" );
302+ PyModule_AddObject (pack, meta?meta->className ():cppClassName, pyobj);
303+ }
304+ info->setPythonQtClassWrapper (pyobj);
305+ return info;
306+ }
307+
298308bool PythonQtPrivate::isEnumType (const QMetaObject* meta, const QByteArray& name) {
299309 int i = meta?meta->indexOfEnumerator (name.constData ()):-1 ;
300310 if (i!=-1 ) {
@@ -337,10 +347,10 @@ PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
337347 classInfo = _knownQtClasses.value (obj->metaObject ()->className ());
338348 }
339349 wrap = createNewPythonQtInstanceWrapper (obj, classInfo);
340- // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->_info ->wrappedClassName().latin1());
350+ // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo() ->wrappedClassName().latin1());
341351 } else {
342352 Py_INCREF (wrap);
343- // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->_info ->wrappedClassName().latin1());
353+ // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo() ->wrappedClassName().latin1());
344354 }
345355 return (PyObject*)wrap;
346356}
@@ -371,7 +381,7 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
371381 info = _knownQtClasses.value (qptr->metaObject ()->className ());
372382 }
373383 wrap = createNewPythonQtInstanceWrapper (qptr, info);
374- // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->_info ->wrappedClassName().latin1());
384+ // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo() ->wrappedClassName().latin1());
375385 } else {
376386 // maybe it is a PyObject, which we can return directly
377387 if (name == " PyObject" ) {
@@ -389,32 +399,37 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
389399 }
390400 PythonQtClassInfo* info = _knownQtWrapperClasses.value (name);
391401 if (!info) {
392- info = new PythonQtClassInfo (wrapper?wrapper->metaObject ():NULL , name);
393- _knownQtWrapperClasses.insert (name, info);
394- PyModule_AddObject (_pythonQtModule, name, (PyObject*)createNewPythonQtClassWrapper (info));
395- } else {
396- if (wrapper && (info->metaObject () != wrapper->metaObject ())) {
397- info->setMetaObject (wrapper->metaObject ());
398- }
402+ registerCPPClass (name.constData ());
403+ info = _knownQtWrapperClasses.value (name);
404+ }
405+ if (wrapper && (info->metaObject () != wrapper->metaObject ())) {
406+ info->setMetaObject (wrapper->metaObject ());
399407 }
400408 wrap = createNewPythonQtInstanceWrapper (wrapper, info, ptr);
401- // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->_info ->wrappedClassName().latin1());
409+ // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo() ->wrappedClassName().latin1());
402410 }
403411 } else {
404412 Py_INCREF (wrap);
405- // mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->_info ->wrappedClassName().latin1());
413+ // mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo() ->wrappedClassName().latin1());
406414 }
407415 return (PyObject*)wrap;
408416}
409417
418+ PyObject* PythonQtPrivate::dummyTuple () {
419+ static PyObject* dummyTuple = NULL ;
420+ if (dummyTuple==NULL ) {
421+ dummyTuple = PyTuple_New (1 );
422+ PyTuple_SET_ITEM (dummyTuple, 0 , PyString_FromString (" dummy" ));
423+ }
424+ return dummyTuple;
425+ }
426+
410427
411428PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper (QObject* obj, PythonQtClassInfo* info, void * wrappedPtr) {
412- PythonQtInstanceWrapper* result;
413- result = (PythonQtInstanceWrapper *)PythonQtInstanceWrapper_Type.tp_new (&PythonQtInstanceWrapper_Type,
414- NULL , NULL );
429+ // call the associated class type to create a new instance...
430+ PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call (info->pythonQtClassWrapper (), dummyTuple (), NULL );
415431
416432 result->setQObject (obj);
417- result->_info = info;
418433 result->_wrappedPtr = wrappedPtr;
419434 result->_ownedByPythonQt = false ;
420435 result->_useQMetaTypeDestroy = false ;
@@ -431,11 +446,36 @@ PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObje
431446 return result;
432447}
433448
434- PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper (PythonQtClassInfo* info) {
449+ PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper (PythonQtClassInfo* info, const char * package ) {
435450 PythonQtClassWrapper* result;
436- result = (PythonQtClassWrapper *)PythonQtClassWrapper_Type.tp_new (&PythonQtClassWrapper_Type,
437- NULL , NULL );
438- result->_info = info;
451+
452+ PyObject* className = PyString_FromString (info->className ());
453+
454+ PyObject* baseClasses = PyTuple_New (1 );
455+ PyTuple_SET_ITEM (baseClasses, 0 , (PyObject*)&PythonQtInstanceWrapper_Type);
456+
457+ PyObject* typeDict = PyDict_New ();
458+ QByteArray moduleName (" PythonQt" );
459+ if (package && strcmp (package, " " )!=0 ) {
460+ moduleName += " ." ;
461+ moduleName += package;
462+ }
463+ PyDict_SetItemString (typeDict, " __module__" , PyString_FromString (moduleName.constData ()));
464+
465+ PyObject* args = Py_BuildValue (" OOO" , className, baseClasses, typeDict);
466+
467+ // set the class info so that PythonQtClassWrapper_new can read it
468+ _currentClassInfoForClassWrapperCreation = info;
469+ // create the new type object by calling the type
470+ result = (PythonQtClassWrapper *)PyObject_Call ((PyObject *)&PythonQtClassWrapper_Type, args, NULL );
471+
472+ Py_DECREF (baseClasses);
473+ Py_DECREF (typeDict);
474+ Py_DECREF (args);
475+ Py_DECREF (className);
476+
477+ // TODO XXX why is this incref needed? It looks like the types get garbage collected somehow?!
478+ Py_INCREF ((PyObject*)result);
439479 return result;
440480}
441481
@@ -666,7 +706,7 @@ QStringList PythonQt::introspection(PyObject* module, const QString& objectname,
666706 }
667707 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
668708 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object ();
669- PythonQtSlotInfo* info = o->_info ->constructors ();
709+ PythonQtSlotInfo* info = o->classInfo () ->constructors ();
670710
671711 while (info) {
672712 results << info->fullSignature (false );
@@ -817,23 +857,21 @@ void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
817857 _p->_cppWrapperFactories .append (factory);
818858}
819859
820- void PythonQt::addConstructorHandler (PythonQtConstructorHandler* factory)
821- {
822- _p->_constructorHandlers .append (factory);
823- }
824-
825- const QList<PythonQtConstructorHandler*>& PythonQt::constructorHandlers ()
826- {
827- return _p->_constructorHandlers ;
828- };
829-
830860// ---------------------------------------------------------------------------------------------------
831861PythonQtPrivate::PythonQtPrivate ()
832862{
833863 _importInterface = NULL ;
834864 _defaultImporter = new PythonQtQFileImporter;
835865 _noLongerWrappedCB = NULL ;
836866 _wrappedCB = NULL ;
867+ _currentClassInfoForClassWrapperCreation = NULL ;
868+ }
869+
870+ PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation ()
871+ {
872+ PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
873+ _currentClassInfoForClassWrapperCreation = NULL ;
874+ return info;
837875}
838876
839877void PythonQtPrivate::addDecorators (QObject* o, int decoTypes)
@@ -1006,16 +1044,8 @@ void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentT
10061044{
10071045 PythonQtClassInfo* info = _knownQtWrapperClasses.value (typeName);
10081046 if (!info) {
1009- info = new PythonQtClassInfo (NULL , typeName);
1047+ info = createPythonQtClassInfo (NULL , typeName, package );
10101048 _knownQtWrapperClasses.insert (typeName, info);
1011- PythonQtObjectPtr pack = packageByName (package);
1012- PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper (info);
1013- PyModule_AddObject (pack, typeName, pyobj);
1014- if (package && strncmp (package," Qt" ,2 )==0 ) {
1015- // put all qt objects into Qt as well
1016- PythonQtObjectPtr pack = packageByName (" Qt" );
1017- PyModule_AddObject (pack, typeName, pyobj);
1018- }
10191049 }
10201050 if (parentTypeName) {
10211051 info->setWrappedParentClassName (parentTypeName);
@@ -1055,6 +1085,11 @@ void PythonQtPrivate::removeWrapperPointer(void* obj)
10551085 _wrappedObjects.remove (obj);
10561086}
10571087
1088+ void PythonQtPrivate::addWrapperPointer (void * obj, PythonQtInstanceWrapper* wrapper)
1089+ {
1090+ _wrappedObjects.insert (obj, wrapper);
1091+ }
1092+
10581093PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused (void * obj)
10591094{
10601095 PythonQtInstanceWrapper* wrap = _wrappedObjects.value (obj);
0 commit comments