Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/ElmerGUI/PythonQt/src/PythonQtSlot.cpp
3206 views
1
/*
2
*
3
* Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4
*
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public
7
* License as published by the Free Software Foundation; either
8
* version 2.1 of the License, or (at your option) any later version.
9
*
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
14
*
15
* Further, this software is distributed without any warranty that it is
16
* free of the rightful claim of any third person regarding infringement
17
* or the like. Any license provided herein, whether implied or
18
* otherwise, applies only to this software file. Patent licenses, if
19
* any, provided herein do not apply to combinations of this program with
20
* other software, or any other product whatsoever.
21
*
22
* You should have received a copy of the GNU Lesser General Public
23
* License along with this library; if not, write to the Free Software
24
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
*
26
* Contact information: MeVis Research GmbH, Universitaetsallee 29,
27
* 28359 Bremen, Germany or:
28
*
29
* http://www.mevis.de
30
*
31
*/
32
33
//----------------------------------------------------------------------------------
34
/*!
35
// \file PythonQtSlot.cpp
36
// \author Florian Link
37
// \author Last changed by $Author: florian $
38
// \date 2006-05
39
*/
40
//----------------------------------------------------------------------------------
41
42
#include "PythonQt.h"
43
#include "PythonQtSlot.h"
44
#include "PythonQtWrapper.h"
45
#include "PythonQtClassInfo.h"
46
#include "PythonQtMisc.h"
47
#include "PythonQtConversion.h"
48
#include <iostream>
49
50
#define PYTHONQT_MAX_ARGS 32
51
52
// Correction by A. Powell:
53
#if PY_VERSION_HEX >= 0x02060000 || defined EG_MODS
54
#define WRITE_RESTRICTED PY_WRITE_RESTRICTED
55
#endif
56
57
PyObject* PythonQtCallSlot(QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, bool isVariantCall, void* firstArgument)
58
{
59
if (isVariantCall && info->isInstanceDecorator()) return NULL;
60
61
static unsigned int recursiveEntry = 0;
62
63
// store the current storage position, so that we can get back to this state after a slot is called
64
// (do this locally, so that we have all positions on the stack
65
PythonQtValueStoragePosition globalValueStoragePos;
66
PythonQtValueStoragePosition globalPtrStoragePos;
67
PythonQtValueStoragePosition globalVariantStoragePos;
68
PythonQtConv::global_valueStorage.getPos(globalValueStoragePos);
69
PythonQtConv::global_ptrStorage.getPos(globalPtrStoragePos);
70
PythonQtConv::global_variantStorage.getPos(globalVariantStoragePos);
71
72
recursiveEntry++;
73
74
// the arguments that are passed to qt_metacall
75
void* argList[PYTHONQT_MAX_ARGS];
76
PyObject* result = NULL;
77
int argc = info->parameterCount();
78
const QList<PythonQtSlotInfo::ParameterInfo>& params = info->parameters();
79
80
bool returnValueIsEnum = false;
81
const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0);
82
if (returnValueParam.typeId != QMetaType::Void) {
83
// extra handling of enum return value
84
if (!returnValueParam.isPointer && returnValueParam.typeId == PythonQtMethodInfo::Unknown) {
85
returnValueIsEnum = PythonQt::priv()->isEnumType(objectToCall->metaObject(), returnValueParam.name);
86
if (returnValueIsEnum) {
87
PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, argList[0]);
88
}
89
} else {
90
// create empty default value for the return value
91
argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam);
92
}
93
} else {
94
argList[0] = NULL;
95
}
96
97
const QMetaObject* meta = objectToCall?objectToCall->metaObject():NULL;
98
bool ok = true;
99
if (info->isInstanceDecorator() || isVariantCall) {
100
if (!firstArgument) {
101
argList[1] = &objectToCall;
102
} else {
103
// for the variant call we take the ptr to the variant data, for decorators on CPP objects, we take the cpp ptr
104
argList[1] = &firstArgument;
105
}
106
if (ok) {
107
for (int i = 2; i<argc && ok; i++) {
108
const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
109
//std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl;
110
argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-2), strict, meta);
111
if (argList[i]==NULL) {
112
ok = false;
113
break;
114
}
115
}
116
}
117
} else {
118
for (int i = 1; i<argc && ok; i++) {
119
const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
120
//std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl;
121
argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-1), strict, meta);
122
if (argList[i]==NULL) {
123
ok = false;
124
break;
125
}
126
}
127
}
128
129
if (ok) {
130
(info->decorator()?info->decorator():objectToCall)->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList);
131
132
if (!returnValueIsEnum) {
133
result = PythonQtConv::ConvertQtValueToPython(returnValueParam, argList[0]);
134
} else {
135
result = PyInt_FromLong(*((unsigned int*)argList[0]));
136
}
137
}
138
recursiveEntry--;
139
140
// reset the parameter storage position to the stored pos to "pop" the parameter stack
141
PythonQtConv::global_valueStorage.setPos(globalValueStoragePos);
142
PythonQtConv::global_ptrStorage.setPos(globalPtrStoragePos);
143
PythonQtConv::global_variantStorage.setPos(globalVariantStoragePos);
144
145
// NOTE: it is important to only return here, otherwise the stack will not be popped!!!
146
return result;
147
}
148
149
//-----------------------------------------------------------------------------------
150
151
static PythonQtSlotFunctionObject *pythonqtslot_free_list = NULL;
152
153
PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw)
154
{
155
PythonQtSlotFunctionObject* f = (PythonQtSlotFunctionObject*)func;
156
PythonQtSlotInfo* info = f->m_ml;
157
if (f->m_self->ob_type == &PythonQtWrapper_Type) {
158
PythonQtWrapper* self = (PythonQtWrapper*) f->m_self;
159
return PythonQtSlotFunction_CallImpl(self->_obj, info, args, kw, false, self->_wrappedPtr);
160
} else if (f->m_self->ob_type == &PythonQtVariantWrapper_Type) {
161
PythonQtVariantWrapper* self = (PythonQtVariantWrapper*) f->m_self;
162
if (!info->isClassDecorator()) {
163
return PythonQtSlotFunction_CallImpl(self->_wrapper, info, args, kw, true, (void*)self->_variant->constData());
164
} else {
165
return PythonQtSlotFunction_CallImpl(NULL, info, args, kw);
166
}
167
} else if (f->m_self->ob_type == &PythonQtMetaObjectWrapper_Type) {
168
return PythonQtSlotFunction_CallImpl(NULL, info, args, kw);
169
} else {
170
return NULL;
171
}
172
}
173
174
PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject *kw, bool isVariantCall, void* firstArg)
175
{
176
int argc = PyTuple_Size(args);
177
178
#ifdef PYTHONQT_DEBUG
179
std::cout << "called " << info->metaMethod()->typeName() << " " << info->metaMethod()->signature() << std::endl;
180
#endif
181
182
PyObject* r = NULL;
183
184
if (info->nextInfo()) {
185
// overloaded slot call, try on all slots with strict conversion first
186
PythonQtSlotInfo* i = info;
187
while (i && r==NULL) {
188
bool skipFirst = (i->isInstanceDecorator() || isVariantCall);
189
if (i->parameterCount()-1-(skipFirst?1:0) == argc) {
190
r = PythonQtCallSlot(objectToCall, args, true, i, isVariantCall, firstArg);
191
}
192
i = i->nextInfo();
193
}
194
if (!r) {
195
// try on all slots with non-strict conversion
196
i = info;
197
while (i && r==NULL) {
198
bool skipFirst = (i->isInstanceDecorator() || isVariantCall);
199
if (i->parameterCount()-1-(skipFirst?1:0) == argc) {
200
r = PythonQtCallSlot(objectToCall, args, false, i, isVariantCall, firstArg);
201
}
202
i = i->nextInfo();
203
}
204
}
205
if (r==0) {
206
QString e = QString("Could not find matching overload for given arguments:\n" + PythonQtConv::PyObjGetString(args) + "\n The following slots are available:\n");
207
PythonQtSlotInfo* i = info;
208
while (i) {
209
bool skipFirst = (i->isInstanceDecorator() || isVariantCall);
210
e += QString(i->fullSignature(skipFirst)) + "\n";
211
i = i->nextInfo();
212
}
213
PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
214
}
215
} else {
216
// simple (non-overloaded) slot call
217
bool skipFirst = (info->isInstanceDecorator() || isVariantCall);
218
if (info->parameterCount()-1-(skipFirst?1:0) == argc) {
219
r = PythonQtCallSlot(objectToCall, args, false, info, isVariantCall, firstArg);
220
if (!r) {
221
QString e = QString("Called ") + info->fullSignature(skipFirst) + " with wrong arguments: " + PythonQtConv::PyObjGetString(args);
222
PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
223
}
224
} else {
225
QString e = QString("Called ") + info->fullSignature(skipFirst) + " with wrong number of arguments: " + PythonQtConv::PyObjGetString(args);
226
PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
227
}
228
}
229
230
return r;
231
}
232
233
PyObject *
234
PythonQtSlotFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *module)
235
{
236
PythonQtSlotFunctionObject *op;
237
op = pythonqtslot_free_list;
238
if (op != NULL) {
239
pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(op->m_self);
240
PyObject_INIT(op, &PythonQtSlotFunction_Type);
241
}
242
else {
243
op = PyObject_GC_New(PythonQtSlotFunctionObject, &PythonQtSlotFunction_Type);
244
if (op == NULL)
245
return NULL;
246
}
247
op->m_ml = ml;
248
Py_XINCREF(self);
249
op->m_self = self;
250
Py_XINCREF(module);
251
op->m_module = module;
252
PyObject_GC_Track(op);
253
return (PyObject *)op;
254
}
255
256
PythonQtSlotInfo*
257
PythonQtSlotFunction_GetSlotInfo(PyObject *op)
258
{
259
if (!PythonQtSlotFunction_Check(op)) {
260
PyErr_BadInternalCall();
261
return NULL;
262
}
263
return ((PythonQtSlotFunctionObject *)op) -> m_ml;
264
}
265
266
PyObject *
267
PythonQtSlotFunction_GetSelf(PyObject *op)
268
{
269
if (!PythonQtSlotFunction_Check(op)) {
270
PyErr_BadInternalCall();
271
return NULL;
272
}
273
return ((PythonQtSlotFunctionObject *)op) -> m_self;
274
}
275
276
/* Methods (the standard built-in methods, that is) */
277
278
static void
279
meth_dealloc(PythonQtSlotFunctionObject *m)
280
{
281
PyObject_GC_UnTrack(m);
282
Py_XDECREF(m->m_self);
283
Py_XDECREF(m->m_module);
284
m->m_self = (PyObject *)pythonqtslot_free_list;
285
pythonqtslot_free_list = m;
286
}
287
288
static PyObject *
289
meth_get__doc__(PythonQtSlotFunctionObject *m, void *closure)
290
{
291
Py_INCREF(Py_None);
292
return Py_None;
293
}
294
295
static PyObject *
296
meth_get__name__(PythonQtSlotFunctionObject *m, void *closure)
297
{
298
return PyString_FromString(m->m_ml->metaMethod()->signature());
299
}
300
301
static int
302
meth_traverse(PythonQtSlotFunctionObject *m, visitproc visit, void *arg)
303
{
304
int err;
305
if (m->m_self != NULL) {
306
err = visit(m->m_self, arg);
307
if (err)
308
return err;
309
}
310
if (m->m_module != NULL) {
311
err = visit(m->m_module, arg);
312
if (err)
313
return err;
314
}
315
return 0;
316
}
317
318
static PyObject *
319
meth_get__self__(PythonQtSlotFunctionObject *m, void *closure)
320
{
321
PyObject *self;
322
if (PyEval_GetRestricted()) {
323
PyErr_SetString(PyExc_RuntimeError,
324
"method.__self__ not accessible in restricted mode");
325
return NULL;
326
}
327
self = m->m_self;
328
if (self == NULL)
329
self = Py_None;
330
Py_INCREF(self);
331
return self;
332
}
333
334
static PyGetSetDef meth_getsets [] = {
335
{"__doc__", (getter)meth_get__doc__, NULL, NULL},
336
{"__name__", (getter)meth_get__name__, NULL, NULL},
337
{"__self__", (getter)meth_get__self__, NULL, NULL},
338
{0}
339
};
340
341
#define OFF(x) offsetof(PythonQtSlotFunctionObject, x)
342
343
static PyMemberDef meth_members[] = {
344
{"__module__", T_OBJECT, OFF(m_module), WRITE_RESTRICTED},
345
{NULL}
346
};
347
348
static PyObject *
349
meth_repr(PythonQtSlotFunctionObject *m)
350
{
351
return PyString_FromFormat("<built-in qt slot %s of %s object at %p>",
352
m->m_ml->metaMethod()->signature(),
353
m->m_self->ob_type->tp_name,
354
m->m_self);
355
}
356
357
static int
358
meth_compare(PythonQtSlotFunctionObject *a, PythonQtSlotFunctionObject *b)
359
{
360
if (a->m_self != b->m_self)
361
return (a->m_self < b->m_self) ? -1 : 1;
362
if (a->m_ml == b->m_ml)
363
return 0;
364
if (strcmp(a->m_ml->metaMethod()->signature(), b->m_ml->metaMethod()->signature()) < 0)
365
return -1;
366
else
367
return 1;
368
}
369
370
static long
371
meth_hash(PythonQtSlotFunctionObject *a)
372
{
373
long x,y;
374
if (a->m_self == NULL)
375
x = 0;
376
else {
377
x = PyObject_Hash(a->m_self);
378
if (x == -1)
379
return -1;
380
}
381
y = _Py_HashPointer((void*)(a->m_ml));
382
if (y == -1)
383
return -1;
384
x ^= y;
385
if (x == -1)
386
x = -2;
387
return x;
388
}
389
390
391
PyTypeObject PythonQtSlotFunction_Type = {
392
PyObject_HEAD_INIT(&PyType_Type)
393
0,
394
"builtin_qt_slot",
395
sizeof(PythonQtSlotFunctionObject),
396
0,
397
(destructor)meth_dealloc, /* tp_dealloc */
398
0, /* tp_print */
399
0, /* tp_getattr */
400
0, /* tp_setattr */
401
(cmpfunc)meth_compare, /* tp_compare */
402
(reprfunc)meth_repr, /* tp_repr */
403
0, /* tp_as_number */
404
0, /* tp_as_sequence */
405
0, /* tp_as_mapping */
406
(hashfunc)meth_hash, /* tp_hash */
407
PythonQtSlotFunction_Call, /* tp_call */
408
0, /* tp_str */
409
PyObject_GenericGetAttr, /* tp_getattro */
410
0, /* tp_setattro */
411
0, /* tp_as_buffer */
412
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
413
0, /* tp_doc */
414
(traverseproc)meth_traverse, /* tp_traverse */
415
0, /* tp_clear */
416
0, /* tp_richcompare */
417
0, /* tp_weaklistoffset */
418
0, /* tp_iter */
419
0, /* tp_iternext */
420
0, /* tp_methods */
421
meth_members, /* tp_members */
422
meth_getsets, /* tp_getset */
423
0, /* tp_base */
424
0, /* tp_dict */
425
};
426
427
/* Clear out the free list */
428
429
void
430
PythonQtSlotFunction_Fini(void)
431
{
432
while (pythonqtslot_free_list) {
433
PythonQtSlotFunctionObject *v = pythonqtslot_free_list;
434
pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(v->m_self);
435
PyObject_GC_Del(v);
436
}
437
}
438
439
440