summaryrefslogtreecommitdiffstats
path: root/qtruby/rubylib/qtruby/Qt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'qtruby/rubylib/qtruby/Qt.cpp')
-rw-r--r--qtruby/rubylib/qtruby/Qt.cpp2967
1 files changed, 2967 insertions, 0 deletions
diff --git a/qtruby/rubylib/qtruby/Qt.cpp b/qtruby/rubylib/qtruby/Qt.cpp
new file mode 100644
index 00000000..a8415512
--- /dev/null
+++ b/qtruby/rubylib/qtruby/Qt.cpp
@@ -0,0 +1,2967 @@
+/***************************************************************************
+ Qt.cpp - description
+ -------------------
+ begin : Fri Jul 4 2003
+ copyright : (C) 2003-2004 by Richard Dale
+ email : Richard_Dale@tipitina.demon.co.uk
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <qglobal.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <qptrdict.h>
+#include <qintdict.h>
+#include <qapplication.h>
+#include <qmetaobject.h>
+#include <private/qucomextra_p.h>
+#include <qvariant.h>
+#include <qcursor.h>
+#include <qobjectlist.h>
+#include <qsignalslotimp.h>
+#include <qcstring.h>
+
+#undef DEBUG
+#ifndef __USE_POSIX
+#define __USE_POSIX
+#endif
+#ifndef __USE_XOPEN
+#define __USE_XOPEN
+#endif
+#ifdef _BOOL
+#define HAS_BOOL
+#endif
+
+#include <ruby.h>
+
+#ifndef QT_VERSION_STR
+#define QT_VERSION_STR "Unknown"
+#endif
+
+#undef free
+#undef malloc
+
+#include "marshall.h"
+#include "qtruby.h"
+#include "smokeruby.h"
+#include "smoke.h"
+
+// #define DEBUG
+
+#define QTRUBY_VERSION "1.0.13"
+
+extern Smoke *qt_Smoke;
+extern void init_qt_Smoke();
+extern void smokeruby_mark(void * ptr);
+extern void smokeruby_free(void * ptr);
+extern VALUE qchar_to_s(VALUE self);
+
+#ifdef DEBUG
+int do_debug = qtdb_gc;
+#else
+int do_debug = qtdb_none;
+#endif
+
+QPtrDict<VALUE> pointer_map(2179);
+int object_count = 0;
+
+QAsciiDict<Smoke::Index> methcache(2179);
+QAsciiDict<Smoke::Index> classcache(2179);
+// Maps from a classname in the form Qt::Widget to an int id
+QIntDict<char> classname(2179);
+
+extern "C" {
+VALUE qt_module = Qnil;
+VALUE qext_scintilla_module = Qnil;
+VALUE kde_module = Qnil;
+VALUE kparts_module = Qnil;
+VALUE kio_module = Qnil;
+VALUE kns_module = Qnil;
+VALUE dom_module = Qnil;
+VALUE kontact_module = Qnil;
+VALUE kate_module = Qnil;
+VALUE ktexteditor_module = Qnil;
+VALUE koffice_module = Qnil;
+VALUE qt_internal_module = Qnil;
+VALUE qt_base_class = Qnil;
+VALUE qmetaobject_class = Qnil;
+VALUE qvariant_class = Qnil;
+VALUE kconfigskeleton_class = Qnil;
+VALUE kconfigskeleton_itemenum_class = Qnil;
+VALUE kconfigskeleton_itemenum_choice_class = Qnil;
+VALUE kio_udsatom_class = Qnil;
+VALUE kwin_class = Qnil;
+VALUE konsole_part_class = Qnil;
+bool application_terminated = false;
+};
+
+#define logger logger_backend
+void rb_str_catf(VALUE self, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+
+static VALUE (*_new_kde)(int, VALUE *, VALUE) = 0;
+static VALUE (*_kconfigskeletonitem_immutable)(VALUE) = 0;
+
+Smoke::Index _current_method = 0;
+
+extern TypeHandler Qt_handlers[];
+void install_handlers(TypeHandler *);
+
+smokeruby_object *value_obj_info(VALUE ruby_value) { // ptr on success, null on fail
+ if (TYPE(ruby_value) != T_DATA) {
+ return 0;
+ }
+
+ smokeruby_object * o = 0;
+ Data_Get_Struct(ruby_value, smokeruby_object, o);
+ return o;
+}
+
+void *value_to_ptr(VALUE ruby_value) { // ptr on success, null on fail
+ smokeruby_object *o = value_obj_info(ruby_value);
+ return o;
+}
+
+VALUE getPointerObject(void *ptr);
+
+bool isQObject(Smoke *smoke, Smoke::Index classId) {
+ if(qstrcmp(smoke->classes[classId].className, "QObject") == 0)
+ return true;
+ for(Smoke::Index *p = smoke->inheritanceList + smoke->classes[classId].parents;
+ *p;
+ p++) {
+ if(isQObject(smoke, *p))
+ return true;
+ }
+ return false;
+}
+
+bool isDerivedFrom(Smoke *smoke, Smoke::Index classId, Smoke::Index baseId) {
+ if(classId == 0 && baseId == 0)
+ return false;
+ if(classId == baseId)
+ return true;
+ for(Smoke::Index *p = smoke->inheritanceList + smoke->classes[classId].parents;
+ *p;
+ p++) {
+ if(isDerivedFrom(smoke, *p, baseId))
+ return true;
+ }
+ return false;
+}
+
+bool isDerivedFromByName(Smoke *smoke, const char *className, const char *baseClassName) {
+ if(!smoke || !className || !baseClassName)
+ return false;
+ Smoke::Index idClass = smoke->idClass(className);
+ Smoke::Index idBase = smoke->idClass(baseClassName);
+ return isDerivedFrom(smoke, idClass, idBase);
+}
+
+VALUE getPointerObject(void *ptr) {
+ if (pointer_map[ptr] == 0) {
+ return Qnil;
+ } else {
+ return *(pointer_map[ptr]);
+ }
+}
+
+void unmapPointer(smokeruby_object *o, Smoke::Index classId, void *lastptr) {
+ void *ptr = o->smoke->cast(o->ptr, o->classId, classId);
+ if(ptr != lastptr) {
+ lastptr = ptr;
+ if (pointer_map[ptr] != 0) {
+ VALUE * obj_ptr = pointer_map[ptr];
+
+ if (do_debug & qtdb_gc) {
+ const char *className = o->smoke->classes[o->classId].className;
+ qWarning("unmapPointer (%s*)%p -> %p", className, ptr, obj_ptr);
+ }
+
+ pointer_map.remove(ptr);
+ free((void*) obj_ptr);
+ }
+ }
+ for(Smoke::Index *i = o->smoke->inheritanceList + o->smoke->classes[classId].parents;
+ *i;
+ i++) {
+ unmapPointer(o, *i, lastptr);
+ }
+}
+
+// Store pointer in pointer_map hash : "pointer_to_Qt_object" => weak ref to associated Ruby object
+// Recurse to store it also as casted to its parent classes.
+
+void mapPointer(VALUE obj, smokeruby_object *o, Smoke::Index classId, void *lastptr) {
+ void *ptr = o->smoke->cast(o->ptr, o->classId, classId);
+
+ if (ptr != lastptr) {
+ lastptr = ptr;
+ VALUE * obj_ptr = (VALUE *) malloc(sizeof(VALUE));
+ memcpy(obj_ptr, &obj, sizeof(VALUE));
+
+ if (do_debug & qtdb_gc) {
+ const char *className = o->smoke->classes[o->classId].className;
+ qWarning("mapPointer (%s*)%p -> %p", className, ptr, (void*)obj);
+ }
+
+ pointer_map.insert(ptr, obj_ptr);
+ }
+
+ for(Smoke::Index *i = o->smoke->inheritanceList + o->smoke->classes[classId].parents;
+ *i;
+ i++) {
+ mapPointer(obj, o, *i, lastptr);
+ }
+
+ return;
+}
+
+Marshall::HandlerFn getMarshallFn(const SmokeType &type);
+
+class VirtualMethodReturnValue : public Marshall {
+ Smoke *_smoke;
+ Smoke::Index _method;
+ Smoke::Stack _stack;
+ SmokeType _st;
+ VALUE _retval;
+public:
+ const Smoke::Method &method() { return _smoke->methods[_method]; }
+ SmokeType type() { return _st; }
+ Marshall::Action action() { return Marshall::FromVALUE; }
+ Smoke::StackItem &item() { return _stack[0]; }
+ VALUE * var() { return &_retval; }
+
+ void unsupported() {
+ rb_raise(rb_eArgError, "Cannot handle '%s' as return-type of virtual method %s::%s",
+ type().name(),
+ _smoke->className(method().classId),
+ _smoke->methodNames[method().name]);
+ }
+
+ Smoke *smoke() { return _smoke; }
+ void next() {}
+ bool cleanup() { return false; }
+
+ VirtualMethodReturnValue(Smoke *smoke, Smoke::Index meth, Smoke::Stack stack, VALUE retval) :
+ _smoke(smoke), _method(meth), _stack(stack), _retval(retval) {
+ _st.set(_smoke, method().ret);
+ Marshall::HandlerFn fn = getMarshallFn(type());
+ (*fn)(this);
+ }
+};
+
+class VirtualMethodCall : public Marshall {
+ Smoke *_smoke;
+ Smoke::Index _method;
+ Smoke::Stack _stack;
+ VALUE _obj;
+ int _cur;
+ Smoke::Index *_args;
+ VALUE *_sp;
+ bool _called;
+
+public:
+ SmokeType type() { return SmokeType(_smoke, _args[_cur]); }
+ Marshall::Action action() { return Marshall::ToVALUE; }
+ Smoke::StackItem &item() { return _stack[_cur + 1]; }
+ VALUE * var() { return _sp + _cur; }
+ const Smoke::Method &method() { return _smoke->methods[_method]; }
+ void unsupported() {
+ rb_raise(rb_eArgError, "Cannot handle '%s' as argument of virtual method %s::%s",
+ type().name(),
+ _smoke->className(method().classId),
+ _smoke->methodNames[method().name]);
+ }
+ Smoke *smoke() { return _smoke; }
+ void callMethod() {
+ if(_called) return;
+ _called = true;
+
+ VALUE _retval = rb_funcall2(_obj,
+ rb_intern(_smoke->methodNames[method().name]),
+ method().numArgs,
+ _sp );
+ VirtualMethodReturnValue r(_smoke, _method, _stack, _retval);
+ }
+
+ void next() {
+ int oldcur = _cur;
+ _cur++;
+ while(!_called && _cur < method().numArgs) {
+ Marshall::HandlerFn fn = getMarshallFn(type());
+ (*fn)(this);
+ _cur++;
+ }
+ callMethod();
+ _cur = oldcur;
+ }
+
+ bool cleanup() { return false; } // is this right?
+
+ VirtualMethodCall(Smoke *smoke, Smoke::Index meth, Smoke::Stack stack, VALUE obj) :
+ _smoke(smoke), _method(meth), _stack(stack), _obj(obj), _cur(-1), _sp(0), _called(false) {
+ _sp = (VALUE *) calloc(method().numArgs, sizeof(VALUE));
+
+ _args = _smoke->argumentList + method().args;
+ }
+
+ ~VirtualMethodCall() {
+ free(_sp);
+ }
+};
+
+class MethodReturnValue : public Marshall {
+ Smoke *_smoke;
+ Smoke::Index _method;
+ VALUE * _retval;
+ Smoke::Stack _stack;
+public:
+ MethodReturnValue(Smoke *smoke, Smoke::Index method, Smoke::Stack stack, VALUE * retval) :
+ _smoke(smoke), _method(method), _retval(retval), _stack(stack) {
+ Marshall::HandlerFn fn = getMarshallFn(type());
+ (*fn)(this);
+ }
+
+ const Smoke::Method &method() { return _smoke->methods[_method]; }
+ SmokeType type() { return SmokeType(_smoke, method().ret); }
+ Marshall::Action action() { return Marshall::ToVALUE; }
+ Smoke::StackItem &item() { return _stack[0]; }
+ VALUE * var() {
+ return _retval;
+ }
+ void unsupported() {
+ rb_raise(rb_eArgError, "Cannot handle '%s' as return-type of %s::%s",
+ type().name(),
+ qstrcmp(_smoke->className(method().classId), "QGlobalSpace") == 0 ? "" : _smoke->className(method().classId),
+ _smoke->methodNames[method().name]);
+ }
+ Smoke *smoke() { return _smoke; }
+ void next() {}
+ bool cleanup() { return false; }
+};
+
+class MethodCall : public Marshall {
+ int _cur;
+ Smoke *_smoke;
+ Smoke::Stack _stack;
+ Smoke::Index _method;
+ Smoke::Index *_args;
+ VALUE _target;
+ void *_current_object;
+ Smoke::Index _current_object_class;
+ VALUE *_sp;
+ int _items;
+ VALUE _retval;
+ bool _called;
+public:
+ MethodCall(Smoke *smoke, Smoke::Index method, VALUE target, VALUE *sp, int items) :
+ _cur(-1), _smoke(smoke), _method(method), _target(target), _current_object(0), _sp(sp), _items(items), _called(false)
+ {
+
+ if (_target != Qnil) {
+ smokeruby_object *o = value_obj_info(_target);
+ if (o && o->ptr) {
+ _current_object = o->ptr;
+ _current_object_class = o->classId;
+ }
+ }
+
+ _args = _smoke->argumentList + _smoke->methods[_method].args;
+ _items = _smoke->methods[_method].numArgs;
+ _stack = new Smoke::StackItem[items + 1];
+ _retval = Qnil;
+ }
+
+ ~MethodCall() {
+ delete[] _stack;
+ }
+
+ SmokeType type() {
+ return SmokeType(_smoke, _args[_cur]);
+ }
+
+ Marshall::Action action() {
+ return Marshall::FromVALUE;
+ }
+ Smoke::StackItem &item() {
+ return _stack[_cur + 1];
+ }
+
+ VALUE * var() {
+ if(_cur < 0) return &_retval;
+ return _sp + _cur;
+ }
+
+ inline const Smoke::Method &method() {
+ return _smoke->methods[_method];
+ }
+
+ void unsupported() {
+ if (qstrcmp(_smoke->className(method().classId), "QGlobalSpace") == 0) {
+ rb_raise(rb_eArgError, "Cannot handle '%s' as argument to %s",
+ type().name(),
+ _smoke->methodNames[method().name]);
+ } else {
+ rb_raise(rb_eArgError, "Cannot handle '%s' as argument to %s::%s",
+ type().name(),
+ _smoke->className(method().classId),
+ _smoke->methodNames[method().name]);
+ }
+ }
+
+ Smoke *smoke() {
+ return _smoke;
+ }
+
+ inline void callMethod() {
+ if(_called) return;
+ _called = true;
+
+ QString className(_smoke->className(method().classId));
+
+ if ( ! className.endsWith(_smoke->methodNames[method().name])
+ && TYPE(_target) != T_DATA
+ && _target != Qnil
+ && !(method().flags & Smoke::mf_static) )
+ {
+ rb_raise(rb_eArgError, "Instance is not initialized, cannot call %s",
+ _smoke->methodNames[method().name]);
+ }
+
+ if (_target == Qnil && !(method().flags & Smoke::mf_static)) {
+ rb_raise(rb_eArgError, "%s is not a class method\n", _smoke->methodNames[method().name]);
+ }
+
+ Smoke::ClassFn fn = _smoke->classes[method().classId].classFn;
+ void *ptr = _smoke->cast(_current_object, _current_object_class, method().classId);
+ _items = -1;
+ (*fn)(method().method, ptr, _stack);
+ MethodReturnValue r(_smoke, _method, _stack, &_retval);
+ }
+
+ void next() {
+ int oldcur = _cur;
+ _cur++;
+
+ while(!_called && _cur < _items) {
+ Marshall::HandlerFn fn = getMarshallFn(type());
+ (*fn)(this);
+ _cur++;
+ }
+ callMethod();
+ _cur = oldcur;
+ }
+
+ bool cleanup() {
+ return true;
+ }
+};
+
+class UnencapsulatedQObject : public QObject {
+public:
+ QConnectionList *public_receivers(int signal) const { return receivers(signal); }
+ void public_activate_signal(QConnectionList *clist, QUObject *o) { activate_signal(clist, o); }
+};
+
+class EmitSignal : public Marshall {
+ UnencapsulatedQObject *_qobj;
+ int _id;
+ MocArgument *_args;
+ VALUE *_sp;
+ int _items;
+ int _cur;
+ Smoke::Stack _stack;
+ bool _called;
+public:
+ EmitSignal(QObject *qobj, int id, int items, VALUE args, VALUE *sp) :
+ _qobj((UnencapsulatedQObject*)qobj), _id(id), _sp(sp), _items(items),
+ _cur(-1), _called(false)
+ {
+ _items = NUM2INT(rb_ary_entry(args, 0));
+ Data_Get_Struct(rb_ary_entry(args, 1), MocArgument, _args);
+ _stack = new Smoke::StackItem[_items];
+ }
+ ~EmitSignal() {
+ delete[] _stack;
+ }
+ const MocArgument &arg() { return _args[_cur]; }
+ SmokeType type() { return arg().st; }
+ Marshall::Action action() { return Marshall::FromVALUE; }
+ Smoke::StackItem &item() { return _stack[_cur]; }
+ VALUE * var() { return _sp + _cur; }
+ void unsupported() {
+ rb_raise(rb_eArgError, "Cannot handle '%s' as signal argument", type().name());
+ }
+ Smoke *smoke() { return type().smoke(); }
+ void emitSignal() {
+ if(_called) return;
+ _called = true;
+
+ QConnectionList *clist = _qobj->public_receivers(_id);
+ if(!clist) return;
+
+ QUObject *o = new QUObject[_items + 1];
+ for(int i = 0; i < _items; i++) {
+ QUObject *po = o + i + 1;
+ Smoke::StackItem *si = _stack + i;
+ switch(_args[i].argType) {
+ case xmoc_bool:
+ static_QUType_bool.set(po, si->s_bool);
+ break;
+ case xmoc_int:
+ static_QUType_int.set(po, si->s_int);
+ break;
+ case xmoc_double:
+ static_QUType_double.set(po, si->s_double);
+ break;
+ case xmoc_charstar:
+ static_QUType_charstar.set(po, (char*)si->s_voidp);
+ break;
+ case xmoc_QString:
+ static_QUType_QString.set(po, *(QString*)si->s_voidp);
+ break;
+ default:
+ {
+ const SmokeType &t = _args[i].st;
+ void *p;
+ switch(t.elem()) {
+ case Smoke::t_bool:
+ p = &si->s_bool;
+ break;
+ case Smoke::t_char:
+ p = &si->s_char;
+ break;
+ case Smoke::t_uchar:
+ p = &si->s_uchar;
+ break;
+ case Smoke::t_short:
+ p = &si->s_short;
+ break;
+ case Smoke::t_ushort:
+ p = &si->s_ushort;
+ break;
+ case Smoke::t_int:
+ p = &si->s_int;
+ break;
+ case Smoke::t_uint:
+ p = &si->s_uint;
+ break;
+ case Smoke::t_long:
+ p = &si->s_long;
+ break;
+ case Smoke::t_ulong:
+ p = &si->s_ulong;
+ break;
+ case Smoke::t_float:
+ p = &si->s_float;
+ break;
+ case Smoke::t_double:
+ p = &si->s_double;
+ break;
+ case Smoke::t_enum:
+ {
+ // allocate a new enum value
+ Smoke::EnumFn fn = SmokeClass(t).enumFn();
+ if(!fn) {
+ rb_warning("Unknown enumeration %s\n", t.name());
+ p = new int((int)si->s_enum);
+ break;
+ }
+ Smoke::Index id = t.typeId();
+ (*fn)(Smoke::EnumNew, id, p, si->s_enum);
+ (*fn)(Smoke::EnumFromLong, id, p, si->s_enum);
+ // FIXME: MEMORY LEAK
+ }
+ break;
+ case Smoke::t_class:
+ case Smoke::t_voidp:
+ p = si->s_voidp;
+ break;
+ default:
+ p = 0;
+ break;
+ }
+ static_QUType_ptr.set(po, p);
+ }
+ }
+ }
+
+ _qobj->public_activate_signal(clist, o);
+ delete[] o;
+ }
+ void next() {
+ int oldcur = _cur;
+ _cur++;
+
+ while(!_called && _cur < _items) {
+ Marshall::HandlerFn fn = getMarshallFn(type());
+ (*fn)(this);
+ _cur++;
+ }
+
+ emitSignal();
+ _cur = oldcur;
+ }
+ bool cleanup() { return true; }
+};
+
+class InvokeSlot : public Marshall {
+ VALUE _obj;
+ ID _slotname;
+ int _items;
+ MocArgument *_args;
+ QUObject *_o;
+ int _cur;
+ bool _called;
+ VALUE *_sp;
+ Smoke::Stack _stack;
+public:
+ const MocArgument &arg() { return _args[_cur]; }
+ SmokeType type() { return arg().st; }
+ Marshall::Action action() { return Marshall::ToVALUE; }
+ Smoke::StackItem &item() { return _stack[_cur]; }
+ VALUE * var() { return _sp + _cur; }
+ Smoke *smoke() { return type().smoke(); }
+ bool cleanup() { return false; }
+ void unsupported() {
+ rb_raise(rb_eArgError, "Cannot handle '%s' as slot argument\n", type().name());
+ }
+ void copyArguments() {
+ for(int i = 0; i < _items; i++) {
+ QUObject *o = _o + i + 1;
+ switch(_args[i].argType) {
+ case xmoc_bool:
+ _stack[i].s_bool = static_QUType_bool.get(o);
+ break;
+ case xmoc_int:
+ _stack[i].s_int = static_QUType_int.get(o);
+ break;
+ case xmoc_double:
+ _stack[i].s_double = static_QUType_double.get(o);
+ break;
+ case xmoc_charstar:
+ _stack[i].s_voidp = static_QUType_charstar.get(o);
+ break;
+ case xmoc_QString:
+ _stack[i].s_voidp = &static_QUType_QString.get(o);
+ break;
+ default: // case xmoc_ptr:
+ {
+ const SmokeType &t = _args[i].st;
+ void *p = static_QUType_ptr.get(o);
+ switch(t.elem()) {
+ case Smoke::t_bool:
+ _stack[i].s_bool = *(bool*)p;
+ break;
+ case Smoke::t_char:
+ _stack[i].s_char = *(char*)p;
+ break;
+ case Smoke::t_uchar:
+ _stack[i].s_uchar = *(unsigned char*)p;
+ break;
+ case Smoke::t_short:
+ _stack[i].s_short = *(short*)p;
+ break;
+ case Smoke::t_ushort:
+ _stack[i].s_ushort = *(unsigned short*)p;
+ break;
+ case Smoke::t_int:
+ _stack[i].s_int = *(int*)p;
+ break;
+ case Smoke::t_uint:
+ _stack[i].s_uint = *(unsigned int*)p;
+ break;
+ case Smoke::t_long:
+ _stack[i].s_long = *(long*)p;
+ break;
+ case Smoke::t_ulong:
+ _stack[i].s_ulong = *(unsigned long*)p;
+ break;
+ case Smoke::t_float:
+ _stack[i].s_float = *(float*)p;
+ break;
+ case Smoke::t_double:
+ _stack[i].s_double = *(double*)p;
+ break;
+ case Smoke::t_enum:
+ {
+ Smoke::EnumFn fn = SmokeClass(t).enumFn();
+ if(!fn) {
+ rb_warning("Unknown enumeration %s\n", t.name());
+ _stack[i].s_enum = *(int*)p;
+ break;
+ }
+ Smoke::Index id = t.typeId();
+ (*fn)(Smoke::EnumToLong, id, p, _stack[i].s_enum);
+ }
+ break;
+ case Smoke::t_class:
+ case Smoke::t_voidp:
+ _stack[i].s_voidp = p;
+ break;
+ }
+ }
+ }
+ }
+ }
+ void invokeSlot() {
+ if(_called) return;
+ _called = true;
+
+ (void) rb_funcall2(_obj, _slotname, _items, _sp);
+ }
+
+ void next() {
+ int oldcur = _cur;
+ _cur++;
+
+ while(!_called && _cur < _items) {
+ Marshall::HandlerFn fn = getMarshallFn(type());
+ (*fn)(this);
+ _cur++;
+ }
+
+ invokeSlot();
+ _cur = oldcur;
+ }
+
+ InvokeSlot(VALUE obj, ID slotname, VALUE args, QUObject *o) :
+ _obj(obj), _slotname(slotname), _o(o), _cur(-1), _called(false)
+ {
+ _items = NUM2INT(rb_ary_entry(args, 0));
+ Data_Get_Struct(rb_ary_entry(args, 1), MocArgument, _args);
+ _sp = (VALUE *) calloc(_items, sizeof(VALUE));
+ _stack = new Smoke::StackItem[_items];
+ copyArguments();
+ }
+
+ ~InvokeSlot() {
+ delete[] _stack;
+ free(_sp);
+ }
+};
+
+class QtRubySmokeBinding : public SmokeBinding {
+public:
+ QtRubySmokeBinding(Smoke *s) : SmokeBinding(s) {}
+
+ void deleted(Smoke::Index classId, void *ptr) {
+ VALUE obj = getPointerObject(ptr);
+ smokeruby_object *o = value_obj_info(obj);
+ if(do_debug & qtdb_gc) {
+ qWarning("%p->~%s()", ptr, smoke->className(classId));
+ }
+ if(!o || !o->ptr) {
+ return;
+ }
+ unmapPointer(o, o->classId, 0);
+ o->ptr = 0;
+ }
+
+ bool callMethod(Smoke::Index method, void *ptr, Smoke::Stack args, bool /*isAbstract*/) {
+ VALUE obj = getPointerObject(ptr);
+ smokeruby_object *o = value_obj_info(obj);
+
+ if (do_debug & qtdb_virtual) {
+ Smoke::Method & meth = smoke->methods[method];
+ QCString signature(smoke->methodNames[meth.name]);
+ signature += "(";
+
+ for (int i = 0; i < meth.numArgs; i++) {
+ if (i != 0) signature += ", ";
+ signature += smoke->types[smoke->argumentList[meth.args + i]].name;
+ }
+
+ signature += ")";
+ if (meth.flags & Smoke::mf_const) {
+ signature += " const";
+ }
+
+ qWarning( "virtual %p->%s::%s called",
+ ptr,
+ smoke->classes[smoke->methods[method].classId].className,
+ (const char *) signature );
+ }
+
+ if(!o) {
+ if( do_debug & qtdb_virtual ) // if not in global destruction
+ qWarning("Cannot find object for virtual method %p -> %p", ptr, &obj);
+ return false;
+ }
+
+ const char *methodName = smoke->methodNames[smoke->methods[method].name];
+
+ // If the virtual method hasn't been overriden, just call the C++ one.
+ if (rb_respond_to(obj, rb_intern(methodName)) == 0) {
+ return false;
+ }
+
+ VirtualMethodCall c(smoke, method, args, obj);
+ c.next();
+ return true;
+ }
+
+ char *className(Smoke::Index classId) {
+ return classname.find((int) classId);
+ }
+};
+
+void rb_str_catf(VALUE self, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ char *p = 0;
+ int len;
+ if (len = vasprintf(&p, format, ap), len != -1) {
+ rb_str_cat(self, p, len);
+ free(p);
+ }
+ va_end(ap);
+}
+
+extern "C" {
+
+static VALUE
+qdebug(VALUE klass, VALUE msg)
+{
+ qDebug("%s", StringValuePtr(msg));
+ return klass;
+}
+
+static VALUE
+qfatal(VALUE klass, VALUE msg)
+{
+ qFatal("%s", StringValuePtr(msg));
+ return klass;
+}
+
+static VALUE
+qwarning(VALUE klass, VALUE msg)
+{
+ qWarning("%s", StringValuePtr(msg));
+ return klass;
+}
+
+// ---------------- Helpers -------------------
+
+//---------- All functions except fully qualified statics & enums ---------
+
+static VALUE qobject_metaobject(VALUE self);
+static VALUE kde_package_to_class(const char * package, VALUE base_class);
+
+VALUE
+set_obj_info(const char * className, smokeruby_object * o)
+{
+ VALUE klass = rb_funcall(qt_internal_module,
+ rb_intern("find_class"),
+ 1,
+ rb_str_new2(className) );
+
+ Smoke::Index *r = classcache.find(className);
+ if (r != 0) {
+ o->classId = (int)*r;
+ }
+
+ // If the instance is a subclass of QObject, then check to see if the
+ // className from its QMetaObject is in the Smoke library. If not then
+ // create a Ruby class for it dynamically. Remove the first letter from
+ // any class names beginning with 'Q' or 'K' and put them under the Qt::
+ // or KDE:: modules respectively.
+ if (isDerivedFrom(o->smoke, o->classId, o->smoke->idClass("QObject"))) {
+ QObject * qobject = (QObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject"));
+ QMetaObject * meta = qobject->metaObject();
+ int classId = o->smoke->idClass(meta->className());
+ // The class isn't in the Smoke lib..
+ if (classId == 0) {
+ VALUE new_klass = Qnil;
+ QString className(meta->className());
+ // The konsolePart class is in kdebase, and so it can't be in the Smoke library.
+ // This hack instantiates a Ruby KDE::KonsolePart instance
+ if (className == "konsolePart") {
+ new_klass = konsole_part_class;
+ } else if (className.startsWith("Q")) {
+ className.replace("Q", "");
+ className = className.mid(0, 1).upper() + className.mid(1);
+ new_klass = rb_define_class_under(qt_module, className.latin1(), klass);
+ } else if (kde_module == Qnil) {
+ new_klass = rb_define_class(className.latin1(), klass);
+ } else {
+ new_klass = kde_package_to_class(className.latin1(), klass);
+ }
+
+ if (new_klass != Qnil) {
+ klass = new_klass;
+ }
+
+ // Add a Qt::Object.metaObject method which will do dynamic despatch on the
+ // metaObject() virtual method so that the true QMetaObject of the class
+ // is returned, rather than for the one for the parent class that is in
+ // the Smoke library.
+ rb_define_method(klass, "metaObject", (VALUE (*) (...)) qobject_metaobject, 0);
+ }
+ }
+
+ VALUE obj = Data_Wrap_Struct(klass, smokeruby_mark, smokeruby_free, (void *) o);
+ return obj;
+}
+
+static VALUE mapObject(VALUE self, VALUE obj);
+
+VALUE
+cast_object_to(VALUE /*self*/, VALUE object, VALUE new_klass)
+{
+ smokeruby_object *o = value_obj_info(object);
+
+ VALUE new_klassname = rb_funcall(new_klass, rb_intern("name"), 0);
+
+ Smoke::Index * cast_to_id = classcache.find(StringValuePtr(new_klassname));
+ if (cast_to_id == 0) {
+ rb_raise(rb_eArgError, "unable to find class \"%s\" to cast to\n", StringValuePtr(new_klassname));
+ }
+
+ smokeruby_object *o_cast = (smokeruby_object *) malloc(sizeof(smokeruby_object));
+ memcpy(o_cast, o, sizeof(smokeruby_object));
+
+ o_cast->allocated = o->allocated;
+ o->allocated = false;
+
+ o_cast->classId = (int) *cast_to_id;
+ o_cast->ptr = o->smoke->cast(o->ptr, o->classId, o_cast->classId);
+
+ VALUE obj = Data_Wrap_Struct(new_klass, smokeruby_mark, smokeruby_free, (void *) o_cast);
+ mapPointer(obj, o_cast, o_cast->classId, 0);
+ return obj;
+}
+
+const char *
+get_VALUEtype(VALUE ruby_value)
+{
+ char * classname = rb_obj_classname(ruby_value);
+ const char *r = "";
+ if(ruby_value == Qnil)
+ r = "u";
+ else if(TYPE(ruby_value) == T_FIXNUM || TYPE(ruby_value) == T_BIGNUM || qstrcmp(classname, "Qt::Integer") == 0)
+ r = "i";
+ else if(TYPE(ruby_value) == T_FLOAT)
+ r = "n";
+ else if(TYPE(ruby_value) == T_STRING)
+ r = "s";
+ else if(ruby_value == Qtrue || ruby_value == Qfalse || qstrcmp(classname, "Qt::Boolean") == 0)
+ r = "B";
+ else if(qstrcmp(classname, "Qt::Enum") == 0) {
+ VALUE temp = rb_funcall(qt_internal_module, rb_intern("get_qenum_type"), 1, ruby_value);
+ r = StringValuePtr(temp);
+ } else if(TYPE(ruby_value) == T_DATA) {
+ smokeruby_object *o = value_obj_info(ruby_value);
+ if(!o) {
+ r = "a";
+ } else {
+ r = o->smoke->classes[o->classId].className;
+ }
+ }
+ else {
+ r = "U";
+ }
+
+ return r;
+}
+
+VALUE prettyPrintMethod(Smoke::Index id)
+{
+ VALUE r = rb_str_new2("");
+ Smoke::Method &meth = qt_Smoke->methods[id];
+ const char *tname = qt_Smoke->types[meth.ret].name;
+ if(meth.flags & Smoke::mf_static) rb_str_catf(r, "static ");
+ rb_str_catf(r, "%s ", (tname ? tname:"void"));
+ rb_str_catf(r, "%s::%s(", qt_Smoke->classes[meth.classId].className, qt_Smoke->methodNames[meth.name]);
+ for(int i = 0; i < meth.numArgs; i++) {
+ if(i) rb_str_catf(r, ", ");
+ tname = qt_Smoke->types[qt_Smoke->argumentList[meth.args+i]].name;
+ rb_str_catf(r, "%s", (tname ? tname:"void"));
+ }
+ rb_str_catf(r, ")");
+ if(meth.flags & Smoke::mf_const) rb_str_catf(r, " const");
+ return r;
+}
+
+//---------- Ruby methods (for all functions except fully qualified statics & enums) ---------
+
+// Used to display debugging info about the signals a Qt::Object has connected.
+// Returns a Hash with keys of the signals names, and values of Arrays of
+// Qt::Connections for the target slots
+static VALUE
+receivers_qobject(VALUE self)
+{
+ if (TYPE(self) != T_DATA) {
+ return Qnil;
+ }
+
+ smokeruby_object * o = 0;
+ Data_Get_Struct(self, smokeruby_object, o);
+ UnencapsulatedQObject * qobject = (UnencapsulatedQObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject"));
+ VALUE result = rb_hash_new();
+ QStrList signalNames = qobject->metaObject()->signalNames(true);
+
+ for (int sig = 0; sig < qobject->metaObject()->numSignals(true); sig++) {
+ QConnectionList * clist = qobject->public_receivers(sig);
+ if (clist != 0) {
+ VALUE name = rb_str_new2(signalNames.at(sig));
+ VALUE members = rb_ary_new();
+
+ for ( QConnection * connection = clist->first();
+ connection != 0;
+ connection = clist->next() )
+ {
+ VALUE obj = getPointerObject(connection);
+ if (obj == Qnil) {
+ smokeruby_object * c = ALLOC(smokeruby_object);
+ c->classId = o->smoke->idClass("QConnection");
+ c->smoke = o->smoke;
+ c->ptr = connection;
+ c->allocated = false;
+ obj = set_obj_info("Qt::Connection", c);
+ }
+
+ rb_ary_push(members, obj);
+ }
+
+ rb_hash_aset(result, name, members);
+ }
+ }
+
+ return result;
+}
+
+// Takes a variable name and a QProperty with QVariant value, and returns a '
+// variable=value' pair with the value in ruby inspect style
+static QCString
+inspectProperty(Smoke * smoke, const QMetaProperty * property, const char * name, QVariant & value)
+{
+ if (property->isEnumType()) {
+ QMetaObject * metaObject = *(property->meta);
+ return QCString().sprintf( " %s=%s::%s",
+ name,
+ smoke->binding->className(smoke->idClass(metaObject->className())),
+ property->valueToKey(value.toInt()) );
+ }
+
+ switch (value.type()) {
+ case QVariant::String:
+ case QVariant::CString:
+ {
+ if (value.toString().isNull()) {
+ return QCString().sprintf(" %s=nil", name);
+ } else {
+ return QCString().sprintf( " %s=\"%s\"",
+ name,
+ value.toString().latin1() );
+ }
+ }
+
+ case QVariant::Bool:
+ {
+ QString rubyName;
+ QRegExp name_re("^(is|has)(.)(.*)");
+
+ if (name_re.search(name) != -1) {
+ rubyName = name_re.cap(2).lower() + name_re.cap(3) + "?";
+ } else {
+ rubyName = name;
+ }
+
+ return QCString().sprintf(" %s=%s", rubyName.latin1(), value.toString().latin1());
+ }
+
+ case QVariant::Color:
+ {
+ QColor c = value.toColor();
+ return QCString().sprintf(" %s=#<Qt::Color:0x0 %s>", name, c.name().latin1());
+ }
+
+ case QVariant::Cursor:
+ {
+ QCursor c = value.toCursor();
+ return QCString().sprintf(" %s=#<Qt::Cursor:0x0 shape=%d>", name, c.shape());
+ }
+
+ case QVariant::Double:
+ {
+ return QCString().sprintf(" %s=%.4f", name, value.toDouble());
+ }
+
+ case QVariant::Font:
+ {
+ QFont f = value.toFont();
+ return QCString().sprintf( " %s=#<Qt::Font:0x0 family=%s, pointSize=%d, weight=%d, italic=%s, bold=%s, underline=%s, strikeOut=%s>",
+ name,
+ f.family().latin1(), f.pointSize(), f.weight(),
+ f.italic() ? "true" : "false", f.bold() ? "true" : "false",
+ f.underline() ? "true" : "false", f.strikeOut() ? "true" : "false" );
+ }
+
+ case QVariant::Point:
+ {
+ QPoint p = value.toPoint();
+ return QCString().sprintf( " %s=#<Qt::Point:0x0 x=%d, y=%d>",
+ name,
+ p.x(), p.y() );
+ }
+
+ case QVariant::Rect:
+ {
+ QRect r = value.toRect();
+ return QCString().sprintf( " %s=#<Qt::Rect:0x0 left=%d, right=%d, top=%d, bottom=%d>",
+ name,
+ r.left(), r.right(), r.top(), r.bottom() );
+ }
+
+ case QVariant::Size:
+ {
+ QSize s = value.toSize();
+ return QCString().sprintf( " %s=#<Qt::Size:0x0 width=%d, height=%d>",
+ name,
+ s.width(), s.height() );
+ }
+
+ case QVariant::SizePolicy:
+ {
+ QSizePolicy s = value.toSizePolicy();
+ return QCString().sprintf( " %s=#<Qt::SizePolicy:0x0 horData=%d, verData=%d>",
+ name,
+ s.horData(), s.verData() );
+ }
+
+ case QVariant::Brush:
+ case QVariant::ColorGroup:
+ case QVariant::Image:
+ case QVariant::Palette:
+ case QVariant::Pixmap:
+ case QVariant::Region:
+ {
+ return QCString().sprintf(" %s=#<Qt::%s:0x0>", name, value.typeName() + 1);
+ }
+
+ default:
+ return QCString().sprintf( " %s=%s",
+ name,
+ (value.isNull() || value.toString().isNull()) ? "nil" : value.toString().latin1() );
+ }
+}
+
+// Retrieves the properties for a QObject and returns them as 'name=value' pairs
+// in a ruby inspect string. For example:
+//
+// #<Qt::HBoxLayout:0x30139030 name=unnamed, margin=0, spacing=0, resizeMode=3>
+//
+static VALUE
+inspect_qobject(VALUE self)
+{
+ if (TYPE(self) != T_DATA) {
+ return Qnil;
+ }
+
+ // Start with #<Qt::HBoxLayout:0x30139030> from the original inspect() call
+ // Drop the closing '>'
+ VALUE inspect_str = rb_call_super(0, 0);
+ rb_str_resize(inspect_str, RSTRING(inspect_str)->len - 1);
+
+ smokeruby_object * o = 0;
+ Data_Get_Struct(self, smokeruby_object, o);
+ QObject * qobject = (QObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject"));
+
+ QCString value_list;
+ value_list.append(QCString().sprintf(" name=\"%s\"", qobject->name()));
+
+ if (qobject->isWidgetType()) {
+ QWidget * w = (QWidget *) qobject;
+ value_list.append(QCString().sprintf( ", x=%d, y=%d, width=%d, height=%d",
+ w->x(),
+ w->y(),
+ w->width(),
+ w->height() ) );
+ }
+
+ value_list.append(">");
+ rb_str_cat(inspect_str, value_list.data(), strlen(value_list.data()));
+
+ return inspect_str;
+}
+
+// Retrieves the properties for a QObject and pretty_prints them as 'name=value' pairs
+// For example:
+//
+// #<Qt::HBoxLayout:0x30139030
+// name=unnamed,
+// margin=0,
+// spacing=0,
+// resizeMode=3>
+//
+static VALUE
+pretty_print_qobject(VALUE self, VALUE pp)
+{
+ if (TYPE(self) != T_DATA) {
+ return Qnil;
+ }
+
+ // Start with #<Qt::HBoxLayout:0x30139030>
+ // Drop the closing '>'
+ VALUE inspect_str = rb_funcall(self, rb_intern("to_s"), 0, 0);
+ rb_str_resize(inspect_str, RSTRING(inspect_str)->len - 1);
+ rb_funcall(pp, rb_intern("text"), 1, inspect_str);
+ rb_funcall(pp, rb_intern("breakable"), 0);
+
+ smokeruby_object * o = 0;
+ Data_Get_Struct(self, smokeruby_object, o);
+ UnencapsulatedQObject * qobject = (UnencapsulatedQObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject"));
+ QStrList names = qobject->metaObject()->propertyNames(true);
+
+ QCString value_list;
+
+ if (qobject->parent() != 0) {
+ QCString parentInspectString;
+ VALUE obj = getPointerObject(qobject->parent());
+ if (obj != Qnil) {
+ VALUE parent_inspect_str = rb_funcall(obj, rb_intern("to_s"), 0, 0);
+ rb_str_resize(parent_inspect_str, RSTRING(parent_inspect_str)->len - 1);
+ parentInspectString = StringValuePtr(parent_inspect_str);
+ } else {
+ parentInspectString.sprintf("#<%s:0x0", qobject->parent()->className());
+ }
+
+ if (qobject->parent()->isWidgetType()) {
+ QWidget * w = (QWidget *) qobject->parent();
+ value_list = QCString().sprintf( " parent=%s name=\"%s\", x=%d, y=%d, width=%d, height=%d>,\n",
+ parentInspectString.data(),
+ w->name(),
+ w->x(),
+ w->y(),
+ w->width(),
+ w->height() );
+ } else {
+ value_list = QCString().sprintf( " parent=%s name=\"%s\">,\n",
+ parentInspectString.data(),
+ qobject->parent()->name() );
+ }
+
+ rb_funcall(pp, rb_intern("text"), 1, rb_str_new2(value_list.data()));
+ }
+
+ if (qobject->children() != 0) {
+ value_list = QCString().sprintf(" children=Array (%d element(s)),\n", qobject->children()->count());
+ rb_funcall(pp, rb_intern("text"), 1, rb_str_new2(value_list.data()));
+ }
+
+ value_list = QCString(" metaObject=#<Qt::MetaObject:0x0");
+ value_list.append(QCString().sprintf(" className=%s", qobject->metaObject()->className()));
+
+ if (qobject->metaObject()->superClass() != 0) {
+ value_list.append(QCString().sprintf(", superClass=#<Qt::MetaObject:0x0>", qobject->metaObject()->superClass()));
+ }
+
+ if (qobject->metaObject()->numSignals() > 0) {
+ value_list.append(QCString().sprintf(", signalNames=Array (%d element(s))", qobject->metaObject()->numSignals()));
+ }
+
+ if (qobject->metaObject()->numSlots() > 0) {
+ value_list.append(QCString().sprintf(", slotNames=Array (%d element(s))", qobject->metaObject()->numSlots()));
+ }
+
+ value_list.append(">,\n");
+ rb_funcall(pp, rb_intern("text"), 1, rb_str_new2(value_list.data()));
+
+ int signalCount = 0;
+ for (int sig = 0; sig < qobject->metaObject()->numSignals(true); sig++) {
+ QConnectionList * clist = qobject->public_receivers(sig);
+ if (clist != 0) {
+ signalCount++;
+ }
+ }
+
+ if (signalCount > 0) {
+ value_list = QCString().sprintf(" receivers=Hash (%d element(s)),\n", signalCount);
+ rb_funcall(pp, rb_intern("text"), 1, rb_str_new2(value_list.data()));
+ }
+
+ int index = 0;
+ const char * name = names.first();
+
+ if (name != 0) {
+ QVariant value = qobject->property(name);
+ const QMetaProperty * property = qobject->metaObject()->property(index, true);
+ value_list = " " + inspectProperty(o->smoke, property, name, value);
+ rb_funcall(pp, rb_intern("text"), 1, rb_str_new2(value_list.data()));
+ index++;
+
+ for ( name = names.next();
+ name != 0;
+ name = names.next(), index++ )
+ {
+ rb_funcall(pp, rb_intern("text"), 1, rb_str_new2(",\n"));
+
+ value = qobject->property(name);
+ property = qobject->metaObject()->property(index, true);
+ value_list = " " + inspectProperty(o->smoke, property, name, value);
+ rb_funcall(pp, rb_intern("text"), 1, rb_str_new2(value_list.data()));
+ }
+ }
+
+ rb_funcall(pp, rb_intern("text"), 1, rb_str_new2(">"));
+
+ return self;
+}
+
+static VALUE
+metaObject(VALUE self)
+{
+ VALUE metaObject = rb_funcall(qt_internal_module, rb_intern("getMetaObject"), 1, self);
+ return metaObject;
+}
+
+static VALUE
+qobject_metaobject(VALUE self)
+{
+ smokeruby_object * o = value_obj_info(self);
+ QObject * qobject = (QObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject"));
+ QMetaObject * meta = qobject->metaObject();
+ VALUE obj = getPointerObject(meta);
+ if (obj != Qnil) {
+ return obj;
+ }
+
+ smokeruby_object * m = (smokeruby_object *) malloc(sizeof(smokeruby_object));
+ m->smoke = o->smoke;
+ m->classId = m->smoke->idClass("QMetaObject");
+ m->ptr = meta;
+ m->allocated = false;
+ obj = set_obj_info("Qt::MetaObject", m);
+ return obj;
+}
+
+static VALUE
+new_qvariant(int argc, VALUE * argv, VALUE self)
+{
+static Smoke::Index new_qvariant_qlist = 0;
+static Smoke::Index new_qvariant_qmap = 0;
+
+ if (new_qvariant_qlist == 0) {
+ Smoke::Index nameId = qt_Smoke->idMethodName("QVariant?");
+ Smoke::Index meth = qt_Smoke->findMethod(qt_Smoke->idClass("QVariant"), nameId);
+ Smoke::Index i = qt_Smoke->methodMaps[meth].method;
+ i = -i; // turn into ambiguousMethodList index
+ while (qt_Smoke->ambiguousMethodList[i] != 0) {
+ const char * argType = qt_Smoke->types[qt_Smoke->argumentList[qt_Smoke->methods[qt_Smoke->ambiguousMethodList[i]].args]].name;
+
+ if (qstrcmp(argType, "const QValueList<QVariant>&" ) == 0) {
+ new_qvariant_qlist = qt_Smoke->ambiguousMethodList[i];
+ } else if (qstrcmp(argType, "const QMap<QString,QVariant>&" ) == 0) {
+ new_qvariant_qmap = qt_Smoke->ambiguousMethodList[i];
+ }
+
+ i++;
+ }
+ }
+
+ if (argc == 1 && TYPE(argv[0]) == T_HASH) {
+ _current_method = new_qvariant_qmap;
+ MethodCall c(qt_Smoke, _current_method, self, argv, argc-1);
+ c.next();
+ return *(c.var());
+ } else if ( argc == 1
+ && TYPE(argv[0]) == T_ARRAY
+ && RARRAY(argv[0])->len > 0
+ && TYPE(rb_ary_entry(argv[0], 0)) != T_STRING )
+ {
+ _current_method = new_qvariant_qlist;
+ MethodCall c(qt_Smoke, _current_method, self, argv, argc-1);
+ c.next();
+ return *(c.var());
+ }
+
+ return rb_call_super(argc, argv);
+}
+
+static QCString *
+find_cached_selector(int argc, VALUE * argv, VALUE klass, char * methodName)
+{
+ // Look in the cache
+static QCString * mcid = 0;
+ if (mcid == 0) {
+ mcid = new QCString();
+ }
+ *mcid = rb_class2name(klass);
+ *mcid += ';';
+ *mcid += methodName;
+ for(int i=3; i<argc ; i++)
+ {
+ *mcid += ';';
+ *mcid += get_VALUEtype(argv[i]);
+ }
+
+ Smoke::Index *rcid = methcache.find((const char *)*mcid);
+#ifdef DEBUG
+ if (do_debug & qtdb_calls) qWarning("method_missing mcid: %s", (const char *) *mcid);
+#endif
+
+ if (rcid) {
+ // Got a hit
+#ifdef DEBUG
+ if (do_debug & qtdb_calls) qWarning("method_missing cache hit, mcid: %s", (const char *) *mcid);
+#endif
+ _current_method = *rcid;
+ } else {
+ _current_method = -1;
+ }
+
+ return mcid;
+}
+
+static VALUE
+method_missing(int argc, VALUE * argv, VALUE self)
+{
+ char * methodName = rb_id2name(SYM2ID(argv[0]));
+ VALUE klass = rb_funcall(self, rb_intern("class"), 0);
+
+ // Look for 'thing?' methods, and try to match isThing() or hasThing() in the Smoke runtime
+static QString * pred = 0;
+ if (pred == 0) {
+ pred = new QString();
+ }
+
+ *pred = methodName;
+ if (pred->endsWith("?")) {
+ smokeruby_object *o = value_obj_info(self);
+ if(!o || !o->ptr) {
+ rb_call_super(argc, argv);
+ }
+
+ // Drop the trailing '?'
+ pred->replace(pred->length() - 1, 1, "");
+
+ pred->replace(0, 1, pred->at(0).upper());
+ pred->replace(0, 0, QString("is"));
+ Smoke::Index meth = o->smoke->findMethod(o->smoke->classes[o->classId].className, pred->latin1());
+
+ if (meth == 0) {
+ pred->replace(0, 2, QString("has"));
+ meth = o->smoke->findMethod(o->smoke->classes[o->classId].className, pred->latin1());
+ }
+
+ if (meth > 0) {
+ methodName = (char *) pred->latin1();
+ }
+ }
+
+ VALUE * temp_stack = (VALUE *) calloc(argc+3, sizeof(VALUE));
+ temp_stack[0] = rb_str_new2("Qt");
+ temp_stack[1] = rb_str_new2(methodName);
+ temp_stack[2] = klass;
+ temp_stack[3] = self;
+ for (int count = 1; count < argc; count++) {
+ temp_stack[count+3] = argv[count];
+ }
+
+ {
+ QCString * mcid = find_cached_selector(argc+3, temp_stack, klass, methodName);
+
+ if (_current_method == -1) {
+ // Find the C++ method to call. Do that from Ruby for now
+
+ VALUE retval = rb_funcall2(qt_internal_module, rb_intern("do_method_missing"), argc+3, temp_stack);
+ if (_current_method == -1) {
+ char * op = rb_id2name(SYM2ID(argv[0]));
+ if ( qstrcmp(op, "-") == 0
+ || qstrcmp(op, "+") == 0
+ || qstrcmp(op, "/") == 0
+ || qstrcmp(op, "%") == 0
+ || qstrcmp(op, "|") == 0 )
+ {
+ // Look for operator methods of the form 'operator+=', 'operator-=' and so on..
+ char op1[3];
+ op1[0] = op[0];
+ op1[1] = '=';
+ op1[2] = '\0';
+ temp_stack[1] = rb_str_new2(op1);
+ retval = rb_funcall2(qt_internal_module, rb_intern("do_method_missing"), argc+3, temp_stack);
+ }
+
+ if (_current_method == -1) {
+ free(temp_stack);
+
+ // Check for property getter/setter calls
+ smokeruby_object *o = value_obj_info(self);
+ if ( o != 0
+ && o->ptr != 0
+ && isDerivedFrom(o->smoke, o->classId, o->smoke->idClass("QObject")) )
+ {
+ QObject * qobject = (QObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject"));
+static QString * prop = 0;
+ if (prop == 0) {
+ prop = new QString();
+ }
+
+ *prop = rb_id2name(SYM2ID(argv[0]));
+ QMetaObject * meta = qobject->metaObject();
+ if (argc == 1) {
+ if (prop->endsWith("?")) {
+ prop->replace(0, 1, pred->at(0).upper());
+ prop->replace(0, 0, QString("is"));
+ if (meta->findProperty(prop->latin1(), true) == -1) {
+ prop->replace(0, 2, QString("has"));
+ }
+ }
+
+ if (meta->findProperty(prop->latin1(), true) != -1) {
+ VALUE qvariant = rb_funcall(self, rb_intern("property"), 1, rb_str_new2(prop->latin1()));
+ return rb_funcall(qvariant, rb_intern("to_ruby"), 0);
+ }
+ } else if (argc == 2 && prop->endsWith("=")) {
+ prop->replace("=", "");
+ if (meta->findProperty(prop->latin1(), true) != -1) {
+ VALUE qvariant = rb_funcall(qvariant_class, rb_intern("new"), 1, argv[1]);
+ return rb_funcall(self, rb_intern("setProperty"), 2, rb_str_new2(prop->latin1()), qvariant);
+ }
+ }
+ }
+
+ rb_call_super(argc, argv);
+ }
+ }
+ // Success. Cache result.
+ methcache.insert((const char *)*mcid, new Smoke::Index(_current_method));
+ }
+ }
+
+ MethodCall c(qt_Smoke, _current_method, self, temp_stack+4, argc-1);
+ c.next();
+ VALUE result = *(c.var());
+ free(temp_stack);
+
+ return result;
+}
+
+static VALUE
+class_method_missing(int argc, VALUE * argv, VALUE klass)
+{
+ VALUE result = Qnil;
+ char * methodName = rb_id2name(SYM2ID(argv[0]));
+ VALUE * temp_stack = (VALUE *) calloc(argc+3, sizeof(VALUE));
+ temp_stack[0] = rb_str_new2("Qt");
+ temp_stack[1] = rb_str_new2(methodName);
+ temp_stack[2] = klass;
+ temp_stack[3] = Qnil;
+ for (int count = 1; count < argc; count++) {
+ temp_stack[count+3] = argv[count];
+ }
+
+ {
+ QCString * mcid = find_cached_selector(argc+3, temp_stack, klass, methodName);
+
+ if (_current_method == -1) {
+ VALUE retval = rb_funcall2(qt_internal_module, rb_intern("do_method_missing"), argc+3, temp_stack);
+ Q_UNUSED(retval);
+ if (_current_method != -1) {
+ // Success. Cache result.
+ methcache.insert((const char *)*mcid, new Smoke::Index(_current_method));
+ }
+ }
+ }
+
+ if (_current_method == -1) {
+static QRegExp * rx = 0;
+ if (rx == 0) {
+ rx = new QRegExp("[a-zA-Z]+");
+ }
+
+ if (rx->search(methodName) == -1) {
+ // If an operator method hasn't been found as an instance method,
+ // then look for a class method - after 'op(self,a)' try 'self.op(a)'
+ VALUE * method_stack = (VALUE *) calloc(argc - 1, sizeof(VALUE));
+ method_stack[0] = argv[0];
+ for (int count = 1; count < argc - 1; count++) {
+ method_stack[count] = argv[count+1];
+ }
+ result = method_missing(argc-1, method_stack, argv[1]);
+ free(method_stack);
+ free(temp_stack);
+ return result;
+ } else {
+ rb_call_super(argc, argv);
+ }
+ }
+
+ MethodCall c(qt_Smoke, _current_method, Qnil, temp_stack+4, argc-1);
+ c.next();
+ result = *(c.var());
+ free(temp_stack);
+ return result;
+}
+
+static VALUE module_method_missing(int argc, VALUE * argv, VALUE /*klass*/)
+{
+ return class_method_missing(argc, argv, qt_module);
+}
+
+static VALUE kde_module_method_missing(int argc, VALUE * argv, VALUE klass)
+{
+ return class_method_missing(argc, argv, klass);
+}
+
+/*
+
+class LCDRange < Qt::Widget
+
+ def initialize(s, parent, name)
+ super(parent, name)
+ init()
+ ...
+
+For a case such as the above, the QWidget can't be instantiated until
+the initializer has been run up to the point where 'super(parent, name)'
+is called. Only then, can the number and type of arguments passed to the
+constructor be known. However, the rest of the intializer
+can't be run until 'self' is a proper T_DATA object with a wrapped C++
+instance.
+
+The solution is to run the initialize code twice. First, only up to the
+'super(parent, name)' call, where the QWidget would get instantiated in
+initialize_qt(). And then rb_throw() jumps out of the
+initializer returning the wrapped object as a result.
+
+The second time round 'self' will be the wrapped instance of type T_DATA,
+so initialize() can be allowed to proceed to the end.
+*/
+static VALUE
+initialize_qt(int argc, VALUE * argv, VALUE self)
+{
+ VALUE retval;
+ VALUE temp_obj;
+
+ if (TYPE(self) == T_DATA) {
+ // If a ruby block was passed then run that now
+ if (rb_block_given_p()) {
+ rb_funcall(qt_internal_module, rb_intern("run_initializer_block"), 2, self, rb_block_proc());
+ }
+
+ return self;
+ }
+
+ VALUE klass = rb_funcall(self, rb_intern("class"), 0);
+ VALUE constructor_name = rb_str_new2("new");
+
+ VALUE * temp_stack = (VALUE *) calloc(argc+4, sizeof(VALUE));
+ temp_stack[0] = rb_str_new2("Qt");
+ temp_stack[1] = constructor_name;
+ temp_stack[2] = klass;
+ temp_stack[3] = self;
+ for (int count = 0; count < argc; count++) {
+ temp_stack[count+4] = argv[count];
+ }
+
+ {
+ // Put this in a C block so that the mcid will be de-allocated at the end of the block,
+ // rather than on f'n exit, to avoid the longjmp problem described below
+ QCString * mcid = find_cached_selector(argc+4, temp_stack, klass, rb_class2name(klass));
+
+ if (_current_method == -1) {
+ retval = rb_funcall2(qt_internal_module, rb_intern("do_method_missing"), argc+4, temp_stack);
+ if (_current_method != -1) {
+ // Success. Cache result.
+ methcache.insert((const char *)*mcid, new Smoke::Index(_current_method));
+ }
+ }
+ }
+
+ if (_current_method == -1) {
+ free(temp_stack);
+ // Another longjmp here..
+ rb_raise(rb_eArgError, "unresolved constructor call %s\n", rb_class2name(klass));
+ }
+
+ {
+ // Allocate the MethodCall within a C block. Otherwise, because the continue_new_instance()
+ // call below will longjmp out, it wouldn't give C++ an opportunity to clean up
+ MethodCall c(qt_Smoke, _current_method, self, temp_stack+4, argc);
+ c.next();
+ temp_obj = *(c.var());
+ }
+
+ smokeruby_object * p = 0;
+ Data_Get_Struct(temp_obj, smokeruby_object, p);
+ smokeruby_object * o = (smokeruby_object *) malloc(sizeof(smokeruby_object));
+ memcpy(o, p, sizeof(smokeruby_object));
+ p->ptr = 0;
+ p->allocated = false;
+ o->allocated = true;
+ VALUE result = Data_Wrap_Struct(klass, smokeruby_mark, smokeruby_free, o);
+ mapObject(result, result);
+ free(temp_stack);
+ // Off with a longjmp, never to return..
+ rb_throw("newqt", result);
+ /*NOTREACHED*/
+ return self;
+}
+
+VALUE
+new_qt(int argc, VALUE * argv, VALUE klass)
+{
+ VALUE * temp_stack = (VALUE *) calloc(argc + 1, sizeof(VALUE));
+ temp_stack[0] = rb_obj_alloc(klass);
+ for (int count = 0; count < argc; count++) {
+ temp_stack[count+1] = argv[count];
+ }
+
+ VALUE result = rb_funcall2(qt_internal_module, rb_intern("try_initialize"), argc+1, temp_stack);
+ rb_obj_call_init(result, argc, argv);
+
+ free(temp_stack);
+ return result;
+}
+
+static VALUE
+new_qapplication(int argc, VALUE * argv, VALUE klass)
+{
+ VALUE result = Qnil;
+
+ if (argc == 1 && TYPE(argv[0]) == T_ARRAY) {
+ // Convert '(ARGV)' to '(NUM, [$0]+ARGV)'
+ VALUE * local_argv = (VALUE *) calloc(argc + 1, sizeof(VALUE));
+ VALUE temp = rb_ary_dup(argv[0]);
+ rb_ary_unshift(temp, rb_gv_get("$0"));
+ local_argv[0] = INT2NUM(RARRAY(temp)->len);
+ local_argv[1] = temp;
+ result = new_qt(2, local_argv, klass);
+ free(local_argv);
+ } else {
+ result = new_qt(argc, argv, klass);
+ }
+
+ rb_gv_set("$qApp", result);
+ return result;
+}
+
+// Returns $qApp.ARGV() - the original ARGV array with Qt command line options removed
+static VALUE
+qapplication_argv(VALUE /*self*/)
+{
+ VALUE result = rb_ary_new();
+ // Drop argv[0], as it isn't included in the ruby global ARGV
+ for (int index = 1; index < qApp->argc(); index++) {
+ rb_ary_push(result, rb_str_new2(qApp->argv()[index]));
+ }
+
+ return result;
+}
+
+//----------------- Sig/Slot ------------------
+
+
+VALUE
+getmetainfo(VALUE self, int &offset, int &index)
+{
+ char * signalname = rb_id2name(rb_frame_last_func());
+ VALUE metaObject_value = rb_funcall(qt_internal_module, rb_intern("getMetaObject"), 1, self);
+
+ smokeruby_object *ometa = value_obj_info(metaObject_value);
+ if(!ometa) return 0;
+ QMetaObject *metaobject = (QMetaObject*)ometa->ptr;
+
+ offset = metaobject->signalOffset();
+
+ VALUE signalInfo = rb_funcall(qt_internal_module, rb_intern("signalInfo"), 2, self, rb_str_new2(signalname));
+ VALUE member = rb_ary_entry(signalInfo, 0);
+ index = NUM2INT(rb_ary_entry(signalInfo, 1));
+ return rb_funcall(qt_internal_module, rb_intern("getMocArguments"), 1, member);
+}
+
+VALUE
+getslotinfo(VALUE self, int id, char *&slotname, int &index, bool isSignal = false)
+{
+ VALUE member;
+
+ VALUE metaObject_value = rb_funcall(qt_internal_module, rb_intern("getMetaObject"), 1, self);
+ smokeruby_object *ometa = value_obj_info(metaObject_value);
+ if(!ometa) return Qnil;
+
+ QMetaObject *metaobject = (QMetaObject*)ometa->ptr;
+
+ int offset = isSignal ? metaobject->signalOffset() : metaobject->slotOffset();
+
+ index = id - offset; // where we at
+ if(index < 0) return Qnil;
+
+ if (isSignal) {
+ member = rb_funcall(qt_internal_module, rb_intern("signalAt"), 2, self, INT2NUM(index));
+ } else {
+ member = rb_funcall(qt_internal_module, rb_intern("slotAt"), 2, self, INT2NUM(index));
+ }
+
+ VALUE mocArgs = rb_funcall(qt_internal_module, rb_intern("getMocArguments"), 1, member);
+ slotname = StringValuePtr(member);
+
+ return mocArgs;
+}
+
+static VALUE
+qt_signal(int argc, VALUE * argv, VALUE self)
+{
+ smokeruby_object *o = value_obj_info(self);
+ QObject *qobj = (QObject*)o->smoke->cast(
+ o->ptr,
+ o->classId,
+ o->smoke->idClass("QObject")
+ );
+ if(qobj->signalsBlocked()) return Qfalse;
+
+ int offset;
+ int index;
+
+ VALUE args = getmetainfo(self, offset, index);
+
+ if(args == Qnil) return Qfalse;
+
+ // Okay, we have the signal info. *whew*
+ EmitSignal signal(qobj, offset + index, argc, args, argv);
+ signal.next();
+
+ return Qtrue;
+}
+
+static VALUE
+qt_invoke(int /*argc*/, VALUE * argv, VALUE self)
+{
+ // Arguments: int id, QUObject *o
+ int id = NUM2INT(argv[0]);
+ QUObject *_o = 0;
+
+ Data_Get_Struct(rb_ary_entry(argv[1], 0), QUObject, _o);
+ if(_o == 0) {
+ rb_raise(rb_eRuntimeError, "Cannot create QUObject\n");
+ }
+
+ smokeruby_object *o = value_obj_info(self);
+ (void) (QObject*)o->smoke->cast(
+ o->ptr,
+ o->classId,
+ o->smoke->idClass("QObject")
+ );
+
+ // Now, I need to find out if this means me
+ int index;
+ char *slotname;
+ bool isSignal = qstrcmp(rb_id2name(rb_frame_last_func()), "qt_emit") == 0;
+ VALUE mocArgs = getslotinfo(self, id, slotname, index, isSignal);
+ if(mocArgs == Qnil) {
+ // No ruby slot/signal found, assume the target is a C++ one
+ Smoke::Index nameId = o->smoke->idMethodName(isSignal ? "qt_emit$?" : "qt_invoke$?");
+ Smoke::Index meth = o->smoke->findMethod(o->classId, nameId);
+ if(meth > 0) {
+ Smoke::Method &m = o->smoke->methods[o->smoke->methodMaps[meth].method];
+ Smoke::ClassFn fn = o->smoke->classes[m.classId].classFn;
+ Smoke::StackItem i[3];
+ i[1].s_int = id;
+ i[2].s_class = _o;
+ (*fn)(m.method, o->ptr, i);
+ return i[0].s_bool == 1 ? Qtrue : Qfalse;
+ }
+
+ // Should never happen..
+ rb_raise(rb_eRuntimeError, "Cannot find %s::qt_invoke() method\n",
+ o->smoke->classes[o->classId].className );
+ }
+
+ QString name(slotname);
+static QRegExp * rx = 0;
+ if (rx == 0) {
+ rx = new QRegExp("\\(.*");
+ }
+ name.replace(*rx, "");
+
+ InvokeSlot slot(self, rb_intern(name.latin1()), mocArgs, _o);
+ slot.next();
+
+ return Qtrue;
+}
+
+static VALUE
+qobject_connect(int argc, VALUE * argv, VALUE self)
+{
+ if (rb_block_given_p()) {
+ if (argc == 1) {
+ return rb_funcall(qt_internal_module, rb_intern("signal_connect"), 3, self, argv[0], rb_block_proc());
+ } else if (argc == 2) {
+ return rb_funcall(qt_internal_module, rb_intern("connect"), 4, argv[0], argv[1], self, rb_block_proc());
+ } else if (argc == 3) {
+ return rb_funcall(qt_internal_module, rb_intern("connect"), 4, argv[0], argv[1], argv[2], rb_block_proc());
+ } else {
+ rb_raise(rb_eArgError, "Invalid argument list");
+ }
+ } else {
+ return rb_call_super(argc, argv);
+ }
+}
+
+// --------------- Ruby C functions for Qt::_internal.* helpers ----------------
+
+
+static VALUE
+getMethStat(VALUE /*self*/)
+{
+ VALUE result_list = rb_ary_new();
+ rb_ary_push(result_list, INT2NUM((int)methcache.size()));
+ rb_ary_push(result_list, INT2NUM((int)methcache.count()));
+ return result_list;
+}
+
+static VALUE
+getClassStat(VALUE /*self*/)
+{
+ VALUE result_list = rb_ary_new();
+ rb_ary_push(result_list, INT2NUM((int)classcache.size()));
+ rb_ary_push(result_list, INT2NUM((int)classcache.count()));
+ return result_list;
+}
+
+static VALUE
+getIsa(VALUE /*self*/, VALUE classId)
+{
+ VALUE parents_list = rb_ary_new();
+
+ Smoke::Index *parents =
+ qt_Smoke->inheritanceList +
+ qt_Smoke->classes[NUM2INT(classId)].parents;
+
+ while(*parents) {
+ //qWarning("\tparent: %s", qt_Smoke->classes[*parents].className);
+ rb_ary_push(parents_list, rb_str_new2(qt_Smoke->classes[*parents++].className));
+ }
+ return parents_list;
+}
+
+// Return the class name of a QObject. Note that the name will be in the
+// form of Qt::Widget rather than QWidget. Is this a bug or a feature?
+static VALUE
+class_name(VALUE self)
+{
+ VALUE klass = rb_funcall(self, rb_intern("class"), 0);
+ return rb_funcall(klass, rb_intern("name"), 0);
+}
+
+// Allow classnames in both 'Qt::Widget' and 'QWidget' formats to be
+// used as an argument to Qt::Object.inherits()
+static VALUE
+inherits_qobject(int argc, VALUE * argv, VALUE /*self*/)
+{
+ if (argc != 1) {
+ return rb_call_super(argc, argv);
+ }
+
+ Smoke::Index * classId = classcache.find(StringValuePtr(argv[0]));
+
+ if (classId == 0) {
+ return rb_call_super(argc, argv);
+ } else {
+ VALUE super_class = rb_str_new2(qt_Smoke->classes[*classId].className);
+ return rb_call_super(argc, &super_class);
+ }
+}
+
+static VALUE
+qbytearray_data(VALUE self)
+{
+ smokeruby_object *o = value_obj_info(self);
+ if (o == 0 || o->ptr == 0) {
+ return Qnil;
+ }
+ QByteArray * dataArray = (QByteArray*) o->ptr;
+ return rb_str_new(dataArray->data(), (long) dataArray->size());
+}
+
+static VALUE
+qbytearray_size(VALUE self)
+{
+ smokeruby_object *o = value_obj_info(self);
+ if (o == 0 || o->ptr == 0) {
+ return Qnil;
+ }
+ QByteArray * dataArray = (QByteArray*) o->ptr;
+ return UINT2NUM(dataArray->size());
+}
+
+static VALUE
+qbytearray_setRawData(VALUE self, VALUE data)
+{
+ smokeruby_object *o = value_obj_info(self);
+ if (o == 0 || o->ptr == 0) {
+ return Qnil;
+ }
+ QByteArray * dataArray = (QByteArray*) o->ptr;
+ dataArray->setRawData(StringValuePtr(data), RSTRING(data)->len);
+ return self;
+}
+
+static void
+mocargs_free(void * ptr)
+{
+ MocArgument * mocArgs = (MocArgument *) ptr;
+ delete[] mocArgs;
+ return;
+}
+
+static VALUE
+allocateMocArguments(VALUE /*self*/, VALUE count_value)
+{
+ int count = NUM2INT(count_value);
+ MocArgument * ptr = new MocArgument[count + 1];
+ return Data_Wrap_Struct(rb_cObject, 0, mocargs_free, ptr);
+}
+
+static VALUE
+setMocType(VALUE /*self*/, VALUE ptr, VALUE idx_value, VALUE name_value, VALUE static_type_value)
+{
+ int idx = NUM2INT(idx_value);
+ char *name = StringValuePtr(name_value);
+ char *static_type = StringValuePtr(static_type_value);
+ Smoke::Index typeId = qt_Smoke->idType(name);
+ if(!typeId) return Qfalse;
+ MocArgument *arg = 0;
+ Data_Get_Struct(ptr, MocArgument, arg);
+ arg[idx].st.set(qt_Smoke, typeId);
+ if(qstrcmp(static_type, "ptr") == 0)
+ arg[idx].argType = xmoc_ptr;
+ else if(qstrcmp(static_type, "bool") == 0)
+ arg[idx].argType = xmoc_bool;
+ else if(qstrcmp(static_type, "int") == 0)
+ arg[idx].argType = xmoc_int;
+ else if(qstrcmp(static_type, "double") == 0)
+ arg[idx].argType = xmoc_double;
+ else if(qstrcmp(static_type, "char*") == 0)
+ arg[idx].argType = xmoc_charstar;
+ else if(qstrcmp(static_type, "QString") == 0)
+ arg[idx].argType = xmoc_QString;
+ return Qtrue;
+}
+
+static VALUE
+setDebug(VALUE self, VALUE on_value)
+{
+ int on = NUM2INT(on_value);
+ do_debug = on;
+ return self;
+}
+
+static VALUE
+debugging(VALUE /*self*/)
+{
+ return INT2NUM(do_debug);
+}
+
+static VALUE
+getTypeNameOfArg(VALUE /*self*/, VALUE method_value, VALUE idx_value)
+{
+ int method = NUM2INT(method_value);
+ int idx = NUM2INT(idx_value);
+ Smoke::Method &m = qt_Smoke->methods[method];
+ Smoke::Index *args = qt_Smoke->argumentList + m.args;
+ return rb_str_new2((char*)qt_Smoke->types[args[idx]].name);
+}
+
+static VALUE
+classIsa(VALUE /*self*/, VALUE className_value, VALUE base_value)
+{
+ char *className = StringValuePtr(className_value);
+ char *base = StringValuePtr(base_value);
+ return isDerivedFromByName(qt_Smoke, className, base) ? Qtrue : Qfalse;
+}
+
+static VALUE
+isEnum(VALUE /*self*/, VALUE enumName_value)
+{
+ char *enumName = StringValuePtr(enumName_value);
+ Smoke::Index typeId = qt_Smoke->idType(enumName);
+ return typeId > 0
+ && ( (qt_Smoke->types[typeId].flags & Smoke::tf_elem) == Smoke::t_enum
+ || (qt_Smoke->types[typeId].flags & Smoke::tf_elem) == Smoke::t_ulong
+ || (qt_Smoke->types[typeId].flags & Smoke::tf_elem) == Smoke::t_long
+ || (qt_Smoke->types[typeId].flags & Smoke::tf_elem) == Smoke::t_uint
+ || (qt_Smoke->types[typeId].flags & Smoke::tf_elem) == Smoke::t_int ) ? Qtrue : Qfalse;
+}
+
+static VALUE
+insert_pclassid(VALUE self, VALUE p_value, VALUE ix_value)
+{
+ char *p = StringValuePtr(p_value);
+ int ix = NUM2INT(ix_value);
+ classcache.insert(p, new Smoke::Index((Smoke::Index)ix));
+ classname.insert(ix, strdup(p));
+ return self;
+}
+
+static VALUE
+find_pclassid(VALUE /*self*/, VALUE p_value)
+{
+ char *p = StringValuePtr(p_value);
+ Smoke::Index *r = classcache.find(p);
+ if(r)
+ return INT2NUM((int)*r);
+ else
+ return INT2NUM(0);
+}
+
+static VALUE
+insert_mcid(VALUE self, VALUE mcid_value, VALUE ix_value)
+{
+ char *mcid = StringValuePtr(mcid_value);
+ int ix = NUM2INT(ix_value);
+ methcache.insert(mcid, new Smoke::Index((Smoke::Index)ix));
+ return self;
+}
+
+static VALUE
+find_mcid(VALUE /*self*/, VALUE mcid_value)
+{
+ char *mcid = StringValuePtr(mcid_value);
+ Smoke::Index *r = methcache.find(mcid);
+ if(r)
+ return INT2NUM((int)*r);
+ else
+ return INT2NUM(0);
+}
+
+static VALUE
+getVALUEtype(VALUE /*self*/, VALUE ruby_value)
+{
+ return rb_str_new2(get_VALUEtype(ruby_value));
+}
+
+static VALUE
+make_QUParameter(VALUE /*self*/, VALUE name_value, VALUE type_value, VALUE /*extra*/, VALUE inout_value)
+{
+ char *name = StringValuePtr(name_value);
+ char *type = StringValuePtr(type_value);
+ int inout = NUM2INT(inout_value);
+ QUParameter *p = new QUParameter;
+ p->name = new char[strlen(name) + 1];
+ strcpy((char*)p->name, name);
+ if(qstrcmp(type, "bool") == 0)
+ p->type = &static_QUType_bool;
+ else if(qstrcmp(type, "int") == 0)
+ p->type = &static_QUType_int;
+ else if(qstrcmp(type, "double") == 0)
+ p->type = &static_QUType_double;
+ else if(qstrcmp(type, "char*") == 0 || qstrcmp(type, "const char*") == 0)
+ p->type = &static_QUType_charstar;
+ else if(qstrcmp(type, "QString") == 0 || qstrcmp(type, "QString&") == 0 ||
+ qstrcmp(type, "const QString") == 0 || qstrcmp(type, "const QString&") == 0)
+ p->type = &static_QUType_QString;
+ else
+ p->type = &static_QUType_ptr;
+ // Lacking support for several types. Evil.
+ p->inOut = inout;
+ p->typeExtra = 0;
+ return Data_Wrap_Struct(rb_cObject, 0, 0, p);
+}
+
+static VALUE
+make_QMetaData(VALUE /*self*/, VALUE name_value, VALUE method)
+{
+ char *name = StringValuePtr(name_value);
+ QMetaData *m = new QMetaData; // will be deleted
+ m->name = new char[strlen(name) + 1];
+ strcpy((char*)m->name, name);
+ Data_Get_Struct(method, QUMethod, m->method);
+ m->access = QMetaData::Public;
+ return Data_Wrap_Struct(rb_cObject, 0, 0, m);
+}
+
+static VALUE
+make_QUMethod(VALUE /*self*/, VALUE name_value, VALUE params)
+{
+ char *name = StringValuePtr(name_value);
+ QUMethod *m = new QUMethod; // permanent memory allocation
+ m->name = new char[strlen(name) + 1]; // this too
+ strcpy((char*)m->name, name);
+ m->parameters = 0;
+ m->count = RARRAY(params)->len;
+
+ if (m->count > 0) {
+ m->parameters = new QUParameter[m->count];
+ for (long i = 0; i < m->count; i++) {
+ VALUE param = rb_ary_entry(params, i);
+ QUParameter *p = 0;
+ Data_Get_Struct(param, QUParameter, p);
+ ((QUParameter *) m->parameters)[i] = *p;
+ delete p;
+ }
+ }
+ return Data_Wrap_Struct(rb_cObject, 0, 0, m);
+}
+
+static VALUE
+make_QMetaData_tbl(VALUE /*self*/, VALUE list)
+{
+ long count = RARRAY(list)->len;
+ QMetaData *m = new QMetaData[count];
+
+ for (long i = 0; i < count; i++) {
+ VALUE item = rb_ary_entry(list, i);
+
+ QMetaData *old = 0;
+ Data_Get_Struct(item, QMetaData, old);
+ m[i] = *old;
+ delete old;
+ }
+
+ return Data_Wrap_Struct(rb_cObject, 0, 0, m);
+}
+
+static VALUE
+make_metaObject(VALUE /*self*/, VALUE className_value, VALUE parent, VALUE slot_tbl_value, VALUE slot_count_value, VALUE signal_tbl_value, VALUE signal_count_value)
+{
+ char *className = strdup(StringValuePtr(className_value));
+
+ QMetaData * slot_tbl = 0;
+ int slot_count = 0;
+ if (slot_tbl_value != Qnil) {
+ Data_Get_Struct(slot_tbl_value, QMetaData, slot_tbl);
+ slot_count = NUM2INT(slot_count_value);
+ }
+
+ QMetaData * signal_tbl = 0;
+ int signal_count = 0;
+ if (signal_tbl_value != Qnil) {
+ Data_Get_Struct(signal_tbl_value, QMetaData, signal_tbl);
+ signal_count = NUM2INT(signal_count_value);
+ }
+
+ smokeruby_object *po = value_obj_info(parent);
+ if(!po || !po->ptr) {
+ rb_raise(rb_eRuntimeError, "Cannot create metaObject\n");
+ }
+
+ QMetaObject *meta = QMetaObject::new_metaobject(
+ className, (QMetaObject*)po->ptr,
+ (const QMetaData*)slot_tbl, slot_count, // slots
+ (const QMetaData*)signal_tbl, signal_count, // signals
+ 0, 0, // properties
+ 0, 0, // enums
+ 0, 0);
+
+ smokeruby_object * o = (smokeruby_object *) malloc(sizeof(smokeruby_object));
+ o->smoke = qt_Smoke;
+ o->classId = qt_Smoke->idClass("QMetaObject");
+ o->ptr = meta;
+ o->allocated = true;
+
+ return Data_Wrap_Struct(qmetaobject_class, smokeruby_mark, smokeruby_free, o);
+}
+
+static VALUE
+add_metaobject_methods(VALUE self, VALUE klass)
+{
+ rb_define_method(klass, "qt_invoke", (VALUE (*) (...)) qt_invoke, -1);
+ rb_define_method(klass, "qt_emit", (VALUE (*) (...)) qt_invoke, -1);
+ rb_define_method(klass, "metaObject", (VALUE (*) (...)) metaObject, 0);
+ return self;
+}
+
+static VALUE
+add_signal_methods(VALUE self, VALUE klass, VALUE signalNames)
+{
+ for (long index = 0; index < RARRAY(signalNames)->len; index++) {
+ VALUE signal = rb_ary_entry(signalNames, index);
+ rb_define_method(klass, StringValuePtr(signal), (VALUE (*) (...)) qt_signal, -1);
+ }
+ return self;
+}
+
+static VALUE
+dispose(VALUE self)
+{
+ smokeruby_object *o = value_obj_info(self);
+ if(!o || !o->ptr) { return Qnil; }
+
+ const char *className = o->smoke->classes[o->classId].className;
+ if(do_debug & qtdb_gc) printf("Deleting (%s*)%p\n", className, o->ptr);
+
+ unmapPointer(o, o->classId, 0);
+ object_count--;
+
+ char *methodName = new char[strlen(className) + 2];
+ methodName[0] = '~';
+ strcpy(methodName + 1, className);
+ Smoke::Index nameId = o->smoke->idMethodName(methodName);
+ Smoke::Index meth = o->smoke->findMethod(o->classId, nameId);
+ if(meth > 0) {
+ Smoke::Method &m = o->smoke->methods[o->smoke->methodMaps[meth].method];
+ Smoke::ClassFn fn = o->smoke->classes[m.classId].classFn;
+ Smoke::StackItem i[1];
+ (*fn)(m.method, o->ptr, i);
+ }
+ delete[] methodName;
+ o->ptr = 0;
+ o->allocated = false;
+
+ return self;
+}
+
+static VALUE
+is_disposed(VALUE self)
+{
+ smokeruby_object *o = value_obj_info(self);
+ if(!o || !o->ptr) { return Qtrue; }
+ return Qfalse;
+}
+
+static VALUE
+mapObject(VALUE self, VALUE obj)
+{
+ smokeruby_object *o = value_obj_info(obj);
+ if(!o)
+ return Qnil;
+ mapPointer(obj, o, o->classId, 0);
+ return self;
+}
+
+static VALUE
+isaQObject(VALUE /*self*/, VALUE classid)
+{
+ int classid_value = NUM2INT(classid);
+ return isQObject(qt_Smoke, classid_value) ? Qtrue : Qfalse;
+}
+
+// Returns the Smoke classId of a ruby instance
+static VALUE
+idInstance(VALUE /*self*/, VALUE instance)
+{
+ smokeruby_object *o = value_obj_info(instance);
+ if(!o)
+ return Qnil;
+
+ return INT2NUM(o->classId);
+}
+
+static VALUE
+idClass(VALUE /*self*/, VALUE name_value)
+{
+ char *name = StringValuePtr(name_value);
+ return INT2NUM(qt_Smoke->idClass(name));
+}
+
+static VALUE
+idMethodName(VALUE /*self*/, VALUE name_value)
+{
+ char *name = StringValuePtr(name_value);
+ return INT2NUM(qt_Smoke->idMethodName(name));
+}
+
+static VALUE
+idMethod(VALUE /*self*/, VALUE idclass_value, VALUE idmethodname_value)
+{
+ int idclass = NUM2INT(idclass_value);
+ int idmethodname = NUM2INT(idmethodname_value);
+ return INT2NUM(qt_Smoke->idMethod(idclass, idmethodname));
+}
+
+static VALUE
+findMethod(VALUE /*self*/, VALUE c_value, VALUE name_value)
+{
+ char *c = StringValuePtr(c_value);
+ char *name = StringValuePtr(name_value);
+ VALUE result = rb_ary_new();
+ Smoke::Index meth = qt_Smoke->findMethod(c, name);
+#ifdef DEBUG
+ if (do_debug & qtdb_calls) qWarning("DAMNIT on %s::%s => %d", c, name, meth);
+#endif
+ if(!meth) {
+ meth = qt_Smoke->findMethod("QGlobalSpace", name);
+#ifdef DEBUG
+ if (do_debug & qtdb_calls) qWarning("DAMNIT on QGlobalSpace::%s => %d", name, meth);
+#endif
+ }
+
+ if(!meth) {
+ return result;
+ // empty list
+ } else if(meth > 0) {
+ Smoke::Index i = qt_Smoke->methodMaps[meth].method;
+ if(!i) { // shouldn't happen
+ rb_raise(rb_eArgError, "Corrupt method %s::%s", c, name);
+ } else if(i > 0) { // single match
+ Smoke::Method &methodRef = qt_Smoke->methods[i];
+ if ((methodRef.flags & Smoke::mf_internal) == 0) {
+ rb_ary_push(result, INT2NUM(i));
+ }
+ } else { // multiple match
+ i = -i; // turn into ambiguousMethodList index
+ while(qt_Smoke->ambiguousMethodList[i]) {
+ Smoke::Method &methodRef = qt_Smoke->methods[qt_Smoke->ambiguousMethodList[i]];
+ if ((methodRef.flags & Smoke::mf_internal) == 0) {
+ rb_ary_push(result, INT2NUM(qt_Smoke->ambiguousMethodList[i]));
+#ifdef DEBUG
+ if (do_debug & qtdb_calls) qWarning("Ambiguous Method %s::%s => %d", c, name, qt_Smoke->ambiguousMethodList[i]);
+#endif
+
+ }
+ i++;
+ }
+ }
+ }
+ return result;
+}
+
+// findAllMethods(classid [, startingWith]) : returns { "mungedName" => [index in methods, ...], ... }
+
+static VALUE
+findAllMethods(int argc, VALUE * argv, VALUE /*self*/)
+{
+ VALUE classid = argv[0];
+ VALUE result = rb_hash_new();
+ if(classid != Qnil) {
+ Smoke::Index c = (Smoke::Index) NUM2INT(classid);
+ if (c > qt_Smoke->numClasses) {
+ return Qnil;
+ }
+ char * pat = 0L;
+ if(argc > 1 && TYPE(argv[1]) == T_STRING)
+ pat = StringValuePtr(argv[1]);
+#ifdef DEBUG
+ if (do_debug & qtdb_calls) qWarning("findAllMethods called with classid = %d, pat == %s", c, pat);
+#endif
+ Smoke::Index imax = qt_Smoke->numMethodMaps;
+ Smoke::Index imin = 0, icur = -1, methmin, methmax;
+ methmin = -1; methmax = -1; // kill warnings
+ int icmp = -1;
+ while(imax >= imin) {
+ icur = (imin + imax) / 2;
+ icmp = qt_Smoke->leg(qt_Smoke->methodMaps[icur].classId, c);
+ if(!icmp) {
+ Smoke::Index pos = icur;
+ while(icur && qt_Smoke->methodMaps[icur-1].classId == c)
+ icur --;
+ methmin = icur;
+ icur = pos;
+ while(icur < imax && qt_Smoke->methodMaps[icur+1].classId == c)
+ icur ++;
+ methmax = icur;
+ break;
+ }
+ if (icmp > 0)
+ imax = icur - 1;
+ else
+ imin = icur + 1;
+ }
+ if(!icmp) {
+ for(Smoke::Index i=methmin ; i <= methmax ; i++) {
+ Smoke::Index m = qt_Smoke->methodMaps[i].name;
+ if(!pat || !qstrncmp(qt_Smoke->methodNames[m], pat, strlen(pat))) {
+ Smoke::Index ix= qt_Smoke->methodMaps[i].method;
+ VALUE meths = rb_ary_new();
+ if(ix >= 0) { // single match
+ Smoke::Method &methodRef = qt_Smoke->methods[ix];
+ if ((methodRef.flags & Smoke::mf_internal) == 0) {
+ rb_ary_push(meths, INT2NUM((int)ix));
+ }
+ } else { // multiple match
+ ix = -ix; // turn into ambiguousMethodList index
+ while(qt_Smoke->ambiguousMethodList[ix]) {
+ Smoke::Method &methodRef = qt_Smoke->methods[qt_Smoke->ambiguousMethodList[ix]];
+ if ((methodRef.flags & Smoke::mf_internal) == 0) {
+ rb_ary_push(meths, INT2NUM((int)qt_Smoke->ambiguousMethodList[ix]));
+ }
+ ix++;
+ }
+ }
+ rb_hash_aset(result, rb_str_new2(qt_Smoke->methodNames[m]), meths);
+ }
+ }
+ }
+ }
+ return result;
+}
+
+/*
+ Flags values
+ 0 All methods, except enum values and protected non-static methods
+ mf_static Static methods only
+ mf_enum Enums only
+ mf_protected Protected non-static methods only
+*/
+
+#define PUSH_QTRUBY_METHOD \
+ if ( (methodRef.flags & (Smoke::mf_internal|Smoke::mf_ctor|Smoke::mf_dtor)) == 0 \
+ && qstrcmp(qt_Smoke->methodNames[methodRef.name], "operator=") != 0 \
+ && qstrcmp(qt_Smoke->methodNames[methodRef.name], "operator!=") != 0 \
+ && qstrcmp(qt_Smoke->methodNames[methodRef.name], "operator--") != 0 \
+ && qstrcmp(qt_Smoke->methodNames[methodRef.name], "operator++") != 0 \
+ && qstrncmp(qt_Smoke->methodNames[methodRef.name], "operator ", strlen("operator ")) != 0 \
+ && ( (flags == 0 && (methodRef.flags & (Smoke::mf_static|Smoke::mf_enum|Smoke::mf_protected)) == 0) \
+ || ( flags == Smoke::mf_static \
+ && (methodRef.flags & Smoke::mf_enum) == 0 \
+ && (methodRef.flags & Smoke::mf_static) == Smoke::mf_static ) \
+ || (flags == Smoke::mf_enum && (methodRef.flags & Smoke::mf_enum) == Smoke::mf_enum) \
+ || ( flags == Smoke::mf_protected \
+ && (methodRef.flags & Smoke::mf_static) == 0 \
+ && (methodRef.flags & Smoke::mf_protected) == Smoke::mf_protected ) ) ) { \
+ if (qstrncmp(qt_Smoke->methodNames[methodRef.name], "operator", strlen("operator")) == 0) { \
+ if (op_re.search(qt_Smoke->methodNames[methodRef.name]) != -1) { \
+ rb_ary_push(result, rb_str_new2(op_re.cap(1) + op_re.cap(2))); \
+ } else { \
+ rb_ary_push(result, rb_str_new2(qt_Smoke->methodNames[methodRef.name] + strlen("operator"))); \
+ } \
+ } else if (predicate_re.search(qt_Smoke->methodNames[methodRef.name]) != -1 && methodRef.numArgs == 0) { \
+ rb_ary_push(result, rb_str_new2(predicate_re.cap(2).lower() + predicate_re.cap(3) + "?")); \
+ } else if (set_re.search(qt_Smoke->methodNames[methodRef.name]) != -1 && methodRef.numArgs == 1) { \
+ rb_ary_push(result, rb_str_new2(set_re.cap(2).lower() + set_re.cap(3) + "=")); \
+ } else { \
+ rb_ary_push(result, rb_str_new2(qt_Smoke->methodNames[methodRef.name])); \
+ } \
+ }
+
+static VALUE
+findAllMethodNames(VALUE /*self*/, VALUE result, VALUE classid, VALUE flags_value)
+{
+ QRegExp predicate_re("^(is|has)(.)(.*)");
+ QRegExp set_re("^(set)([A-Z])(.*)");
+ QRegExp op_re("operator(.*)(([-%~/+|&*])|(>>)|(<<)|(&&)|(\\|\\|)|(\\*\\*))=$");
+
+ unsigned short flags = (unsigned short) NUM2UINT(flags_value);
+ if (classid != Qnil) {
+ Smoke::Index c = (Smoke::Index) NUM2INT(classid);
+ if (c > qt_Smoke->numClasses) {
+ return Qnil;
+ }
+#ifdef DEBUG
+ if (do_debug & qtdb_calls) qWarning("findAllMethodNames called with classid = %d", c);
+#endif
+ Smoke::Index imax = qt_Smoke->numMethodMaps;
+ Smoke::Index imin = 0, icur = -1, methmin, methmax;
+ methmin = -1; methmax = -1; // kill warnings
+ int icmp = -1;
+
+ while (imax >= imin) {
+ icur = (imin + imax) / 2;
+ icmp = qt_Smoke->leg(qt_Smoke->methodMaps[icur].classId, c);
+ if (icmp == 0) {
+ Smoke::Index pos = icur;
+ while(icur && qt_Smoke->methodMaps[icur-1].classId == c)
+ icur --;
+ methmin = icur;
+ icur = pos;
+ while(icur < imax && qt_Smoke->methodMaps[icur+1].classId == c)
+ icur ++;
+ methmax = icur;
+ break;
+ }
+ if (icmp > 0)
+ imax = icur - 1;
+ else
+ imin = icur + 1;
+ }
+
+ if (icmp == 0) {
+ for (Smoke::Index i=methmin ; i <= methmax ; i++) {
+ Smoke::Index ix= qt_Smoke->methodMaps[i].method;
+ if (ix >= 0) { // single match
+ Smoke::Method &methodRef = qt_Smoke->methods[ix];
+ PUSH_QTRUBY_METHOD
+ } else { // multiple match
+ ix = -ix; // turn into ambiguousMethodList index
+ while (qt_Smoke->ambiguousMethodList[ix]) {
+ Smoke::Method &methodRef = qt_Smoke->methods[qt_Smoke->ambiguousMethodList[ix]];
+ PUSH_QTRUBY_METHOD
+ ix++;
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
+
+static VALUE
+dumpCandidates(VALUE /*self*/, VALUE rmeths)
+{
+ VALUE errmsg = rb_str_new2("");
+ if(rmeths != Qnil) {
+ int count = RARRAY(rmeths)->len;
+ for(int i = 0; i < count; i++) {
+ rb_str_catf(errmsg, "\t");
+ int id = NUM2INT(rb_ary_entry(rmeths, i));
+ Smoke::Method &meth = qt_Smoke->methods[id];
+ const char *tname = qt_Smoke->types[meth.ret].name;
+ if(meth.flags & Smoke::mf_enum) {
+ rb_str_catf(errmsg, "enum ");
+ rb_str_catf(errmsg, "%s::%s", qt_Smoke->classes[meth.classId].className, qt_Smoke->methodNames[meth.name]);
+ rb_str_catf(errmsg, "\n");
+ } else {
+ if(meth.flags & Smoke::mf_static) rb_str_catf(errmsg, "static ");
+ rb_str_catf(errmsg, "%s ", (tname ? tname:"void"));
+ rb_str_catf(errmsg, "%s::%s(", qt_Smoke->classes[meth.classId].className, qt_Smoke->methodNames[meth.name]);
+ for(int i = 0; i < meth.numArgs; i++) {
+ if(i) rb_str_catf(errmsg, ", ");
+ tname = qt_Smoke->types[qt_Smoke->argumentList[meth.args+i]].name;
+ rb_str_catf(errmsg, "%s", (tname ? tname:"void"));
+ }
+ rb_str_catf(errmsg, ")");
+ if(meth.flags & Smoke::mf_const) rb_str_catf(errmsg, " const");
+ rb_str_catf(errmsg, "\n");
+ }
+ }
+ }
+ return errmsg;
+}
+
+static VALUE
+isObject(VALUE /*self*/, VALUE obj)
+{
+ void * ptr = 0;
+ ptr = value_to_ptr(obj);
+ return (ptr > 0 ? Qtrue : Qfalse);
+}
+
+static VALUE
+setCurrentMethod(VALUE self, VALUE meth_value)
+{
+ int meth = NUM2INT(meth_value);
+ // FIXME: damn, this is lame, and it doesn't handle ambiguous methods
+ _current_method = meth; //qt_Smoke->methodMaps[meth].method;
+ return self;
+}
+
+static VALUE
+getClassList(VALUE /*self*/)
+{
+ VALUE class_list = rb_ary_new();
+
+ for(int i = 1; i <= qt_Smoke->numClasses; i++) {
+ rb_ary_push(class_list, rb_str_new2(qt_Smoke->classes[i].className));
+ }
+
+ return class_list;
+}
+
+static VALUE
+kde_package_to_class(const char * package, VALUE base_class)
+{
+ VALUE klass = Qnil;
+ QString packageName(package);
+static QRegExp * scope_op = 0;
+ if (scope_op == 0) {
+ scope_op = new QRegExp("^([^:]+)::([^:]+)$");
+ }
+
+ if (packageName.startsWith("KDE::ConfigSkeleton::ItemEnum::")) {
+ klass = rb_define_class_under(kconfigskeleton_itemenum_class, package+strlen("KDE::ConfigSkeleton::EnumItem::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ kconfigskeleton_itemenum_choice_class = klass;
+ } else if (packageName.startsWith("KDE::ConfigSkeleton::")) {
+ klass = rb_define_class_under(kconfigskeleton_class, package+strlen("KDE::ConfigSkeleton::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ rb_define_method(klass, "immutable?", (VALUE (*) (...)) _kconfigskeletonitem_immutable, 0);
+ rb_define_method(klass, "isImmutable", (VALUE (*) (...)) _kconfigskeletonitem_immutable, 0);
+ } else if (packageName.startsWith("KDE::Win::")) {
+ klass = rb_define_class_under(kwin_class, package+strlen("KDE::Win::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ } else if (packageName.startsWith("KDE::")) {
+ klass = rb_define_class_under(kde_module, package+strlen("KDE::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ } else if (packageName.startsWith("KParts::")) {
+ klass = rb_define_class_under(kparts_module, package+strlen("KParts::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ if (packageName == "KParts::ReadOnlyPart") {
+ konsole_part_class = rb_define_class_under(kde_module, "KonsolePart", klass);
+ }
+ } else if (packageName.startsWith("KNS::")) {
+ klass = rb_define_class_under(kns_module, package+strlen("KNS::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ } else if (packageName.startsWith("KIO::")) {
+ klass = rb_define_class_under(kio_module, package+strlen("KIO::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ if (packageName == "KIO::UDSAtom") {
+ kio_udsatom_class = klass;
+ }
+ } else if (packageName.startsWith("DOM::")) {
+ klass = rb_define_class_under(dom_module, package+strlen("DOM::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ } else if (packageName.startsWith("Kontact::")) {
+ klass = rb_define_class_under(kontact_module, package+strlen("Kontact::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ } else if (packageName.startsWith("Ko") && scope_op->search(packageName) == -1) {
+ klass = rb_define_class_under(koffice_module, package+strlen("Ko"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ } else if (packageName.startsWith("Kate::")) {
+ klass = rb_define_class_under(kate_module, package+strlen("Kate::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ } else if (packageName.startsWith("Kate")) {
+ klass = rb_define_class_under(kate_module, package+strlen("Kate"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ } else if (packageName.startsWith("KTextEditor::")) {
+ klass = rb_define_class_under(ktexteditor_module, package+strlen("KTextEditor::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ } else if (scope_op->search(packageName) != -1) {
+ // If an unrecognised classname of the form 'XXXXXX::YYYYYY' is found,
+ // then create a module XXXXXX to put the class YYYYYY under
+ VALUE module = rb_define_module(scope_op->cap(1).latin1());
+ klass = rb_define_class_under(module, scope_op->cap(2).latin1(), base_class);
+ } else if ( packageName.startsWith("K")
+ && packageName.mid(1, 1).contains(QRegExp("[A-Z]")) == 1 )
+ {
+ klass = rb_define_class_under(kde_module, package+strlen("K"), base_class);
+ } else {
+ packageName = packageName.mid(0, 1).upper() + packageName.mid(1);
+ klass = rb_define_class_under(kde_module, packageName.latin1(), base_class);
+ }
+
+ return klass;
+}
+
+static VALUE
+create_qobject_class(VALUE /*self*/, VALUE package_value)
+{
+ const char *package = StringValuePtr(package_value);
+ VALUE klass;
+
+ if (QString(package).startsWith("Qt::")) {
+ klass = rb_define_class_under(qt_module, package+strlen("Qt::"), qt_base_class);
+ if (qstrcmp(package, "Qt::Application") == 0) {
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) new_qapplication, -1);
+ rb_define_method(klass, "ARGV", (VALUE (*) (...)) qapplication_argv, 0);
+ }
+ } else if (QString(package).startsWith("Qext::")) {
+ if (qext_scintilla_module == Qnil) {
+ qext_scintilla_module = rb_define_module("Qext");
+ }
+ klass = rb_define_class_under(qext_scintilla_module, package+strlen("Qext::"), qt_base_class);
+ } else {
+ klass = kde_package_to_class(package, qt_base_class);
+ }
+
+ rb_define_method(klass, "inspect", (VALUE (*) (...)) inspect_qobject, 0);
+ rb_define_method(klass, "pretty_print", (VALUE (*) (...)) pretty_print_qobject, 1);
+ rb_define_method(klass, "receivers", (VALUE (*) (...)) receivers_qobject, 0);
+ rb_define_method(klass, "className", (VALUE (*) (...)) class_name, 0);
+ rb_define_method(klass, "inherits", (VALUE (*) (...)) inherits_qobject, -1);
+ rb_define_method(klass, "connect", (VALUE (*) (...)) qobject_connect, -1);
+ rb_define_singleton_method(klass, "connect", (VALUE (*) (...)) qobject_connect, -1);
+
+ return klass;
+}
+
+static VALUE
+create_qt_class(VALUE /*self*/, VALUE package_value)
+{
+ const char *package = StringValuePtr(package_value);
+ VALUE klass;
+
+ if (QString(package).startsWith("Qt::")) {
+ klass = rb_define_class_under(qt_module, package+strlen("Qt::"), qt_base_class);
+ } else if (QString(package).startsWith("Qext::")) {
+ if (qext_scintilla_module == Qnil) {
+ qext_scintilla_module = rb_define_module("Qext");
+ }
+ klass = rb_define_class_under(qext_scintilla_module, package+strlen("Qext::"), qt_base_class);
+ } else {
+ klass = kde_package_to_class(package, qt_base_class);
+ }
+
+ if (qstrcmp(package, "Qt::MetaObject") == 0) {
+ qmetaobject_class = klass;
+ } else if (qstrcmp(package, "Qt::Variant") == 0) {
+ qvariant_class = klass;
+ rb_define_singleton_method(qvariant_class, "new", (VALUE (*) (...)) new_qvariant, -1);
+ } else if (qstrcmp(package, "Qt::ByteArray") == 0) {
+ rb_define_method(klass, "data", (VALUE (*) (...)) qbytearray_data, 0);
+ rb_define_method(klass, "size", (VALUE (*) (...)) qbytearray_size, 0);
+ rb_define_method(klass, "setRawData", (VALUE (*) (...)) qbytearray_setRawData, 1);
+ } else if (qstrcmp(package, "Qt::Char") == 0) {
+ rb_define_method(klass, "to_s", (VALUE (*) (...)) qchar_to_s, 0);
+ }
+
+ return klass;
+}
+
+static VALUE
+version(VALUE /*self*/)
+{
+ return rb_str_new2(QT_VERSION_STR);
+}
+
+static VALUE
+qtruby_version(VALUE /*self*/)
+{
+ return rb_str_new2(QTRUBY_VERSION);
+}
+
+void
+set_new_kde(VALUE (*new_kde) (int, VALUE *, VALUE))
+{
+ _new_kde = new_kde;
+
+ if (qt_module == Qnil) {
+ qt_module = rb_define_module("Qt");
+ qt_internal_module = rb_define_module_under(qt_module, "Internal");
+ qt_base_class = rb_define_class_under(qt_module, "Base", rb_cObject);
+ }
+
+ kde_module = rb_define_module("KDE");
+ rb_define_singleton_method(kde_module, "method_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+ rb_define_singleton_method(kde_module, "const_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+
+ kparts_module = rb_define_module("KParts");
+ rb_define_singleton_method(kparts_module, "method_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+ rb_define_singleton_method(kparts_module, "const_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+
+ kns_module = rb_define_module("KNS");
+ rb_define_singleton_method(kns_module, "method_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+ rb_define_singleton_method(kns_module, "const_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+
+ kio_module = rb_define_module("KIO");
+ rb_define_singleton_method(kio_module, "method_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+ rb_define_singleton_method(kio_module, "const_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+
+ dom_module = rb_define_module("DOM");
+ rb_define_singleton_method(dom_module, "method_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+ rb_define_singleton_method(dom_module, "const_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+
+ kontact_module = rb_define_module("Kontact");
+ rb_define_singleton_method(kontact_module, "method_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+ rb_define_singleton_method(kontact_module, "const_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+
+ ktexteditor_module = rb_define_module("KTextEditor");
+ rb_define_singleton_method(ktexteditor_module, "method_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+ rb_define_singleton_method(ktexteditor_module, "const_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+
+ kwin_class = rb_define_class_under(kde_module, "Win", qt_base_class);
+
+ kate_module = rb_define_module("Kate");
+ rb_define_singleton_method(kate_module, "method_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+ rb_define_singleton_method(kate_module, "const_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+
+ koffice_module = rb_define_module("Ko");
+ rb_define_singleton_method(koffice_module, "method_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+ rb_define_singleton_method(koffice_module, "const_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+}
+
+void
+set_kconfigskeletonitem_immutable(VALUE (*kconfigskeletonitem_immutable) (VALUE))
+{
+ _kconfigskeletonitem_immutable = kconfigskeletonitem_immutable;
+
+ kconfigskeleton_class = rb_define_class_under(kde_module, "ConfigSkeleton", qt_base_class);
+ kconfigskeleton_itemenum_class = rb_define_class_under(kconfigskeleton_class, "ItemEnum", qt_base_class);
+}
+
+static VALUE
+set_application_terminated(VALUE /*self*/, VALUE yn)
+{
+ application_terminated = (yn == Qtrue ? true : false);
+ return Qnil;
+}
+
+void
+Init_qtruby()
+{
+ if (qt_Smoke != 0L) {
+ // This function must have been called twice because both
+ // 'require Qt' and 'require Korundum' statements have
+ // been included in a ruby program
+ rb_fatal("require 'Qt' must not follow require 'Korundum'\n");
+ return;
+ }
+
+ init_qt_Smoke();
+ qt_Smoke->binding = new QtRubySmokeBinding(qt_Smoke);
+ install_handlers(Qt_handlers);
+
+ methcache.setAutoDelete(true);
+ classcache.setAutoDelete(true);
+
+ if (qt_module == Qnil) {
+ qt_module = rb_define_module("Qt");
+ qt_internal_module = rb_define_module_under(qt_module, "Internal");
+ qt_base_class = rb_define_class_under(qt_module, "Base", rb_cObject);
+ }
+
+ rb_define_singleton_method(qt_base_class, "new", (VALUE (*) (...)) new_qt, -1);
+ rb_define_method(qt_base_class, "initialize", (VALUE (*) (...)) initialize_qt, -1);
+ rb_define_singleton_method(qt_base_class, "method_missing", (VALUE (*) (...)) class_method_missing, -1);
+ rb_define_singleton_method(qt_module, "method_missing", (VALUE (*) (...)) module_method_missing, -1);
+ rb_define_method(qt_base_class, "method_missing", (VALUE (*) (...)) method_missing, -1);
+
+ rb_define_singleton_method(qt_base_class, "const_missing", (VALUE (*) (...)) class_method_missing, -1);
+ rb_define_singleton_method(qt_module, "const_missing", (VALUE (*) (...)) module_method_missing, -1);
+ rb_define_method(qt_base_class, "const_missing", (VALUE (*) (...)) method_missing, -1);
+
+ rb_define_method(qt_base_class, "dispose", (VALUE (*) (...)) dispose, 0);
+ rb_define_method(qt_base_class, "isDisposed", (VALUE (*) (...)) is_disposed, 0);
+ rb_define_method(qt_base_class, "disposed?", (VALUE (*) (...)) is_disposed, 0);
+
+ rb_define_method(rb_cObject, "qDebug", (VALUE (*) (...)) qdebug, 1);
+ rb_define_method(rb_cObject, "qFatal", (VALUE (*) (...)) qfatal, 1);
+ rb_define_method(rb_cObject, "qWarning", (VALUE (*) (...)) qwarning, 1);
+
+ rb_define_module_function(qt_internal_module, "getMethStat", (VALUE (*) (...)) getMethStat, 0);
+ rb_define_module_function(qt_internal_module, "getClassStat", (VALUE (*) (...)) getClassStat, 0);
+ rb_define_module_function(qt_internal_module, "getIsa", (VALUE (*) (...)) getIsa, 1);
+ rb_define_module_function(qt_internal_module, "allocateMocArguments", (VALUE (*) (...)) allocateMocArguments, 1);
+ rb_define_module_function(qt_internal_module, "setMocType", (VALUE (*) (...)) setMocType, 4);
+ rb_define_module_function(qt_internal_module, "setDebug", (VALUE (*) (...)) setDebug, 1);
+ rb_define_module_function(qt_internal_module, "debug", (VALUE (*) (...)) debugging, 0);
+ rb_define_module_function(qt_internal_module, "getTypeNameOfArg", (VALUE (*) (...)) getTypeNameOfArg, 2);
+ rb_define_module_function(qt_internal_module, "classIsa", (VALUE (*) (...)) classIsa, 2);
+ rb_define_module_function(qt_internal_module, "isEnum", (VALUE (*) (...)) isEnum, 1);
+ rb_define_module_function(qt_internal_module, "insert_pclassid", (VALUE (*) (...)) insert_pclassid, 2);
+ rb_define_module_function(qt_internal_module, "find_pclassid", (VALUE (*) (...)) find_pclassid, 1);
+ rb_define_module_function(qt_internal_module, "insert_mcid", (VALUE (*) (...)) insert_mcid, 2);
+ rb_define_module_function(qt_internal_module, "find_mcid", (VALUE (*) (...)) find_mcid, 1);
+ rb_define_module_function(qt_internal_module, "getVALUEtype", (VALUE (*) (...)) getVALUEtype, 1);
+ rb_define_module_function(qt_internal_module, "make_QUParameter", (VALUE (*) (...)) make_QUParameter, 4);
+ rb_define_module_function(qt_internal_module, "make_QMetaData", (VALUE (*) (...)) make_QMetaData, 2);
+ rb_define_module_function(qt_internal_module, "make_QUMethod", (VALUE (*) (...)) make_QUMethod, 2);
+ rb_define_module_function(qt_internal_module, "make_QMetaData_tbl", (VALUE (*) (...)) make_QMetaData_tbl, 1);
+ rb_define_module_function(qt_internal_module, "make_metaObject", (VALUE (*) (...)) make_metaObject, 6);
+ rb_define_module_function(qt_internal_module, "addMetaObjectMethods", (VALUE (*) (...)) add_metaobject_methods, 1);
+ rb_define_module_function(qt_internal_module, "addSignalMethods", (VALUE (*) (...)) add_signal_methods, 2);
+ rb_define_module_function(qt_internal_module, "mapObject", (VALUE (*) (...)) mapObject, 1);
+ // isQOjbect => isaQObject
+ rb_define_module_function(qt_internal_module, "isQObject", (VALUE (*) (...)) isaQObject, 1);
+ rb_define_module_function(qt_internal_module, "idInstance", (VALUE (*) (...)) idInstance, 1);
+ rb_define_module_function(qt_internal_module, "idClass", (VALUE (*) (...)) idClass, 1);
+ rb_define_module_function(qt_internal_module, "idMethodName", (VALUE (*) (...)) idMethodName, 1);
+ rb_define_module_function(qt_internal_module, "idMethod", (VALUE (*) (...)) idMethod, 2);
+ rb_define_module_function(qt_internal_module, "findMethod", (VALUE (*) (...)) findMethod, 2);
+ rb_define_module_function(qt_internal_module, "findAllMethods", (VALUE (*) (...)) findAllMethods, -1);
+ rb_define_module_function(qt_internal_module, "findAllMethodNames", (VALUE (*) (...)) findAllMethodNames, 3);
+ rb_define_module_function(qt_internal_module, "dumpCandidates", (VALUE (*) (...)) dumpCandidates, 1);
+ rb_define_module_function(qt_internal_module, "isObject", (VALUE (*) (...)) isObject, 1);
+ rb_define_module_function(qt_internal_module, "setCurrentMethod", (VALUE (*) (...)) setCurrentMethod, 1);
+ rb_define_module_function(qt_internal_module, "getClassList", (VALUE (*) (...)) getClassList, 0);
+ rb_define_module_function(qt_internal_module, "create_qt_class", (VALUE (*) (...)) create_qt_class, 1);
+ rb_define_module_function(qt_internal_module, "create_qobject_class", (VALUE (*) (...)) create_qobject_class, 1);
+ rb_define_module_function(qt_internal_module, "cast_object_to", (VALUE (*) (...)) cast_object_to, 2);
+ rb_define_module_function(qt_internal_module, "application_terminated=", (VALUE (*) (...)) set_application_terminated, 1);
+
+ rb_define_module_function(qt_module, "version", (VALUE (*) (...)) version, 0);
+ rb_define_module_function(qt_module, "qtruby_version", (VALUE (*) (...)) qtruby_version, 0);
+
+ rb_require("Qt/qtruby.rb");
+
+ // Do package initialization
+ rb_funcall(qt_internal_module, rb_intern("init_all_classes"), 0);
+}
+
+};