1 /************************************************************************
2 *
3 * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com)
4 *
5 * This file is part of SuperCollider Qt GUI.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 ************************************************************************/
21
22 #include "primitives.h"
23 #include "../QObjectProxy.h"
24 #include "../QcObjectFactory.h"
25 #include "../QcApplication.h"
26 #include "../Common.h"
27 #include "../type_codec.hpp"
28 #include "../metatype.hpp"
29 #include "../painting.h"
30
31 #include <PyrObject.h>
32 #include <PyrKernel.h>
33 #include <GC.h>
34 #include <SCBase.h>
35
36 #include <QMetaObject>
37 #include <QMetaProperty>
38 #include <QMetaMethod>
39
40 #if defined _WIN32
41 # include "SC_Win32Utils.h"
42 #elif defined __FreeBSD__
43 # include <stdlib.h>
44 #else
45 # include <alloca.h>
46 #endif
47
48 #define IS_OBJECT_NIL(a) IsNil(slotRawObject(a)->slots)
49
50 #define QOBJECT_FROM_SLOT(s) ((QObjectProxy*)slotRawPtr(slotRawObject(s)->slots))
51
52 #define CLASS_NAME(slot) slotRawSymbol(&slotRawObject(slot)->classptr->name)->name
53
54 namespace QtCollider {
55
56 int QObject_Finalize(struct VMGlobals*, struct PyrObject*);
57
58 QC_LANG_PRIMITIVE(QObject_New, 2, PyrSlot* r, PyrSlot* a, VMGlobals* g) {
59 if (NotSym(a + 0))
60 return errWrongType;
61
62 PyrObject* scObject = slotRawObject(r);
63 QString qtClassName = QString(slotRawSymbol(a + 0)->name);
64
65 qcSCObjectDebugMsg(1, scObject, QStringLiteral("CREATE: %2").arg(qtClassName));
66
67 if (!QcApplication::compareThread())
68 return QtCollider::wrongThreadError();
69
70 QcAbstractFactory* f = QtCollider::factories().value(qtClassName);
71
72 if (!f) {
73 qcErrorMsg(QStringLiteral("Factory for class '%1' not found!").arg(qtClassName));
74 return errFailed;
75 }
76
77 QObjectProxy* proxy = 0;
78
79 MetaValue args[10];
80
81 PyrSlot* argSlot = a + 1;
82 int argc;
83
84 if (isKindOfSlot(argSlot, class_array)) {
85 PyrObject* array = slotRawObject(argSlot);
86 argSlot = array->slots;
87 argc = array->size;
88 } else {
89 argc = 1;
90 }
91
92 for (int i = 0; i < argc && i < 10; ++i) {
93 PyrSlot* slot = argSlot + i;
94 MetaType* type = MetaType::find(slot);
95 if (type) {
96 void* mem = alloca(type->size());
97 Q_ASSERT(mem);
98 args[i].read(mem, type, slot);
99 }
100 }
101
102 proxy = f->newInstance(scObject, args);
103 if (!proxy)
104 return errFailed;
105
106 SetPtr(scObject->slots, proxy);
107
108 InstallFinalizer(g, scObject, 1, QObject_Finalize);
109
110 return errNone;
111 }
112
113 QC_LANG_PRIMITIVE(QObject_Destroy, 0, PyrSlot* r, PyrSlot* a, VMGlobals* g) {
114 qcSCObjectDebugMsg(1, slotRawObject(r), "DESTROY");
115
116 QObjectProxy* proxy = QOBJECT_FROM_SLOT(r);
117
118 if (!proxy->compareThread())
119 return QtCollider::wrongThreadError();
120
121 // Post the destruction event asynchronously;
122 DestroyEvent* e = new DestroyEvent(QObjectProxy::DestroyObject);
123 QApplication::postEvent(proxy, e);
124
125 return errNone;
126 }
127
QObject_Finalize(struct VMGlobals *,struct PyrObject * obj)128 int QObject_Finalize(struct VMGlobals*, struct PyrObject* obj) {
129 qcSCObjectDebugMsg(1, obj, "FINALIZE");
130
131 QObjectProxy* proxy = (QObjectProxy*)slotRawPtr(obj->slots);
132
133 // Invalidate proxy's SC object pointer directly.
134 // Note that it is protected by language mutex;
135 proxy->finalize();
136
137 // Post the destruction event asynchronously;
138 DestroyEvent* e = new DestroyEvent(QObjectProxy::DestroyProxyAndObject);
139 QApplication::postEvent(proxy, e);
140
141 return errNone;
142 }
143
144 QC_LANG_PRIMITIVE(QObject_SetParent, 1, PyrSlot* r, PyrSlot* a, VMGlobals* g) {
145 QObjectProxy* proxy = QOBJECT_FROM_SLOT(r);
146
147 QObjectProxy* parent = QtCollider::get(a);
148 if (!parent)
149 return errWrongType;
150
151 qcSCObjectDebugMsg(1, slotRawObject(r), "SET PARENT");
152
153 if (!proxy->compareThread())
154 return QtCollider::wrongThreadError();
155
156 bool ok = proxy->setParent(parent);
157
158 return ok ? errNone : errFailed;
159 }
160
qcGetProperties(const QMetaObject * mo,PyrSlot * r,VMGlobals * g)161 static void qcGetProperties(const QMetaObject* mo, PyrSlot* r, VMGlobals* g) {
162 int count = mo->propertyCount();
163
164 PyrObject* array = newPyrArray(g->gc, count, 0, true);
165 SetObject(r, array);
166
167 PyrSlot* s = array->slots;
168 for (int i = 0; i < count; ++i, ++s) {
169 SetSymbol(s, getsym(mo->property(i).name()));
170 array->size++;
171 }
172 }
173
qcGetMethods(const QMetaObject * mo,bool getPlain,bool getSignals,bool getSlots,PyrSlot * r,VMGlobals * g)174 static void qcGetMethods(const QMetaObject* mo, bool getPlain, bool getSignals, bool getSlots, PyrSlot* r,
175 VMGlobals* g) {
176 int count = mo->methodCount();
177
178 PyrObject* array = newPyrArray(g->gc, count, 0, true);
179 SetObject(r, array);
180
181 PyrSlot* s = array->slots;
182 for (int i = 0; i < count; ++i) {
183 QMetaMethod method = mo->method(i);
184 switch (method.methodType()) {
185 case QMetaMethod::Method:
186 if (!getPlain || (method.access() != QMetaMethod::Public))
187 continue;
188 break;
189 case QMetaMethod::Signal:
190 if (!getSignals)
191 continue;
192 break;
193 case QMetaMethod::Slot:
194 if (!getSlots || (method.access() != QMetaMethod::Public))
195 continue;
196 break;
197 default:
198 continue;
199 }
200 QtCollider::set(s, QString::fromLatin1(method.methodSignature()));
201 array->size++;
202 g->gc->GCWrite(array, s);
203 ++s;
204 }
205 }
206
207 QC_LANG_PRIMITIVE(QMetaObject_Properties, 0, PyrSlot* r, PyrSlot* a, VMGlobals* g) {
208 if (!QcApplication::compareThread())
209 return QtCollider::wrongThreadError();
210
211 PyrSlot* sClassName = slotRawObject(r)->slots + 0;
212 if (NotSym(sClassName))
213 return errWrongType;
214 QString className(slotRawSymbol(sClassName)->name);
215
216 QcAbstractFactory* f = QtCollider::factories().value(className);
217
218 if (!f) {
219 qcErrorMsg(QStringLiteral("Factory for class '%1' not found!").arg(className));
220 return errFailed;
221 }
222
223 const QMetaObject* mo = f->metaObject();
224 qcGetProperties(mo, r, g);
225
226 return errNone;
227 }
228
229 QC_LANG_PRIMITIVE(QMetaObject_Methods, 3, PyrSlot* r, PyrSlot* a, VMGlobals* g) {
230 if (!QcApplication::compareThread())
231 return QtCollider::wrongThreadError();
232
233 PyrSlot* sClassName = slotRawObject(r)->slots + 0;
234 if (NotSym(sClassName))
235 return errWrongType;
236 QString className(slotRawSymbol(sClassName)->name);
237
238 QcAbstractFactory* f = QtCollider::factories().value(className);
239
240 if (!f) {
241 qcErrorMsg(QStringLiteral("Factory for class '%1' not found!").arg(className));
242 return errFailed;
243 }
244
245 bool getPlain = IsTrue(a + 0);
246 bool getSignals = IsTrue(a + 1);
247 bool getSlots = IsTrue(a + 2);
248
249 const QMetaObject* mo = f->metaObject();
250 qcGetMethods(mo, getPlain, getSignals, getSlots, r, g);
251
252 return errNone;
253 }
254
255 QC_LANG_PRIMITIVE(QObject_GetProperties, 0, PyrSlot* r, PyrSlot* a, VMGlobals* g) {
256 QObjectProxy* proxy = QOBJECT_FROM_SLOT(r);
257 if (!proxy->compareThread())
258 return QtCollider::wrongThreadError();
259
260 QObject* obj = proxy->object();
261 if (!obj) {
262 SetNil(r);
263 return errNone;
264 }
265
266 const QMetaObject* mo = obj->metaObject();
267 qcGetProperties(mo, r, g);
268
269 return errNone;
270 }
271
272 QC_LANG_PRIMITIVE(QObject_GetMethods, 3, PyrSlot* r, PyrSlot* a, VMGlobals* g) {
273 QObjectProxy* proxy = QOBJECT_FROM_SLOT(r);
274 if (!proxy->compareThread())
275 return QtCollider::wrongThreadError();
276
277 QObject* obj = proxy->object();
278 if (!obj) {
279 SetNil(r);
280 return errNone;
281 }
282
283 bool getPlain = IsTrue(a + 0);
284 bool getSignals = IsTrue(a + 1);
285 bool getSlots = IsTrue(a + 2);
286
287 const QMetaObject* mo = obj->metaObject();
288 qcGetMethods(mo, getPlain, getSignals, getSlots, r, g);
289
290 return errNone;
291 }
292
293 QC_LANG_PRIMITIVE(QObject_SetProperty, 3, PyrSlot* r, PyrSlot* a, VMGlobals* g) {
294 QObjectProxy* proxy = QOBJECT_FROM_SLOT(r);
295
296 if (NotSym(a))
297 return errWrongType;
298 PyrSymbol* property = slotRawSymbol(a);
299 bool sync = IsTrue(a + 2);
300
301 qcSCObjectDebugMsg(1, slotRawObject(r), QStringLiteral("SET: %1").arg(property->name));
302
303 if (!proxy->compareThread())
304 return QtCollider::wrongThreadError();
305
306 QVariant val = QtCollider::get(a + 1);
307
308 if (sync && !QtCollider::isPaintingObject(proxy)) {
309 proxy->setProperty(property->name, val);
310 } else {
311 SetPropertyEvent* e = new SetPropertyEvent();
312 e->property = property;
313 e->value = val;
314 QApplication::postEvent(proxy, e);
315 }
316
317 return errNone;
318 }
319
320 QC_LANG_PRIMITIVE(QObject_GetProperty, 1, PyrSlot* r, PyrSlot* a, VMGlobals* g) {
321 QObjectProxy* proxy = QOBJECT_FROM_SLOT(r);
322
323 if (NotSym(a))
324 return errWrongType;
325 PyrSymbol* symProp = slotRawSymbol(a);
326
327 qcSCObjectDebugMsg(1, slotRawObject(r), QStringLiteral("GET: %1").arg(symProp->name));
328
329 if (!proxy->compareThread())
330 return QtCollider::wrongThreadError();
331
332 QVariant val = proxy->property(symProp->name);
333 if (!val.isValid()) {
334 qcDebugMsg(1, QStringLiteral("WARNING: Invalid property '%1'").arg(symProp->name));
335 SetNil(r);
336 return errNone;
337 }
338
339 if (QtCollider::set(r, val))
340 return errNone;
341 else
342 return errFailed;
343 }
344
345 QC_LANG_PRIMITIVE(QObject_SetEventHandler, 4, PyrSlot* r, PyrSlot* a, VMGlobals* g) {
346 QObjectProxy* proxy = QOBJECT_FROM_SLOT(r);
347
348 if (NotInt(a + 0) || NotSym(a + 1))
349 return errWrongType;
350 int eventType = QtCollider::get(a + 0);
351 PyrSymbol* method = 0;
352 slotSymbolVal(a + 1, &method);
353 Synchronicity sync = IsTrue(a + 2) ? Synchronous : Asynchronous;
354 bool enabled = IsTrue(a + 3);
355
356 qcSCObjectDebugMsg(1, slotRawObject(r),
357 QStringLiteral("SET EVENT HANDLER: type %1 -> %2 [%3, %4]")
358 .arg(eventType)
359 .arg(method->name)
360 .arg(sync == Synchronous ? "SYNC" : "ASYNC")
361 .arg(enabled ? "on" : "off"));
362
363 if (!proxy->compareThread())
364 return QtCollider::wrongThreadError();
365
366 bool ok = proxy->setEventHandler(eventType, method, sync, enabled);
367
368 return ok ? errNone : errFailed;
369 }
370
371 QC_LANG_PRIMITIVE(QObject_SetEventHandlerEnabled, 2, PyrSlot* r, PyrSlot* a, VMGlobals* g) {
372 if (NotInt(a + 0))
373 return errWrongType;
374 bool enabled = IsTrue(a + 1);
375 if (!enabled && !IsFalse(a + 1))
376 return errWrongType;
377 int type = QtCollider::get(a + 0);
378
379 qcSCObjectDebugMsg(1, slotRawObject(r),
380 QStringLiteral("SET EVENT HANDLER STATE: type %1 = %2").arg(type).arg(enabled ? "on" : "off"));
381
382 QObjectProxy* proxy = QOBJECT_FROM_SLOT(r);
383
384 if (!proxy->compareThread())
385 return QtCollider::wrongThreadError();
386
387 bool ok = proxy->setEventHandlerEnabled(type, enabled);
388
389 return ok ? errNone : errFailed;
390 }
391
392 QC_LANG_PRIMITIVE(QObject_ConnectMethod, 3, PyrSlot* r, PyrSlot* a, VMGlobals* g) {
393 if (NotSym(a + 0) || NotSym(a + 1))
394 return errWrongType;
395
396 PyrSymbol* signal = slotRawSymbol(a + 0);
397 PyrSymbol* handler = slotRawSymbol(a + 1);
398 Qt::ConnectionType ctype = IsTrue(a + 2) ? Qt::DirectConnection : Qt::QueuedConnection;
399
400 qcSCObjectDebugMsg(1, slotRawObject(r),
401 QStringLiteral("CONNECT METHOD: %1 -> %2 [%3]")
402 .arg(signal->name)
403 .arg(handler->name)
404 .arg(IsTrue(a + 2) ? "SYNC" : "ASYNC"));
405
406 QObjectProxy* proxy = QOBJECT_FROM_SLOT(r);
407
408 if (!proxy->compareThread())
409 return QtCollider::wrongThreadError();
410
411 bool ok = proxy->connectMethod(signal->name, handler, ctype);
412
413 return ok ? errNone : errFailed;
414 }
415
416 QC_LANG_PRIMITIVE(QObject_DisconnectMethod, 2, PyrSlot* r, PyrSlot* a, VMGlobals* g) {
417 if (NotSym(a + 0) || NotSym(a + 1))
418 return errWrongType;
419
420 PyrSymbol* signal = slotRawSymbol(a + 0);
421 PyrSymbol* handler = slotRawSymbol(a + 1);
422
423 qcSCObjectDebugMsg(1, slotRawObject(r),
424 QStringLiteral("DISCONNECT METHOD: %1 -> %2").arg(signal->name).arg(handler->name));
425
426 QObjectProxy* proxy = QOBJECT_FROM_SLOT(r);
427
428 if (!proxy->compareThread())
429 return QtCollider::wrongThreadError();
430
431 bool ok = proxy->disconnectMethod(signal->name, handler);
432
433 return ok ? errNone : errFailed;
434 }
435
436 QC_LANG_PRIMITIVE(QObject_ConnectObject, 3, PyrSlot* r, PyrSlot* a, VMGlobals* g) {
437 if (NotSym(a + 0) || NotObj(a + 1))
438 return errWrongType;
439
440 PyrSymbol* signal = slotRawSymbol(a + 0);
441 PyrObject* handlerObj = slotRawObject(a + 1);
442 Qt::ConnectionType ctype = IsTrue(a + 2) ? Qt::DirectConnection : Qt::QueuedConnection;
443
444 qcSCObjectDebugMsg(1, slotRawObject(r),
445 QStringLiteral("CONNECT OBJECT: %1 -> %2 [%3]")
446 .arg(signal->name)
447 .arg(slotRawSymbol(&handlerObj->classptr->name)->name)
448 .arg(IsTrue(a + 2) ? "SYNC" : "ASYNC"));
449
450 QObjectProxy* proxy = QOBJECT_FROM_SLOT(r);
451
452 if (!proxy->compareThread())
453 return QtCollider::wrongThreadError();
454
455 bool ok = proxy->connectObject(signal->name, handlerObj, ctype);
456
457 return ok ? errNone : errFailed;
458 }
459
460 QC_LANG_PRIMITIVE(QObject_DisconnectObject, 2, PyrSlot* r, PyrSlot* a, VMGlobals* g) {
461 if (NotSym(a + 0) || NotObj(a + 1))
462 return errWrongType;
463
464 PyrSymbol* signal = slotRawSymbol(a + 0);
465 PyrObject* handlerObj = slotRawObject(a + 1);
466
467 qcSCObjectDebugMsg(1, slotRawObject(r), QStringLiteral("DISCONNECT OBJECT: %1").arg(signal->name));
468
469 QObjectProxy* proxy = QOBJECT_FROM_SLOT(r);
470
471 if (!proxy->compareThread())
472 return QtCollider::wrongThreadError();
473
474 bool ok = proxy->disconnectObject(signal->name, handlerObj);
475
476 return ok ? errNone : errFailed;
477 }
478
479 QC_LANG_PRIMITIVE(QObject_ConnectSlot, 3, PyrSlot* r, PyrSlot* a, VMGlobals* g) {
480 // Args: signal, receiver, slot
481 if (!isKindOfSlot(a + 1, SC_CLASS(QObject)) || NotSym(a + 0) || NotSym(a + 2))
482 return errWrongType;
483
484 PyrSymbol* symSig = slotRawSymbol(a + 0);
485 PyrSymbol* symSlot = slotRawSymbol(a + 2);
486 QObjectProxy* sndProxy = QOBJECT_FROM_SLOT(r);
487 QObjectProxy* rcvProxy = QOBJECT_FROM_SLOT(a + 1);
488
489 qcSCObjectDebugMsg(1, slotRawObject(r),
490 QStringLiteral("CONNECT TO SLOT: %1 -> %2").arg(symSig->name).arg(symSlot->name));
491
492 QString strSig = QStringLiteral("2") + symSig->name;
493 QString strSlot = QStringLiteral("1") + symSlot->name;
494
495 sndProxy->lock();
496 rcvProxy->lock();
497 bool ok;
498 if (!sndProxy->object() || !rcvProxy->object()) {
499 ok = true;
500 } else {
501 ok = QObject::connect(sndProxy->object(), strSig.toStdString().c_str(), rcvProxy->object(),
502 strSlot.toStdString().c_str());
503 }
504 sndProxy->unlock();
505 rcvProxy->unlock();
506
507 if (!ok) {
508 qcErrorMsg(QStringLiteral("Failed to connect %1::%2 to %3::%4!\n")
509 .arg(sndProxy->scClassName())
510 .arg(symSig->name)
511 .arg(rcvProxy->scClassName())
512 .arg(symSlot->name));
513 return errFailed;
514 }
515
516 return errNone;
517 }
518
519 QC_LANG_PRIMITIVE(QObject_InvokeMethod, 3, PyrSlot* r, PyrSlot* a, VMGlobals* g) {
520 if (NotSym(a + 0))
521 return errWrongType;
522
523 PyrSymbol* method = slotRawSymbol(a + 0);
524 PyrSlot* methodArgs = a + 1;
525 bool sync = !IsFalse(a + 2);
526
527 qcSCObjectDebugMsg(1, slotRawObject(r),
528 QStringLiteral("INVOKE: '%1' [%2]").arg(method->name).arg(sync ? "SYNC" : "ASYNC"));
529
530 QObjectProxy* proxy = QOBJECT_FROM_SLOT(r);
531
532 PyrSlot* retSlot;
533 Qt::ConnectionType cType;
534
535 if (sync) {
536 if (!proxy->compareThread())
537 return QtCollider::wrongThreadError();
538 retSlot = r;
539 cType = Qt::DirectConnection;
540 } else {
541 retSlot = 0;
542 cType = Qt::QueuedConnection;
543 }
544
545 bool ok = proxy->invokeMethod(method->name, retSlot, methodArgs, cType);
546
547 return ok ? errNone : errFailed;
548 }
549
550 QC_LANG_PRIMITIVE(QObject_IsValid, 0, PyrSlot* r, PyrSlot* a, VMGlobals* g) {
551 QObjectProxy* proxy = QOBJECT_FROM_SLOT(r);
552
553 bool needLock = !proxy->compareThread();
554
555 if (needLock)
556 proxy->lock();
557
558 bool hasObject = proxy->object() != 0;
559
560 if (needLock)
561 proxy->unlock();
562
563 SetBool(r, hasObject);
564
565 return errNone;
566 }
567
568 QC_LANG_PRIMITIVE(QObject_GetChildren, 1, PyrSlot* r, PyrSlot* a, VMGlobals* g) {
569 if (NotSym(a) && NotNil(a))
570 return errWrongType;
571
572 QObjectProxy* proxy = QOBJECT_FROM_SLOT(r);
573 PyrSymbol* className = IsSym(a) ? slotRawSymbol(a) : 0;
574
575 qcSCObjectDebugMsg(1, slotRawObject(r),
576 QStringLiteral("GET CHILDREN: of class '%1'").arg(className ? className->name : "QObject"));
577
578 if (!proxy->compareThread())
579 return QtCollider::wrongThreadError();
580
581 QList<PyrObject*> children = proxy->children(className);
582
583 int count = children.count();
584 PyrObject* array = newPyrArray(g->gc, count, 0, true);
585 SetObject(r, array);
586
587 PyrSlot* s = array->slots;
Q_FOREACH(PyrObject * obj,children)588 Q_FOREACH (PyrObject* obj, children) {
589 SetObject(s, obj);
590 ++array->size;
591 g->gc->GCWrite(array, s);
592 ++s;
593 }
594
595 return errNone;
596 }
597
598 QC_LANG_PRIMITIVE(QObject_GetParent, 1, PyrSlot* r, PyrSlot* a, VMGlobals* g) {
599 if (NotSym(a) && NotNil(a))
600 return errWrongType;
601
602 QObjectProxy* proxy = QOBJECT_FROM_SLOT(r);
603 PyrSymbol* className = IsSym(a) ? slotRawSymbol(a) : 0;
604
605 qcSCObjectDebugMsg(1, slotRawObject(r), QStringLiteral("GET PARENT"));
606
607 if (!proxy->compareThread())
608 return QtCollider::wrongThreadError();
609
610 PyrObject* parent = proxy->parent(className);
611
612 if (parent)
613 SetObject(r, parent);
614 else
615 SetNil(r);
616
617 return errNone;
618 }
619
defineQObjectPrimitives()620 void defineQObjectPrimitives() {
621 LangPrimitiveDefiner definer;
622 definer.define<QObject_New>();
623 definer.define<QObject_Destroy>();
624 definer.define<QObject_SetParent>();
625 definer.define<QMetaObject_Properties>();
626 definer.define<QMetaObject_Methods>();
627 definer.define<QObject_GetProperties>();
628 definer.define<QObject_GetMethods>();
629 definer.define<QObject_SetProperty>();
630 definer.define<QObject_GetProperty>();
631 definer.define<QObject_SetEventHandler>();
632 definer.define<QObject_SetEventHandlerEnabled>();
633 definer.define<QObject_ConnectMethod>();
634 definer.define<QObject_DisconnectMethod>();
635 definer.define<QObject_ConnectObject>();
636 definer.define<QObject_DisconnectObject>();
637 definer.define<QObject_ConnectSlot>();
638 definer.define<QObject_InvokeMethod>();
639 definer.define<QObject_IsValid>();
640 definer.define<QObject_GetChildren>();
641 definer.define<QObject_GetParent>();
642 }
643
644 } // namespace QtCollider
645