qtbindings 4.8.6.1 → 4.8.6.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0b9baa4afefcf8d0ed536de82ee1f1e1b0e3006f
4
- data.tar.gz: 5983bda5c916bf7eab47a310c2ee6d85cc811441
3
+ metadata.gz: 874c746da6fcf13bcc0fb15ad796433b0b15096e
4
+ data.tar.gz: 1de49eb84b084043466eb169b6f1f08693ac872d
5
5
  SHA512:
6
- metadata.gz: 77a35e23b4a07ffb93d1be557d3b74f2987fdc401b1cf390e144413a38832ae707acd4ada0cae0e847fe7b44527506b40e824a16537a4a3120e0c9ebc0278ca3
7
- data.tar.gz: 18922390ecad498679aaf990fa8265e7aa78fc42e617eb2ea4aabc8bc6d04fc03e936577ba825e4f6e6e5c1154abdc2be21621e35c5136657a308d2a8fa85278
6
+ metadata.gz: 0e707b3a1425145c4a03d1102d315c4765301d0f35fd26a26fffe276028065907388e38f1aae4826921b6ad8468a9fe7e681f3a74f65d91ea1f9c489c5c50244
7
+ data.tar.gz: 9a7cd631a80d509a3b23fa5a5e1d1ab63d318c9b7d4070e9f4f6a2f833da4fe3aa35d7f564b75989ea7736c86f4ba17bd8d64c89a53b027b0aab85891a4bbe6f
File without changes
data/bin/rbrcc CHANGED
File without changes
data/bin/rbuic4 CHANGED
File without changes
File without changes
File without changes
@@ -1,1310 +1,1327 @@
1
- /***************************************************************************
2
- Qt.cpp - description
3
- -------------------
4
- begin : Fri Jul 4 2003
5
- copyright : (C) 2003-2006 by Richard Dale
6
- email : Richard_Dale@tipitina.demon.co.uk
7
- ***************************************************************************/
8
-
9
- /***************************************************************************
10
- * *
11
- * This program is free software; you can redistribute it and/or modify *
12
- * it under the terms of the GNU Lesser General Public License as *
13
- * published by the Free Software Foundation; either version 2 of the *
14
- * License, or (at your option) any later version. *
15
- * *
16
- ***************************************************************************/
17
-
18
- #ifndef _GNU_SOURCE
19
- #define _GNU_SOURCE
20
- #endif
21
- #include <stdio.h>
22
- #include <stdarg.h>
23
-
24
- #include <QtCore/qabstractitemmodel.h>
25
- #include <QtCore/qglobal.h>
26
- #include <QtCore/qhash.h>
27
- #include <QtCore/qline.h>
28
- #include <QtCore/qmetaobject.h>
29
- #include <QtCore/qobject.h>
30
- #include <QtCore/qrect.h>
31
- #include <QtCore/qregexp.h>
32
- #include <QtCore/qstring.h>
33
- #include <QtCore/qvariant.h>
34
- #include <QtCore/qmutex.h>
35
- #include <QtGui/qapplication.h>
36
- #include <QtGui/qbitmap.h>
37
- #include <QtGui/qcolor.h>
38
- #include <QtGui/qcursor.h>
39
- #include <QtGui/qfont.h>
40
- #include <QtGui/qicon.h>
41
- #include <QtGui/qitemselectionmodel.h>
42
- #include <QtGui/qpalette.h>
43
- #include <QtGui/qpen.h>
44
- #include <QtGui/qpixmap.h>
45
- #include <QtGui/qpolygon.h>
46
- #include <QtGui/qtextformat.h>
47
- #include <QtGui/qwidget.h>
48
-
49
- #ifdef QT_QTDBUS
50
- #include <QtDBus/qdbusargument.h>
51
- #endif
52
-
53
- #undef DEBUG
54
- #ifndef __USE_POSIX
55
- #define __USE_POSIX
56
- #endif
57
- #ifndef __USE_XOPEN
58
- #define __USE_XOPEN
59
- #endif
60
- #ifdef _BOOL
61
- #define HAS_BOOL
62
- #endif
63
-
64
- #include <ruby.h>
65
-
66
- #include <smoke/smoke.h>
67
- #include <smoke/qtcore_smoke.h>
68
-
69
- #undef free
70
- #undef malloc
71
-
72
- #include "marshall.h"
73
- #include "qtruby.h"
74
- #include "smokeruby.h"
75
- #include "smoke.h"
76
- #include "marshall_types.h"
77
- // #define DEBUG
78
-
79
- extern "C" {
80
- VALUE qt_internal_module = Qnil;
81
- VALUE qt_module = Qnil;
82
-
83
- VALUE qlistmodel_class = Qnil;
84
- VALUE qmetaobject_class = Qnil;
85
- VALUE qtablemodel_class = Qnil;
86
- VALUE qt_base_class = Qnil;
87
- VALUE qvariant_class = Qnil;
88
-
89
- VALUE moduleindex_class = Qnil;
90
-
91
- bool application_terminated = false;
92
- }
93
-
94
- QList<Smoke*> smokeList;
95
- QHash<Smoke*, QtRubyModule> qtruby_modules;
96
-
97
- #ifdef DEBUG
98
- int do_debug = qtdb_gc;
99
- #else
100
- int do_debug = qtdb_none;
101
- #endif
102
-
103
- typedef QHash<void *, SmokeValue> PointerMap;
104
- static QMutex pointer_map_mutex;
105
- Q_GLOBAL_STATIC(PointerMap, pointer_map)
106
- int object_count = 0;
107
-
108
- // FIXME:
109
- // Don't the two following hashs create memory leaks by using pointers to Smoke::(Module)Index ?
110
- QHash<QByteArray, Smoke::ModuleIndex *> methcache;
111
- QHash<QByteArray, Smoke::ModuleIndex *> classcache;
112
-
113
- QHash<Smoke::ModuleIndex, QByteArray*> IdToClassNameMap;
114
-
115
- #define logger logger_backend
116
-
117
- Smoke::ModuleIndex _current_method;
118
-
119
- smokeruby_object *
120
- alloc_smokeruby_object(bool allocated, Smoke * smoke, int classId, void * ptr)
121
- {
122
- smokeruby_object * o = ALLOC(smokeruby_object);
123
- o->classId = classId;
124
- o->smoke = smoke;
125
- o->ptr = ptr;
126
- o->allocated = allocated;
127
- return o;
128
- }
129
-
130
- void
131
- free_smokeruby_object(smokeruby_object * o)
132
- {
133
- o->ptr = 0;
134
- xfree(o);
135
- return;
136
- }
137
-
138
- smokeruby_object *value_obj_info(VALUE ruby_value) { // ptr on success, null on fail
139
- if (TYPE(ruby_value) != T_DATA) {
140
- return 0;
141
- }
142
-
143
- smokeruby_object * o = 0;
144
- Data_Get_Struct(ruby_value, smokeruby_object, o);
145
- return o;
146
- }
147
-
148
- void *value_to_ptr(VALUE ruby_value) { // ptr on success, null on fail
149
- smokeruby_object *o = value_obj_info(ruby_value);
150
- return o;
151
- }
152
-
153
- VALUE getPointerObject(void *ptr) {
154
- return getSmokeValue(ptr).value;
155
- }
156
-
157
- SmokeValue getSmokeValue(void *ptr) {
158
- pointer_map_mutex.lock();
159
-
160
- if (!pointer_map() || !pointer_map()->contains(ptr)) {
161
- if (do_debug & qtdb_gc) {
162
- qWarning("getPointerObject %p -> nil", ptr);
163
- if (!pointer_map()) {
164
- qWarning("getPointerObject pointer_map deleted");
165
- }
166
- }
167
- pointer_map_mutex.unlock();
168
- return SmokeValue();
169
- } else {
170
- if (do_debug & qtdb_gc) {
171
- qWarning("getPointerObject %p -> %p", ptr, (void *) pointer_map()->operator[](ptr).value);
172
- }
173
- pointer_map_mutex.unlock();
174
- return pointer_map()->operator[](ptr);
175
- }
176
- }
177
-
178
- void unmapPointer(void *ptr, Smoke *smoke, Smoke::Index fromClassId, Smoke::Index toClassId, void *lastptr) {
179
- pointer_map_mutex.lock();
180
- ptr = smoke->cast(ptr, fromClassId, toClassId);
181
-
182
- if (ptr != lastptr) {
183
- lastptr = ptr;
184
- if (pointer_map() && pointer_map()->contains(ptr)) {
185
- VALUE obj_ptr = pointer_map()->operator[](ptr).value;
186
-
187
- if (do_debug & qtdb_gc) {
188
- const char *className = smoke->classes[fromClassId].className;
189
- qWarning("unmapPointer (%s*)%p -> %p size: %d", className, ptr, (void*)(&obj_ptr), pointer_map()->size() - 1);
190
- }
191
-
192
- pointer_map()->remove(ptr);
193
- }
194
- }
195
-
196
- if (smoke->classes[toClassId].external) {
197
- // encountered external class
198
- Smoke::ModuleIndex mi = Smoke::findClass(smoke->classes[toClassId].className);
199
- if (!mi.index || !mi.smoke) return;
200
-
201
- smoke = mi.smoke;
202
- toClassId = mi.index;
203
- }
204
-
205
- pointer_map_mutex.unlock();
206
- for (Smoke::Index *i = smoke->inheritanceList + smoke->classes[toClassId].parents; *i; i++) {
207
- unmapPointer(ptr, smoke, toClassId, *i, lastptr);
208
- }
209
-
210
- }
211
-
212
- void unmapPointer(smokeruby_object *o, Smoke::Index classId, void *lastptr) {
213
- unmapPointer(o->ptr, o->smoke, o->classId, classId, lastptr);
214
- }
215
-
216
- // Store pointer in pointer_map hash : "pointer_to_Qt_object" => weak ref to associated Ruby object
217
- // Recurse to store it also as casted to its parent classes.
218
-
219
- void mapPointer(VALUE obj, smokeruby_object* o, void *ptr, Smoke *smoke, Smoke::Index fromClassId, Smoke::Index toClassId, void *lastptr) {
220
- pointer_map_mutex.unlock();
221
-
222
- ptr = smoke->cast(ptr, fromClassId, toClassId);
223
-
224
- if (ptr != lastptr) {
225
- lastptr = ptr;
226
-
227
- if (do_debug & qtdb_gc) {
228
- const char *className = smoke->classes[fromClassId].className;
229
- qWarning("mapPointer (%s*)%p -> %p size: %d", className, ptr, (void*)obj, pointer_map()->size() + 1);
230
- }
231
-
232
- SmokeValue value(obj, o);
233
- pointer_map()->insert(ptr, value);
234
- }
235
-
236
- if (smoke->classes[toClassId].external) {
237
- // encountered external class
238
- Smoke::ModuleIndex mi = Smoke::findClass(smoke->classes[toClassId].className);
239
- if (!mi.index || !mi.smoke) return;
240
-
241
- smoke = mi.smoke;
242
- toClassId = mi.index;
243
- }
244
-
245
- pointer_map_mutex.unlock();
246
- for (Smoke::Index *i = smoke->inheritanceList + smoke->classes[toClassId].parents; *i; i++) {
247
- mapPointer(obj, o, ptr, smoke, toClassId, *i, lastptr);
248
- }
249
-
250
- return;
251
- }
252
-
253
- void mapPointer(VALUE obj, smokeruby_object *o, Smoke::Index classId, void *lastptr) {
254
- mapPointer(obj, o, o->ptr, o->smoke, o->classId, classId, lastptr);
255
- }
256
-
257
- namespace QtRuby {
258
-
259
- Binding::Binding() : SmokeBinding(0) {}
260
- Binding::Binding(Smoke *s) : SmokeBinding(s) {}
261
-
262
- void
263
- Binding::deleted(Smoke::Index classId, void *ptr) {
264
- if (!pointer_map()) {
265
- return;
266
- }
267
-
268
- smokeruby_object *o = getSmokeValue(ptr).o;
269
- if (do_debug & qtdb_gc) {
270
- qWarning("unmapping: o = %p, ptr = %p\n", o, ptr);
271
- qWarning("%p->~%s()", ptr, smoke->className(classId));
272
- }
273
- if (!o || !o->ptr) {
274
- return;
275
- }
276
- unmapPointer(o, o->classId, 0);
277
- o->ptr = 0;
278
- }
279
-
280
- bool
281
- Binding::callMethod(Smoke::Index method, void *ptr, Smoke::Stack args, bool /*isAbstract*/) {
282
- VALUE obj = getPointerObject(ptr);
283
- smokeruby_object *o = value_obj_info(obj);
284
-
285
- if (do_debug & qtdb_virtual) {
286
- const Smoke::Method & meth = smoke->methods[method];
287
- QByteArray signature(smoke->methodNames[meth.name]);
288
- signature += "(";
289
- for (int i = 0; i < meth.numArgs; i++) {
290
- if (i != 0) signature += ", ";
291
- signature += smoke->types[smoke->argumentList[meth.args + i]].name;
292
- }
293
- signature += ")";
294
- if (meth.flags & Smoke::mf_const) {
295
- signature += " const";
296
- }
297
- qWarning( "module: %s virtual %p->%s::%s called",
298
- smoke->moduleName(),
299
- ptr,
300
- smoke->classes[smoke->methods[method].classId].className,
301
- (const char *) signature );
302
- }
303
-
304
- if (o == 0) {
305
- if( do_debug & qtdb_virtual ) // if not in global destruction
306
- qWarning("Cannot find object for virtual method %p -> %p", ptr, &obj);
307
- return false;
308
- }
309
- const char *methodName = smoke->methodNames[smoke->methods[method].name];
310
- if (qstrncmp(methodName, "operator", sizeof("operator") - 1) == 0) {
311
- methodName += (sizeof("operator") - 1);
312
- }
313
-
314
- // If not in a ruby thread, just call the C++ version
315
- // During GC, avoid checking for override and just call the C++ version
316
- // If the virtual method hasn't been overriden, just call the C++ one.
317
- #ifdef HAVE_RUBY_RUBY_H
318
- int ruby_thread = ruby_native_thread_p();
319
- if ((ruby_thread == 0) || rb_during_gc() || rb_respond_to(obj, rb_intern(methodName)) == 0) {
320
- return false;
321
- }
322
- #else
323
- if (rb_during_gc() || ruby_stack_check() || rb_respond_to(obj, rb_intern(methodName)) == 0) {
324
- return false;
325
- }
326
- #endif
327
-
328
- QtRuby::VirtualMethodCall c(smoke, method, args, obj, ALLOCA_N(VALUE, smoke->methods[method].numArgs));
329
- c.next();
330
- return true;
331
- }
332
-
333
- char*
334
- Binding::className(Smoke::Index classId) {
335
- Smoke::ModuleIndex mi(smoke, classId);
336
- return (char *) (const char *) *(IdToClassNameMap.value(mi));
337
- }
338
-
339
- /*
340
- Converts a C++ value returned by a signal invocation to a Ruby
341
- reply type
342
- */
343
- class SignalReturnValue : public Marshall {
344
- QList<MocArgument*> _replyType;
345
- Smoke::Stack _stack;
346
- VALUE * _result;
347
- public:
348
- SignalReturnValue(void ** o, VALUE * result, QList<MocArgument*> replyType)
349
- {
350
- _result = result;
351
- _replyType = replyType;
352
- _stack = new Smoke::StackItem[1];
353
- smokeStackFromQtStack(_stack, o, 0, 1, _replyType);
354
- Marshall::HandlerFn fn = getMarshallFn(type());
355
- (*fn)(this);
356
- }
357
-
358
- SmokeType type() {
359
- return _replyType[0]->st;
360
- }
361
- Marshall::Action action() { return Marshall::ToVALUE; }
362
- Smoke::StackItem &item() { return _stack[0]; }
363
- VALUE * var() {
364
- return _result;
365
- }
366
-
367
- void unsupported()
368
- {
369
- rb_raise(rb_eArgError, "Cannot handle '%s' as signal reply-type", type().name());
370
- }
371
- Smoke *smoke() { return type().smoke(); }
372
-
373
- void next() {}
374
-
375
- bool cleanup() { return false; }
376
-
377
- ~SignalReturnValue() {
378
- delete[] _stack;
379
- }
380
- };
381
-
382
- /* Note that the SignalReturnValue and EmitSignal classes really belong in
383
- marshall_types.cpp. However, for unknown reasons they don't link with certain
384
- versions of gcc. So they were moved here in to work round that bug.
385
- */
386
- EmitSignal::EmitSignal(QObject *obj, int id, int /*items*/, QList<MocArgument*> args, VALUE *sp, VALUE * result) : SigSlotBase(args),
387
- _obj(obj), _id(id)
388
- {
389
- _sp = sp;
390
- _result = result;
391
- }
392
-
393
- Marshall::Action
394
- EmitSignal::action()
395
- {
396
- return Marshall::FromVALUE;
397
- }
398
-
399
- Smoke::StackItem &
400
- EmitSignal::item()
401
- {
402
- return _stack[_cur];
403
- }
404
-
405
- const char *
406
- EmitSignal::mytype()
407
- {
408
- return "signal";
409
- }
410
-
411
- void
412
- EmitSignal::emitSignal()
413
- {
414
- if (_called) return;
415
- _called = true;
416
- void ** o = new void*[_items];
417
- smokeStackToQtStack(_stack, o + 1, 1, _items, _args);
418
- void * ptr;
419
- o[0] = &ptr;
420
- prepareReturnValue(o);
421
-
422
- _obj->metaObject()->activate(_obj, _id, o);
423
-
424
- if (_args[0]->argType != xmoc_void) {
425
- SignalReturnValue r(o, _result, _args);
426
- }
427
- delete[] o;
428
- }
429
-
430
- void
431
- EmitSignal::mainfunction()
432
- {
433
- emitSignal();
434
- }
435
-
436
- bool
437
- EmitSignal::cleanup()
438
- {
439
- return true;
440
- }
441
-
442
- InvokeNativeSlot::InvokeNativeSlot(QObject *obj, int id, int /*items*/, QList<MocArgument*> args, VALUE *sp, VALUE * result) : SigSlotBase(args),
443
- _obj(obj), _id(id)
444
- {
445
- _sp = sp;
446
- _result = result;
447
- }
448
-
449
- Marshall::Action
450
- InvokeNativeSlot::action()
451
- {
452
- return Marshall::FromVALUE;
453
- }
454
-
455
- Smoke::StackItem &
456
- InvokeNativeSlot::item()
457
- {
458
- return _stack[_cur];
459
- }
460
-
461
- const char *
462
- InvokeNativeSlot::mytype()
463
- {
464
- return "slot";
465
- }
466
-
467
- void
468
- InvokeNativeSlot::invokeSlot()
469
- {
470
- if (_called) return;
471
- _called = true;
472
- void ** o = new void*[_items];
473
- smokeStackToQtStack(_stack, o + 1, 1, _items, _args);
474
- void * ptr;
475
- o[0] = &ptr;
476
- prepareReturnValue(o);
477
-
478
- _obj->qt_metacall(QMetaObject::InvokeMetaMethod, _id, o);
479
-
480
- if (_args[0]->argType != xmoc_void) {
481
- SignalReturnValue r(o, _result, _args);
482
- }
483
- delete[] o;
484
- }
485
-
486
- void
487
- InvokeNativeSlot::mainfunction()
488
- {
489
- invokeSlot();
490
- }
491
-
492
- bool
493
- InvokeNativeSlot::cleanup()
494
- {
495
- return true;
496
- }
497
-
498
- }
499
-
500
- VALUE rb_str_catf(VALUE self, const char *format, ...)
501
- {
502
- #define CAT_BUFFER_SIZE 2048
503
- static char p[CAT_BUFFER_SIZE];
504
- va_list ap;
505
- va_start(ap, format);
506
- qvsnprintf(p, CAT_BUFFER_SIZE, format, ap);
507
- p[CAT_BUFFER_SIZE - 1] = '\0';
508
- rb_str_cat2(self, p);
509
- va_end(ap);
510
- return self;
511
- }
512
-
513
- const char *
514
- resolve_classname(smokeruby_object * o)
515
- {
516
- if (Smoke::isDerivedFrom(o->smoke->classes[o->classId].className, "QObject")) {
517
- QObject * qobject = (QObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject").index);
518
- const QMetaObject * meta = qobject->metaObject();
519
-
520
- while (meta != 0) {
521
- Smoke::ModuleIndex mi = o->smoke->findClass(meta->className());
522
- o->smoke = mi.smoke;
523
- o->classId = mi.index;
524
- if (o->smoke != 0) {
525
- if (o->classId != 0) {
526
- return qtruby_modules[o->smoke].binding->className(o->classId);
527
- }
528
- }
529
-
530
- meta = meta->superClass();
531
- }
532
- }
533
-
534
- if (o->smoke->classes[o->classId].external) {
535
- Smoke::ModuleIndex mi = o->smoke->findClass(o->smoke->className(o->classId));
536
- o->smoke = mi.smoke;
537
- o->classId = mi.index;
538
- return qtruby_modules.value(mi.smoke).resolve_classname(o);
539
- }
540
- return qtruby_modules.value(o->smoke).resolve_classname(o);
541
- }
542
-
543
- VALUE
544
- findMethod(VALUE /*self*/, VALUE c_value, VALUE name_value)
545
- {
546
- char *c = StringValuePtr(c_value);
547
- char *name = StringValuePtr(name_value);
548
- VALUE result = rb_ary_new();
549
- Smoke::ModuleIndex classId = Smoke::findClass(c);
550
- Smoke::ModuleIndex meth = Smoke::NullModuleIndex;
551
- QList<Smoke::ModuleIndex> milist;
552
- if (classId.smoke != 0) {
553
- meth = classId.smoke->findMethod(c, name);
554
- }
555
- #ifdef DEBUG
556
- if (do_debug & qtdb_calls) qWarning("Found method %s::%s => %d", c, name, meth.index);
557
- #endif
558
- if(!meth.index) {
559
- // since every smoke module defines a class 'QGlobalSpace' we can't rely on the classMap,
560
- // so we search for methods by hand
561
- foreach (Smoke* s, smokeList) {
562
- Smoke::ModuleIndex cid = s->idClass("QGlobalSpace");
563
- Smoke::ModuleIndex mnid = s->idMethodName(name);
564
- if (!cid.index || !mnid.index) continue;
565
- meth = s->idMethod(cid.index, mnid.index);
566
- if (meth.index) milist.append(meth);
567
- }
568
- #ifdef DEBUG
569
- if (do_debug & qtdb_calls) qWarning("Found method QGlobalSpace::%s => %d", name, meth.index);
570
- #endif
571
- }
572
- else
573
- {
574
- milist.append(meth);
575
- }
576
-
577
- if (milist.count() == 0) {
578
- return result;
579
- // empty list
580
- } else {
581
- foreach (Smoke::ModuleIndex meth, milist) {
582
- if (meth.index > 0) {
583
- Smoke::Index i = meth.smoke->methodMaps[meth.index].method;
584
- if (i == 0) { // shouldn't happen
585
- rb_raise(rb_eArgError, "Corrupt method %s::%s", c, name);
586
- } else if(i > 0) { // single match
587
- const Smoke::Method &methodRef = meth.smoke->methods[i];
588
- if ((methodRef.flags & Smoke::mf_internal) == 0) {
589
- rb_ary_push(result, rb_funcall(moduleindex_class, rb_intern("new"), 2, INT2NUM(smokeList.indexOf(meth.smoke)), INT2NUM(i)));
590
- }
591
- } else { // multiple match
592
- i = -i; // turn into ambiguousMethodList index
593
- while (meth.smoke->ambiguousMethodList[i]) {
594
- const Smoke::Method &methodRef = meth.smoke->methods[meth.smoke->ambiguousMethodList[i]];
595
- if ((methodRef.flags & Smoke::mf_internal) == 0) {
596
- rb_ary_push(result, rb_funcall(moduleindex_class, rb_intern("new"), 2, INT2NUM(smokeList.indexOf(meth.smoke)), INT2NUM(meth.smoke->ambiguousMethodList[i])));
597
- //#ifdef DEBUG
598
- if (do_debug & qtdb_calls) qWarning("Ambiguous Method %s::%s => %d", c, name, meth.smoke->ambiguousMethodList[i]);
599
- //#endif
600
-
601
- }
602
- i++;
603
- }
604
- }
605
- }
606
- }
607
- }
608
- return result;
609
- }
610
-
611
- // findAllMethods(ModuleIndex [, startingWith]) : returns { "mungedName" => [index in methods, ...], ... }
612
-
613
- VALUE
614
- findAllMethods(int argc, VALUE * argv, VALUE /*self*/)
615
- {
616
- VALUE rb_mi = argv[0];
617
- VALUE result = rb_hash_new();
618
- if (rb_mi != Qnil) {
619
- Smoke::Index c = (Smoke::Index) NUM2INT(rb_funcall(rb_mi, rb_intern("index"), 0));
620
- Smoke *smoke = smokeList[NUM2INT(rb_funcall(rb_mi, rb_intern("smoke"), 0))];
621
- if (c > smoke->numClasses) {
622
- return Qnil;
623
- }
624
- char * pat = 0L;
625
- if(argc > 1 && TYPE(argv[1]) == T_STRING)
626
- pat = StringValuePtr(argv[1]);
627
- #ifdef DEBUG
628
- if (do_debug & qtdb_calls) qWarning("findAllMethods called with classid = %d, pat == %s", c, pat);
629
- #endif
630
- Smoke::Index imax = smoke->numMethodMaps;
631
- Smoke::Index imin = 0, icur = -1, methmin, methmax;
632
- methmin = -1; methmax = -1; // kill warnings
633
- int icmp = -1;
634
- while(imax >= imin) {
635
- icur = (imin + imax) / 2;
636
- icmp = smoke->leg(smoke->methodMaps[icur].classId, c);
637
- if (icmp == 0) {
638
- Smoke::Index pos = icur;
639
- while (icur && smoke->methodMaps[icur-1].classId == c)
640
- icur --;
641
- methmin = icur;
642
- icur = pos;
643
- while(icur < imax && smoke->methodMaps[icur+1].classId == c)
644
- icur ++;
645
- methmax = icur;
646
- break;
647
- }
648
- if (icmp > 0)
649
- imax = icur - 1;
650
- else
651
- imin = icur + 1;
652
- }
653
- if (icmp == 0) {
654
- for (Smoke::Index i = methmin; i <= methmax; i++) {
655
- Smoke::Index m = smoke->methodMaps[i].name;
656
- if (pat == 0L || strncmp(smoke->methodNames[m], pat, strlen(pat)) == 0) {
657
- Smoke::Index ix = smoke->methodMaps[i].method;
658
- VALUE meths = rb_ary_new();
659
- if (ix >= 0) { // single match
660
- const Smoke::Method &methodRef = smoke->methods[ix];
661
- if ((methodRef.flags & Smoke::mf_internal) == 0) {
662
- rb_ary_push(meths, rb_funcall(moduleindex_class, rb_intern("new"), 2, INT2NUM(smokeList.indexOf(smoke)), INT2NUM((int) ix)));
663
- }
664
- } else { // multiple match
665
- ix = -ix; // turn into ambiguousMethodList index
666
- while (smoke->ambiguousMethodList[ix]) {
667
- const Smoke::Method &methodRef = smoke->methods[smoke->ambiguousMethodList[ix]];
668
- if ((methodRef.flags & Smoke::mf_internal) == 0) {
669
- rb_ary_push(meths, rb_funcall(moduleindex_class, rb_intern("new"), 2, INT2NUM(smokeList.indexOf(smoke)), INT2NUM((int)smoke->ambiguousMethodList[ix])));
670
- }
671
- ix++;
672
- }
673
- }
674
- rb_hash_aset(result, rb_str_new2(smoke->methodNames[m]), meths);
675
- }
676
- }
677
- }
678
- }
679
- return result;
680
- }
681
-
682
- /*
683
- Flags values
684
- 0 All methods, except enum values and protected non-static methods
685
- mf_static Static methods only
686
- mf_enum Enums only
687
- mf_protected Protected non-static methods only
688
- */
689
-
690
- #define PUSH_QTRUBY_METHOD \
691
- if ( (methodRef.flags & (Smoke::mf_internal|Smoke::mf_ctor|Smoke::mf_dtor)) == 0 \
692
- && strcmp(s->methodNames[methodRef.name], "operator=") != 0 \
693
- && strcmp(s->methodNames[methodRef.name], "operator!=") != 0 \
694
- && strcmp(s->methodNames[methodRef.name], "operator--") != 0 \
695
- && strcmp(s->methodNames[methodRef.name], "operator++") != 0 \
696
- && strncmp(s->methodNames[methodRef.name], "operator ", strlen("operator ")) != 0 \
697
- && ( (flags == 0 && (methodRef.flags & (Smoke::mf_static|Smoke::mf_enum|Smoke::mf_protected)) == 0) \
698
- || ( flags == Smoke::mf_static \
699
- && (methodRef.flags & Smoke::mf_enum) == 0 \
700
- && (methodRef.flags & Smoke::mf_static) == Smoke::mf_static ) \
701
- || (flags == Smoke::mf_enum && (methodRef.flags & Smoke::mf_enum) == Smoke::mf_enum) \
702
- || ( flags == Smoke::mf_protected \
703
- && (methodRef.flags & Smoke::mf_static) == 0 \
704
- && (methodRef.flags & Smoke::mf_protected) == Smoke::mf_protected ) ) ) { \
705
- if (strncmp(s->methodNames[methodRef.name], "operator", strlen("operator")) == 0) { \
706
- if (op_re.indexIn(s->methodNames[methodRef.name]) != -1) { \
707
- rb_ary_push(result, rb_str_new2((op_re.cap(1) + op_re.cap(2)).toLatin1())); \
708
- } else { \
709
- rb_ary_push(result, rb_str_new2(s->methodNames[methodRef.name] + strlen("operator"))); \
710
- } \
711
- } else if (predicate_re.indexIn(s->methodNames[methodRef.name]) != -1 && methodRef.numArgs == 0) { \
712
- rb_ary_push(result, rb_str_new2((predicate_re.cap(2).toLower() + predicate_re.cap(3) + "?").toLatin1())); \
713
- } else if (set_re.indexIn(s->methodNames[methodRef.name]) != -1 && methodRef.numArgs == 1) { \
714
- rb_ary_push(result, rb_str_new2((set_re.cap(2).toLower() + set_re.cap(3) + "=").toLatin1())); \
715
- } else { \
716
- rb_ary_push(result, rb_str_new2(s->methodNames[methodRef.name])); \
717
- } \
718
- }
719
-
720
- VALUE
721
- findAllMethodNames(VALUE /*self*/, VALUE result, VALUE classid, VALUE flags_value)
722
- {
723
- QRegExp predicate_re("^(is|has)(.)(.*)");
724
- QRegExp set_re("^(set)([A-Z])(.*)");
725
- QRegExp op_re("operator(.*)(([-%~/+|&*])|(>>)|(<<)|(&&)|(\\|\\|)|(\\*\\*))=$");
726
-
727
- unsigned short flags = (unsigned short) NUM2UINT(flags_value);
728
- if (classid != Qnil) {
729
- Smoke::Index c = (Smoke::Index) NUM2INT(rb_funcall(classid, rb_intern("index"), 0));
730
- Smoke* s = smokeList[NUM2INT(rb_funcall(classid, rb_intern("smoke"), 0))];
731
- if (c > s->numClasses) {
732
- return Qnil;
733
- }
734
- #ifdef DEBUG
735
- if (do_debug & qtdb_calls) qWarning("findAllMethodNames called with classid = %d in module %s", c, s->moduleName());
736
- #endif
737
- Smoke::Index imax = s->numMethodMaps;
738
- Smoke::Index imin = 0, icur = -1, methmin, methmax;
739
- methmin = -1; methmax = -1; // kill warnings
740
- int icmp = -1;
741
-
742
- while (imax >= imin) {
743
- icur = (imin + imax) / 2;
744
- icmp = s->leg(s->methodMaps[icur].classId, c);
745
- if (icmp == 0) {
746
- Smoke::Index pos = icur;
747
- while(icur && s->methodMaps[icur-1].classId == c)
748
- icur --;
749
- methmin = icur;
750
- icur = pos;
751
- while(icur < imax && s->methodMaps[icur+1].classId == c)
752
- icur ++;
753
- methmax = icur;
754
- break;
755
- }
756
- if (icmp > 0)
757
- imax = icur - 1;
758
- else
759
- imin = icur + 1;
760
- }
761
-
762
- if (icmp == 0) {
763
- for (Smoke::Index i=methmin ; i <= methmax ; i++) {
764
- Smoke::Index ix= s->methodMaps[i].method;
765
- if (ix > 0) { // single match
766
- const Smoke::Method &methodRef = s->methods[ix];
767
- PUSH_QTRUBY_METHOD
768
- } else { // multiple match
769
- ix = -ix; // turn into ambiguousMethodList index
770
- while (s->ambiguousMethodList[ix]) {
771
- const Smoke::Method &methodRef = s->methods[s->ambiguousMethodList[ix]];
772
- PUSH_QTRUBY_METHOD
773
- ix++;
774
- }
775
- }
776
- }
777
- }
778
- }
779
- return result;
780
- }
781
-
782
- QByteArray *
783
- find_cached_selector(int argc, VALUE * argv, VALUE klass, const char * methodName)
784
- {
785
- // Look in the cache
786
- static QByteArray * mcid = 0;
787
- if (mcid == 0) {
788
- mcid = new QByteArray();
789
- }
790
-
791
- *mcid = rb_class2name(klass);
792
- *mcid += ';';
793
- *mcid += methodName;
794
- for(int i=4; i<argc ; i++)
795
- {
796
- *mcid += ';';
797
- *mcid += value_to_type_flag(argv[i]);
798
- }
799
- Smoke::ModuleIndex *rcid = methcache.value(*mcid);
800
- #ifdef DEBUG
801
- if (do_debug & qtdb_calls) qWarning("method_missing mcid: %s", (const char *) *mcid);
802
- #endif
803
-
804
- if (rcid) {
805
- // Got a hit
806
- #ifdef DEBUG
807
- if (do_debug & qtdb_calls) qWarning("method_missing cache hit, mcid: %s", (const char *) *mcid);
808
- #endif
809
- _current_method.smoke = rcid->smoke;
810
- _current_method.index = rcid->index;
811
- } else {
812
- _current_method.smoke = 0;
813
- _current_method.index = -1;
814
- }
815
-
816
- return mcid;
817
- }
818
-
819
- VALUE
820
- method_missing(int argc, VALUE * argv, VALUE self)
821
- {
822
- const char * methodName = rb_id2name(SYM2ID(argv[0]));
823
- VALUE klass = rb_funcall(self, rb_intern("class"), 0);
824
-
825
- VALUE retval = Qnil;
826
-
827
- // Look for 'thing?' methods, and try to match isThing() or hasThing() in the Smoke runtime
828
- static QByteArray * pred = 0;
829
- if (pred == 0) {
830
- pred = new QByteArray();
831
- }
832
-
833
- *pred = methodName;
834
- if (pred->endsWith("?")) {
835
- smokeruby_object *o = value_obj_info(self);
836
- if(!o || !o->ptr) {
837
- return rb_call_super(argc, argv);
838
- }
839
-
840
- // Drop the trailing '?'
841
- pred->replace(pred->length() - 1, 1, "");
842
-
843
- pred->replace(0, 1, pred->mid(0, 1).toUpper());
844
- pred->replace(0, 0, "is");
845
- Smoke::ModuleIndex meth = o->smoke->findMethod(o->smoke->classes[o->classId].className, (const char *) *pred);
846
-
847
- if (meth.index == 0) {
848
- pred->replace(0, 2, "has");
849
- meth = o->smoke->findMethod(o->smoke->classes[o->classId].className, *pred);
850
- }
851
-
852
- if (meth.index > 0) {
853
- methodName = (char *) (const char *) *pred;
854
- }
855
- }
856
-
857
- VALUE * temp_stack = ALLOCA_N(VALUE, argc+3);
858
- temp_stack[0] = rb_str_new2("Qt");
859
- temp_stack[1] = rb_str_new2(methodName);
860
- temp_stack[2] = klass;
861
- temp_stack[3] = self;
862
- for (int count = 1; count < argc; count++) {
863
- temp_stack[count+3] = argv[count];
864
- }
865
-
866
- {
867
- QByteArray * mcid = find_cached_selector(argc+3, temp_stack, klass, methodName);
868
-
869
- if (_current_method.index == -1) {
870
- // Find the C++ method to call. Do that from Ruby for now
871
-
872
- retval = rb_funcall2(qt_internal_module, rb_intern("do_method_missing"), argc+3, temp_stack);
873
- if (_current_method.index == -1) {
874
- const char * op = rb_id2name(SYM2ID(argv[0]));
875
- if ( qstrcmp(op, "-") == 0
876
- || qstrcmp(op, "+") == 0
877
- || qstrcmp(op, "/") == 0
878
- || qstrcmp(op, "%") == 0
879
- || qstrcmp(op, "|") == 0 )
880
- {
881
- // Look for operator methods of the form 'operator+=', 'operator-=' and so on..
882
- char op1[3];
883
- op1[0] = op[0];
884
- op1[1] = '=';
885
- op1[2] = '\0';
886
- temp_stack[1] = rb_str_new2(op1);
887
- retval = rb_funcall2(qt_internal_module, rb_intern("do_method_missing"), argc+3, temp_stack);
888
- }
889
-
890
- if (_current_method.index == -1) {
891
- // Check for property getter/setter calls, and for slots in QObject classes
892
- // not in the smoke library
893
- smokeruby_object *o = value_obj_info(self);
894
- if ( o != 0
895
- && o->ptr != 0
896
- && Smoke::isDerivedFrom(Smoke::ModuleIndex(o->smoke, o->classId), Smoke::findClass("QObject")) )
897
- {
898
- QObject * qobject = (QObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject").index);
899
- static QByteArray * name = 0;
900
- if (name == 0) {
901
- name = new QByteArray();
902
- }
903
-
904
- *name = rb_id2name(SYM2ID(argv[0]));
905
- const QMetaObject * meta = qobject->metaObject();
906
-
907
- if (argc == 1) {
908
- if (name->endsWith("?")) {
909
- name->replace(0, 1, pred->mid(0, 1).toUpper());
910
- name->replace(0, 0, "is");
911
- if (meta->indexOfProperty(*name) == -1) {
912
- name->replace(0, 2, "has");
913
- }
914
- }
915
-
916
- if (meta->indexOfProperty(*name) != -1) {
917
- VALUE qvariant = rb_funcall(self, rb_intern("property"), 1, rb_str_new2(*name));
918
- return rb_funcall(qvariant, rb_intern("value"), 0);
919
- }
920
- }
921
-
922
- if (argc == 2 && name->endsWith("=")) {
923
- name->replace("=", "");
924
- if (meta->indexOfProperty(*name) != -1) {
925
- VALUE qvariant = rb_funcall(self, rb_intern("qVariantFromValue"), 1, argv[1]);
926
- return rb_funcall(self, rb_intern("setProperty"), 2, rb_str_new2(*name), qvariant);
927
- }
928
- }
929
-
930
- int classId = o->smoke->idClass(meta->className()).index;
931
-
932
- // The class isn't in the Smoke lib. But if it is called 'local::Merged'
933
- // it is from a QDBusInterface and the slots are remote, so don't try to
934
- // those.
935
- while ( classId == 0
936
- && qstrcmp(meta->className(), "local::Merged") != 0
937
- && qstrcmp(meta->superClass()->className(), "QDBusAbstractInterface") != 0 )
938
- {
939
- // Assume the QObject has slots which aren't in the Smoke library, so try
940
- // and call the slot directly
941
- for (int id = meta->methodOffset(); id < meta->methodCount(); id++) {
942
- if (meta->method(id).methodType() == QMetaMethod::Slot) {
943
- QByteArray signature(meta->method(id).signature());
944
- QByteArray methodName = signature.mid(0, signature.indexOf('('));
945
-
946
- // Don't check that the types of the ruby args match the c++ ones for now,
947
- // only that the name and arg count is the same.
948
- if (*name == methodName && meta->method(id).parameterTypes().count() == (argc - 1)) {
949
- QList<MocArgument*> args = get_moc_arguments( o->smoke, meta->method(id).typeName(),
950
- meta->method(id).parameterTypes() );
951
- VALUE result = Qnil;
952
- QtRuby::InvokeNativeSlot slot(qobject, id, argc - 1, args, argv + 1, &result);
953
- slot.next();
954
- return result;
955
- }
956
- }
957
- }
958
- meta = meta->superClass();
959
- classId = o->smoke->idClass(meta->className()).index;
960
- }
961
- }
962
-
963
- return rb_call_super(argc, argv);
964
- }
965
- }
966
- // Success. Cache result.
967
- methcache.insert(*mcid, new Smoke::ModuleIndex(_current_method));
968
- }
969
- }
970
- QtRuby::MethodCall c(_current_method.smoke, _current_method.index, self, temp_stack+4, argc-1);
971
- c.next();
972
- VALUE result = *(c.var());
973
- return result;
974
- }
975
-
976
- VALUE
977
- class_method_missing(int argc, VALUE * argv, VALUE klass)
978
- {
979
- VALUE result = Qnil;
980
- VALUE retval = Qnil;
981
- const char * methodName = rb_id2name(SYM2ID(argv[0]));
982
- VALUE * temp_stack = ALLOCA_N(VALUE, argc+3);
983
- temp_stack[0] = rb_str_new2("Qt");
984
- temp_stack[1] = rb_str_new2(methodName);
985
- temp_stack[2] = klass;
986
- temp_stack[3] = Qnil;
987
- for (int count = 1; count < argc; count++) {
988
- temp_stack[count+3] = argv[count];
989
- }
990
-
991
- {
992
- QByteArray * mcid = find_cached_selector(argc+3, temp_stack, klass, methodName);
993
-
994
- if (_current_method.index == -1) {
995
- retval = rb_funcall2(qt_internal_module, rb_intern("do_method_missing"), argc+3, temp_stack);
996
- if (_current_method.index != -1) {
997
- // Success. Cache result.
998
- methcache.insert(*mcid, new Smoke::ModuleIndex(_current_method));
999
- }
1000
- }
1001
- }
1002
-
1003
- if (_current_method.index == -1) {
1004
- static QRegExp * rx = 0;
1005
- if (rx == 0) {
1006
- rx = new QRegExp("[a-zA-Z]+");
1007
- }
1008
-
1009
- if (rx->indexIn(methodName) == -1) {
1010
- // If an operator method hasn't been found as an instance method,
1011
- // then look for a class method - after 'op(self,a)' try 'self.op(a)'
1012
- VALUE * method_stack = ALLOCA_N(VALUE, argc - 1);
1013
- method_stack[0] = argv[0];
1014
- for (int count = 1; count < argc - 1; count++) {
1015
- method_stack[count] = argv[count+1];
1016
- }
1017
- result = method_missing(argc-1, method_stack, argv[1]);
1018
- return result;
1019
- } else {
1020
- return rb_call_super(argc, argv);
1021
- }
1022
- }
1023
- QtRuby::MethodCall c(_current_method.smoke, _current_method.index, Qnil, temp_stack+4, argc-1);
1024
- c.next();
1025
- result = *(c.var());
1026
- return result;
1027
- }
1028
-
1029
- QList<MocArgument*>
1030
- get_moc_arguments(Smoke* smoke, const char * typeName, QList<QByteArray> methodTypes)
1031
- {
1032
- static QRegExp * rx = 0;
1033
- if (rx == 0) {
1034
- rx = new QRegExp("^(bool|int|uint|long|ulong|double|char\\*|QString)&?$");
1035
- }
1036
- methodTypes.prepend(QByteArray(typeName));
1037
- QList<MocArgument*> result;
1038
-
1039
- foreach (QByteArray name, methodTypes) {
1040
- MocArgument *arg = new MocArgument;
1041
- Smoke::Index typeId = 0;
1042
-
1043
- if (name.isEmpty()) {
1044
- arg->argType = xmoc_void;
1045
- result.append(arg);
1046
- } else {
1047
- name.replace("const ", "");
1048
- QString staticType = (rx->indexIn(name) != -1 ? rx->cap(1) : "ptr");
1049
- if (staticType == "ptr") {
1050
- arg->argType = xmoc_ptr;
1051
- QByteArray targetType = name;
1052
- typeId = smoke->idType(targetType.constData());
1053
- if (typeId == 0 && !name.contains('*')) {
1054
- if (!name.contains("&")) {
1055
- targetType += "&";
1056
- }
1057
- typeId = smoke->idType(targetType.constData());
1058
- }
1059
-
1060
- // This shouldn't be necessary because the type of the slot arg should always be in the
1061
- // smoke module of the slot being invoked. However, that isn't true for a dataUpdated()
1062
- // slot in a PlasmaScripting::Applet
1063
- if (typeId == 0) {
1064
- QHash<Smoke*, QtRubyModule>::const_iterator it;
1065
- for (it = qtruby_modules.constBegin(); it != qtruby_modules.constEnd(); ++it) {
1066
- smoke = it.key();
1067
- targetType = name;
1068
- typeId = smoke->idType(targetType.constData());
1069
- if (typeId != 0) {
1070
- break;
1071
- }
1072
-
1073
- if (typeId == 0 && !name.contains('*')) {
1074
- if (!name.contains("&")) {
1075
- targetType += "&";
1076
- }
1077
-
1078
- typeId = smoke->idType(targetType.constData());
1079
-
1080
- if (typeId != 0) {
1081
- break;
1082
- }
1083
- }
1084
- }
1085
- }
1086
- } else if (staticType == "bool") {
1087
- arg->argType = xmoc_bool;
1088
- smoke = qtcore_Smoke;
1089
- typeId = smoke->idType(name.constData());
1090
- } else if (staticType == "int") {
1091
- arg->argType = xmoc_int;
1092
- smoke = qtcore_Smoke;
1093
- typeId = smoke->idType(name.constData());
1094
- } else if (staticType == "uint") {
1095
- arg->argType = xmoc_uint;
1096
- smoke = qtcore_Smoke;
1097
- typeId = smoke->idType("unsigned int");
1098
- } else if (staticType == "long") {
1099
- arg->argType = xmoc_long;
1100
- smoke = qtcore_Smoke;
1101
- typeId = smoke->idType(name.constData());
1102
- } else if (staticType == "ulong") {
1103
- arg->argType = xmoc_ulong;
1104
- smoke = qtcore_Smoke;
1105
- typeId = smoke->idType("unsigned long");
1106
- } else if (staticType == "double") {
1107
- arg->argType = xmoc_double;
1108
- smoke = qtcore_Smoke;
1109
- typeId = smoke->idType(name.constData());
1110
- } else if (staticType == "char*") {
1111
- arg->argType = xmoc_charstar;
1112
- smoke = qtcore_Smoke;
1113
- typeId = smoke->idType(name.constData());
1114
- } else if (staticType == "QString") {
1115
- arg->argType = xmoc_QString;
1116
- name += "*";
1117
- smoke = qtcore_Smoke;
1118
- typeId = smoke->idType(name.constData());
1119
- }
1120
-
1121
- if (typeId == 0) {
1122
- rb_raise(rb_eArgError, "Cannot handle '%s' as slot argument\n", name.constData());
1123
- return result;
1124
- }
1125
-
1126
- arg->st.set(smoke, typeId);
1127
- result.append(arg);
1128
- }
1129
- }
1130
-
1131
- return result;
1132
- }
1133
-
1134
- extern "C"
1135
- {
1136
- // ---------------- Helpers -------------------
1137
-
1138
- //---------- All functions except fully qualified statics & enums ---------
1139
-
1140
- VALUE
1141
- mapObject(VALUE self, VALUE obj)
1142
- {
1143
- smokeruby_object *o = value_obj_info(obj);
1144
- if(!o)
1145
- return Qnil;
1146
- mapPointer(obj, o, o->classId, 0);
1147
- return self;
1148
- }
1149
-
1150
- VALUE set_obj_info(const char * className, smokeruby_object * o);
1151
-
1152
- VALUE
1153
- qobject_metaobject(VALUE self)
1154
- {
1155
- smokeruby_object * o = value_obj_info(self);
1156
- QObject * qobject = (QObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject").index);
1157
- QMetaObject * meta = (QMetaObject *) qobject->metaObject();
1158
- VALUE obj = getPointerObject(meta);
1159
- if (obj != Qnil) {
1160
- return obj;
1161
- }
1162
-
1163
- smokeruby_object * m = alloc_smokeruby_object( false,
1164
- o->smoke,
1165
- o->smoke->idClass("QMetaObject").index,
1166
- meta );
1167
-
1168
- obj = set_obj_info("Qt::MetaObject", m);
1169
- return obj;
1170
- }
1171
-
1172
- VALUE
1173
- set_obj_info(const char * className, smokeruby_object * o)
1174
- {
1175
- VALUE klass = rb_funcall(qt_internal_module,
1176
- rb_intern("find_class"),
1177
- 1,
1178
- rb_str_new2(className) );
1179
- if (klass == Qnil) {
1180
- rb_raise(rb_eRuntimeError, "Class '%s' not found", className);
1181
- }
1182
-
1183
- Smoke::ModuleIndex *r = classcache.value(className);
1184
- if (r != 0) {
1185
- o->classId = (int) r->index;
1186
- }
1187
- // If the instance is a subclass of QObject, then check to see if the
1188
- // className from its QMetaObject is in the Smoke library. If not then
1189
- // create a Ruby class for it dynamically. Remove the first letter from
1190
- // any class names beginning with 'Q' or 'K' and put them under the Qt::
1191
- // or KDE:: modules respectively.
1192
- if (o->smoke->isDerivedFrom(o->smoke, o->classId, o->smoke->idClass("QObject").smoke, o->smoke->idClass("QObject").index)) {
1193
- QObject * qobject = (QObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject").index);
1194
- const QMetaObject * meta = qobject->metaObject();
1195
- int classId = o->smoke->idClass(meta->className()).index;
1196
- // The class isn't in the Smoke lib..
1197
- if (classId == 0) {
1198
- VALUE new_klass = Qnil;
1199
- QByteArray className(meta->className());
1200
-
1201
- if (className == "QTableModel") {
1202
- new_klass = qtablemodel_class;
1203
- } else if (className == "QListModel") {
1204
- new_klass = qlistmodel_class;
1205
- } else if (className.startsWith("Q")) {
1206
- className.replace("Q", "");
1207
- className = className.mid(0, 1).toUpper() + className.mid(1);
1208
- new_klass = rb_define_class_under(qt_module, className, klass);
1209
- } else {
1210
- new_klass = rb_define_class(className, klass);
1211
- }
1212
-
1213
- if (new_klass != Qnil) {
1214
- klass = new_klass;
1215
-
1216
- for (int id = meta->enumeratorOffset(); id < meta->enumeratorCount(); id++) {
1217
- // If there are any enum keys with the same scope as the new class then
1218
- // add them
1219
- if (qstrcmp(meta->className(), meta->enumerator(id).scope()) == 0) {
1220
- for (int i = 0; i < meta->enumerator(id).keyCount(); i++) {
1221
- rb_define_const( klass,
1222
- meta->enumerator(id).key(i),
1223
- INT2NUM(meta->enumerator(id).value(i)) );
1224
- }
1225
- }
1226
- }
1227
- }
1228
-
1229
- // Add a Qt::Object.metaObject method which will do dynamic despatch on the
1230
- // metaObject() virtual method so that the true QMetaObject of the class
1231
- // is returned, rather than for the one for the parent class that is in
1232
- // the Smoke library.
1233
- rb_define_method(klass, "metaObject", (VALUE (*) (...)) qobject_metaobject, 0);
1234
- }
1235
- }
1236
-
1237
- VALUE obj = Data_Wrap_Struct(klass, smokeruby_mark, smokeruby_free, (void *) o);
1238
- return obj;
1239
- }
1240
-
1241
- VALUE
1242
- kross2smoke(VALUE /*self*/, VALUE krobject, VALUE new_klass)
1243
- {
1244
- VALUE new_klassname = rb_funcall(new_klass, rb_intern("name"), 0);
1245
-
1246
- Smoke::ModuleIndex * cast_to_id = classcache.value(StringValuePtr(new_klassname));
1247
- if (cast_to_id == 0) {
1248
- rb_raise(rb_eArgError, "unable to find class \"%s\" to cast to\n", StringValuePtr(new_klassname));
1249
- }
1250
-
1251
- void* o;
1252
- Data_Get_Struct(krobject, void, o);
1253
-
1254
- smokeruby_object * o_cast = alloc_smokeruby_object(false, cast_to_id->smoke, (int) cast_to_id->index, o);
1255
-
1256
- VALUE obj = Data_Wrap_Struct(new_klass, smokeruby_mark, smokeruby_free, (void *) o_cast);
1257
- mapPointer(obj, o_cast, o_cast->classId, 0);
1258
- return obj;
1259
- }
1260
-
1261
- const char *
1262
- value_to_type_flag(VALUE ruby_value)
1263
- {
1264
- const char * classname = rb_obj_classname(ruby_value);
1265
- const char *r = "";
1266
- if (ruby_value == Qnil)
1267
- r = "u";
1268
- else if (TYPE(ruby_value) == T_FIXNUM || TYPE(ruby_value) == T_BIGNUM || qstrcmp(classname, "Qt::Integer") == 0)
1269
- r = "i";
1270
- else if (TYPE(ruby_value) == T_FLOAT)
1271
- r = "n";
1272
- else if (TYPE(ruby_value) == T_STRING)
1273
- r = "s";
1274
- else if(ruby_value == Qtrue || ruby_value == Qfalse || qstrcmp(classname, "Qt::Boolean") == 0)
1275
- r = "B";
1276
- else if (qstrcmp(classname, "Qt::Enum") == 0) {
1277
- VALUE temp = rb_funcall(qt_internal_module, rb_intern("get_qenum_type"), 1, ruby_value);
1278
- r = StringValuePtr(temp);
1279
- } else if (TYPE(ruby_value) == T_DATA) {
1280
- smokeruby_object *o = value_obj_info(ruby_value);
1281
- if (o == 0 || o->smoke == 0) {
1282
- r = "a";
1283
- } else {
1284
- r = o->smoke->classes[o->classId].className;
1285
- }
1286
- } else {
1287
- r = "U";
1288
- }
1289
-
1290
- return r;
1291
- }
1292
-
1293
- VALUE prettyPrintMethod(Smoke::Index id)
1294
- {
1295
- VALUE r = rb_str_new2("");
1296
- const Smoke::Method &meth = qtcore_Smoke->methods[id];
1297
- const char *tname = qtcore_Smoke->types[meth.ret].name;
1298
- if(meth.flags & Smoke::mf_static) rb_str_catf(r, "static ");
1299
- rb_str_catf(r, "%s ", (tname ? tname:"void"));
1300
- rb_str_catf(r, "%s::%s(", qtcore_Smoke->classes[meth.classId].className, qtcore_Smoke->methodNames[meth.name]);
1301
- for(int i = 0; i < meth.numArgs; i++) {
1302
- if(i) rb_str_catf(r, ", ");
1303
- tname = qtcore_Smoke->types[qtcore_Smoke->argumentList[meth.args+i]].name;
1304
- rb_str_catf(r, "%s", (tname ? tname:"void"));
1305
- }
1306
- rb_str_catf(r, ")");
1307
- if(meth.flags & Smoke::mf_const) rb_str_catf(r, " const");
1308
- return r;
1309
- }
1310
- }
1
+ /***************************************************************************
2
+ Qt.cpp - description
3
+ -------------------
4
+ begin : Fri Jul 4 2003
5
+ copyright : (C) 2003-2006 by Richard Dale
6
+ email : Richard_Dale@tipitina.demon.co.uk
7
+ ***************************************************************************/
8
+
9
+ /***************************************************************************
10
+ * *
11
+ * This program is free software; you can redistribute it and/or modify *
12
+ * it under the terms of the GNU Lesser General Public License as *
13
+ * published by the Free Software Foundation; either version 2 of the *
14
+ * License, or (at your option) any later version. *
15
+ * *
16
+ ***************************************************************************/
17
+
18
+ #ifndef _GNU_SOURCE
19
+ #define _GNU_SOURCE
20
+ #endif
21
+ #include <stdio.h>
22
+ #include <stdarg.h>
23
+
24
+ #include <QtCore/qabstractitemmodel.h>
25
+ #include <QtCore/qglobal.h>
26
+ #include <QtCore/qhash.h>
27
+ #include <QtCore/qline.h>
28
+ #include <QtCore/qmetaobject.h>
29
+ #include <QtCore/qobject.h>
30
+ #include <QtCore/qrect.h>
31
+ #include <QtCore/qregexp.h>
32
+ #include <QtCore/qstring.h>
33
+ #include <QtCore/qvariant.h>
34
+ #include <QtCore/qmutex.h>
35
+ #include <QtGui/qapplication.h>
36
+ #include <QtGui/qbitmap.h>
37
+ #include <QtGui/qcolor.h>
38
+ #include <QtGui/qcursor.h>
39
+ #include <QtGui/qfont.h>
40
+ #include <QtGui/qicon.h>
41
+ #include <QtGui/qitemselectionmodel.h>
42
+ #include <QtGui/qpalette.h>
43
+ #include <QtGui/qpen.h>
44
+ #include <QtGui/qpixmap.h>
45
+ #include <QtGui/qpolygon.h>
46
+ #include <QtGui/qtextformat.h>
47
+ #include <QtGui/qwidget.h>
48
+
49
+ #ifdef QT_QTDBUS
50
+ #include <QtDBus/qdbusargument.h>
51
+ #endif
52
+
53
+ #undef DEBUG
54
+ #ifndef __USE_POSIX
55
+ #define __USE_POSIX
56
+ #endif
57
+ #ifndef __USE_XOPEN
58
+ #define __USE_XOPEN
59
+ #endif
60
+ #ifdef _BOOL
61
+ #define HAS_BOOL
62
+ #endif
63
+
64
+ #include <ruby.h>
65
+
66
+ #include <smoke/smoke.h>
67
+ #include <smoke/qtcore_smoke.h>
68
+
69
+ #undef free
70
+ #undef malloc
71
+
72
+ #include "marshall.h"
73
+ #include "qtruby.h"
74
+ #include "smokeruby.h"
75
+ #include "smoke.h"
76
+ #include "marshall_types.h"
77
+ // #define DEBUG
78
+
79
+ extern "C" {
80
+ VALUE qt_internal_module = Qnil;
81
+ VALUE qt_module = Qnil;
82
+
83
+ VALUE qlistmodel_class = Qnil;
84
+ VALUE qmetaobject_class = Qnil;
85
+ VALUE qtablemodel_class = Qnil;
86
+ VALUE qt_base_class = Qnil;
87
+ VALUE qvariant_class = Qnil;
88
+
89
+ VALUE moduleindex_class = Qnil;
90
+
91
+ bool application_terminated = false;
92
+ }
93
+
94
+ QList<Smoke*> smokeList;
95
+ QHash<Smoke*, QtRubyModule> qtruby_modules;
96
+
97
+ #ifdef DEBUG
98
+ int do_debug = qtdb_gc;
99
+ #else
100
+ int do_debug = qtdb_none;
101
+ #endif
102
+
103
+ typedef QHash<void *, SmokeValue> PointerMap;
104
+ static QMutex pointer_map_mutex;
105
+ Q_GLOBAL_STATIC(PointerMap, pointer_map)
106
+ int object_count = 0;
107
+
108
+ // FIXME:
109
+ // Don't the two following hashs create memory leaks by using pointers to Smoke::(Module)Index ?
110
+ QHash<QByteArray, Smoke::ModuleIndex *> methcache;
111
+ QHash<QByteArray, Smoke::ModuleIndex *> classcache;
112
+
113
+ QHash<Smoke::ModuleIndex, QByteArray*> IdToClassNameMap;
114
+
115
+ #define logger logger_backend
116
+
117
+ Smoke::ModuleIndex _current_method;
118
+
119
+ smokeruby_object *
120
+ alloc_smokeruby_object(bool allocated, Smoke * smoke, int classId, void * ptr)
121
+ {
122
+ smokeruby_object * o = ALLOC(smokeruby_object);
123
+ o->classId = classId;
124
+ o->smoke = smoke;
125
+ o->ptr = ptr;
126
+ o->allocated = allocated;
127
+ return o;
128
+ }
129
+
130
+ void
131
+ free_smokeruby_object(smokeruby_object * o)
132
+ {
133
+ o->ptr = 0;
134
+ xfree(o);
135
+ return;
136
+ }
137
+
138
+ smokeruby_object *value_obj_info(VALUE ruby_value) { // ptr on success, null on fail
139
+ if (TYPE(ruby_value) != T_DATA) {
140
+ return 0;
141
+ }
142
+
143
+ smokeruby_object * o = 0;
144
+ Data_Get_Struct(ruby_value, smokeruby_object, o);
145
+ return o;
146
+ }
147
+
148
+ void *value_to_ptr(VALUE ruby_value) { // ptr on success, null on fail
149
+ smokeruby_object *o = value_obj_info(ruby_value);
150
+ return o;
151
+ }
152
+
153
+ VALUE getPointerObject(void *ptr) {
154
+ return getSmokeValue(ptr).value;
155
+ }
156
+
157
+ SmokeValue getSmokeValue(void *ptr) {
158
+ pointer_map_mutex.lock();
159
+
160
+ if (!pointer_map() || !pointer_map()->contains(ptr)) {
161
+ if (do_debug & qtdb_gc) {
162
+ qWarning("getPointerObject %p -> nil", ptr);
163
+ if (!pointer_map()) {
164
+ qWarning("getPointerObject pointer_map deleted");
165
+ }
166
+ }
167
+ pointer_map_mutex.unlock();
168
+ return SmokeValue();
169
+ } else {
170
+ if (do_debug & qtdb_gc) {
171
+ qWarning("getPointerObject %p -> %p", ptr, (void *) pointer_map()->operator[](ptr).value);
172
+ }
173
+ pointer_map_mutex.unlock();
174
+ return pointer_map()->operator[](ptr);
175
+ }
176
+ }
177
+
178
+ void unmapPointer(void *ptr, Smoke *smoke, Smoke::Index fromClassId, Smoke::Index toClassId, void *lastptr) {
179
+ pointer_map_mutex.lock();
180
+ ptr = smoke->cast(ptr, fromClassId, toClassId);
181
+
182
+ if (ptr != lastptr) {
183
+ lastptr = ptr;
184
+ if (pointer_map() && pointer_map()->contains(ptr)) {
185
+ VALUE obj_ptr = pointer_map()->operator[](ptr).value;
186
+
187
+ if (do_debug & qtdb_gc) {
188
+ const char *className = smoke->classes[fromClassId].className;
189
+ qWarning("unmapPointer (%s*)%p -> %p size: %d", className, ptr, (void*)(&obj_ptr), pointer_map()->size() - 1);
190
+ }
191
+
192
+ pointer_map()->remove(ptr);
193
+ }
194
+ }
195
+
196
+ if (smoke->classes[toClassId].external) {
197
+ // encountered external class
198
+ Smoke::ModuleIndex mi = Smoke::findClass(smoke->classes[toClassId].className);
199
+ if (!mi.index || !mi.smoke) return;
200
+
201
+ smoke = mi.smoke;
202
+ toClassId = mi.index;
203
+ }
204
+
205
+ pointer_map_mutex.unlock();
206
+ for (Smoke::Index *i = smoke->inheritanceList + smoke->classes[toClassId].parents; *i; i++) {
207
+ unmapPointer(ptr, smoke, toClassId, *i, lastptr);
208
+ }
209
+
210
+ }
211
+
212
+ void unmapPointer(smokeruby_object *o, Smoke::Index classId, void *lastptr) {
213
+ unmapPointer(o->ptr, o->smoke, o->classId, classId, lastptr);
214
+ }
215
+
216
+ // Store pointer in pointer_map hash : "pointer_to_Qt_object" => weak ref to associated Ruby object
217
+ // Recurse to store it also as casted to its parent classes.
218
+
219
+ void mapPointer(VALUE obj, smokeruby_object* o, void *ptr, Smoke *smoke, Smoke::Index fromClassId, Smoke::Index toClassId, void *lastptr) {
220
+ pointer_map_mutex.unlock();
221
+
222
+ ptr = smoke->cast(ptr, fromClassId, toClassId);
223
+
224
+ if (ptr != lastptr) {
225
+ lastptr = ptr;
226
+
227
+ if (do_debug & qtdb_gc) {
228
+ const char *className = smoke->classes[fromClassId].className;
229
+ qWarning("mapPointer (%s*)%p -> %p size: %d", className, ptr, (void*)obj, pointer_map()->size() + 1);
230
+ }
231
+
232
+ SmokeValue value(obj, o);
233
+ pointer_map()->insert(ptr, value);
234
+ }
235
+
236
+ if (smoke->classes[toClassId].external) {
237
+ // encountered external class
238
+ Smoke::ModuleIndex mi = Smoke::findClass(smoke->classes[toClassId].className);
239
+ if (!mi.index || !mi.smoke) return;
240
+
241
+ smoke = mi.smoke;
242
+ toClassId = mi.index;
243
+ }
244
+
245
+ pointer_map_mutex.unlock();
246
+ for (Smoke::Index *i = smoke->inheritanceList + smoke->classes[toClassId].parents; *i; i++) {
247
+ mapPointer(obj, o, ptr, smoke, toClassId, *i, lastptr);
248
+ }
249
+
250
+ return;
251
+ }
252
+
253
+ void mapPointer(VALUE obj, smokeruby_object *o, Smoke::Index classId, void *lastptr) {
254
+ mapPointer(obj, o, o->ptr, o->smoke, o->classId, classId, lastptr);
255
+ }
256
+
257
+ namespace QtRuby {
258
+
259
+ Binding::Binding() : SmokeBinding(0) {}
260
+ Binding::Binding(Smoke *s) : SmokeBinding(s) {}
261
+
262
+ void
263
+ Binding::deleted(Smoke::Index classId, void *ptr) {
264
+ if (!pointer_map()) {
265
+ return;
266
+ }
267
+
268
+ smokeruby_object *o = getSmokeValue(ptr).o;
269
+ if (do_debug & qtdb_gc) {
270
+ qWarning("unmapping: o = %p, ptr = %p\n", o, ptr);
271
+ qWarning("%p->~%s()", ptr, smoke->className(classId));
272
+ }
273
+ if (!o || !o->ptr) {
274
+ return;
275
+ }
276
+ unmapPointer(o, o->classId, 0);
277
+ o->ptr = 0;
278
+ }
279
+
280
+ bool
281
+ Binding::callMethod(Smoke::Index method, void *ptr, Smoke::Stack args, bool /*isAbstract*/) {
282
+ VALUE obj = getPointerObject(ptr);
283
+ smokeruby_object *o = value_obj_info(obj);
284
+
285
+ if (do_debug & qtdb_virtual) {
286
+ const Smoke::Method & meth = smoke->methods[method];
287
+ QByteArray signature(smoke->methodNames[meth.name]);
288
+ signature += "(";
289
+ for (int i = 0; i < meth.numArgs; i++) {
290
+ if (i != 0) signature += ", ";
291
+ signature += smoke->types[smoke->argumentList[meth.args + i]].name;
292
+ }
293
+ signature += ")";
294
+ if (meth.flags & Smoke::mf_const) {
295
+ signature += " const";
296
+ }
297
+ qWarning( "module: %s virtual %p->%s::%s called",
298
+ smoke->moduleName(),
299
+ ptr,
300
+ smoke->classes[smoke->methods[method].classId].className,
301
+ (const char *) signature );
302
+ }
303
+
304
+ if (o == 0) {
305
+ if( do_debug & qtdb_virtual ) // if not in global destruction
306
+ qWarning("Cannot find object for virtual method %p -> %p", ptr, &obj);
307
+ return false;
308
+ }
309
+ const char *methodName = smoke->methodNames[smoke->methods[method].name];
310
+ if (qstrncmp(methodName, "operator", sizeof("operator") - 1) == 0) {
311
+ methodName += (sizeof("operator") - 1);
312
+ }
313
+
314
+ // If not in a ruby thread, just call the C++ version
315
+ // During GC, avoid checking for override and just call the C++ version
316
+ // If the virtual method hasn't been overriden, just call the C++ one.
317
+ #ifdef HAVE_RUBY_RUBY_H
318
+ int ruby_thread = ruby_native_thread_p();
319
+ if ((ruby_thread == 0) || rb_during_gc() || rb_respond_to(obj, rb_intern(methodName)) == 0) {
320
+ return false;
321
+ }
322
+ #else
323
+ if (rb_during_gc() || ruby_stack_check() || rb_respond_to(obj, rb_intern(methodName)) == 0) {
324
+ return false;
325
+ }
326
+ #endif
327
+
328
+ QtRuby::VirtualMethodCall c(smoke, method, args, obj, ALLOCA_N(VALUE, smoke->methods[method].numArgs));
329
+ c.next();
330
+ return true;
331
+ }
332
+
333
+ char*
334
+ Binding::className(Smoke::Index classId) {
335
+ Smoke::ModuleIndex mi(smoke, classId);
336
+ return (char *) (const char *) *(IdToClassNameMap.value(mi));
337
+ }
338
+
339
+ /*
340
+ Converts a C++ value returned by a signal invocation to a Ruby
341
+ reply type
342
+ */
343
+ class SignalReturnValue : public Marshall {
344
+ QList<MocArgument*> _replyType;
345
+ Smoke::Stack _stack;
346
+ VALUE * _result;
347
+ public:
348
+ SignalReturnValue(void ** o, VALUE * result, QList<MocArgument*> replyType)
349
+ {
350
+ _result = result;
351
+ _replyType = replyType;
352
+ _stack = new Smoke::StackItem[1];
353
+ smokeStackFromQtStack(_stack, o, 0, 1, _replyType);
354
+ Marshall::HandlerFn fn = getMarshallFn(type());
355
+ (*fn)(this);
356
+ }
357
+
358
+ SmokeType type() {
359
+ return _replyType[0]->st;
360
+ }
361
+ Marshall::Action action() { return Marshall::ToVALUE; }
362
+ Smoke::StackItem &item() { return _stack[0]; }
363
+ VALUE * var() {
364
+ return _result;
365
+ }
366
+
367
+ void unsupported()
368
+ {
369
+ rb_raise(rb_eArgError, "Cannot handle '%s' as signal reply-type", type().name());
370
+ }
371
+ Smoke *smoke() { return type().smoke(); }
372
+
373
+ void next() {}
374
+
375
+ bool cleanup() { return false; }
376
+
377
+ ~SignalReturnValue() {
378
+ delete[] _stack;
379
+ }
380
+ };
381
+
382
+ /* Note that the SignalReturnValue and EmitSignal classes really belong in
383
+ marshall_types.cpp. However, for unknown reasons they don't link with certain
384
+ versions of gcc. So they were moved here in to work round that bug.
385
+ */
386
+ EmitSignal::EmitSignal(QObject *obj, int id, int /*items*/, QList<MocArgument*> args, VALUE *sp, VALUE * result) : SigSlotBase(args),
387
+ _obj(obj), _id(id)
388
+ {
389
+ _sp = sp;
390
+ _result = result;
391
+ }
392
+
393
+ Marshall::Action
394
+ EmitSignal::action()
395
+ {
396
+ return Marshall::FromVALUE;
397
+ }
398
+
399
+ Smoke::StackItem &
400
+ EmitSignal::item()
401
+ {
402
+ return _stack[_cur];
403
+ }
404
+
405
+ const char *
406
+ EmitSignal::mytype()
407
+ {
408
+ return "signal";
409
+ }
410
+
411
+ void
412
+ EmitSignal::emitSignal()
413
+ {
414
+ if (_called) return;
415
+ _called = true;
416
+ void ** o = new void*[_items];
417
+ smokeStackToQtStack(_stack, o + 1, 1, _items, _args);
418
+ void * ptr;
419
+ o[0] = &ptr;
420
+ prepareReturnValue(o);
421
+
422
+ _obj->metaObject()->activate(_obj, _id, o);
423
+
424
+ if (_args[0]->argType != xmoc_void) {
425
+ SignalReturnValue r(o, _result, _args);
426
+ }
427
+ delete[] o;
428
+ }
429
+
430
+ void
431
+ EmitSignal::mainfunction()
432
+ {
433
+ emitSignal();
434
+ }
435
+
436
+ bool
437
+ EmitSignal::cleanup()
438
+ {
439
+ return true;
440
+ }
441
+
442
+ InvokeNativeSlot::InvokeNativeSlot(QObject *obj, int id, int /*items*/, QList<MocArgument*> args, VALUE *sp, VALUE * result) : SigSlotBase(args),
443
+ _obj(obj), _id(id)
444
+ {
445
+ _sp = sp;
446
+ _result = result;
447
+ }
448
+
449
+ Marshall::Action
450
+ InvokeNativeSlot::action()
451
+ {
452
+ return Marshall::FromVALUE;
453
+ }
454
+
455
+ Smoke::StackItem &
456
+ InvokeNativeSlot::item()
457
+ {
458
+ return _stack[_cur];
459
+ }
460
+
461
+ const char *
462
+ InvokeNativeSlot::mytype()
463
+ {
464
+ return "slot";
465
+ }
466
+
467
+ void
468
+ InvokeNativeSlot::invokeSlot()
469
+ {
470
+ if (_called) return;
471
+ _called = true;
472
+ void ** o = new void*[_items];
473
+ smokeStackToQtStack(_stack, o + 1, 1, _items, _args);
474
+ void * ptr;
475
+ o[0] = &ptr;
476
+ prepareReturnValue(o);
477
+
478
+ _obj->qt_metacall(QMetaObject::InvokeMetaMethod, _id, o);
479
+
480
+ if (_args[0]->argType != xmoc_void) {
481
+ SignalReturnValue r(o, _result, _args);
482
+ }
483
+ delete[] o;
484
+ }
485
+
486
+ void
487
+ InvokeNativeSlot::mainfunction()
488
+ {
489
+ invokeSlot();
490
+ }
491
+
492
+ bool
493
+ InvokeNativeSlot::cleanup()
494
+ {
495
+ return true;
496
+ }
497
+
498
+ }
499
+
500
+ VALUE rb_str_catf(VALUE self, const char *format, ...)
501
+ {
502
+ #define CAT_BUFFER_SIZE 2048
503
+ static char p[CAT_BUFFER_SIZE];
504
+ va_list ap;
505
+ va_start(ap, format);
506
+ qvsnprintf(p, CAT_BUFFER_SIZE, format, ap);
507
+ p[CAT_BUFFER_SIZE - 1] = '\0';
508
+ rb_str_cat2(self, p);
509
+ va_end(ap);
510
+ return self;
511
+ }
512
+
513
+ const char *
514
+ resolve_classname(smokeruby_object * o)
515
+ {
516
+ if (Smoke::isDerivedFrom(o->smoke->classes[o->classId].className, "QObject")) {
517
+ QObject * qobject = (QObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject").index);
518
+ const QMetaObject * meta = qobject->metaObject();
519
+
520
+ while (meta != 0) {
521
+ Smoke::ModuleIndex mi = o->smoke->findClass(meta->className());
522
+ o->smoke = mi.smoke;
523
+ o->classId = mi.index;
524
+ if (o->smoke != 0) {
525
+ if (o->classId != 0) {
526
+ return qtruby_modules[o->smoke].binding->className(o->classId);
527
+ }
528
+ }
529
+
530
+ meta = meta->superClass();
531
+ }
532
+ }
533
+
534
+ if (o->smoke->classes[o->classId].external) {
535
+ Smoke::ModuleIndex mi = o->smoke->findClass(o->smoke->className(o->classId));
536
+ o->smoke = mi.smoke;
537
+ o->classId = mi.index;
538
+ return qtruby_modules.value(mi.smoke).resolve_classname(o);
539
+ }
540
+ return qtruby_modules.value(o->smoke).resolve_classname(o);
541
+ }
542
+
543
+ VALUE
544
+ findMethod(VALUE /*self*/, VALUE c_value, VALUE name_value)
545
+ {
546
+ char *c = StringValuePtr(c_value);
547
+ char *name = StringValuePtr(name_value);
548
+ VALUE result = rb_ary_new();
549
+ Smoke::ModuleIndex classId = Smoke::findClass(c);
550
+ Smoke::ModuleIndex meth = Smoke::NullModuleIndex;
551
+ QList<Smoke::ModuleIndex> milist;
552
+ if (classId.smoke != 0) {
553
+ meth = classId.smoke->findMethod(c, name);
554
+ }
555
+ #ifdef DEBUG
556
+ if (do_debug & qtdb_calls) qWarning("Found method %s::%s => %d", c, name, meth.index);
557
+ #endif
558
+ if(!meth.index) {
559
+ // since every smoke module defines a class 'QGlobalSpace' we can't rely on the classMap,
560
+ // so we search for methods by hand
561
+ foreach (Smoke* s, smokeList) {
562
+ Smoke::ModuleIndex cid = s->idClass("QGlobalSpace");
563
+ Smoke::ModuleIndex mnid = s->idMethodName(name);
564
+ if (!cid.index || !mnid.index) continue;
565
+ meth = s->idMethod(cid.index, mnid.index);
566
+ if (meth.index) milist.append(meth);
567
+ }
568
+ #ifdef DEBUG
569
+ if (do_debug & qtdb_calls) qWarning("Found method QGlobalSpace::%s => %d", name, meth.index);
570
+ #endif
571
+ }
572
+ else
573
+ {
574
+ milist.append(meth);
575
+ }
576
+
577
+ if (milist.count() == 0) {
578
+ return result;
579
+ // empty list
580
+ } else {
581
+ foreach (Smoke::ModuleIndex meth, milist) {
582
+ if (meth.index > 0) {
583
+ Smoke::Index i = meth.smoke->methodMaps[meth.index].method;
584
+ if (i == 0) { // shouldn't happen
585
+ rb_raise(rb_eArgError, "Corrupt method %s::%s", c, name);
586
+ } else if(i > 0) { // single match
587
+ const Smoke::Method &methodRef = meth.smoke->methods[i];
588
+ if ((methodRef.flags & Smoke::mf_internal) == 0) {
589
+ rb_ary_push(result, rb_funcall(moduleindex_class, rb_intern("new"), 2, INT2NUM(smokeList.indexOf(meth.smoke)), INT2NUM(i)));
590
+ }
591
+ } else { // multiple match
592
+ i = -i; // turn into ambiguousMethodList index
593
+ while (meth.smoke->ambiguousMethodList[i]) {
594
+ const Smoke::Method &methodRef = meth.smoke->methods[meth.smoke->ambiguousMethodList[i]];
595
+ if ((methodRef.flags & Smoke::mf_internal) == 0) {
596
+ rb_ary_push(result, rb_funcall(moduleindex_class, rb_intern("new"), 2, INT2NUM(smokeList.indexOf(meth.smoke)), INT2NUM(meth.smoke->ambiguousMethodList[i])));
597
+ //#ifdef DEBUG
598
+ if (do_debug & qtdb_calls) qWarning("Ambiguous Method %s::%s => %d", c, name, meth.smoke->ambiguousMethodList[i]);
599
+ //#endif
600
+
601
+ }
602
+ i++;
603
+ }
604
+ }
605
+ }
606
+ }
607
+ }
608
+ return result;
609
+ }
610
+
611
+ // findAllMethods(ModuleIndex [, startingWith]) : returns { "mungedName" => [index in methods, ...], ... }
612
+
613
+ VALUE
614
+ findAllMethods(int argc, VALUE * argv, VALUE /*self*/)
615
+ {
616
+ VALUE rb_mi = argv[0];
617
+ VALUE result = rb_hash_new();
618
+ if (rb_mi != Qnil) {
619
+ Smoke::Index c = (Smoke::Index) NUM2INT(rb_funcall(rb_mi, rb_intern("index"), 0));
620
+ Smoke *smoke = smokeList[NUM2INT(rb_funcall(rb_mi, rb_intern("smoke"), 0))];
621
+ if (c > smoke->numClasses) {
622
+ return Qnil;
623
+ }
624
+ char * pat = 0L;
625
+ if(argc > 1 && TYPE(argv[1]) == T_STRING)
626
+ pat = StringValuePtr(argv[1]);
627
+ #ifdef DEBUG
628
+ if (do_debug & qtdb_calls) qWarning("findAllMethods called with classid = %d, pat == %s", c, pat);
629
+ #endif
630
+ Smoke::Index imax = smoke->numMethodMaps;
631
+ Smoke::Index imin = 0, icur = -1, methmin, methmax;
632
+ methmin = -1; methmax = -1; // kill warnings
633
+ int icmp = -1;
634
+ while(imax >= imin) {
635
+ icur = (imin + imax) / 2;
636
+ icmp = smoke->leg(smoke->methodMaps[icur].classId, c);
637
+ if (icmp == 0) {
638
+ Smoke::Index pos = icur;
639
+ while (icur && smoke->methodMaps[icur-1].classId == c)
640
+ icur --;
641
+ methmin = icur;
642
+ icur = pos;
643
+ while(icur < imax && smoke->methodMaps[icur+1].classId == c)
644
+ icur ++;
645
+ methmax = icur;
646
+ break;
647
+ }
648
+ if (icmp > 0)
649
+ imax = icur - 1;
650
+ else
651
+ imin = icur + 1;
652
+ }
653
+ if (icmp == 0) {
654
+ for (Smoke::Index i = methmin; i <= methmax; i++) {
655
+ Smoke::Index m = smoke->methodMaps[i].name;
656
+ if (pat == 0L || strncmp(smoke->methodNames[m], pat, strlen(pat)) == 0) {
657
+ Smoke::Index ix = smoke->methodMaps[i].method;
658
+ VALUE meths = rb_ary_new();
659
+ if (ix >= 0) { // single match
660
+ const Smoke::Method &methodRef = smoke->methods[ix];
661
+ if ((methodRef.flags & Smoke::mf_internal) == 0) {
662
+ rb_ary_push(meths, rb_funcall(moduleindex_class, rb_intern("new"), 2, INT2NUM(smokeList.indexOf(smoke)), INT2NUM((int) ix)));
663
+ }
664
+ } else { // multiple match
665
+ ix = -ix; // turn into ambiguousMethodList index
666
+ while (smoke->ambiguousMethodList[ix]) {
667
+ const Smoke::Method &methodRef = smoke->methods[smoke->ambiguousMethodList[ix]];
668
+ if ((methodRef.flags & Smoke::mf_internal) == 0) {
669
+ rb_ary_push(meths, rb_funcall(moduleindex_class, rb_intern("new"), 2, INT2NUM(smokeList.indexOf(smoke)), INT2NUM((int)smoke->ambiguousMethodList[ix])));
670
+ }
671
+ ix++;
672
+ }
673
+ }
674
+ rb_hash_aset(result, rb_str_new2(smoke->methodNames[m]), meths);
675
+ }
676
+ }
677
+ }
678
+ }
679
+ return result;
680
+ }
681
+
682
+ /*
683
+ Flags values
684
+ 0 All methods, except enum values and protected non-static methods
685
+ mf_static Static methods only
686
+ mf_enum Enums only
687
+ mf_protected Protected non-static methods only
688
+ */
689
+
690
+ #define PUSH_QTRUBY_METHOD \
691
+ if ( (methodRef.flags & (Smoke::mf_internal|Smoke::mf_ctor|Smoke::mf_dtor)) == 0 \
692
+ && strcmp(s->methodNames[methodRef.name], "operator=") != 0 \
693
+ && strcmp(s->methodNames[methodRef.name], "operator!=") != 0 \
694
+ && strcmp(s->methodNames[methodRef.name], "operator--") != 0 \
695
+ && strcmp(s->methodNames[methodRef.name], "operator++") != 0 \
696
+ && strncmp(s->methodNames[methodRef.name], "operator ", strlen("operator ")) != 0 \
697
+ && ( (flags == 0 && (methodRef.flags & (Smoke::mf_static|Smoke::mf_enum|Smoke::mf_protected)) == 0) \
698
+ || ( flags == Smoke::mf_static \
699
+ && (methodRef.flags & Smoke::mf_enum) == 0 \
700
+ && (methodRef.flags & Smoke::mf_static) == Smoke::mf_static ) \
701
+ || (flags == Smoke::mf_enum && (methodRef.flags & Smoke::mf_enum) == Smoke::mf_enum) \
702
+ || ( flags == Smoke::mf_protected \
703
+ && (methodRef.flags & Smoke::mf_static) == 0 \
704
+ && (methodRef.flags & Smoke::mf_protected) == Smoke::mf_protected ) ) ) { \
705
+ if (strncmp(s->methodNames[methodRef.name], "operator", strlen("operator")) == 0) { \
706
+ if (op_re.indexIn(s->methodNames[methodRef.name]) != -1) { \
707
+ rb_ary_push(result, rb_str_new2((op_re.cap(1) + op_re.cap(2)).toLatin1())); \
708
+ } else { \
709
+ rb_ary_push(result, rb_str_new2(s->methodNames[methodRef.name] + strlen("operator"))); \
710
+ } \
711
+ } else if (predicate_re.indexIn(s->methodNames[methodRef.name]) != -1 && methodRef.numArgs == 0) { \
712
+ rb_ary_push(result, rb_str_new2((predicate_re.cap(2).toLower() + predicate_re.cap(3) + "?").toLatin1())); \
713
+ } else if (set_re.indexIn(s->methodNames[methodRef.name]) != -1 && methodRef.numArgs == 1) { \
714
+ rb_ary_push(result, rb_str_new2((set_re.cap(2).toLower() + set_re.cap(3) + "=").toLatin1())); \
715
+ } else { \
716
+ rb_ary_push(result, rb_str_new2(s->methodNames[methodRef.name])); \
717
+ } \
718
+ }
719
+
720
+ VALUE
721
+ findAllMethodNames(VALUE /*self*/, VALUE result, VALUE classid, VALUE flags_value)
722
+ {
723
+ QRegExp predicate_re("^(is|has)(.)(.*)");
724
+ QRegExp set_re("^(set)([A-Z])(.*)");
725
+ QRegExp op_re("operator(.*)(([-%~/+|&*])|(>>)|(<<)|(&&)|(\\|\\|)|(\\*\\*))=$");
726
+
727
+ unsigned short flags = (unsigned short) NUM2UINT(flags_value);
728
+ if (classid != Qnil) {
729
+ Smoke::Index c = (Smoke::Index) NUM2INT(rb_funcall(classid, rb_intern("index"), 0));
730
+ Smoke* s = smokeList[NUM2INT(rb_funcall(classid, rb_intern("smoke"), 0))];
731
+ if (c > s->numClasses) {
732
+ return Qnil;
733
+ }
734
+ #ifdef DEBUG
735
+ if (do_debug & qtdb_calls) qWarning("findAllMethodNames called with classid = %d in module %s", c, s->moduleName());
736
+ #endif
737
+ Smoke::Index imax = s->numMethodMaps;
738
+ Smoke::Index imin = 0, icur = -1, methmin, methmax;
739
+ methmin = -1; methmax = -1; // kill warnings
740
+ int icmp = -1;
741
+
742
+ while (imax >= imin) {
743
+ icur = (imin + imax) / 2;
744
+ icmp = s->leg(s->methodMaps[icur].classId, c);
745
+ if (icmp == 0) {
746
+ Smoke::Index pos = icur;
747
+ while(icur && s->methodMaps[icur-1].classId == c)
748
+ icur --;
749
+ methmin = icur;
750
+ icur = pos;
751
+ while(icur < imax && s->methodMaps[icur+1].classId == c)
752
+ icur ++;
753
+ methmax = icur;
754
+ break;
755
+ }
756
+ if (icmp > 0)
757
+ imax = icur - 1;
758
+ else
759
+ imin = icur + 1;
760
+ }
761
+
762
+ if (icmp == 0) {
763
+ for (Smoke::Index i=methmin ; i <= methmax ; i++) {
764
+ Smoke::Index ix= s->methodMaps[i].method;
765
+ if (ix > 0) { // single match
766
+ const Smoke::Method &methodRef = s->methods[ix];
767
+ PUSH_QTRUBY_METHOD
768
+ } else { // multiple match
769
+ ix = -ix; // turn into ambiguousMethodList index
770
+ while (s->ambiguousMethodList[ix]) {
771
+ const Smoke::Method &methodRef = s->methods[s->ambiguousMethodList[ix]];
772
+ PUSH_QTRUBY_METHOD
773
+ ix++;
774
+ }
775
+ }
776
+ }
777
+ }
778
+ }
779
+ return result;
780
+ }
781
+
782
+ QByteArray *
783
+ find_cached_selector(int argc, VALUE * argv, VALUE klass, const char * methodName)
784
+ {
785
+ // Look in the cache
786
+ static QByteArray * mcid = 0;
787
+ if (mcid == 0) {
788
+ mcid = new QByteArray();
789
+ }
790
+
791
+ *mcid = rb_class2name(klass);
792
+ *mcid += ';';
793
+ *mcid += methodName;
794
+ for(int i=4; i<argc ; i++)
795
+ {
796
+ *mcid += ';';
797
+ *mcid += value_to_type_flag(argv[i]);
798
+ }
799
+ Smoke::ModuleIndex *rcid = methcache.value(*mcid);
800
+ #ifdef DEBUG
801
+ if (do_debug & qtdb_calls) qWarning("method_missing mcid: %s", (const char *) *mcid);
802
+ #endif
803
+
804
+ if (rcid) {
805
+ // Got a hit
806
+ #ifdef DEBUG
807
+ if (do_debug & qtdb_calls) qWarning("method_missing cache hit, mcid: %s", (const char *) *mcid);
808
+ #endif
809
+ _current_method.smoke = rcid->smoke;
810
+ _current_method.index = rcid->index;
811
+ } else {
812
+ _current_method.smoke = 0;
813
+ _current_method.index = -1;
814
+ }
815
+
816
+ return mcid;
817
+ }
818
+
819
+ VALUE
820
+ method_missing(int argc, VALUE * argv, VALUE self)
821
+ {
822
+ const char * methodName = rb_id2name(SYM2ID(argv[0]));
823
+ VALUE klass = rb_funcall(self, rb_intern("class"), 0);
824
+
825
+ VALUE retval = Qnil;
826
+
827
+ // Look for 'thing?' methods, and try to match isThing() or hasThing() in the Smoke runtime
828
+ static QByteArray * pred = 0;
829
+ static VALUE mainThread = Qnil;
830
+ if (pred == 0) {
831
+ pred = new QByteArray();
832
+ }
833
+ if (mainThread == Qnil) {
834
+ mainThread = rb_thread_main();
835
+ }
836
+
837
+ if (rb_thread_current() != mainThread) {
838
+ rb_raise(rb_eRuntimeError, "Qt methods cannot be called from outside of the main thread");
839
+ }
840
+
841
+ *pred = methodName;
842
+ if (pred->endsWith("?")) {
843
+ smokeruby_object *o = value_obj_info(self);
844
+ if(!o || !o->ptr) {
845
+ return rb_call_super(argc, argv);
846
+ }
847
+
848
+ // Drop the trailing '?'
849
+ pred->replace(pred->length() - 1, 1, "");
850
+
851
+ pred->replace(0, 1, pred->mid(0, 1).toUpper());
852
+ pred->replace(0, 0, "is");
853
+ Smoke::ModuleIndex meth = o->smoke->findMethod(o->smoke->classes[o->classId].className, (const char *) *pred);
854
+
855
+ if (meth.index == 0) {
856
+ pred->replace(0, 2, "has");
857
+ meth = o->smoke->findMethod(o->smoke->classes[o->classId].className, *pred);
858
+ }
859
+
860
+ if (meth.index > 0) {
861
+ methodName = (char *) (const char *) *pred;
862
+ }
863
+ }
864
+
865
+ VALUE * temp_stack = ALLOCA_N(VALUE, argc+3);
866
+ temp_stack[0] = rb_str_new2("Qt");
867
+ temp_stack[1] = rb_str_new2(methodName);
868
+ temp_stack[2] = klass;
869
+ temp_stack[3] = self;
870
+ for (int count = 1; count < argc; count++) {
871
+ temp_stack[count+3] = argv[count];
872
+ }
873
+
874
+ {
875
+ QByteArray * mcid = find_cached_selector(argc+3, temp_stack, klass, methodName);
876
+
877
+ if (_current_method.index == -1) {
878
+ // Find the C++ method to call. Do that from Ruby for now
879
+
880
+ retval = rb_funcall2(qt_internal_module, rb_intern("do_method_missing"), argc+3, temp_stack);
881
+ if (_current_method.index == -1) {
882
+ const char * op = rb_id2name(SYM2ID(argv[0]));
883
+ if ( qstrcmp(op, "-") == 0
884
+ || qstrcmp(op, "+") == 0
885
+ || qstrcmp(op, "/") == 0
886
+ || qstrcmp(op, "%") == 0
887
+ || qstrcmp(op, "|") == 0 )
888
+ {
889
+ // Look for operator methods of the form 'operator+=', 'operator-=' and so on..
890
+ char op1[3];
891
+ op1[0] = op[0];
892
+ op1[1] = '=';
893
+ op1[2] = '\0';
894
+ temp_stack[1] = rb_str_new2(op1);
895
+ retval = rb_funcall2(qt_internal_module, rb_intern("do_method_missing"), argc+3, temp_stack);
896
+ }
897
+
898
+ if (_current_method.index == -1) {
899
+ // Check for property getter/setter calls, and for slots in QObject classes
900
+ // not in the smoke library
901
+ smokeruby_object *o = value_obj_info(self);
902
+ if ( o != 0
903
+ && o->ptr != 0
904
+ && Smoke::isDerivedFrom(Smoke::ModuleIndex(o->smoke, o->classId), Smoke::findClass("QObject")) )
905
+ {
906
+ QObject * qobject = (QObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject").index);
907
+ static QByteArray * name = 0;
908
+ if (name == 0) {
909
+ name = new QByteArray();
910
+ }
911
+
912
+ *name = rb_id2name(SYM2ID(argv[0]));
913
+ const QMetaObject * meta = qobject->metaObject();
914
+
915
+ if (argc == 1) {
916
+ if (name->endsWith("?")) {
917
+ name->replace(0, 1, pred->mid(0, 1).toUpper());
918
+ name->replace(0, 0, "is");
919
+ if (meta->indexOfProperty(*name) == -1) {
920
+ name->replace(0, 2, "has");
921
+ }
922
+ }
923
+
924
+ if (meta->indexOfProperty(*name) != -1) {
925
+ VALUE qvariant = rb_funcall(self, rb_intern("property"), 1, rb_str_new2(*name));
926
+ return rb_funcall(qvariant, rb_intern("value"), 0);
927
+ }
928
+ }
929
+
930
+ if (argc == 2 && name->endsWith("=")) {
931
+ name->replace("=", "");
932
+ if (meta->indexOfProperty(*name) != -1) {
933
+ VALUE qvariant = rb_funcall(self, rb_intern("qVariantFromValue"), 1, argv[1]);
934
+ return rb_funcall(self, rb_intern("setProperty"), 2, rb_str_new2(*name), qvariant);
935
+ }
936
+ }
937
+
938
+ int classId = o->smoke->idClass(meta->className()).index;
939
+
940
+ // The class isn't in the Smoke lib. But if it is called 'local::Merged'
941
+ // it is from a QDBusInterface and the slots are remote, so don't try to
942
+ // those.
943
+ while ( classId == 0
944
+ && qstrcmp(meta->className(), "local::Merged") != 0
945
+ && qstrcmp(meta->superClass()->className(), "QDBusAbstractInterface") != 0 )
946
+ {
947
+ // Assume the QObject has slots which aren't in the Smoke library, so try
948
+ // and call the slot directly
949
+ for (int id = meta->methodOffset(); id < meta->methodCount(); id++) {
950
+ if (meta->method(id).methodType() == QMetaMethod::Slot) {
951
+ QByteArray signature(meta->method(id).signature());
952
+ QByteArray methodName = signature.mid(0, signature.indexOf('('));
953
+
954
+ // Don't check that the types of the ruby args match the c++ ones for now,
955
+ // only that the name and arg count is the same.
956
+ if (*name == methodName && meta->method(id).parameterTypes().count() == (argc - 1)) {
957
+ QList<MocArgument*> args = get_moc_arguments( o->smoke, meta->method(id).typeName(),
958
+ meta->method(id).parameterTypes() );
959
+ VALUE result = Qnil;
960
+ QtRuby::InvokeNativeSlot slot(qobject, id, argc - 1, args, argv + 1, &result);
961
+ slot.next();
962
+ return result;
963
+ }
964
+ }
965
+ }
966
+ meta = meta->superClass();
967
+ classId = o->smoke->idClass(meta->className()).index;
968
+ }
969
+ }
970
+
971
+ return rb_call_super(argc, argv);
972
+ }
973
+ }
974
+ // Success. Cache result.
975
+ methcache.insert(*mcid, new Smoke::ModuleIndex(_current_method));
976
+ }
977
+ }
978
+ QtRuby::MethodCall c(_current_method.smoke, _current_method.index, self, temp_stack+4, argc-1);
979
+ c.next();
980
+ VALUE result = *(c.var());
981
+ return result;
982
+ }
983
+
984
+ VALUE
985
+ class_method_missing(int argc, VALUE * argv, VALUE klass)
986
+ {
987
+ VALUE result = Qnil;
988
+ VALUE retval = Qnil;
989
+ const char * methodName = rb_id2name(SYM2ID(argv[0]));
990
+ VALUE * temp_stack = ALLOCA_N(VALUE, argc+3);
991
+ static VALUE mainThread = Qnil;
992
+ if (mainThread == Qnil) {
993
+ mainThread = rb_thread_main();
994
+ }
995
+ temp_stack[0] = rb_str_new2("Qt");
996
+ temp_stack[1] = rb_str_new2(methodName);
997
+ temp_stack[2] = klass;
998
+ temp_stack[3] = Qnil;
999
+
1000
+ if (rb_thread_current() != mainThread) {
1001
+ rb_raise(rb_eRuntimeError, "Qt methods cannot be called from outside of the main thread");
1002
+ }
1003
+
1004
+ for (int count = 1; count < argc; count++) {
1005
+ temp_stack[count+3] = argv[count];
1006
+ }
1007
+
1008
+ {
1009
+ QByteArray * mcid = find_cached_selector(argc+3, temp_stack, klass, methodName);
1010
+
1011
+ if (_current_method.index == -1) {
1012
+ retval = rb_funcall2(qt_internal_module, rb_intern("do_method_missing"), argc+3, temp_stack);
1013
+ if (_current_method.index != -1) {
1014
+ // Success. Cache result.
1015
+ methcache.insert(*mcid, new Smoke::ModuleIndex(_current_method));
1016
+ }
1017
+ }
1018
+ }
1019
+
1020
+ if (_current_method.index == -1) {
1021
+ static QRegExp * rx = 0;
1022
+ if (rx == 0) {
1023
+ rx = new QRegExp("[a-zA-Z]+");
1024
+ }
1025
+
1026
+ if (rx->indexIn(methodName) == -1) {
1027
+ // If an operator method hasn't been found as an instance method,
1028
+ // then look for a class method - after 'op(self,a)' try 'self.op(a)'
1029
+ VALUE * method_stack = ALLOCA_N(VALUE, argc - 1);
1030
+ method_stack[0] = argv[0];
1031
+ for (int count = 1; count < argc - 1; count++) {
1032
+ method_stack[count] = argv[count+1];
1033
+ }
1034
+ result = method_missing(argc-1, method_stack, argv[1]);
1035
+ return result;
1036
+ } else {
1037
+ return rb_call_super(argc, argv);
1038
+ }
1039
+ }
1040
+ QtRuby::MethodCall c(_current_method.smoke, _current_method.index, Qnil, temp_stack+4, argc-1);
1041
+ c.next();
1042
+ result = *(c.var());
1043
+ return result;
1044
+ }
1045
+
1046
+ QList<MocArgument*>
1047
+ get_moc_arguments(Smoke* smoke, const char * typeName, QList<QByteArray> methodTypes)
1048
+ {
1049
+ static QRegExp * rx = 0;
1050
+ if (rx == 0) {
1051
+ rx = new QRegExp("^(bool|int|uint|long|ulong|double|char\\*|QString)&?$");
1052
+ }
1053
+ methodTypes.prepend(QByteArray(typeName));
1054
+ QList<MocArgument*> result;
1055
+
1056
+ foreach (QByteArray name, methodTypes) {
1057
+ MocArgument *arg = new MocArgument;
1058
+ Smoke::Index typeId = 0;
1059
+
1060
+ if (name.isEmpty()) {
1061
+ arg->argType = xmoc_void;
1062
+ result.append(arg);
1063
+ } else {
1064
+ name.replace("const ", "");
1065
+ QString staticType = (rx->indexIn(name) != -1 ? rx->cap(1) : "ptr");
1066
+ if (staticType == "ptr") {
1067
+ arg->argType = xmoc_ptr;
1068
+ QByteArray targetType = name;
1069
+ typeId = smoke->idType(targetType.constData());
1070
+ if (typeId == 0 && !name.contains('*')) {
1071
+ if (!name.contains("&")) {
1072
+ targetType += "&";
1073
+ }
1074
+ typeId = smoke->idType(targetType.constData());
1075
+ }
1076
+
1077
+ // This shouldn't be necessary because the type of the slot arg should always be in the
1078
+ // smoke module of the slot being invoked. However, that isn't true for a dataUpdated()
1079
+ // slot in a PlasmaScripting::Applet
1080
+ if (typeId == 0) {
1081
+ QHash<Smoke*, QtRubyModule>::const_iterator it;
1082
+ for (it = qtruby_modules.constBegin(); it != qtruby_modules.constEnd(); ++it) {
1083
+ smoke = it.key();
1084
+ targetType = name;
1085
+ typeId = smoke->idType(targetType.constData());
1086
+ if (typeId != 0) {
1087
+ break;
1088
+ }
1089
+
1090
+ if (typeId == 0 && !name.contains('*')) {
1091
+ if (!name.contains("&")) {
1092
+ targetType += "&";
1093
+ }
1094
+
1095
+ typeId = smoke->idType(targetType.constData());
1096
+
1097
+ if (typeId != 0) {
1098
+ break;
1099
+ }
1100
+ }
1101
+ }
1102
+ }
1103
+ } else if (staticType == "bool") {
1104
+ arg->argType = xmoc_bool;
1105
+ smoke = qtcore_Smoke;
1106
+ typeId = smoke->idType(name.constData());
1107
+ } else if (staticType == "int") {
1108
+ arg->argType = xmoc_int;
1109
+ smoke = qtcore_Smoke;
1110
+ typeId = smoke->idType(name.constData());
1111
+ } else if (staticType == "uint") {
1112
+ arg->argType = xmoc_uint;
1113
+ smoke = qtcore_Smoke;
1114
+ typeId = smoke->idType("unsigned int");
1115
+ } else if (staticType == "long") {
1116
+ arg->argType = xmoc_long;
1117
+ smoke = qtcore_Smoke;
1118
+ typeId = smoke->idType(name.constData());
1119
+ } else if (staticType == "ulong") {
1120
+ arg->argType = xmoc_ulong;
1121
+ smoke = qtcore_Smoke;
1122
+ typeId = smoke->idType("unsigned long");
1123
+ } else if (staticType == "double") {
1124
+ arg->argType = xmoc_double;
1125
+ smoke = qtcore_Smoke;
1126
+ typeId = smoke->idType(name.constData());
1127
+ } else if (staticType == "char*") {
1128
+ arg->argType = xmoc_charstar;
1129
+ smoke = qtcore_Smoke;
1130
+ typeId = smoke->idType(name.constData());
1131
+ } else if (staticType == "QString") {
1132
+ arg->argType = xmoc_QString;
1133
+ name += "*";
1134
+ smoke = qtcore_Smoke;
1135
+ typeId = smoke->idType(name.constData());
1136
+ }
1137
+
1138
+ if (typeId == 0) {
1139
+ rb_raise(rb_eArgError, "Cannot handle '%s' as slot argument\n", name.constData());
1140
+ return result;
1141
+ }
1142
+
1143
+ arg->st.set(smoke, typeId);
1144
+ result.append(arg);
1145
+ }
1146
+ }
1147
+
1148
+ return result;
1149
+ }
1150
+
1151
+ extern "C"
1152
+ {
1153
+ // ---------------- Helpers -------------------
1154
+
1155
+ //---------- All functions except fully qualified statics & enums ---------
1156
+
1157
+ VALUE
1158
+ mapObject(VALUE self, VALUE obj)
1159
+ {
1160
+ smokeruby_object *o = value_obj_info(obj);
1161
+ if(!o)
1162
+ return Qnil;
1163
+ mapPointer(obj, o, o->classId, 0);
1164
+ return self;
1165
+ }
1166
+
1167
+ VALUE set_obj_info(const char * className, smokeruby_object * o);
1168
+
1169
+ VALUE
1170
+ qobject_metaobject(VALUE self)
1171
+ {
1172
+ smokeruby_object * o = value_obj_info(self);
1173
+ QObject * qobject = (QObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject").index);
1174
+ QMetaObject * meta = (QMetaObject *) qobject->metaObject();
1175
+ VALUE obj = getPointerObject(meta);
1176
+ if (obj != Qnil) {
1177
+ return obj;
1178
+ }
1179
+
1180
+ smokeruby_object * m = alloc_smokeruby_object( false,
1181
+ o->smoke,
1182
+ o->smoke->idClass("QMetaObject").index,
1183
+ meta );
1184
+
1185
+ obj = set_obj_info("Qt::MetaObject", m);
1186
+ return obj;
1187
+ }
1188
+
1189
+ VALUE
1190
+ set_obj_info(const char * className, smokeruby_object * o)
1191
+ {
1192
+ VALUE klass = rb_funcall(qt_internal_module,
1193
+ rb_intern("find_class"),
1194
+ 1,
1195
+ rb_str_new2(className) );
1196
+ if (klass == Qnil) {
1197
+ rb_raise(rb_eRuntimeError, "Class '%s' not found", className);
1198
+ }
1199
+
1200
+ Smoke::ModuleIndex *r = classcache.value(className);
1201
+ if (r != 0) {
1202
+ o->classId = (int) r->index;
1203
+ }
1204
+ // If the instance is a subclass of QObject, then check to see if the
1205
+ // className from its QMetaObject is in the Smoke library. If not then
1206
+ // create a Ruby class for it dynamically. Remove the first letter from
1207
+ // any class names beginning with 'Q' or 'K' and put them under the Qt::
1208
+ // or KDE:: modules respectively.
1209
+ if (o->smoke->isDerivedFrom(o->smoke, o->classId, o->smoke->idClass("QObject").smoke, o->smoke->idClass("QObject").index)) {
1210
+ QObject * qobject = (QObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject").index);
1211
+ const QMetaObject * meta = qobject->metaObject();
1212
+ int classId = o->smoke->idClass(meta->className()).index;
1213
+ // The class isn't in the Smoke lib..
1214
+ if (classId == 0) {
1215
+ VALUE new_klass = Qnil;
1216
+ QByteArray className(meta->className());
1217
+
1218
+ if (className == "QTableModel") {
1219
+ new_klass = qtablemodel_class;
1220
+ } else if (className == "QListModel") {
1221
+ new_klass = qlistmodel_class;
1222
+ } else if (className.startsWith("Q")) {
1223
+ className.replace("Q", "");
1224
+ className = className.mid(0, 1).toUpper() + className.mid(1);
1225
+ new_klass = rb_define_class_under(qt_module, className, klass);
1226
+ } else {
1227
+ new_klass = rb_define_class(className, klass);
1228
+ }
1229
+
1230
+ if (new_klass != Qnil) {
1231
+ klass = new_klass;
1232
+
1233
+ for (int id = meta->enumeratorOffset(); id < meta->enumeratorCount(); id++) {
1234
+ // If there are any enum keys with the same scope as the new class then
1235
+ // add them
1236
+ if (qstrcmp(meta->className(), meta->enumerator(id).scope()) == 0) {
1237
+ for (int i = 0; i < meta->enumerator(id).keyCount(); i++) {
1238
+ rb_define_const( klass,
1239
+ meta->enumerator(id).key(i),
1240
+ INT2NUM(meta->enumerator(id).value(i)) );
1241
+ }
1242
+ }
1243
+ }
1244
+ }
1245
+
1246
+ // Add a Qt::Object.metaObject method which will do dynamic despatch on the
1247
+ // metaObject() virtual method so that the true QMetaObject of the class
1248
+ // is returned, rather than for the one for the parent class that is in
1249
+ // the Smoke library.
1250
+ rb_define_method(klass, "metaObject", (VALUE (*) (...)) qobject_metaobject, 0);
1251
+ }
1252
+ }
1253
+
1254
+ VALUE obj = Data_Wrap_Struct(klass, smokeruby_mark, smokeruby_free, (void *) o);
1255
+ return obj;
1256
+ }
1257
+
1258
+ VALUE
1259
+ kross2smoke(VALUE /*self*/, VALUE krobject, VALUE new_klass)
1260
+ {
1261
+ VALUE new_klassname = rb_funcall(new_klass, rb_intern("name"), 0);
1262
+
1263
+ Smoke::ModuleIndex * cast_to_id = classcache.value(StringValuePtr(new_klassname));
1264
+ if (cast_to_id == 0) {
1265
+ rb_raise(rb_eArgError, "unable to find class \"%s\" to cast to\n", StringValuePtr(new_klassname));
1266
+ }
1267
+
1268
+ void* o;
1269
+ Data_Get_Struct(krobject, void, o);
1270
+
1271
+ smokeruby_object * o_cast = alloc_smokeruby_object(false, cast_to_id->smoke, (int) cast_to_id->index, o);
1272
+
1273
+ VALUE obj = Data_Wrap_Struct(new_klass, smokeruby_mark, smokeruby_free, (void *) o_cast);
1274
+ mapPointer(obj, o_cast, o_cast->classId, 0);
1275
+ return obj;
1276
+ }
1277
+
1278
+ const char *
1279
+ value_to_type_flag(VALUE ruby_value)
1280
+ {
1281
+ const char * classname = rb_obj_classname(ruby_value);
1282
+ const char *r = "";
1283
+ if (ruby_value == Qnil)
1284
+ r = "u";
1285
+ else if (TYPE(ruby_value) == T_FIXNUM || TYPE(ruby_value) == T_BIGNUM || qstrcmp(classname, "Qt::Integer") == 0)
1286
+ r = "i";
1287
+ else if (TYPE(ruby_value) == T_FLOAT)
1288
+ r = "n";
1289
+ else if (TYPE(ruby_value) == T_STRING)
1290
+ r = "s";
1291
+ else if(ruby_value == Qtrue || ruby_value == Qfalse || qstrcmp(classname, "Qt::Boolean") == 0)
1292
+ r = "B";
1293
+ else if (qstrcmp(classname, "Qt::Enum") == 0) {
1294
+ VALUE temp = rb_funcall(qt_internal_module, rb_intern("get_qenum_type"), 1, ruby_value);
1295
+ r = StringValuePtr(temp);
1296
+ } else if (TYPE(ruby_value) == T_DATA) {
1297
+ smokeruby_object *o = value_obj_info(ruby_value);
1298
+ if (o == 0 || o->smoke == 0) {
1299
+ r = "a";
1300
+ } else {
1301
+ r = o->smoke->classes[o->classId].className;
1302
+ }
1303
+ } else {
1304
+ r = "U";
1305
+ }
1306
+
1307
+ return r;
1308
+ }
1309
+
1310
+ VALUE prettyPrintMethod(Smoke::Index id)
1311
+ {
1312
+ VALUE r = rb_str_new2("");
1313
+ const Smoke::Method &meth = qtcore_Smoke->methods[id];
1314
+ const char *tname = qtcore_Smoke->types[meth.ret].name;
1315
+ if(meth.flags & Smoke::mf_static) rb_str_catf(r, "static ");
1316
+ rb_str_catf(r, "%s ", (tname ? tname:"void"));
1317
+ rb_str_catf(r, "%s::%s(", qtcore_Smoke->classes[meth.classId].className, qtcore_Smoke->methodNames[meth.name]);
1318
+ for(int i = 0; i < meth.numArgs; i++) {
1319
+ if(i) rb_str_catf(r, ", ");
1320
+ tname = qtcore_Smoke->types[qtcore_Smoke->argumentList[meth.args+i]].name;
1321
+ rb_str_catf(r, "%s", (tname ? tname:"void"));
1322
+ }
1323
+ rb_str_catf(r, ")");
1324
+ if(meth.flags & Smoke::mf_const) rb_str_catf(r, " const");
1325
+ return r;
1326
+ }
1327
+ }