PythonQtSlot.cpp
515 lines
| 17.6 KiB
| text/x-c
|
CppLexer
/ src / PythonQtSlot.cpp
ezust
|
r0 | /* | ||
* | ||||
* Copyright (C) 2006 MeVis Research GmbH All Rights Reserved. | ||||
* | ||||
* This library is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU Lesser General Public | ||||
* License as published by the Free Software Foundation; either | ||||
* version 2.1 of the License, or (at your option) any later version. | ||||
* | ||||
* This library is distributed in the hope that it will be useful, | ||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
* Lesser General Public License for more details. | ||||
* | ||||
* Further, this software is distributed without any warranty that it is | ||||
* free of the rightful claim of any third person regarding infringement | ||||
* or the like. Any license provided herein, whether implied or | ||||
* otherwise, applies only to this software file. Patent licenses, if | ||||
* any, provided herein do not apply to combinations of this program with | ||||
* other software, or any other product whatsoever. | ||||
* | ||||
* You should have received a copy of the GNU Lesser General Public | ||||
* License along with this library; if not, write to the Free Software | ||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||
* | ||||
* Contact information: MeVis Research GmbH, Universitaetsallee 29, | ||||
* 28359 Bremen, Germany or: | ||||
* | ||||
* http://www.mevis.de | ||||
* | ||||
*/ | ||||
//---------------------------------------------------------------------------------- | ||||
/*! | ||||
// \file PythonQtSlot.cpp | ||||
// \author Florian Link | ||||
// \author Last changed by $Author: florian $ | ||||
// \date 2006-05 | ||||
*/ | ||||
//---------------------------------------------------------------------------------- | ||||
#include "PythonQt.h" | ||||
#include "PythonQtSlot.h" | ||||
florianlink
|
r16 | #include "PythonQtInstanceWrapper.h" | ||
ezust
|
r0 | #include "PythonQtClassInfo.h" | ||
#include "PythonQtMisc.h" | ||||
#include "PythonQtConversion.h" | ||||
#include <iostream> | ||||
#define PYTHONQT_MAX_ARGS 32 | ||||
florianlink
|
r41 | bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument, PyObject** pythonReturnValue, void** directReturnValuePointer) | ||
ezust
|
r0 | { | ||
static unsigned int recursiveEntry = 0; | ||||
florianlink
|
r18 | if (directReturnValuePointer) { | ||
*directReturnValuePointer = NULL; | ||||
} | ||||
ezust
|
r0 | // store the current storage position, so that we can get back to this state after a slot is called | ||
// (do this locally, so that we have all positions on the stack | ||||
PythonQtValueStoragePosition globalValueStoragePos; | ||||
PythonQtValueStoragePosition globalPtrStoragePos; | ||||
PythonQtValueStoragePosition globalVariantStoragePos; | ||||
PythonQtConv::global_valueStorage.getPos(globalValueStoragePos); | ||||
PythonQtConv::global_ptrStorage.getPos(globalPtrStoragePos); | ||||
PythonQtConv::global_variantStorage.getPos(globalVariantStoragePos); | ||||
recursiveEntry++; | ||||
// the arguments that are passed to qt_metacall | ||||
void* argList[PYTHONQT_MAX_ARGS]; | ||||
PyObject* result = NULL; | ||||
int argc = info->parameterCount(); | ||||
const QList<PythonQtSlotInfo::ParameterInfo>& params = info->parameters(); | ||||
bool returnValueIsEnum = false; | ||||
const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0); | ||||
// set return argument to NULL | ||||
argList[0] = NULL; | ||||
bool ok = true; | ||||
bool skipFirst = false; | ||||
florianlink
|
r10 | if (info->isInstanceDecorator()) { | ||
ezust
|
r0 | skipFirst = true; | ||
florianlink
|
r24 | |||
// for decorators on CPP objects, we take the cpp ptr, for QObjects we take the QObject pointer | ||||
void* arg1 = firstArgument; | ||||
if (!arg1) { | ||||
arg1 = objectToCall; | ||||
ezust
|
r0 | } | ||
florianlink
|
r24 | if (arg1) { | ||
// upcast to correct parent class | ||||
arg1 = ((char*)arg1)+info->upcastingOffset(); | ||||
} | ||||
argList[1] = &arg1; | ||||
ezust
|
r0 | if (ok) { | ||
for (int i = 2; i<argc && ok; i++) { | ||||
const PythonQtSlotInfo::ParameterInfo& param = params.at(i); | ||||
//std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl; | ||||
florianlink
|
r41 | argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-2), strict, classInfo); | ||
ezust
|
r0 | if (argList[i]==NULL) { | ||
ok = false; | ||||
break; | ||||
} | ||||
} | ||||
} | ||||
} else { | ||||
for (int i = 1; i<argc && ok; i++) { | ||||
const PythonQtSlotInfo::ParameterInfo& param = params.at(i); | ||||
//std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl; | ||||
florianlink
|
r41 | argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-1), strict, classInfo); | ||
ezust
|
r0 | if (argList[i]==NULL) { | ||
ok = false; | ||||
break; | ||||
} | ||||
} | ||||
} | ||||
if (ok) { | ||||
florianlink
|
r45 | // parameters are ok, now create the qt return value which is assigned to by metacall | ||
if (returnValueParam.typeId != QMetaType::Void) { | ||||
// extra handling of enum return value | ||||
if (!returnValueParam.isPointer && returnValueParam.typeId == PythonQtMethodInfo::Unknown) { | ||||
returnValueIsEnum = PythonQtClassInfo::hasEnum(returnValueParam.name, classInfo); | ||||
if (returnValueIsEnum) { | ||||
// create enum return value | ||||
PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, argList[0]); | ||||
} | ||||
} | ||||
if (argList[0]==NULL) { | ||||
// create empty default value for the return value | ||||
if (!directReturnValuePointer) { | ||||
// create empty default value for the return value | ||||
argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam); | ||||
florianlink
|
r46 | if (argList[0]==NULL) { | ||
// return value could not be created, maybe we have a registered class with a default constructor, so that we can construct the pythonqt wrapper object and | ||||
// pass its internal pointer | ||||
PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(returnValueParam.name); | ||||
if (info && info->pythonQtClassWrapper()) { | ||||
PyObject* emptyTuple = PyTuple_New(0); | ||||
// 1) default construct an empty object as python object (owned by PythonQt), by calling the meta class with empty arguments | ||||
result = PyObject_Call((PyObject*)info->pythonQtClassWrapper(), emptyTuple, NULL); | ||||
if (result) { | ||||
argList[0] = ((PythonQtInstanceWrapper*)result)->_wrappedPtr; | ||||
} | ||||
Py_DECREF(emptyTuple); | ||||
} | ||||
} | ||||
florianlink
|
r45 | } else { | ||
// we can use our pointer directly! | ||||
argList[0] = directReturnValuePointer; | ||||
} | ||||
} | ||||
} | ||||
// invoke the slot via metacall | ||||
ezust
|
r0 | (info->decorator()?info->decorator():objectToCall)->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList); | ||
florianlink
|
r45 | |||
// handle the return value (which in most cases still needs to be converted to a Python object) | ||||
ezust
|
r0 | if (argList[0] || returnValueParam.typeId == QMetaType::Void) { | ||
florianlink
|
r18 | if (directReturnValuePointer) { | ||
result = NULL; | ||||
ezust
|
r0 | } else { | ||
florianlink
|
r18 | if (!returnValueIsEnum) { | ||
florianlink
|
r46 | // the resulting object maybe present already, because we created it above at 1)... | ||
if (!result) { | ||||
result = PythonQtConv::ConvertQtValueToPython(returnValueParam, argList[0]); | ||||
} | ||||
florianlink
|
r18 | } else { | ||
result = PyInt_FromLong(*((unsigned int*)argList[0])); | ||||
} | ||||
ezust
|
r0 | } | ||
} else { | ||||
florianlink
|
r46 | QString e = QString("Called ") + info->fullSignature() + ", return type '" + returnValueParam.name + "' is ignored because it is unknown to PythonQt. Probably you should register it using qRegisterMetaType() or add a default constructor decorator to the class."; | ||
ezust
|
r0 | PyErr_SetString(PyExc_ValueError, e.toLatin1().data()); | ||
result = NULL; | ||||
} | ||||
} | ||||
recursiveEntry--; | ||||
// reset the parameter storage position to the stored pos to "pop" the parameter stack | ||||
PythonQtConv::global_valueStorage.setPos(globalValueStoragePos); | ||||
PythonQtConv::global_ptrStorage.setPos(globalPtrStoragePos); | ||||
PythonQtConv::global_variantStorage.setPos(globalVariantStoragePos); | ||||
florianlink
|
r18 | *pythonReturnValue = result; | ||
ezust
|
r0 | // NOTE: it is important to only return here, otherwise the stack will not be popped!!! | ||
florianlink
|
r18 | return result || (directReturnValuePointer && *directReturnValuePointer); | ||
ezust
|
r0 | } | ||
//----------------------------------------------------------------------------------- | ||||
static PythonQtSlotFunctionObject *pythonqtslot_free_list = NULL; | ||||
PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw) | ||||
{ | ||||
PythonQtSlotFunctionObject* f = (PythonQtSlotFunctionObject*)func; | ||||
PythonQtSlotInfo* info = f->m_ml; | ||||
florianlink
|
r18 | if (PyObject_TypeCheck(f->m_self, &PythonQtInstanceWrapper_Type)) { | ||
florianlink
|
r16 | PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) f->m_self; | ||
florianlink
|
r41 | return PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, args, kw, self->_wrappedPtr); | ||
florianlink
|
r16 | } else if (f->m_self->ob_type == &PythonQtClassWrapper_Type) { | ||
florianlink
|
r41 | PythonQtClassWrapper* type = (PythonQtClassWrapper*) f->m_self; | ||
florianlink
|
r23 | if (info->isClassDecorator()) { | ||
florianlink
|
r41 | return PythonQtSlotFunction_CallImpl(type->classInfo(), NULL, info, args, kw); | ||
florianlink
|
r23 | } else { | ||
// otherwise, it is an unbound call and we have an instanceDecorator or normal slot... | ||||
Py_ssize_t argc = PyTuple_Size(args); | ||||
if (argc>0) { | ||||
PyObject* firstArg = PyTuple_GET_ITEM(args, 0); | ||||
if (PyObject_TypeCheck(firstArg, (PyTypeObject*)&PythonQtInstanceWrapper_Type) | ||||
florianlink
|
r24 | && ((PythonQtInstanceWrapper*)firstArg)->classInfo()->inherits(type->classInfo())) { | ||
florianlink
|
r23 | PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*)firstArg; | ||
// strip the first argument... | ||||
florianlink
|
r24 | PyObject* newargs = PyTuple_GetSlice(args, 1, argc); | ||
florianlink
|
r41 | PyObject* result = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, newargs, kw, self->_wrappedPtr); | ||
florianlink
|
r23 | Py_DECREF(newargs); | ||
return result; | ||||
} else { | ||||
// first arg is not of correct type! | ||||
QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument, got " + firstArg->ob_type->tp_name; | ||||
PyErr_SetString(PyExc_ValueError, error.toLatin1().data()); | ||||
return NULL; | ||||
} | ||||
} else { | ||||
// wrong number of args | ||||
QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument."; | ||||
PyErr_SetString(PyExc_ValueError, error.toLatin1().data()); | ||||
return NULL; | ||||
} | ||||
} | ||||
ezust
|
r0 | } | ||
florianlink
|
r23 | return NULL; | ||
ezust
|
r0 | } | ||
florianlink
|
r41 | PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * /*kw*/, void* firstArg, void** directReturnValuePointer) | ||
ezust
|
r0 | { | ||
int argc = PyTuple_Size(args); | ||||
florianlink
|
r24 | |||
ezust
|
r0 | #ifdef PYTHONQT_DEBUG | ||
std::cout << "called " << info->metaMethod()->typeName() << " " << info->metaMethod()->signature() << std::endl; | ||||
#endif | ||||
PyObject* r = NULL; | ||||
florianlink
|
r18 | bool ok = false; | ||
if (directReturnValuePointer) { | ||||
*directReturnValuePointer = NULL; | ||||
} | ||||
ezust
|
r0 | if (info->nextInfo()) { | ||
// overloaded slot call, try on all slots with strict conversion first | ||||
florianlink
|
r18 | bool strict = true; | ||
ezust
|
r0 | PythonQtSlotInfo* i = info; | ||
florianlink
|
r18 | while (i) { | ||
florianlink
|
r10 | bool skipFirst = i->isInstanceDecorator(); | ||
ezust
|
r0 | if (i->parameterCount()-1-(skipFirst?1:0) == argc) { | ||
PyErr_Clear(); | ||||
florianlink
|
r41 | ok = PythonQtCallSlot(classInfo, objectToCall, args, strict, i, firstArg, &r, directReturnValuePointer); | ||
florianlink
|
r18 | if (PyErr_Occurred() || ok) break; | ||
ezust
|
r0 | } | ||
i = i->nextInfo(); | ||||
florianlink
|
r18 | if (!i) { | ||
if (strict) { | ||||
// one more run without being strict | ||||
strict = false; | ||||
i = info; | ||||
ezust
|
r0 | } | ||
} | ||||
} | ||||
florianlink
|
r18 | if (!ok && !PyErr_Occurred()) { | ||
ezust
|
r0 | QString e = QString("Could not find matching overload for given arguments:\n" + PythonQtConv::PyObjGetString(args) + "\n The following slots are available:\n"); | ||
PythonQtSlotInfo* i = info; | ||||
while (i) { | ||||
florianlink
|
r23 | e += QString(i->fullSignature()) + "\n"; | ||
ezust
|
r0 | i = i->nextInfo(); | ||
} | ||||
PyErr_SetString(PyExc_ValueError, e.toLatin1().data()); | ||||
} | ||||
} else { | ||||
// simple (non-overloaded) slot call | ||||
florianlink
|
r10 | bool skipFirst = info->isInstanceDecorator(); | ||
ezust
|
r0 | if (info->parameterCount()-1-(skipFirst?1:0) == argc) { | ||
PyErr_Clear(); | ||||
florianlink
|
r41 | ok = PythonQtCallSlot(classInfo, objectToCall, args, false, info, firstArg, &r, directReturnValuePointer); | ||
florianlink
|
r18 | if (!ok && !PyErr_Occurred()) { | ||
florianlink
|
r23 | QString e = QString("Called ") + info->fullSignature() + " with wrong arguments: " + PythonQtConv::PyObjGetString(args); | ||
ezust
|
r0 | PyErr_SetString(PyExc_ValueError, e.toLatin1().data()); | ||
} | ||||
} else { | ||||
florianlink
|
r23 | QString e = QString("Called ") + info->fullSignature() + " with wrong number of arguments: " + PythonQtConv::PyObjGetString(args); | ||
ezust
|
r0 | PyErr_SetString(PyExc_ValueError, e.toLatin1().data()); | ||
} | ||||
} | ||||
return r; | ||||
} | ||||
PyObject * | ||||
PythonQtSlotFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *module) | ||||
{ | ||||
PythonQtSlotFunctionObject *op; | ||||
op = pythonqtslot_free_list; | ||||
if (op != NULL) { | ||||
pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(op->m_self); | ||||
PyObject_INIT(op, &PythonQtSlotFunction_Type); | ||||
} | ||||
else { | ||||
op = PyObject_GC_New(PythonQtSlotFunctionObject, &PythonQtSlotFunction_Type); | ||||
if (op == NULL) | ||||
return NULL; | ||||
} | ||||
op->m_ml = ml; | ||||
Py_XINCREF(self); | ||||
op->m_self = self; | ||||
Py_XINCREF(module); | ||||
op->m_module = module; | ||||
PyObject_GC_Track(op); | ||||
return (PyObject *)op; | ||||
} | ||||
PythonQtSlotInfo* | ||||
PythonQtSlotFunction_GetSlotInfo(PyObject *op) | ||||
{ | ||||
if (!PythonQtSlotFunction_Check(op)) { | ||||
PyErr_BadInternalCall(); | ||||
return NULL; | ||||
} | ||||
return ((PythonQtSlotFunctionObject *)op) -> m_ml; | ||||
} | ||||
PyObject * | ||||
PythonQtSlotFunction_GetSelf(PyObject *op) | ||||
{ | ||||
if (!PythonQtSlotFunction_Check(op)) { | ||||
PyErr_BadInternalCall(); | ||||
return NULL; | ||||
} | ||||
return ((PythonQtSlotFunctionObject *)op) -> m_self; | ||||
} | ||||
/* Methods (the standard built-in methods, that is) */ | ||||
static void | ||||
meth_dealloc(PythonQtSlotFunctionObject *m) | ||||
{ | ||||
PyObject_GC_UnTrack(m); | ||||
Py_XDECREF(m->m_self); | ||||
Py_XDECREF(m->m_module); | ||||
m->m_self = (PyObject *)pythonqtslot_free_list; | ||||
pythonqtslot_free_list = m; | ||||
} | ||||
static PyObject * | ||||
florianlink
|
r8 | meth_get__doc__(PythonQtSlotFunctionObject * /*m*/, void * /*closure*/) | ||
ezust
|
r0 | { | ||
Py_INCREF(Py_None); | ||||
return Py_None; | ||||
} | ||||
static PyObject * | ||||
florianlink
|
r8 | meth_get__name__(PythonQtSlotFunctionObject *m, void * /*closure*/) | ||
ezust
|
r0 | { | ||
return PyString_FromString(m->m_ml->metaMethod()->signature()); | ||||
} | ||||
static int | ||||
meth_traverse(PythonQtSlotFunctionObject *m, visitproc visit, void *arg) | ||||
{ | ||||
int err; | ||||
if (m->m_self != NULL) { | ||||
err = visit(m->m_self, arg); | ||||
if (err) | ||||
return err; | ||||
} | ||||
if (m->m_module != NULL) { | ||||
err = visit(m->m_module, arg); | ||||
if (err) | ||||
return err; | ||||
} | ||||
return 0; | ||||
} | ||||
static PyObject * | ||||
florianlink
|
r8 | meth_get__self__(PythonQtSlotFunctionObject *m, void * /*closure*/) | ||
ezust
|
r0 | { | ||
PyObject *self; | ||||
if (PyEval_GetRestricted()) { | ||||
PyErr_SetString(PyExc_RuntimeError, | ||||
"method.__self__ not accessible in restricted mode"); | ||||
return NULL; | ||||
} | ||||
self = m->m_self; | ||||
if (self == NULL) | ||||
self = Py_None; | ||||
Py_INCREF(self); | ||||
return self; | ||||
} | ||||
static PyGetSetDef meth_getsets [] = { | ||||
{"__doc__", (getter)meth_get__doc__, NULL, NULL}, | ||||
{"__name__", (getter)meth_get__name__, NULL, NULL}, | ||||
{"__self__", (getter)meth_get__self__, NULL, NULL}, | ||||
florianlink
|
r8 | {NULL, NULL, NULL,NULL}, | ||
ezust
|
r0 | }; | ||
florianlink
|
r8 | #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 6 | ||
#define PY_WRITE_RESTRICTED WRITE_RESTRICTED | ||||
#endif | ||||
ezust
|
r0 | #define OFF(x) offsetof(PythonQtSlotFunctionObject, x) | ||
static PyMemberDef meth_members[] = { | ||||
florianlink
|
r8 | {"__module__", T_OBJECT, OFF(m_module), PY_WRITE_RESTRICTED}, | ||
ezust
|
r0 | {NULL} | ||
}; | ||||
static PyObject * | ||||
florianlink
|
r23 | meth_repr(PythonQtSlotFunctionObject *f) | ||
ezust
|
r0 | { | ||
florianlink
|
r24 | if (f->m_self->ob_type == &PythonQtClassWrapper_Type) { | ||
florianlink
|
r23 | PythonQtClassWrapper* self = (PythonQtClassWrapper*) f->m_self; | ||
return PyString_FromFormat("<unbound qt slot %s of %s type>", | ||||
florianlink
|
r24 | f->m_ml->slotName().data(), | ||
florianlink
|
r23 | self->classInfo()->className()); | ||
florianlink
|
r24 | } else { | ||
return PyString_FromFormat("<qt slot %s of %s instance at %p>", | ||||
f->m_ml->slotName().data(), | ||||
f->m_self->ob_type->tp_name, | ||||
f->m_self); | ||||
florianlink
|
r23 | } | ||
ezust
|
r0 | } | ||
static int | ||||
meth_compare(PythonQtSlotFunctionObject *a, PythonQtSlotFunctionObject *b) | ||||
{ | ||||
if (a->m_self != b->m_self) | ||||
return (a->m_self < b->m_self) ? -1 : 1; | ||||
if (a->m_ml == b->m_ml) | ||||
return 0; | ||||
if (strcmp(a->m_ml->metaMethod()->signature(), b->m_ml->metaMethod()->signature()) < 0) | ||||
return -1; | ||||
else | ||||
return 1; | ||||
} | ||||
static long | ||||
meth_hash(PythonQtSlotFunctionObject *a) | ||||
{ | ||||
long x,y; | ||||
if (a->m_self == NULL) | ||||
x = 0; | ||||
else { | ||||
x = PyObject_Hash(a->m_self); | ||||
if (x == -1) | ||||
return -1; | ||||
} | ||||
y = _Py_HashPointer((void*)(a->m_ml)); | ||||
if (y == -1) | ||||
return -1; | ||||
x ^= y; | ||||
if (x == -1) | ||||
x = -2; | ||||
return x; | ||||
} | ||||
PyTypeObject PythonQtSlotFunction_Type = { | ||||
PyObject_HEAD_INIT(&PyType_Type) | ||||
0, | ||||
"builtin_qt_slot", | ||||
sizeof(PythonQtSlotFunctionObject), | ||||
0, | ||||
(destructor)meth_dealloc, /* tp_dealloc */ | ||||
0, /* tp_print */ | ||||
0, /* tp_getattr */ | ||||
0, /* tp_setattr */ | ||||
(cmpfunc)meth_compare, /* tp_compare */ | ||||
(reprfunc)meth_repr, /* tp_repr */ | ||||
0, /* tp_as_number */ | ||||
0, /* tp_as_sequence */ | ||||
0, /* tp_as_mapping */ | ||||
(hashfunc)meth_hash, /* tp_hash */ | ||||
PythonQtSlotFunction_Call, /* tp_call */ | ||||
0, /* tp_str */ | ||||
PyObject_GenericGetAttr, /* tp_getattro */ | ||||
0, /* tp_setattro */ | ||||
0, /* tp_as_buffer */ | ||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ | ||||
0, /* tp_doc */ | ||||
(traverseproc)meth_traverse, /* tp_traverse */ | ||||
0, /* tp_clear */ | ||||
0, /* tp_richcompare */ | ||||
0, /* tp_weaklistoffset */ | ||||
0, /* tp_iter */ | ||||
0, /* tp_iternext */ | ||||
0, /* tp_methods */ | ||||
meth_members, /* tp_members */ | ||||
meth_getsets, /* tp_getset */ | ||||
0, /* tp_base */ | ||||
0, /* tp_dict */ | ||||
}; | ||||
/* Clear out the free list */ | ||||
void | ||||
PythonQtSlotFunction_Fini(void) | ||||
{ | ||||
while (pythonqtslot_free_list) { | ||||
PythonQtSlotFunctionObject *v = pythonqtslot_free_list; | ||||
pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(v->m_self); | ||||
PyObject_GC_Del(v); | ||||
} | ||||
} | ||||