summaryrefslogtreecommitdiffstats
path: root/qtruby/rubylib/qtruby
diff options
context:
space:
mode:
Diffstat (limited to 'qtruby/rubylib/qtruby')
-rw-r--r--qtruby/rubylib/qtruby/Makefile.am15
-rw-r--r--qtruby/rubylib/qtruby/Qt.cpp2967
-rw-r--r--qtruby/rubylib/qtruby/configure.in.in19
-rw-r--r--qtruby/rubylib/qtruby/extconf.rb5
-rw-r--r--qtruby/rubylib/qtruby/handlers.cpp1978
-rw-r--r--qtruby/rubylib/qtruby/lib/Makefile.am4
-rw-r--r--qtruby/rubylib/qtruby/lib/Qt.rb1
-rw-r--r--qtruby/rubylib/qtruby/lib/Qt/Makefile.am2
-rw-r--r--qtruby/rubylib/qtruby/lib/Qt/qtruby.rb1978
-rw-r--r--qtruby/rubylib/qtruby/marshall.h46
-rw-r--r--qtruby/rubylib/qtruby/qtruby.h55
-rw-r--r--qtruby/rubylib/qtruby/smokeruby.h321
12 files changed, 7391 insertions, 0 deletions
diff --git a/qtruby/rubylib/qtruby/Makefile.am b/qtruby/rubylib/qtruby/Makefile.am
new file mode 100644
index 00000000..1df273bf
--- /dev/null
+++ b/qtruby/rubylib/qtruby/Makefile.am
@@ -0,0 +1,15 @@
+INCLUDES = -I$(top_srcdir)/smoke $(all_includes) -I$(RUBY_ARCHDIR)
+
+noinst_HEADERS = qtruby.h marshall.h smokeruby.h extconf.rb
+
+noinst_LTLIBRARIES = libqtrubyinternal.la
+libqtrubyinternal_la_SOURCES = Qt.cpp handlers.cpp
+libqtrubyinternal_la_METASOURCES = AUTO
+
+rubylibdir = $(RUBY_SITEARCHDIR)
+rubylib_LTLIBRARIES = qtruby.la
+qtruby_la_SOURCES =
+qtruby_la_LDFLAGS = -module $(all_libraries) -version-info 0:0:0
+qtruby_la_LIBADD = libqtrubyinternal.la $(LIB_QT) $(top_builddir)/smoke/qt/libsmokeqt.la
+
+SUBDIRS = lib
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);
+}
+
+};
diff --git a/qtruby/rubylib/qtruby/configure.in.in b/qtruby/rubylib/qtruby/configure.in.in
new file mode 100644
index 00000000..41654f5e
--- /dev/null
+++ b/qtruby/rubylib/qtruby/configure.in.in
@@ -0,0 +1,19 @@
+AC_CHECK_PROG(RUBY, ruby, ruby)
+
+if test -z "$RUBY"; then
+ DO_NOT_COMPILE="$DO_NOT_COMPILE qtruby"
+else
+ AC_MSG_CHECKING(for ruby dirs)
+ RUBY_ARCHDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"archdir"@:>@)'`
+ RUBY_SITEARCHDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"sitearchdir"@:>@)'`
+ RUBY_SITEDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"sitelibdir"@:>@)'`
+ RUBY_LIBDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"libdir"@:>@)'`
+ RUBY_LIBRUBYARG=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"LIBRUBYARG_SHARED"@:>@)'`
+ AC_MSG_RESULT([archdir $RUBY_ARCHDIR, sitearchdir $RUBY_SITEARCHDIR, sitedir $RUBY_SITEDIR, libdir $RUBY_LIBDIR, librubyarg $RUBY_LIBRUBYARG])
+ AC_SUBST(RUBY_ARCHDIR)
+ AC_SUBST(RUBY_SITEARCHDIR)
+ AC_SUBST(RUBY_SITEDIR)
+ AC_SUBST(RUBY_LIBDIR)
+ AC_SUBST(RUBY_LIBRUBYARG)
+fi
+
diff --git a/qtruby/rubylib/qtruby/extconf.rb b/qtruby/rubylib/qtruby/extconf.rb
new file mode 100644
index 00000000..0ffd2382
--- /dev/null
+++ b/qtruby/rubylib/qtruby/extconf.rb
@@ -0,0 +1,5 @@
+require 'mkmf'
+dir_config('smoke')
+dir_config('qt')
+$LOCAL_LIBS += '-lsmokeqt -lqt-mt -lstdc++'
+create_makefile("qtruby")
diff --git a/qtruby/rubylib/qtruby/handlers.cpp b/qtruby/rubylib/qtruby/handlers.cpp
new file mode 100644
index 00000000..6bddf50c
--- /dev/null
+++ b/qtruby/rubylib/qtruby/handlers.cpp
@@ -0,0 +1,1978 @@
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include <qstring.h>
+#include <qregexp.h>
+#include <qapplication.h>
+#include <qcanvas.h>
+#include <qlistview.h>
+#include <qiconview.h>
+#include <qtable.h>
+#include <qpopupmenu.h>
+#include <qlayout.h>
+#include <qmetaobject.h>
+#include <qvaluelist.h>
+#include <qobjectlist.h>
+#include <qtextcodec.h>
+#include <qhostaddress.h>
+#include <qpair.h>
+
+#include <private/qucomextra_p.h>
+
+#include "smoke.h"
+
+#undef DEBUG
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#ifndef __USE_POSIX
+#define __USE_POSIX
+#endif
+#ifndef __USE_XOPEN
+#define __USE_XOPEN
+#endif
+#include <ruby.h>
+
+#include "marshall.h"
+#include "qtruby.h"
+#include "smokeruby.h"
+
+#ifndef HINT_BYTES
+#define HINT_BYTES HINT_BYTE
+#endif
+
+extern "C" {
+extern VALUE set_obj_info(const char * className, smokeruby_object * o);
+extern VALUE qt_internal_module;
+extern VALUE qvariant_class;
+extern bool application_terminated;
+};
+
+extern bool isDerivedFromByName(Smoke *smoke, const char *className, const char *baseClassName);
+extern void mapPointer(VALUE obj, smokeruby_object *o, Smoke::Index classId, void *lastptr);
+
+static const char * (*_kde_resolve_classname)(Smoke*, int, void*) = 0;
+
+extern "C" {
+
+void
+set_kde_resolve_classname(const char * (*kde_resolve_classname) (Smoke*, int, void *))
+{
+ _kde_resolve_classname = kde_resolve_classname;
+}
+
+};
+
+void
+mark_qobject_children(QObject * qobject)
+{
+ VALUE obj;
+
+ const QObjectList *l = qobject->children();
+ if (l == 0) {
+ return;
+ }
+ QObjectListIt it( *l ); // iterate over the children
+ QObject *child;
+
+ while ( (child = it.current()) != 0 ) {
+ ++it;
+ obj = getPointerObject(child);
+ if (obj != Qnil) {
+ if(do_debug & qtdb_gc) qWarning("Marking (%s*)%p -> %p\n", child->className(), child, (void*)obj);
+ rb_gc_mark(obj);
+ }
+
+ mark_qobject_children(child);
+ }
+}
+
+void
+smokeruby_mark(void * p)
+{
+ VALUE obj;
+ smokeruby_object * o = (smokeruby_object *) p;
+ const char *className = o->smoke->classes[o->classId].className;
+
+ if(do_debug & qtdb_gc) qWarning("Checking for mark (%s*)%p\n", className, o->ptr);
+
+ if(o->ptr && o->allocated) {
+ if (isDerivedFromByName(o->smoke, className, "QListView")) {
+ QListView * listview = (QListView *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QListView"));
+ QListViewItemIterator it(listview);
+ QListViewItem *item;
+
+ while ( (item = it.current()) != 0 ) {
+ ++it;
+ obj = getPointerObject(item);
+ if (obj != Qnil) {
+ if(do_debug & qtdb_gc) qWarning("Marking (%s*)%p -> %p\n", className, item, (void*)obj);
+ rb_gc_mark(obj);
+ }
+ }
+ return;
+ }
+
+ if (isDerivedFromByName(o->smoke, className, "QTable")) {
+ QTable * table = (QTable *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QTable"));
+ QTableItem *item;
+
+ for ( int row = 0; row < table->numRows(); row++ ) {
+ for ( int col = 0; col < table->numCols(); col++ ) {
+ item = table->item(row, col);
+ obj = getPointerObject(item);
+ if (obj != Qnil) {
+ if(do_debug & qtdb_gc) qWarning("Marking (%s*)%p -> %p\n", className, item, (void*)obj);
+ rb_gc_mark(obj);
+ }
+ }
+ }
+ return;
+ }
+
+ if (isDerivedFromByName(o->smoke, className, "QCanvas")) {
+ QCanvas * canvas = (QCanvas *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QCanvas"));
+ QCanvasItemList list = canvas->allItems();
+ for ( QCanvasItemList::iterator it = list.begin(); it != list.end(); ++it ) {
+ obj = getPointerObject(*it);
+ if (obj != Qnil) {
+ if(do_debug & qtdb_gc) qWarning("Marking (%s*)%p -> %p\n", className, *it, (void*)obj);
+ rb_gc_mark(obj);
+ }
+ }
+ return;
+ }
+
+ if (isDerivedFromByName(o->smoke, className, "QCanvasItem")) {
+ QCanvasItem * item = (QCanvasItem *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QCanvasItem"));
+ QCanvas * canvas = item->canvas();
+ obj = getPointerObject(canvas);
+ if (obj != Qnil) {
+ if(do_debug & qtdb_gc) qWarning("Marking (%s*)%p -> %p\n", "QCanvas", canvas, (void*)obj);
+ rb_gc_mark(obj);
+ }
+ return;
+ }
+
+ if (isDerivedFromByName(o->smoke, className, "QObject")) {
+ QObject * qobject = (QObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject"));
+ mark_qobject_children(qobject);
+ return;
+ }
+ }
+}
+
+void
+smokeruby_free(void * p)
+{
+ smokeruby_object *o = (smokeruby_object*)p;
+ const char *className = o->smoke->classes[o->classId].className;
+
+ if(do_debug & qtdb_gc) qWarning("Checking for delete (%s*)%p allocated: %s\n", className, o->ptr, o->allocated ? "true" : "false");
+
+ if(application_terminated || !o->allocated || o->ptr == 0) {
+ free(o);
+ return;
+ }
+
+ unmapPointer(o, o->classId, 0);
+ object_count --;
+
+ if ( qstrcmp(className, "QObject") == 0
+ || qstrcmp(className, "QListBoxItem") == 0
+ || qstrcmp(className, "QStyleSheetItem") == 0
+ || qstrcmp(className, "KCommand") == 0
+ || qstrcmp(className, "KNamedCommand") == 0
+ || qstrcmp(className, "KMacroCommand") == 0
+ || qstrcmp(className, "KAboutData") == 0
+ || qstrcmp(className, "KCmdLineArgs") == 0
+ || qstrcmp(className, "QSqlCursor") == 0 )
+ {
+ // Don't delete instances of these classes for now
+ free(o);
+ return;
+ } else if (isDerivedFromByName(o->smoke, className, "QLayoutItem")) {
+ QLayoutItem * item = (QLayoutItem *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QLayoutItem"));
+ if (item->layout() != 0 || item->widget() != 0 || item->spacerItem() != 0) {
+ free(o);
+ return;
+ }
+ } else if (qstrcmp(className, "QIconViewItem") == 0) {
+ QIconViewItem * item = (QIconViewItem *) o->ptr;
+ if (item->iconView() != 0) {
+ free(o);
+ return;
+ }
+ } else if (qstrcmp(className, "QCheckListItem") == 0) {
+ QCheckListItem * item = (QCheckListItem *) o->ptr;
+ if (item->parent() != 0 || item->listView() != 0) {
+ free(o);
+ return;
+ }
+ } else if (qstrcmp(className, "QListViewItem") == 0) {
+ QListViewItem * item = (QListViewItem *) o->ptr;
+ if (item->parent() != 0 || item->listView() != 0) {
+ free(o);
+ return;
+ }
+ } else if (isDerivedFromByName(o->smoke, className, "QTableItem")) {
+ QTableItem * item = (QTableItem *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QTableItem"));
+ if (item->table() != 0) {
+ free(o);
+ return;
+ }
+ } else if (qstrcmp(className, "QPopupMenu") == 0) {
+ QPopupMenu * item = (QPopupMenu *) o->ptr;
+ if (item->parentWidget(false) != 0) {
+ free(o);
+ return;
+ }
+ } else if (isDerivedFromByName(o->smoke, className, "QWidget")) {
+ QWidget * qwidget = (QWidget *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QWidget"));
+ if (qwidget->parentWidget(true) != 0) {
+ free(o);
+ return;
+ }
+ } else if (isDerivedFromByName(o->smoke, className, "QObject")) {
+ QObject * qobject = (QObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject"));
+ if (qobject->parent() != 0) {
+ free(o);
+ return;
+ }
+ }
+
+ if(do_debug & qtdb_gc) qWarning("Deleting (%s*)%p\n", className, o->ptr);
+
+ 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;
+ free(o);
+
+ return;
+}
+
+/*
+ * Given an approximate classname and a qt instance, try to improve the resolution of the name
+ * by using the various Qt rtti mechanisms for QObjects, QEvents and QCanvasItems
+ */
+static const char *
+resolve_classname(Smoke* smoke, int classId, void * ptr)
+{
+ if (isDerivedFromByName(smoke, smoke->classes[classId].className, "QEvent")) {
+ QEvent * qevent = (QEvent *) smoke->cast(ptr, classId, smoke->idClass("QEvent"));
+ switch (qevent->type()) {
+ case QEvent::ChildInserted:
+ case QEvent::ChildRemoved:
+ return "Qt::ChildEvent";
+ case QEvent::Close:
+ return "Qt::CloseEvent";
+ case QEvent::ContextMenu:
+ return "Qt::ContextMenuEvent";
+// case QEvent::User:
+// return "Qt::CustomEvent";
+ case QEvent::DragEnter:
+ return "Qt::DragEnterEvent";
+ case QEvent::DragLeave:
+ return "Qt::DragLeaveEvent";
+ case QEvent::DragMove:
+ return "Qt::DragMoveEvent";
+ case QEvent::DragResponse:
+ return "Qt::DragResponseEvent";
+ case QEvent::Drop:
+ return "Qt::DropEvent";
+ case QEvent::FocusIn:
+ case QEvent::FocusOut:
+ return "Qt::FocusEvent";
+ case QEvent::Hide:
+ return "Qt::HideEvent";
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ return "Qt::KeyEvent";
+ case QEvent::IMStart:
+ case QEvent::IMCompose:
+ case QEvent::IMEnd:
+ return "Qt::IMEvent";
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseMove:
+ return "Qt::MouseEvent";
+ case QEvent::Move:
+ return "Qt::MoveEvent";
+ case QEvent::Paint:
+ return "Qt::PaintEvent";
+ case QEvent::Resize:
+ return "Qt::ResizeEvent";
+ case QEvent::Show:
+ return "Qt::ShowEvent";
+ // case QEvent::Tablet:
+ // return "Qt::TabletEvent";
+ case QEvent::Timer:
+ return "Qt::TimerEvent";
+ case QEvent::Wheel:
+ return "Qt::WheelEvent";
+ default:
+ break;
+ }
+ } else if (isDerivedFromByName(smoke, smoke->classes[classId].className, "QObject")) {
+ QObject * qobject = (QObject *) smoke->cast(ptr, classId, smoke->idClass("QObject"));
+ QMetaObject * meta = qobject->metaObject();
+
+ while (meta != 0) {
+ Smoke::Index classId = smoke->idClass(meta->className());
+ if (classId != 0) {
+ return smoke->binding->className(classId);
+ }
+
+ meta = meta->superClass();
+ }
+ } else if (isDerivedFromByName(smoke, smoke->classes[classId].className, "QCanvasItem")) {
+ QCanvasItem * qcanvasitem = (QCanvasItem *) smoke->cast(ptr, classId, smoke->idClass("QCanvasItem"));
+ switch (qcanvasitem->rtti()) {
+ case QCanvasItem::Rtti_Sprite:
+ return "Qt::CanvasSprite";
+ case QCanvasItem::Rtti_PolygonalItem:
+ return "Qt::CanvasPolygonalItem";
+ case QCanvasItem::Rtti_Text:
+ return "Qt::CanvasText";
+ case QCanvasItem::Rtti_Polygon:
+ return "Qt::CanvasPolygon";
+ case QCanvasItem::Rtti_Rectangle:
+ return "Qt::CanvasRectangle";
+ case QCanvasItem::Rtti_Ellipse:
+ return "Qt::CanvasEllipse";
+ case QCanvasItem::Rtti_Line:
+ return "Qt::CanvasLine";
+ case QCanvasItem::Rtti_Spline:
+ return "Qt::CanvasSpline";
+ default:
+ break;
+ }
+ } else if (isDerivedFromByName(smoke, smoke->classes[classId].className, "QListViewItem")) {
+ QListViewItem * item = (QListViewItem *) smoke->cast(ptr, classId, smoke->idClass("QListViewItem"));
+ switch (item->rtti()) {
+ case 0:
+ return "Qt::ListViewItem";
+ case 1:
+ return "Qt::CheckListItem";
+ default:
+ return "Qt::ListViewItem";
+ break;
+ }
+ } else if (isDerivedFromByName(smoke, smoke->classes[classId].className, "QTableItem")) {
+ QTableItem * item = (QTableItem *) smoke->cast(ptr, classId, smoke->idClass("QTableItem"));
+ switch (item->rtti()) {
+ case 0:
+ return "Qt::TableItem";
+ case 1:
+ return "Qt::ComboTableItem";
+ case 2:
+ return "Qt::CheckTableItem";
+ default:
+ return "Qt::TableItem";
+ break;
+ }
+ }
+
+ if (_kde_resolve_classname != 0) {
+ return (*_kde_resolve_classname)(smoke, classId, ptr);
+ }
+
+ return smoke->binding->className(classId);
+}
+
+bool
+matches_arg(Smoke *smoke, Smoke::Index meth, Smoke::Index argidx, const char *argtype)
+{
+ Smoke::Index *arg = smoke->argumentList + smoke->methods[meth].args + argidx;
+ SmokeType type = SmokeType(smoke, *arg);
+ return type.name() && qstrcmp(type.name(), argtype) == 0;
+}
+
+void *
+construct_copy(smokeruby_object *o)
+{
+ const char *className = o->smoke->className(o->classId);
+ int classNameLen = strlen(className);
+ char *ccSig = new char[classNameLen + 2]; // copy constructor signature
+ strcpy(ccSig, className);
+ strcat(ccSig, "#");
+ Smoke::Index ccId = o->smoke->idMethodName(ccSig);
+ delete[] ccSig;
+
+ char *ccArg = new char[classNameLen + 8];
+ sprintf(ccArg, "const %s&", className);
+
+ Smoke::Index ccMeth = o->smoke->findMethod(o->classId, ccId);
+
+ if(!ccMeth) {
+ delete[] ccArg;
+ return 0;
+ }
+ Smoke::Index method = o->smoke->methodMaps[ccMeth].method;
+ if(method > 0) {
+ // Make sure it's a copy constructor
+ if(!matches_arg(o->smoke, method, 0, ccArg)) {
+ delete[] ccArg;
+ return 0;
+ }
+ delete[] ccArg;
+ ccMeth = method;
+ } else {
+ // ambiguous method, pick the copy constructor
+ Smoke::Index i = -method;
+ while(o->smoke->ambiguousMethodList[i]) {
+ if(matches_arg(o->smoke, o->smoke->ambiguousMethodList[i], 0, ccArg))
+ break;
+ i++;
+ }
+ delete[] ccArg;
+ ccMeth = o->smoke->ambiguousMethodList[i];
+ if(!ccMeth)
+ return 0;
+ }
+
+ // Okay, ccMeth is the copy constructor. Time to call it.
+ Smoke::StackItem args[2];
+ args[0].s_voidp = 0;
+ args[1].s_voidp = o->ptr;
+ Smoke::ClassFn fn = o->smoke->classes[o->classId].classFn;
+ (*fn)(o->smoke->methods[ccMeth].method, 0, args);
+ return args[0].s_voidp;
+}
+
+void
+marshall_basetype(Marshall *m)
+{
+ switch(m->type().elem()) {
+ case Smoke::t_bool:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ if (TYPE(*(m->var())) == T_OBJECT) {
+ // A Qt::Boolean has been passed as a value
+ VALUE temp = rb_funcall(qt_internal_module, rb_intern("get_qboolean"), 1, *(m->var()));
+ m->item().s_bool = (temp == Qtrue ? true : false);
+ } else {
+ m->item().s_bool = (*(m->var()) == Qtrue ? true : false);
+ }
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = m->item().s_bool ? Qtrue : Qfalse;
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_char:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ m->item().s_char = NUM2CHR(*(m->var()));
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = CHR2FIX(m->item().s_char);
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_uchar:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ m->item().s_uchar = NUM2CHR(*(m->var()));
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = CHR2FIX(m->item().s_uchar);
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_short:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ m->item().s_short = (short) NUM2INT(*(m->var()));
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = INT2NUM(m->item().s_short);
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_ushort:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ m->item().s_ushort = (unsigned short) NUM2UINT(*(m->var()));
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = UINT2NUM(m->item().s_ushort);
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_int:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ if (TYPE(*(m->var())) == T_OBJECT) {
+ m->item().s_int = (int) NUM2INT(rb_funcall(qt_internal_module, rb_intern("get_qinteger"), 1, *(m->var())));
+ } else {
+ m->item().s_int = (int) NUM2INT(*(m->var()));
+ }
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = INT2NUM(m->item().s_int);
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_uint:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ if (TYPE(*(m->var())) == T_OBJECT) {
+ m->item().s_int = (unsigned int) NUM2UINT(rb_funcall(qt_internal_module, rb_intern("get_qinteger"), 1, *(m->var())));
+ } else {
+ m->item().s_uint = (unsigned int) NUM2UINT(*(m->var()));
+ }
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = UINT2NUM(m->item().s_uint);
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_long:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ if (TYPE(*(m->var())) == T_OBJECT) {
+ m->item().s_int = (long) NUM2LONG(rb_funcall(qt_internal_module, rb_intern("get_qinteger"), 1, *(m->var())));
+ } else {
+ m->item().s_long = (long) NUM2LONG(*(m->var()));
+ }
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = INT2NUM(m->item().s_long);
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_ulong:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ if (TYPE(*(m->var())) == T_OBJECT) {
+ m->item().s_int = (unsigned long) NUM2ULONG(rb_funcall(qt_internal_module, rb_intern("get_qinteger"), 1, *(m->var())));
+ } else {
+ m->item().s_ulong = (unsigned long) NUM2ULONG(*(m->var()));
+ }
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = INT2NUM(m->item().s_ulong);
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_float:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ m->item().s_float = (float) NUM2DBL(*(m->var()));
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = rb_float_new((double) m->item().s_float);
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_double:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ m->item().s_double = (double) NUM2DBL(*(m->var()));
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = rb_float_new(m->item().s_double);
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_enum:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ if (TYPE(*(m->var())) == T_OBJECT) {
+ // A Qt::Enum is a subclass of Qt::Integer, so 'get_qinteger()' can be called ok
+ VALUE temp = rb_funcall(qt_internal_module, rb_intern("get_qinteger"), 1, *(m->var()));
+ m->item().s_enum = (long) NUM2LONG(temp);
+ } else {
+ m->item().s_enum = (long) NUM2LONG(*(m->var()));
+ }
+ }
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = rb_funcall( qt_internal_module,
+ rb_intern("create_qenum"),
+ 2, INT2NUM(m->item().s_enum), rb_str_new2(m->type().name()) );
+
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_class:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ if(*(m->var()) == Qnil) {
+ m->item().s_class = 0;
+ break;
+ }
+ if(TYPE(*(m->var())) != T_DATA) {
+ rb_raise(rb_eArgError, "Invalid type, expecting %s\n", m->type().name());
+ break;
+ }
+
+ smokeruby_object *o = value_obj_info(*(m->var()));
+ if(!o || !o->ptr) {
+ if(m->type().isRef()) {
+ rb_warning("References can't be nil\n");
+ m->unsupported();
+ }
+ m->item().s_class = 0;
+ break;
+ }
+ void *ptr = o->ptr;
+ if(!m->cleanup() && m->type().isStack()) {
+ ptr = construct_copy(o);
+ }
+ const Smoke::Class &c = m->smoke()->classes[m->type().classId()];
+ ptr = o->smoke->cast(
+ ptr, // pointer
+ o->classId, // from
+ o->smoke->idClass(c.className) // to
+ );
+ m->item().s_class = ptr;
+ break;
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ if(m->item().s_voidp == 0) {
+ *(m->var()) = Qnil;
+ break;
+ }
+
+ void *p = m->item().s_voidp;
+ VALUE obj = getPointerObject(p);
+ if(obj != Qnil) {
+ *(m->var()) = obj;
+ break;
+ }
+
+ smokeruby_object * o = (smokeruby_object *) malloc(sizeof(smokeruby_object));
+ o->smoke = m->smoke();
+ o->classId = m->type().classId();
+ o->ptr = p;
+ o->allocated = false;
+
+ const char * classname = resolve_classname(o->smoke, o->classId, o->ptr);
+
+ if(m->type().isConst() && m->type().isRef()) {
+ p = construct_copy( o );
+ if(p) {
+ o->ptr = p;
+ o->allocated = true;
+ }
+ }
+
+ obj = set_obj_info(classname, o);
+ if (do_debug & qtdb_calls) {
+ qWarning("allocating %s %p -> %p\n", classname, o->ptr, (void*)obj);
+ }
+
+ if(m->type().isStack()) {
+ o->allocated = true;
+ // Keep a mapping of the pointer so that it is only wrapped once as a ruby VALUE
+ mapPointer(obj, o, o->classId, 0);
+ }
+
+ *(m->var()) = obj;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+static void marshall_void(Marshall * /*m*/) {}
+static void marshall_unknown(Marshall *m) {
+ m->unsupported();
+}
+
+static void marshall_charP(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE rv = *(m->var());
+ if (rv == Qnil) {
+ m->item().s_voidp = 0;
+ break;
+ }
+
+ int len = RSTRING(rv)->len;
+ char* mem = (char*) malloc(len+1);
+ memcpy(mem, StringValuePtr(rv), len);
+ mem[len] ='\0';
+ m->item().s_voidp = mem;
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ char *p = (char*)m->item().s_voidp;
+ if(p)
+ *(m->var()) = rb_str_new2(p);
+ else
+ *(m->var()) = Qnil;
+ if(m->cleanup())
+ delete[] p;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+void marshall_ucharP(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE rv = *(m->var());
+ if (rv == Qnil) {
+ m->item().s_voidp = 0;
+ break;
+ }
+ int len = RSTRING(rv)->len;
+ char* mem = (char*) malloc(len+1);
+ memcpy(mem, StringValuePtr(rv), len);
+ mem[len] ='\0';
+ m->item().s_voidp = mem;
+ }
+ break;
+ case Marshall::ToVALUE:
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+static const char * KCODE = 0;
+static QTextCodec *codec = 0;
+
+static void
+init_codec() {
+ VALUE temp = rb_gv_get("$KCODE");
+ KCODE = StringValuePtr(temp);
+ if (qstrcmp(KCODE, "EUC") == 0) {
+ codec = QTextCodec::codecForName("eucJP");
+ } else if (qstrcmp(KCODE, "SJIS") == 0) {
+ codec = QTextCodec::codecForName("Shift-JIS");
+ }
+}
+
+QString*
+qstringFromRString(VALUE rstring) {
+ if (KCODE == 0) {
+ init_codec();
+ }
+
+ QString * s;
+ if (qstrcmp(KCODE, "UTF8") == 0)
+ s = new QString(QString::fromUtf8(StringValuePtr(rstring), RSTRING(rstring)->len));
+ else if (qstrcmp(KCODE, "EUC") == 0)
+ s = new QString(codec->toUnicode(StringValuePtr(rstring)));
+ else if (qstrcmp(KCODE, "SJIS") == 0)
+ s = new QString(codec->toUnicode(StringValuePtr(rstring)));
+ else if(qstrcmp(KCODE, "NONE") == 0)
+ s = new QString(QString::fromLatin1(StringValuePtr(rstring)));
+ else
+ s = new QString(QString::fromLocal8Bit(StringValuePtr(rstring), RSTRING(rstring)->len));
+ return s;
+}
+
+VALUE
+rstringFromQString(QString * s) {
+ if (KCODE == 0) {
+ init_codec();
+ }
+
+ if (qstrcmp(KCODE, "UTF8") == 0)
+ return rb_str_new2(s->utf8());
+ else if (qstrcmp(KCODE, "EUC") == 0)
+ return rb_str_new2(codec->fromUnicode(*s));
+ else if (qstrcmp(KCODE, "SJIS") == 0)
+ return rb_str_new2(codec->fromUnicode(*s));
+ else if (qstrcmp(KCODE, "NONE") == 0)
+ return rb_str_new2(s->latin1());
+ else
+ return rb_str_new2(s->local8Bit());
+}
+
+static void marshall_QString(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ QString* s = 0;
+ if ( *(m->var()) != Qnil) {
+ s = qstringFromRString(*(m->var()));
+ } else {
+ s = new QString(QString::null);
+ }
+
+ m->item().s_voidp = s;
+ m->next();
+
+ if (!m->type().isConst() && *(m->var()) != Qnil && s != 0 && !s->isNull()) {
+ rb_str_resize(*(m->var()), 0);
+ VALUE temp = rstringFromQString(s);
+ rb_str_cat2(*(m->var()), StringValuePtr(temp));
+ }
+
+ if (s != 0 && m->cleanup()) {
+ delete s;
+ }
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ QString *s = (QString*)m->item().s_voidp;
+ if (s != 0) {
+ if (s->isNull()) {
+ *(m->var()) = Qnil;
+ } else {
+ *(m->var()) = rstringFromQString(s);
+ }
+ if (m->cleanup() || m->type().isStack()) {
+ delete s;
+ }
+ } else {
+ *(m->var()) = Qnil;
+ }
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+// The only way to convert a QChar to a QString is to
+// pass a QChar to a QString constructor. However,
+// QStrings aren't in the QtRuby api, so add this
+// convenience method 'Qt::Char.to_s' to get a ruby
+// string from a Qt::Char.
+VALUE
+qchar_to_s(VALUE self)
+{
+ smokeruby_object *o = value_obj_info(self);
+ if (o == 0 || o->ptr == 0) {
+ return Qnil;
+ }
+
+ QChar * qchar = (QChar*) o->ptr;
+ QString s(*qchar);
+ return rstringFromQString(&s);
+}
+
+#if 0
+static const char *not_ascii(const char *s, uint &len)
+{
+ bool r = false;
+ for(; *s ; s++, len--)
+ if((uint)*s > 0x7F)
+ {
+ r = true;
+ break;
+ }
+ return r ? s : 0L;
+}
+#endif
+
+static void marshall_QCString(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ QCString *s = 0;
+ VALUE rv = *(m->var());
+ if (rv == Qnil) {
+ s = new QCString();
+ } else {
+ // Add 1 to the ruby string length to allow for a QCString '\0' terminator
+ s = new QCString(StringValuePtr(*(m->var())), RSTRING(*(m->var()))->len + 1);
+ }
+ m->item().s_voidp = s;
+
+ m->next();
+
+ if (!m->type().isConst() && rv != Qnil && s != 0) {
+ rb_str_resize(rv, 0);
+ rb_str_cat2(rv, (const char *)*s);
+ }
+ if(s && m->cleanup())
+ delete s;
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ QCString *s = (QCString*)m->item().s_voidp;
+ if(s && (const char *) *s != 0) {
+ *(m->var()) = rb_str_new2((const char *)*s);
+// const char * p = (const char *)*s;
+// uint len = s->length();
+// if(not_ascii(p,len))
+// {
+// #if PERL_VERSION == 6 && PERL_SUBVERSION == 0
+// QTextCodec* c = QTextCodec::codecForMib(106); // utf8
+// if(c->heuristicContentMatch(p,len) >= 0)
+// #else
+// if(is_utf8_string((U8 *)p,len))
+// #endif
+// SvUTF8_on(*(m->var()));
+// }
+ } else {
+ if (m->type().isConst()) {
+ *(m->var()) = Qnil;
+ } else {
+ *(m->var()) = rb_str_new2("");
+ }
+ }
+ m->next();
+
+ if (!m->type().isConst() && s != 0) {
+ *s = (const char *) StringValuePtr(*(m->var()));
+ }
+
+ if(s && m->cleanup())
+ delete s;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+static void marshall_QCOORD_array(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE av = *(m->var());
+ if (TYPE(av) != T_ARRAY) {
+ m->item().s_voidp = 0;
+ break;
+ }
+ int count = RARRAY(av)->len;
+ QCOORD *coord = new QCOORD[count + 2];
+ for(long i = 0; i < count; i++) {
+ VALUE svp = rb_ary_entry(av, i);
+ coord[i] = NUM2INT(svp);
+ }
+ m->item().s_voidp = coord;
+ m->next();
+ }
+ break;
+ default:
+ m->unsupported();
+ }
+}
+
+static void marshall_longlong(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ m->item().s_voidp = new long long;
+ *(long long *)m->item().s_voidp = rb_num2ll(*(m->var()));
+
+ m->next();
+
+ if(m->cleanup() && m->type().isConst()) {
+ delete (long long *) m->item().s_voidp;
+ }
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ *(m->var()) = rb_ll2inum(*(long long *) m->item().s_voidp);
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+static void marshall_ulonglong(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ m->item().s_voidp = new unsigned long long;
+ *(long long *)m->item().s_voidp = rb_num2ull(*(m->var()));
+
+ m->next();
+
+ if(m->cleanup() && m->type().isConst()) {
+ delete (unsigned long long *) m->item().s_voidp;
+ }
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ *(m->var()) = rb_ull2inum(*(unsigned long long *) m->item().s_voidp);
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+static void marshall_intR(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE rv = *(m->var());
+ int * i = new int;
+ if (TYPE(rv) == T_OBJECT) {
+ // A Qt::Integer has been passed as an integer value
+ VALUE temp = rb_funcall(qt_internal_module, rb_intern("get_qinteger"), 1, rv);
+ *i = NUM2INT(temp);
+ m->item().s_voidp = i;
+ m->next();
+ rb_funcall(qt_internal_module, rb_intern("set_qinteger"), 2, rv, INT2NUM(*i));
+ rv = temp;
+ } else {
+ *i = NUM2INT(rv);
+ m->item().s_voidp = i;
+ m->next();
+ }
+ if(m->cleanup() && m->type().isConst()) {
+ delete i;
+ } else {
+ m->item().s_voidp = new int((int)NUM2INT(rv));
+ }
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ int *ip = (int*)m->item().s_voidp;
+ VALUE rv = *(m->var());
+ if(!ip) {
+ rv = Qnil;
+ break;
+ }
+ *(m->var()) = INT2NUM(*ip);
+ m->next();
+ if(!m->type().isConst())
+ *ip = NUM2INT(*(m->var()));
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+static void marshall_boolR(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE rv = *(m->var());
+ bool * b = new bool;
+ if (TYPE(rv) == T_OBJECT) {
+ // A Qt::Boolean has been passed as a value
+ VALUE temp = rb_funcall(qt_internal_module, rb_intern("get_qboolean"), 1, rv);
+ *b = (temp == Qtrue ? true : false);
+ m->item().s_voidp = b;
+ m->next();
+ rb_funcall(qt_internal_module, rb_intern("set_qboolean"), 2, rv, (*b ? Qtrue : Qfalse));
+ } else {
+ *b = (rv == Qtrue ? true : false);
+ m->item().s_voidp = b;
+ m->next();
+ }
+ if(m->cleanup() && m->type().isConst()) {
+ delete b;
+ }
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ bool *ip = (bool*)m->item().s_voidp;
+ if(!ip) {
+ *(m->var()) = Qnil;
+ break;
+ }
+ *(m->var()) = (*ip?Qtrue:Qfalse);
+ m->next();
+ if(!m->type().isConst())
+ *ip = *(m->var()) == Qtrue ? true : false;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+static void marshall_charP_array(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE arglist = *(m->var());
+ if (arglist == Qnil
+ || TYPE(arglist) != T_ARRAY
+ || RARRAY(arglist)->len == 0 )
+ {
+ m->item().s_voidp = 0;
+ break;
+ }
+
+ char **argv = new char *[RARRAY(arglist)->len + 1];
+ long i;
+ for(i = 0; i < RARRAY(arglist)->len; i++) {
+ VALUE item = rb_ary_entry(arglist, i);
+ char *s = StringValuePtr(item);
+ argv[i] = new char[strlen(s) + 1];
+ strcpy(argv[i], s);
+ }
+ argv[i] = 0;
+ m->item().s_voidp = argv;
+ m->next();
+ if(m->cleanup()) {
+ rb_ary_clear(arglist);
+ for(i = 0; argv[i]; i++)
+ rb_ary_push(arglist, rb_str_new2(argv[i]));
+ }
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+void marshall_QStringList(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE list = *(m->var());
+ if (TYPE(list) != T_ARRAY) {
+ m->item().s_voidp = 0;
+ break;
+ }
+
+ int count = RARRAY(list)->len;
+ QStringList *stringlist = new QStringList;
+
+ for(long i = 0; i < count; i++) {
+ VALUE item = rb_ary_entry(list, i);
+ if(TYPE(item) != T_STRING) {
+ stringlist->append(QString());
+ continue;
+ }
+ stringlist->append(*(qstringFromRString(item)));
+ }
+
+ m->item().s_voidp = stringlist;
+ m->next();
+
+
+ if (stringlist != 0 && !m->type().isConst()) {
+ rb_ary_clear(list);
+ for(QStringList::Iterator it = stringlist->begin(); it != stringlist->end(); ++it)
+ rb_ary_push(list, rstringFromQString(&(*it)));
+ }
+
+ if (m->cleanup())
+ delete stringlist;
+ break;
+ }
+ case Marshall::ToVALUE:
+ {
+ QStringList *stringlist = static_cast<QStringList *>(m->item().s_voidp);
+ if(!stringlist) {
+ *(m->var()) = Qnil;
+ break;
+ }
+
+ VALUE av = rb_ary_new();
+ for(QStringList::Iterator it = stringlist->begin(); it != stringlist->end(); ++it) {
+ VALUE rv = rstringFromQString(&(*it));
+ rb_ary_push(av, rv);
+ }
+
+ if(m->cleanup())
+ delete stringlist;
+
+ *(m->var()) = av;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+void marshall_QStrList(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE list = *(m->var());
+ if (TYPE(list) != T_ARRAY) {
+ m->item().s_voidp = 0;
+ break;
+ }
+
+ int count = RARRAY(list)->len;
+ QStrList *stringlist = new QStrList;
+
+ for(long i = 0; i < count; i++) {
+ VALUE item = rb_ary_entry(list, i);
+ if(TYPE(item) != T_STRING) {
+ stringlist->append(QString());
+ continue;
+ }
+ stringlist->append(QString::fromUtf8(StringValuePtr(item), RSTRING(item)->len));
+ }
+
+ m->item().s_voidp = stringlist;
+ m->next();
+
+ if (!m->type().isConst()) {
+ rb_ary_clear(list);
+ for(const char * it = stringlist->first(); it != 0; it = stringlist->next())
+ rb_ary_push(list, rb_str_new2(it));
+ }
+
+ if (m->cleanup()) {
+ delete stringlist;
+ }
+ break;
+ }
+ case Marshall::ToVALUE:
+ {
+ QStrList *stringlist = static_cast<QStrList *>(m->item().s_voidp);
+ if(!stringlist) {
+ *(m->var()) = Qnil;
+ break;
+ }
+
+ VALUE av = rb_ary_new();
+ for(const char * it = stringlist->first(); it != 0; it = stringlist->next()) {
+ VALUE rv = rb_str_new2(it);
+ rb_ary_push(av, rv);
+ }
+
+ if(m->cleanup())
+ delete stringlist;
+
+ *(m->var()) = av;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+template <class Item, class ItemList, class ItemListIterator, const char *ItemSTR >
+void marshall_ItemList(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE list = *(m->var());
+ if (TYPE(list) != T_ARRAY) {
+ m->item().s_voidp = 0;
+ break;
+ }
+ int count = RARRAY(list)->len;
+ ItemList *cpplist = new ItemList;
+ long i;
+ for(i = 0; i < count; i++) {
+ VALUE item = rb_ary_entry(list, i);
+ // TODO do type checking!
+ smokeruby_object *o = value_obj_info(item);
+ if(!o || !o->ptr)
+ continue;
+ void *ptr = o->ptr;
+ ptr = o->smoke->cast(
+ ptr, // pointer
+ o->classId, // from
+ o->smoke->idClass(ItemSTR) // to
+ );
+ cpplist->append((Item*)ptr);
+ }
+
+ m->item().s_voidp = cpplist;
+ m->next();
+
+ if (!m->type().isConst()) {
+ rb_ary_clear(list);
+ for(ItemListIterator it = cpplist->begin();
+ it != cpplist->end();
+ ++it )
+ {
+ VALUE obj = getPointerObject((void*)(*it));
+ rb_ary_push(list, obj);
+ }
+ }
+
+ if (m->cleanup()) {
+ delete cpplist;
+ }
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ ItemList *valuelist = (ItemList*)m->item().s_voidp;
+ if(!valuelist) {
+ *(m->var()) = Qnil;
+ break;
+ }
+
+ VALUE av = rb_ary_new();
+
+ for(ItemListIterator it = valuelist->begin();
+ it != valuelist->end();
+ ++it) {
+ void *p = *it;
+
+ if(m->item().s_voidp == 0) {
+ *(m->var()) = Qnil;
+ break;
+ }
+
+ VALUE obj = getPointerObject(p);
+ if(obj == Qnil) {
+ smokeruby_object * o = ALLOC(smokeruby_object);
+ o->smoke = m->smoke();
+ o->classId = m->smoke()->idClass(ItemSTR);
+ o->ptr = p;
+ o->allocated = false;
+ obj = set_obj_info(resolve_classname(o->smoke, o->classId, o->ptr), o);
+ }
+ rb_ary_push(av, obj);
+ }
+
+ if(m->cleanup())
+ delete valuelist;
+ else
+ *(m->var()) = av;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+void marshall_QValueListInt(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE list = *(m->var());
+ if (TYPE(list) != T_ARRAY) {
+ m->item().s_voidp = 0;
+ break;
+ }
+ int count = RARRAY(list)->len;
+ QValueList<int> *valuelist = new QValueList<int>;
+ long i;
+ for(i = 0; i < count; i++) {
+ VALUE item = rb_ary_entry(list, i);
+ if(TYPE(item) != T_FIXNUM && TYPE(item) != T_BIGNUM) {
+ valuelist->append(0);
+ continue;
+ }
+ valuelist->append(NUM2INT(item));
+ }
+
+ m->item().s_voidp = valuelist;
+ m->next();
+
+ if (!m->type().isConst()) {
+ rb_ary_clear(list);
+ for(QValueListIterator<int> it = valuelist->begin();
+ it != valuelist->end();
+ ++it)
+ rb_ary_push(list, INT2NUM((int)*it));
+ }
+
+ if (m->cleanup()) {
+ delete valuelist;
+ }
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ QValueList<int> *valuelist = (QValueList<int>*)m->item().s_voidp;
+ if(!valuelist) {
+ *(m->var()) = Qnil;
+ break;
+ }
+
+ VALUE av = rb_ary_new();
+
+ for(QValueListIterator<int> it = valuelist->begin();
+ it != valuelist->end();
+ ++it)
+ rb_ary_push(av, INT2NUM(*it));
+
+ *(m->var()) = av;
+
+ if(m->cleanup())
+ delete valuelist;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+void marshall_voidP(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE rv = *(m->var());
+ if (rv != Qnil)
+ m->item().s_voidp = (void*)NUM2INT(*(m->var()));
+ else
+ m->item().s_voidp = 0;
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ *(m->var()) = Data_Wrap_Struct(rb_cObject, 0, 0, m->item().s_voidp);
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+void marshall_QMapQStringQString(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE hash = *(m->var());
+ if (TYPE(hash) != T_HASH) {
+ m->item().s_voidp = 0;
+ break;
+ }
+
+ QMap<QString,QString> * map = new QMap<QString,QString>;
+
+ // Convert the ruby hash to an array of key/value arrays
+ VALUE temp = rb_funcall(hash, rb_intern("to_a"), 0);
+
+ for (long i = 0; i < RARRAY(temp)->len; i++) {
+ VALUE key = rb_ary_entry(rb_ary_entry(temp, i), 0);
+ VALUE value = rb_ary_entry(rb_ary_entry(temp, i), 1);
+ (*map)[QString(StringValuePtr(key))] = QString(StringValuePtr(value));
+ }
+
+ m->item().s_voidp = map;
+ m->next();
+
+ if(m->cleanup())
+ delete map;
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ QMap<QString,QString> *map = (QMap<QString,QString>*)m->item().s_voidp;
+ if(!map) {
+ *(m->var()) = Qnil;
+ break;
+ }
+
+ VALUE hv = rb_hash_new();
+
+ QMap<QString,QString>::Iterator it;
+ for (it = map->begin(); it != map->end(); ++it) {
+ rb_hash_aset(hv, rstringFromQString((QString*)&(it.key())), rstringFromQString((QString*) &(it.data())));
+ }
+
+ *(m->var()) = hv;
+ m->next();
+
+ if(m->cleanup())
+ delete map;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+void marshall_QMapQStringQVariant(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE hash = *(m->var());
+ if (TYPE(hash) != T_HASH) {
+ m->item().s_voidp = 0;
+ break;
+ }
+
+ QMap<QString,QVariant> * map = new QMap<QString,QVariant>;
+
+ // Convert the ruby hash to an array of key/value arrays
+ VALUE temp = rb_funcall(hash, rb_intern("to_a"), 0);
+
+ for (long i = 0; i < RARRAY(temp)->len; i++) {
+ VALUE key = rb_ary_entry(rb_ary_entry(temp, i), 0);
+ VALUE value = rb_ary_entry(rb_ary_entry(temp, i), 1);
+
+ smokeruby_object *o = value_obj_info(value);
+ if (!o || !o->ptr || o->classId != o->smoke->idClass("QVariant")) {
+ // If the value isn't a Qt::Variant, then try and construct
+ // a Qt::Variant from it
+ value = rb_funcall(qvariant_class, rb_intern("new"), 1, value);
+ if (value == Qnil) {
+ continue;
+ }
+ o = value_obj_info(value);
+ }
+
+ void * ptr = o->ptr;
+ ptr = o->smoke->cast(ptr, o->classId, o->smoke->idClass("QVariant"));
+
+ (*map)[QString(StringValuePtr(key))] = (QVariant)*(QVariant*)ptr;
+ }
+
+ m->item().s_voidp = map;
+ m->next();
+
+ if(m->cleanup())
+ delete map;
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ QMap<QString,QVariant> *map = (QMap<QString,QVariant>*)m->item().s_voidp;
+ if(!map) {
+ *(m->var()) = Qnil;
+ break;
+ }
+
+ VALUE hv = rb_hash_new();
+
+ QMap<QString,QVariant>::Iterator it;
+ for (it = map->begin(); it != map->end(); ++it) {
+ void *p = new QVariant(it.data());
+ VALUE obj = getPointerObject(p);
+
+ if (obj == Qnil) {
+ smokeruby_object * o = ALLOC(smokeruby_object);
+ o->classId = m->smoke()->idClass("QVariant");
+ o->smoke = m->smoke();
+ o->ptr = p;
+ o->allocated = true;
+ obj = set_obj_info("Qt::Variant", o);
+ }
+
+ rb_hash_aset(hv, rstringFromQString((QString*)&(it.key())), obj);
+ }
+
+ *(m->var()) = hv;
+ m->next();
+
+ if(m->cleanup())
+ delete map;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+void marshall_QUObject(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE array = *(m->var());
+ if (array != Qnil && TYPE(array) == T_ARRAY) {
+ VALUE rv = rb_ary_entry(array, 0);
+ Data_Get_Struct(rv, QUObject, m->item().s_voidp);
+ } else {
+ m->item().s_voidp = 0;
+ }
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ VALUE rv = Data_Wrap_Struct(rb_cObject, 0, 0, m->item().s_voidp);
+ VALUE array = rb_ary_new2(1);
+ rb_ary_push(array, rv);
+ *(m->var()) = array;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+void marshall_QRgb_array(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE list = *(m->var());
+ if (TYPE(list) != T_ARRAY) {
+ m->item().s_voidp = 0;
+ break;
+ }
+ int count = RARRAY(list)->len;
+ QRgb *rgb = new QRgb[count + 2];
+ long i;
+ for(i = 0; i < count; i++) {
+ VALUE item = rb_ary_entry(list, i);
+ if(TYPE(item) != T_FIXNUM && TYPE(item) != T_BIGNUM) {
+ rgb[i] = 0;
+ continue;
+ }
+
+ rgb[i] = NUM2UINT(item);
+ }
+ m->item().s_voidp = rgb;
+ m->next();
+ }
+ break;
+ case Marshall::ToVALUE:
+ // Implement this with a tied array or something
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+void marshall_QPairintint(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE list = *(m->var());
+ if (TYPE(list) != T_ARRAY || RARRAY(list)->len != 2) {
+ m->item().s_voidp = 0;
+ break;
+ }
+ int int0;
+ int int1;
+ VALUE item = rb_ary_entry(list, 0);
+ if(TYPE(item) != T_FIXNUM && TYPE(item) != T_BIGNUM) {
+ int0 = 0;
+ } else {
+ int0 = NUM2INT(item);
+ }
+
+ item = rb_ary_entry(list, 1);
+ if(TYPE(item) != T_FIXNUM && TYPE(item) != T_BIGNUM) {
+ int1 = 0;
+ } else {
+ int1 = NUM2INT(item);
+ }
+
+ QPair<int,int> * qpair = new QPair<int,int>(int0,int1);
+ m->item().s_voidp = qpair;
+ m->next();
+ if(m->cleanup())
+ delete qpair;
+ }
+ break;
+ case Marshall::ToVALUE:
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+#define DEF_LIST_MARSHALLER(ListIdent,ItemList,Item,Itr) namespace { char ListIdent##STR[] = #Item; }; \
+ Marshall::HandlerFn marshall_##ListIdent = marshall_ItemList<Item,ItemList,Itr,ListIdent##STR>;
+
+#include <qcanvas.h>
+#include <qdir.h>
+#include <qobjectlist.h>
+#include <qwidgetlist.h>
+#include <qdockwindow.h>
+#include <qnetworkprotocol.h>
+#include <qtoolbar.h>
+#include <qtabbar.h>
+
+#if QT_VERSION >= 0x030200
+DEF_LIST_MARSHALLER( QPtrListQNetworkOperation, QPtrList<QNetworkOperation>, QNetworkOperation, QPtrListStdIterator<QNetworkOperation> )
+DEF_LIST_MARSHALLER( QPtrListQToolBar, QPtrList<QToolBar>, QToolBar, QPtrListStdIterator<QToolBar> )
+DEF_LIST_MARSHALLER( QPtrListQTab, QPtrList<QTab>, QTab, QPtrListStdIterator<QTab> )
+DEF_LIST_MARSHALLER( QPtrListQDockWindow, QPtrList<QDockWindow>, QDockWindow, QPtrListStdIterator<QDockWindow> )
+DEF_LIST_MARSHALLER( QFileInfoList, QFileInfoList, QFileInfo, QFileInfoList::Iterator )
+DEF_LIST_MARSHALLER( QObjectList, QObjectList, QObject, QPtrListStdIterator<QObject> )
+DEF_LIST_MARSHALLER( QWidgetList, QWidgetList, QWidget, QPtrListStdIterator<QWidget> )
+#endif
+
+DEF_LIST_MARSHALLER( QCanvasItemList, QCanvasItemList, QCanvasItem, QValueListIterator<QCanvasItem*> )
+
+template <class Item, class ItemList, class ItemListIterator, const char *ItemSTR >
+void marshall_ValueItemList(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE list = *(m->var());
+ if (TYPE(list) != T_ARRAY) {
+ m->item().s_voidp = 0;
+ break;
+ }
+ int count = RARRAY(list)->len;
+ ItemList *cpplist = new ItemList;
+ long i;
+ for(i = 0; i < count; i++) {
+ VALUE item = rb_ary_entry(list, i);
+ // TODO do type checking!
+ smokeruby_object *o = value_obj_info(item);
+
+ // Special case for the QValueList<QVariant> type
+ if ( qstrcmp(ItemSTR, "QVariant") == 0
+ && (!o || !o->ptr || o->classId != o->smoke->idClass("QVariant")) )
+ {
+ // If the value isn't a Qt::Variant, then try and construct
+ // a Qt::Variant from it
+ item = rb_funcall(qvariant_class, rb_intern("new"), 1, item);
+ if (item == Qnil) {
+ continue;
+ }
+ o = value_obj_info(item);
+ }
+
+ if(!o || !o->ptr)
+ continue;
+ void *ptr = o->ptr;
+ ptr = o->smoke->cast(
+ ptr, // pointer
+ o->classId, // from
+ o->smoke->idClass(ItemSTR) // to
+ );
+ cpplist->append(*(Item*)ptr);
+ }
+
+ m->item().s_voidp = cpplist;
+ m->next();
+
+ if (!m->type().isConst()) {
+ rb_ary_clear(list);
+ for(ItemListIterator it = cpplist->begin();
+ it != cpplist->end();
+ ++it)
+ {
+ VALUE obj = getPointerObject((void*)&(*it));
+ rb_ary_push(list, obj);
+ }
+ }
+
+ if (m->cleanup()) {
+ delete cpplist;
+ }
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ ItemList *valuelist = (ItemList*)m->item().s_voidp;
+ if(!valuelist) {
+ *(m->var()) = Qnil;
+ break;
+ }
+
+ VALUE av = rb_ary_new();
+
+ int ix = m->smoke()->idClass(ItemSTR);
+ const char * className = m->smoke()->binding->className(ix);
+
+ for(ItemListIterator it = valuelist->begin();
+ it != valuelist->end();
+ ++it) {
+ void *p = &(*it);
+
+ if(m->item().s_voidp == 0) {
+ *(m->var()) = Qnil;
+ break;
+ }
+
+ VALUE obj = getPointerObject(p);
+ if(obj == Qnil) {
+ smokeruby_object * o = ALLOC(smokeruby_object);
+ o->smoke = m->smoke();
+ o->classId = o->smoke->idClass(ItemSTR);
+ o->ptr = p;
+ o->allocated = false;
+ obj = set_obj_info(className, o);
+ }
+ rb_ary_push(av, obj);
+ }
+
+ if(m->cleanup())
+ delete valuelist;
+ else
+ *(m->var()) = av;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+#define DEF_VALUELIST_MARSHALLER(ListIdent,ItemList,Item,Itr) namespace dummy { char ListIdent##STR[] = #Item; }; \
+ Marshall::HandlerFn marshall_##ListIdent = marshall_ValueItemList<Item,ItemList,Itr,dummy::ListIdent##STR>;
+
+DEF_VALUELIST_MARSHALLER( QVariantList, QValueList<QVariant>, QVariant, QValueList<QVariant>::Iterator )
+DEF_VALUELIST_MARSHALLER( QPixmapList, QValueList<QPixmap>, QPixmap, QValueList<QPixmap>::Iterator )
+DEF_VALUELIST_MARSHALLER( QIconDragItemList, QValueList<QIconDragItem>, QIconDragItem, QValueList<QIconDragItem>::Iterator )
+DEF_VALUELIST_MARSHALLER( QImageTextKeyLangList, QValueList<QImageTextKeyLang>, QImageTextKeyLang, QValueList<QImageTextKeyLang>::Iterator )
+DEF_VALUELIST_MARSHALLER( QUrlInfoList, QValueList<QUrlInfo>, QUrlInfo, QValueList<QUrlInfo>::Iterator )
+DEF_VALUELIST_MARSHALLER( QTranslatorMessageList, QValueList<QTranslatorMessage>, QTranslatorMessage, QValueList<QTranslatorMessage>::Iterator )
+DEF_VALUELIST_MARSHALLER( QHostAddressList, QValueList<QHostAddress>, QHostAddress, QValueList<QHostAddress>::Iterator )
+
+TypeHandler Qt_handlers[] = {
+ { "QString", marshall_QString },
+ { "QString&", marshall_QString },
+ { "QString*", marshall_QString },
+ { "QCString", marshall_QCString },
+ { "QCString&", marshall_QCString },
+ { "QCString*", marshall_QCString },
+ { "QStringList", marshall_QStringList },
+ { "QStringList&", marshall_QStringList },
+ { "QStringList*", marshall_QStringList },
+ { "QStrList", marshall_QStrList },
+ { "QStrList&", marshall_QStrList },
+ { "QStrList*", marshall_QStrList },
+ { "long long int", marshall_longlong },
+ { "long long int&", marshall_longlong },
+ { "Q_INT64", marshall_longlong },
+ { "Q_INT64&", marshall_longlong },
+ { "Q_LLONG", marshall_longlong },
+ { "Q_LLONG&", marshall_longlong },
+ { "KIO::filesize_t", marshall_longlong },
+ { "DOM::DOMTimeStamp", marshall_ulonglong },
+ { "unsigned long long int", marshall_ulonglong },
+ { "unsigned long long int&", marshall_ulonglong },
+ { "Q_UINT64", marshall_ulonglong },
+ { "Q_UINT64&", marshall_ulonglong },
+ { "Q_ULLONG", marshall_ulonglong },
+ { "Q_ULLONG&", marshall_ulonglong },
+ { "signed int&", marshall_intR },
+ { "int&", marshall_intR },
+ { "int*", marshall_intR },
+ { "bool&", marshall_boolR },
+ { "bool*", marshall_boolR },
+ { "char*", marshall_charP },
+ { "char**", marshall_charP_array },
+ { "uchar*", marshall_ucharP },
+ { "QRgb*", marshall_QRgb_array },
+ { "QPair<int,int>&", marshall_QPairintint },
+ { "QUObject*", marshall_QUObject },
+ { "const QCOORD*", marshall_QCOORD_array },
+ { "void", marshall_void },
+ { "QValueList<int>", marshall_QValueListInt },
+ { "QValueList<int>&", marshall_QValueListInt },
+ { "QValueList<QVariant>", marshall_QVariantList },
+ { "QValueList<QVariant>&", marshall_QVariantList },
+ { "QValueList<QPixmap>", marshall_QPixmapList },
+ { "QValueList<QIconDragItem>&", marshall_QIconDragItemList },
+ { "QValueList<QImageTextKeyLang>", marshall_QImageTextKeyLangList },
+ { "QValueList<QUrlInfo>&", marshall_QUrlInfoList },
+ { "QValueList<QTranslatorMessage>", marshall_QTranslatorMessageList },
+ { "QValueList<QHostAddress>", marshall_QHostAddressList },
+ { "QCanvasItemList", marshall_QCanvasItemList },
+ { "QMap<QString,QString>", marshall_QMapQStringQString },
+ { "QMap<QString,QString>&", marshall_QMapQStringQString },
+ { "QMap<QString,QVariant>", marshall_QMapQStringQVariant },
+ { "QMap<QString,QVariant>&", marshall_QMapQStringQVariant },
+#if QT_VERSION >= 0x030200
+ { "QWidgetList", marshall_QWidgetList },
+ { "QWidgetList*", marshall_QWidgetList },
+ { "QWidgetList&", marshall_QWidgetList },
+ { "QObjectList*", marshall_QObjectList },
+ { "QObjectList&", marshall_QObjectList },
+ { "QFileInfoList*", marshall_QFileInfoList },
+ { "QPtrList<QToolBar>", marshall_QPtrListQToolBar },
+ { "QPtrList<QTab>*", marshall_QPtrListQTab },
+ { "QPtrList<QDockWindow>", marshall_QPtrListQDockWindow },
+ { "QPtrList<QDockWindow>*", marshall_QPtrListQDockWindow },
+ { "QPtrList<QNetworkOperation>", marshall_QPtrListQNetworkOperation },
+ { "QPtrList<QNetworkOperation>&", marshall_QPtrListQNetworkOperation },
+#endif
+ { 0, 0 }
+};
+
+QAsciiDict<TypeHandler> type_handlers(199);
+
+void install_handlers(TypeHandler *h) {
+ while(h->name) {
+ type_handlers.insert(h->name, h);
+ h++;
+ }
+}
+
+Marshall::HandlerFn getMarshallFn(const SmokeType &type) {
+ if(type.elem())
+ return marshall_basetype;
+ if(!type.name())
+ return marshall_void;
+ TypeHandler *h = type_handlers[type.name()];
+ if(h == 0 && type.isConst() && strlen(type.name()) > strlen("const ")) {
+ h = type_handlers[type.name() + strlen("const ")];
+ }
+
+ if(h != 0) {
+ return h->fn;
+ }
+
+ return marshall_unknown;
+}
diff --git a/qtruby/rubylib/qtruby/lib/Makefile.am b/qtruby/rubylib/qtruby/lib/Makefile.am
new file mode 100644
index 00000000..e8f6457a
--- /dev/null
+++ b/qtruby/rubylib/qtruby/lib/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS = Qt
+
+rubylibdir = $(RUBY_SITEDIR)
+rubylib_DATA = Qt.rb
diff --git a/qtruby/rubylib/qtruby/lib/Qt.rb b/qtruby/rubylib/qtruby/lib/Qt.rb
new file mode 100644
index 00000000..70e9c776
--- /dev/null
+++ b/qtruby/rubylib/qtruby/lib/Qt.rb
@@ -0,0 +1 @@
+require 'qtruby'
diff --git a/qtruby/rubylib/qtruby/lib/Qt/Makefile.am b/qtruby/rubylib/qtruby/lib/Qt/Makefile.am
new file mode 100644
index 00000000..267582ef
--- /dev/null
+++ b/qtruby/rubylib/qtruby/lib/Qt/Makefile.am
@@ -0,0 +1,2 @@
+qtrubylibdir = $(RUBY_SITEDIR)/Qt
+qtrubylib_DATA = qtruby.rb
diff --git a/qtruby/rubylib/qtruby/lib/Qt/qtruby.rb b/qtruby/rubylib/qtruby/lib/Qt/qtruby.rb
new file mode 100644
index 00000000..50f2eaef
--- /dev/null
+++ b/qtruby/rubylib/qtruby/lib/Qt/qtruby.rb
@@ -0,0 +1,1978 @@
+=begin
+/***************************************************************************
+ qtruby.rb - description
+ -------------------
+ begin : Fri Jul 4 2003
+ copyright : (C) 2003 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. *
+ * *
+ ***************************************************************************/
+=end
+
+module Qt
+ module DebugLevel
+ Off, Minimal, High, Extensive = 0, 1, 2, 3
+ end
+
+ module QtDebugChannel
+ QTDB_NONE = 0x00
+ QTDB_AMBIGUOUS = 0x01
+ QTDB_METHOD_MISSING = 0x02
+ QTDB_CALLS = 0x04
+ QTDB_GC = 0x08
+ QTDB_VIRTUAL = 0x10
+ QTDB_VERBOSE = 0x20
+ QTDB_ALL = QTDB_VERBOSE | QTDB_VIRTUAL | QTDB_GC | QTDB_CALLS | QTDB_METHOD_MISSING | QTDB_AMBIGUOUS
+ end
+
+ @@debug_level = DebugLevel::Off
+ def Qt.debug_level=(level)
+ @@debug_level = level
+ Internal::setDebug Qt::QtDebugChannel::QTDB_ALL if level >= DebugLevel::Extensive
+ end
+
+ def Qt.debug_level
+ @@debug_level
+ end
+
+ class Base
+ def self.signals(*signal_list)
+ meta = Qt::Meta[self.name] || Qt::MetaInfo.new(self)
+ meta.add_signals(signal_list)
+ meta.changed = true
+ end
+
+ def self.slots(*slot_list)
+ meta = Qt::Meta[self.name] || Qt::MetaInfo.new(self)
+ meta.add_slots(slot_list)
+ meta.changed = true
+ end
+
+ def **(a)
+ return Qt::**(self, a)
+ end
+ def +(a)
+ return Qt::+(self, a)
+ end
+ def ~(a)
+ return Qt::~(self, a)
+ end
+ def -@()
+ return Qt::-(self)
+ end
+ def -(a)
+ return Qt::-(self, a)
+ end
+ def *(a)
+ return Qt::*(self, a)
+ end
+ def /(a)
+ return Qt::/(self, a)
+ end
+ def %(a)
+ return Qt::%(self, a)
+ end
+ def >>(a)
+ return Qt::>>(self, a)
+ end
+ def <<(a)
+ return Qt::<<(self, a)
+ end
+ def &(a)
+ return Qt::&(self, a)
+ end
+ def ^(a)
+ return Qt::^(self, a)
+ end
+ def |(a)
+ return Qt::|(self, a)
+ end
+
+# Module has '<', '<=', '>' and '>=' operator instance methods, so pretend they
+# don't exist by calling method_missing() explicitely
+ def <(a)
+ begin
+ Qt::method_missing(:<, self, a)
+ rescue
+ super(a)
+ end
+ end
+
+ def <=(a)
+ begin
+ Qt::method_missing(:<=, self, a)
+ rescue
+ super(a)
+ end
+ end
+
+ def >(a)
+ begin
+ Qt::method_missing(:>, self, a)
+ rescue
+ super(a)
+ end
+ end
+
+ def >=(a)
+ begin
+ Qt::method_missing(:>=, self, a)
+ rescue
+ super(a)
+ end
+ end
+
+# Object has a '==' operator instance method, so pretend it
+# don't exist by calling method_missing() explicitely
+ def ==(a)
+ begin
+ Qt::method_missing(:==, self, a)
+ rescue
+ super(a)
+ end
+ end
+
+ def methods(regular=true)
+ if !regular
+ return singleton_methods
+ end
+
+ qt_methods(super, 0x0)
+ end
+
+ def protected_methods
+ # From smoke.h, Smoke::mf_protected 0x80
+ qt_methods(super, 0x80)
+ end
+
+ def public_methods
+ methods
+ end
+
+ def singleton_methods
+ # From smoke.h, Smoke::mf_static 0x01
+ qt_methods(super, 0x01)
+ end
+
+ private
+ def qt_methods(meths, flags)
+ ids = []
+ # These methods are all defined in Qt::Base, even if they aren't supported by a particular
+ # subclass, so remove them to avoid confusion
+ meths -= ["%", "&", "*", "**", "+", "-", "-@", "/", "<", "<<", "<=", ">", ">=", ">>", "|", "~", "^"]
+ classid = Qt::Internal::idInstance(self)
+ Qt::Internal::getAllParents(classid, ids)
+ ids << classid
+ ids.each { |c| Qt::Internal::findAllMethodNames(meths, c, flags) }
+ return meths.uniq
+ end
+ end # Qt::Base
+
+ # Delete the underlying C++ instance after exec returns
+ # Otherwise, rb_gc_call_finalizer_at_exit() can delete
+ # stuff that Qt::Application still needs for its cleanup.
+ class Application < Qt::Base
+ def exec
+ method_missing(:exec)
+ self.dispose
+ Qt::Internal.application_terminated = true
+ end
+
+ def exit(*args)
+ method_missing(:exit, *args)
+ end
+
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class BoxLayout < Qt::Base
+ include Enumerable
+
+ def each
+ it = iterator()
+ while it.current
+ yield it.current
+ it += 1
+ end
+ end
+ end
+
+ class Buffer < Qt::Base
+ def open(*args)
+ method_missing(:open, *args)
+ end
+ end
+
+ class ButtonGroup < Qt::Base
+ def id(*args)
+ method_missing(:id, *args)
+ end
+ end
+
+ class ByteArray < Qt::Base
+ def to_s
+ return data()
+ end
+
+ def length
+ return size()
+ end
+
+ def data=(data)
+ setRawData(data)
+ end
+ end
+
+ class CheckListItem < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class ChildEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class ClassInfo < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class CloseEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Color < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " %s>" % name)
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, " %s>" % name)
+ end
+
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class Connection < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " memberName=%s, memberType=%s, object=%s>" %
+ [memberName.inspect, memberType == 1 ? "SLOT" : "SIGNAL", object.inspect] )
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, "\n memberName=%s,\n memberType=%s,\n object=%s>" %
+ [memberName.inspect, memberType == 1 ? "SLOT" : "SIGNAL", object.inspect] )
+ end
+ end
+
+ class ContextMenuEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Cursor < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " shape=%d>" % shape)
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, " shape=%d>" % shape)
+ end
+ end
+
+ class CustomEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Date < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " %s>" % toString)
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, " %s>" % toString)
+ end
+ end
+
+ class DateTime < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " %s>" % toString)
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, " %s>" % toString)
+ end
+ end
+
+ class Dialog < Qt::Base
+ def exec(*args)
+ method_missing(:exec, *args)
+ end
+ end
+
+ class DomAttr < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class DomDocumentType < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class DragLeaveEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class DropEvent < Qt::Base
+ def format(*args)
+ method_missing(:format, *args)
+ end
+
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class EucJpCodec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class EucKrCodec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class Event < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class EventLoop < Qt::Base
+ def exec(*args)
+ method_missing(:exec, *args)
+ end
+
+ def exit(*args)
+ method_missing(:exit, *args)
+ end
+ end
+
+ class File < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+
+ def open(*args)
+ method_missing(:open, *args)
+ end
+ end
+
+ class FocusEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Font < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " family=%s, pointSize=%d, weight=%d, italic=%s, bold=%s, underline=%s, strikeOut=%s>" %
+ [family.inspect, pointSize, weight, italic, bold, underline, strikeOut])
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, "\n family=%s,\n pointSize=%d,\n weight=%d,\n italic=%s,\n bold=%s,\n underline=%s,\n strikeOut=%s>" %
+ [family.inspect, pointSize, weight, italic, bold, underline, strikeOut])
+ end
+ end
+
+ class Ftp < Qt::Base
+ def abort(*args)
+ method_missing(:abort, *args)
+ end
+ end
+
+ class GLContext < Qt::Base
+ def format(*args)
+ method_missing(:format, *args)
+ end
+ end
+
+ class GLWidget < Qt::Base
+ def format(*args)
+ method_missing(:format, *args)
+ end
+ end
+
+ class Gb18030Codec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class Gb2312Codec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class GbkCodec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class GridLayout < Qt::Base
+ include Enumerable
+
+ def each
+ it = iterator()
+ while it.current
+ yield it.current
+ it += 1
+ end
+ end
+ end
+
+ class HBoxLayout < Qt::Base
+ include Enumerable
+
+ def each
+ it = iterator()
+ while it.current
+ yield it.current
+ it += 1
+ end
+ end
+ end
+
+ class HebrewCodec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class HideEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Http < Qt::Base
+ def abort(*args)
+ method_missing(:abort, *args)
+ end
+ end
+
+ class HttpRequestHeader < Qt::Base
+ def method(*args)
+ method_missing(:method, *args)
+ end
+ end
+
+ class IconDrag < Qt::Base
+ def format(*args)
+ method_missing(:format, *args)
+ end
+
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Image < Qt::Base
+ def load(*args)
+ method_missing(:load, *args)
+ end
+ end
+
+ class ImageDecoder < Qt::Base
+ def format(*args)
+ method_missing(:format, *args)
+ end
+ end
+
+ class ImageDrag < Qt::Base
+ def format(*args)
+ method_missing(:format, *args)
+ end
+ end
+
+ class ImageIO < Qt::Base
+ def format(*args)
+ method_missing(:format, *args)
+ end
+ end
+
+ class IMEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class JisCodec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class KeyEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class LCDNumber < Qt::Base
+ def display(item)
+ method_missing(:display, item)
+ end
+ end
+
+ class Layout < Qt::Base
+ def freeze(*args)
+ method_missing(:freeze, *args)
+ end
+ end
+
+ class LayoutIterator < Qt::Base
+ def +(a)
+ for i in 1..a
+ send("operator++".to_sym)
+ end
+ return self
+ end
+ end
+
+ class Library < Qt::Base
+ def load(*args)
+ method_missing(:load, *args)
+ end
+ end
+
+ class ListView < Qt::Base
+ include Enumerable
+
+ def each
+ it = Qt::ListViewItemIterator.new(self)
+ while it.current
+ yield it.current
+ it += 1
+ end
+ end
+
+ def sort(*args)
+ method_missing(:sort, *args)
+ end
+ end
+
+ class ListViewItem < Qt::Base
+ include Enumerable
+
+ def each
+ it = Qt::ListViewItemIterator.new(self)
+ while it.current
+ yield it.current
+ it += 1
+ end
+ end
+
+ def sort(*args)
+ method_missing(:sort, *args)
+ end
+
+ def inspect
+ str = super
+ str.sub!(/>$/, "")
+ for i in 0..(listView.columns - 1)
+ str << " text%d=%s," % [i, self.text(i)]
+ end
+ str.sub!(/,?$/, ">")
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ str.sub!(/>$/, "")
+ for i in 0..(listView.columns - 1)
+ str << " text%d=%s," % [i, self.text(i)]
+ end
+ str.sub!(/,?$/, ">")
+ pp.text str
+ end
+ end
+
+ class Locale < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ def system(*args)
+ method_missing(:system, *args)
+ end
+ end
+
+ class MenuItem < Qt::Base
+ def id(*args)
+ method_missing(:id, *args)
+ end
+ end
+
+ class MetaData < Qt::Base
+ def method(*args)
+ method_missing(:method, *args)
+ end
+
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class MetaEnum < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class MetaProperty < Qt::Base
+ def id(*args)
+ method_missing(:id, *args)
+ end
+
+ def name(*args)
+ method_missing(:name, *args)
+ end
+
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class MouseEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class MoveEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Object < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class PaintEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Picture < Qt::Base
+ def load(*args)
+ method_missing(:load, *args)
+ end
+ end
+
+ class Pixmap < Qt::Base
+ def load(*args)
+ method_missing(:load, *args)
+ end
+ end
+
+ class Point < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " x=%d, y=%d>" % [x, y])
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, "\n x=%d,\n y=%d>" % [x, y])
+ end
+ end
+
+ class PolygonScanner < Qt::Base
+ def scan(*args)
+ method_missing(:scan, *args)
+ end
+ end
+
+ class PopupMenu < Qt::Base
+ def exec(*args)
+ method_missing(:exec, *args)
+ end
+ end
+
+ class Printer < Qt::Base
+ def abort(*args)
+ method_missing(:abort, *args)
+ end
+ end
+
+ class MetaObject < Qt::Base
+ def inspect
+ str = super
+ str.sub!(/>$/, "")
+ str << " className=%s," % className
+ str << " propertyNames=Array (%d element(s))," % numProperties unless numProperties == 0
+ str << " signalNames=Array (%d element(s))," % numSignals unless numSignals == 0
+ str << " slotNames=Array (%d element(s))," % numSlots unless numSlots == 0
+ str << " superClass=%s," % superClass.inspect unless superClass == nil
+ str.chop!
+ str << ">"
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ str.sub!(/>$/, "")
+ str << "\n className=%s," % className
+ str << "\n propertyNames=Array (%d element(s))," % numProperties unless numProperties == 0
+ str << "\n signalNames=Array (%d element(s))," % numSignals unless numSignals == 0
+ str << "\n slotNames=Array (%d element(s))," % numSlots unless numSlots == 0
+ str << "\n superClass=%s," % superClass.inspect unless superClass == nil
+ str.chop!
+ str << ">"
+ pp.text str
+ end
+ end
+
+ class Rect < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " left=%d, right=%d, top=%d, bottom=%d>" % [left, right, top, bottom])
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, "\n left=%d,\n right=%d,\n top=%d,\n bottom=%d>" % [left, right, top, bottom])
+ end
+ end
+
+ class ResizeEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class ShowEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Size < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " width=%d, height=%d>" % [width, height])
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, "\n width=%d,\n height=%d>" % [width, height])
+ end
+ end
+
+ class SizePolicy < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " horData=%d, verData=%d>" % [horData, verData])
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, "\n horData=%d,\n verData=%d>" % [horData, verData])
+ end
+ end
+
+ class SjisCodec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class Socket < Qt::Base
+ def open(*args)
+ method_missing(:open, *args)
+ end
+ end
+
+ class SocketDevice < Qt::Base
+ def open(*args)
+ method_missing(:open, *args)
+ end
+
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class SocketNotifier < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class SqlCursor < Qt::Base
+ def exec(*args)
+ method_missing(:exec, *args)
+ end
+
+ def name(*args)
+ method_missing(:name, *args)
+ end
+
+ def select(*args)
+ method_missing(:select, *args)
+ end
+ end
+
+ class SqlDatabase < Qt::Base
+ def exec(*args)
+ method_missing(:exec, *args)
+ end
+ def open(*args)
+ method_missing(:open, *args)
+ end
+ end
+
+ class SqlDriver < Qt::Base
+ def open(*args)
+ method_missing(:open, *args)
+ end
+ end
+
+ class SqlError < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class SqlField < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class SqlFieldInfo < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class SqlIndex < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class SqlQuery < Qt::Base
+ def exec(*args)
+ method_missing(:exec, *args)
+ end
+ end
+
+ class SqlSelectCursor < Qt::Base
+ def exec(*args)
+ method_missing(:exec, *args)
+ end
+
+ def name(*args)
+ method_missing(:name, *args)
+ end
+
+ def select(*args)
+ method_missing(:select, *args)
+ end
+ end
+
+ class StoredDrag < Qt::Base
+ def format(*args)
+ method_missing(:format, *args)
+ end
+ end
+
+ class StyleSheetItem < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class TextDrag < Qt::Base
+ def format(*args)
+ method_missing(:format, *args)
+ end
+ end
+
+ class TabletEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Time < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " %s>" % toString)
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, " %s>" % toString)
+ end
+ end
+
+ class TimeEdit < Qt::Base
+ def display
+ method_missing(:display)
+ end
+ end
+
+ class TimerEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Translator < Qt::Base
+ def load(*args)
+ method_missing(:load, *args)
+ end
+ end
+
+ class TranslatorMessage < Qt::Base
+ def hash(*args)
+ method_missing(:hash, *args)
+ end
+ end
+
+ class TsciiCodec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class UrlInfo < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class Utf16Codec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class Utf8Codec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class Variant < Qt::Base
+ String = 3
+ Date = 26
+ Time = 27
+ DateTime = 28
+
+ def initialize(*args)
+ # In C++, the boolean constructor needs an ugly dummy int argument,
+ # so special case that here to avoid needing it in Ruby
+ if args[0] == true || args[0] == false
+ super(args[0], 0)
+ else
+ super
+ end
+ end
+
+ def to_a
+ return toStringList()
+ end
+
+ def to_f
+ return toDouble()
+ end
+
+ def to_i
+ return toInt()
+ end
+
+ def to_int
+ return toInt()
+ end
+
+ def to_ruby
+ case type()
+ when Qt::Variant::Bitmap
+ return toBitmap
+ when Qt::Variant::Bool
+ return toBool
+ when Qt::Variant::Brush
+ return toBrush
+ when Qt::Variant::ByteArray
+ return toByteArray
+ when Qt::Variant::Color
+ return toColor
+ when Qt::Variant::ColorGroup
+ return toColorGroup
+ when Qt::Variant::CString
+ return toCString
+ when Qt::Variant::Cursor
+ return toCursor
+ when Qt::Variant::Date
+ return toDate
+ when Qt::Variant::DateTime
+ return toDateTime
+ when Qt::Variant::Double
+ return toDouble
+ when Qt::Variant::Font
+ return toFont
+ when Qt::Variant::IconSet
+ return toIconSet
+ when Qt::Variant::Image
+ return toImage
+ when Qt::Variant::Int
+ return toInt
+ when Qt::Variant::KeySequence
+ return toKeySequence
+ when Qt::Variant::List
+ return toList
+ when Qt::Variant::LongLong
+ return toLongLong
+ when Qt::Variant::Map
+ return toMap
+ when Qt::Variant::Palette
+ return toPalette
+ when Qt::Variant::Pen
+ return toPen
+ when Qt::Variant::Pixmap
+ return toPixmap
+ when Qt::Variant::Point
+ return toPoint
+ when Qt::Variant::PointArray
+ return toPointArray
+ when Qt::Variant::Rect
+ return toRect
+ when Qt::Variant::Region
+ return toRegion
+ when Qt::Variant::Size
+ return toSize
+ when Qt::Variant::SizePolicy
+ return toSizePolicy
+ when Qt::Variant::String
+ return toString
+ when Qt::Variant::StringList
+ return toStringList
+ when Qt::Variant::Time
+ return toTime
+ when Qt::Variant::UInt
+ return toUint
+ when Qt::Variant::ULongLong
+ return toULongLong
+ end
+ end
+
+ def inspect
+ str = super
+ str.sub(/>$/, " typeName=%s>" % typeName)
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, " typeName=%s>" % typeName)
+ end
+
+ def load(*args)
+ method_missing(:load, *args)
+ end
+
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class VBoxLayout < Qt::Base
+ include Enumerable
+
+ def each
+ it = iterator()
+ while it.current
+ yield it.current
+ it += 1
+ end
+ end
+ end
+
+ class WhatsThis < Qt::Base
+ def WhatsThis.display(*k)
+ method_missing(:display, *k)
+ end
+ end
+
+ class WheelEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Widget < Qt::Base
+ def raise(*args)
+ method_missing(:raise, *args)
+ end
+ end
+
+ class WidgetStack < Qt::Base
+ def id(*args)
+ method_missing(:id, *args)
+ end
+ end
+
+ class XmlAttributes < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ # Provides a mutable numeric class for passing to methods with
+ # C++ 'int*' or 'int&' arg types
+ class Integer
+ attr_accessor :value
+ def initialize(n=0) @value = n end
+
+ def +(n)
+ return Integer.new(@value + n.to_i)
+ end
+ def -(n)
+ return Integer.new(@value - n.to_i)
+ end
+ def *(n)
+ return Integer.new(@value * n.to_i)
+ end
+ def /(n)
+ return Integer.new(@value / n.to_i)
+ end
+ def %(n)
+ return Integer.new(@value % n.to_i)
+ end
+ def **(n)
+ return Integer.new(@value ** n.to_i)
+ end
+
+ def |(n)
+ return Integer.new(@value | n.to_i)
+ end
+ def &(n)
+ return Integer.new(@value & n.to_i)
+ end
+ def ^(n)
+ return Integer.new(@value ^ n.to_i)
+ end
+ def <<(n)
+ return Integer.new(@value << n.to_i)
+ end
+ def >>(n)
+ return Integer.new(@value >> n.to_i)
+ end
+
+ def >(n)
+ return @value > n.to_i
+ end
+ def >=(n)
+ return @value >= n.to_i
+ end
+ def <(n)
+ return @value < n.to_i
+ end
+ def <=(n)
+ return @value <= n.to_i
+ end
+
+ def <=>(n)
+ if @value < n
+ return -1
+ elsif @value > n
+ return 1
+ else
+ return 0
+ end
+ end
+
+ def to_f() return @value.to_f end
+ def to_i() return @value.to_i end
+ def to_s() return @value.to_s end
+
+ def coerce(n)
+ [n, @value]
+ end
+ end
+
+ # If a C++ enum was converted to an ordinary ruby Integer, the
+ # name of the type is lost. The enum type name is needed for overloaded
+ # method resolution when two methods differ only by an enum type.
+ class Enum < Qt::Integer
+ attr_accessor :type
+ def initialize(n, type)
+ super(n)
+ @value = n
+ @type = type
+ end
+
+ def |(n)
+ return Enum.new(@value | n.to_i, @type)
+ end
+ def &(n)
+ return Enum.new(@value & n.to_i, @type)
+ end
+ def ^(n)
+ return Enum.new(@value ^ n.to_i, @type)
+ end
+ def <(n)
+ return @value < n.to_i
+ end
+ def <=(n)
+ return @value <= n.to_i
+ end
+ def >(n)
+ return @value > n.to_i
+ end
+ def >=(n)
+ return @value >= n.to_i
+ end
+ def <<(n)
+ return Enum.new(@value << n.to_i, @type)
+ end
+ def >>(n)
+ return Enum.new(@value >> n.to_i, @type)
+ end
+
+ def ==(n) return @value == n.to_i end
+ def to_i() return @value end
+
+ def inspect
+ to_s
+ end
+
+ def pretty_print(pp)
+ pp.text "#<%s:0x%8.8x @type=%s, @value=%d>" % [self.class.name, object_id, type, value]
+ end
+ end
+
+ # Provides a mutable boolean class for passing to methods with
+ # C++ 'bool*' or 'bool&' arg types
+ class Boolean
+ attr_accessor :value
+ def initialize(b=false) @value = b end
+ def nil?
+ return !@value
+ end
+ end
+
+ class SignalBlockInvocation < Qt::Object
+ def initialize(parent, block, args)
+ super(parent)
+ self.class.slots "invoke(#{args})"
+ @block = block
+ end
+
+ def invoke(*args)
+ @block.call(*args)
+ end
+ end
+
+ class BlockInvocation < Qt::Object
+ def initialize(target, block, args)
+ super(target)
+ self.class.slots "invoke(#{args})"
+ @target = target
+ @block = block
+ end
+
+ def invoke(*args)
+ @target.instance_exec(*args, &@block)
+ end
+ end
+
+ module Internal
+ @@classes = {}
+ @@cpp_names = {}
+ @@idclass = []
+
+ def Internal.normalize_classname(classname)
+ if classname =~ /^Qext/
+ now = classname.sub(/^Qext(?=[A-Z])/,'Qext::')
+ elsif classname =~ /^Q/
+ now = classname.sub(/^Q(?=[A-Z])/,'Qt::')
+ elsif classname =~ /^(KConfigSkeleton|KWin)::/
+ now = classname.sub(/^K?(?=[A-Z])/,'KDE::')
+ elsif classname !~ /::/
+ now = classname.sub(/^K?(?=[A-Z])/,'KDE::')
+ else
+ now = classname
+ end
+ # puts "normalize_classname = was::#{classname}, now::#{now}"
+ now
+ end
+
+ def Internal.init_class(c)
+ classname = Qt::Internal::normalize_classname(c)
+ classId = Qt::Internal.idClass(c)
+ insert_pclassid(classname, classId)
+ @@idclass[classId] = classname
+ @@cpp_names[classname] = c
+ klass = isQObject(classId) ? create_qobject_class(classname) \
+ : create_qt_class(classname)
+ @@classes[classname] = klass unless klass.nil?
+ end
+
+ def Internal.debug_level
+ Qt.debug_level
+ end
+
+ def Internal.checkarg(argtype, typename)
+ puts " #{typename} (#{argtype})" if debug_level >= DebugLevel::High
+ if argtype == 'i'
+ if typename =~ /^int&?$|^signed int&?$|^signed$|^Q_INT32&?$/
+ return 1
+ elsif typename =~ /^(?:short|ushort|unsigned short int|uchar|uint|long|ulong|unsigned long int|unsigned|float|double|Q_UINT32|Q_UINT16|Q_INT16)$/
+ return 0
+ else
+ t = typename.sub(/^const\s+/, '')
+ t.sub!(/[&*]$/, '')
+ if isEnum(t)
+ return 0
+ end
+ end
+ elsif argtype == 'n'
+ if typename =~ /^double$/
+ return 2
+ elsif typename =~ /^float$/
+ return 1
+ elsif typename =~ /^int&?$/
+ return 0
+ elsif typename =~ /^(?:short|ushort|uint|long|ulong|signed|unsigned|float|double)$/
+ return 0
+ else
+ t = typename.sub(/^const\s+/, '')
+ t.sub!(/[&*]$/, '')
+ if isEnum(t)
+ return 0
+ end
+ end
+ elsif argtype == 'B'
+ if typename =~ /^(?:bool)[*&]?$/
+ return 0
+ end
+ elsif argtype == 's'
+ if typename =~ /^(const )?((QChar)[*&]?)$/
+ return 1
+ elsif typename =~ /^(?:u?char\*|const u?char\*|(?:const )?(Q(C?)String)[*&]?)$/
+ qstring = !$1.nil?
+ c = ("C" == $2)
+ return c ? 2 : (qstring ? 3 : 0)
+ end
+ elsif argtype == 'a'
+ # FIXME: shouldn't be hardcoded. Installed handlers should tell what ruby type they expect.
+ if typename =~ /^(?:
+ const\ QCOORD\*|
+ (?:const\ )?
+ (?:
+ QStringList[\*&]?|
+ QValueList<int>[\*&]?|
+ QRgb\*|
+ char\*\*
+ )
+ )$/x
+ return 0
+ end
+ elsif argtype == 'u'
+ # Give nil matched against string types a higher score than anything else
+ if typename =~ /^(?:u?char\*|const u?char\*|(?:const )?((Q(C?)String))[*&]?)$/
+ return 1
+ # Numerics will give a runtime conversion error, so they fail the match
+ elsif typename =~ /^(?:short|ushort|uint|long|ulong|signed|unsigned|int)$/
+ return -99
+ else
+ return 0
+ end
+ elsif argtype == 'U'
+ if typename =~ /QStringList/
+ return 1
+ else
+ return 0
+ end
+ else
+ t = typename.sub(/^const\s+/, '')
+ t.sub!(/[&*]$/, '')
+ if argtype == t
+ return 1
+ elsif classIsa(argtype, t)
+ return 0
+ elsif isEnum(argtype) and
+ (t =~ /int|Q_INT32|uint|Q_UINT32|long|ulong/ or isEnum(t))
+ return 0
+ end
+ end
+ return -99
+ end
+
+ def Internal.find_class(classname)
+ # puts @@classes.keys.sort.join "\n"
+ @@classes[classname]
+ end
+
+ # Runs the initializer as far as allocating the Qt C++ instance.
+ # Then use a throw to jump back to here with the C++ instance
+ # wrapped in a new ruby variable of type T_DATA
+ def Internal.try_initialize(instance, *args)
+ initializer = instance.method(:initialize)
+ catch "newqt" do
+ initializer.call(*args)
+ end
+ end
+
+ # If a block was passed to the constructor, then
+ # run that now. Either run the context of the new instance
+ # if no args were passed to the block. Or otherwise,
+ # run the block in the context of the arg.
+ def Internal.run_initializer_block(instance, block)
+ if block.arity == -1
+ instance.instance_eval(&block)
+ elsif block.arity == 1
+ block.call(instance)
+ else
+ raise ArgumentError, "Wrong number of arguments to block(#{block.arity} for 1)"
+ end
+ end
+
+ def Internal.do_method_missing(package, method, klass, this, *args)
+ if klass.class == Module
+ classname = klass.name
+ else
+ classname = @@cpp_names[klass.name]
+ if classname.nil?
+ if klass != Object and klass != Qt
+ return do_method_missing(package, method, klass.superclass, this, *args)
+ else
+ return nil
+ end
+ end
+ end
+
+ if method == "new"
+ method = classname.dup
+ method.gsub!(/^(KParts|KIO|KNS|DOM|Kontact|Kate|KTextEditor|KConfigSkeleton::ItemEnum|KConfigSkeleton|KWin)::/,"")
+ end
+ method = "operator" + method.sub("@","") if method !~ /[a-zA-Z]+/
+ # Change foobar= to setFoobar()
+ method = 'set' + method[0,1].upcase + method[1,method.length].sub("=", "") if method =~ /.*[^-+%\/|=]=$/
+
+ methods = []
+ methods << method.dup
+ args.each do |arg|
+ if arg.nil?
+ # For each nil arg encountered, triple the number of munged method
+ # templates, in order to cover all possible types that can match nil
+ temp = []
+ methods.collect! do |meth|
+ temp << meth + '?'
+ temp << meth + '#'
+ meth << '$'
+ end
+ methods.concat(temp)
+ elsif isObject(arg)
+ methods.collect! { |meth| meth << '#' }
+ elsif arg.kind_of? Array or arg.kind_of? Hash
+ methods.collect! { |meth| meth << '?' }
+ else
+ methods.collect! { |meth| meth << '$' }
+ end
+ end
+
+ methodIds = []
+ methods.collect { |meth| methodIds.concat( findMethod(classname, meth) ) }
+
+ if method =~ /_/ && methodIds.length == 0
+ # If the method name contains underscores, convert to camel case
+ # form and try again
+ method.gsub!(/(.)_(.)/) {$1 + $2.upcase}
+ return do_method_missing(package, method, klass, this, *args)
+ end
+
+ if debug_level >= DebugLevel::High
+ puts "classname == #{classname}"
+ puts ":: method == #{method}"
+ puts "-> methodIds == #{methodIds.inspect}"
+ puts "candidate list:"
+ prototypes = dumpCandidates(methodIds).split("\n")
+ line_len = (prototypes.collect { |p| p.length }).max
+ prototypes.zip(methodIds) {
+ |prototype,id| puts "#{prototype.ljust line_len} (#{id})"
+ }
+ end
+
+ chosen = nil
+ if methodIds.length > 0
+ best_match = -1
+ methodIds.each do
+ |id|
+ puts "matching => #{id}" if debug_level >= DebugLevel::High
+ current_match = 0
+ (0...args.length).each do
+ |i|
+ current_match += checkarg( getVALUEtype(args[i]), getTypeNameOfArg(id, i) )
+ end
+
+ # Note that if current_match > best_match, then chosen must be nil
+ if current_match > best_match
+ best_match = current_match
+ chosen = id
+ # Multiple matches are an error; the equality test below _cannot_ be commented out.
+ # If ambiguous matches occur the problem must be fixed be adjusting the relative
+ # ranking of the arg types involved in checkarg().
+ elsif current_match == best_match
+ chosen = nil
+ end
+ puts "match => #{id} score: #{current_match}" if debug_level >= DebugLevel::High
+ end
+
+ puts "Resolved to id: #{chosen}" if !chosen.nil? && debug_level >= DebugLevel::High
+ end
+
+ if debug_level >= DebugLevel::Minimal && chosen.nil? && method !~ /^operator/
+ id = find_pclassid(normalize_classname(klass.name))
+ hash = findAllMethods(id)
+ constructor_names = nil
+ if method == classname
+ puts "No matching constructor found, possibles:\n"
+ constructor_names = hash.keys.grep(/^#{classname}/)
+ else
+ puts "Possible prototypes:"
+ constructor_names = hash.keys
+ end
+ method_ids = hash.values_at(*constructor_names).flatten
+ puts dumpCandidates(method_ids)
+ end
+
+ puts "setCurrentMethod(#{chosen})" if debug_level >= DebugLevel::High
+ setCurrentMethod(chosen) if chosen
+ return nil
+ end
+
+ def Internal.init_all_classes()
+ Qt::Internal::getClassList().each do |c|
+ if c == "Qt"
+ # Don't change Qt to Qt::t, just leave as is
+ @@cpp_names["Qt"] = c
+ elsif c != "QInternal"
+ Qt::Internal::init_class(c)
+ end
+ end
+
+ @@classes['Qt::Integer'] = Qt::Integer
+ @@classes['Qt::Boolean'] = Qt::Boolean
+ @@classes['Qt::Enum'] = Qt::Enum
+ end
+
+ def Internal.get_qinteger(num)
+ return num.value
+ end
+
+ def Internal.set_qinteger(num, val)
+ return num.value = val
+ end
+
+ def Internal.create_qenum(num, type)
+ return Qt::Enum.new(num, type)
+ end
+
+ def Internal.get_qenum_type(e)
+ return e.type
+ end
+
+ def Internal.get_qboolean(b)
+ return b.value
+ end
+
+ def Internal.set_qboolean(b, val)
+ return b.value = val
+ end
+
+ def Internal.getAllParents(class_id, res)
+ getIsa(class_id).each do |s|
+ c = idClass(s)
+ res << c
+ getAllParents(c, res)
+ end
+ end
+
+ def Internal.getSignalNames(klass)
+ meta = Meta[klass.name] || MetaInfo.new(klass)
+ signal_names = []
+ meta.get_signals.each do |signal|
+ signal_names.push signal.name
+ end
+ return signal_names
+ end
+
+ def Internal.signalInfo(qobject, signal_name)
+ signals = Meta[qobject.class.name].get_signals
+ signals.each_with_index do |signal, i|
+ if signal.name == signal_name
+ return [signal.full_name, i]
+ end
+ end
+ end
+
+ def Internal.signalAt(qobject, index)
+ klass = qobject.class
+ begin
+ meta = Meta[klass.name]
+ klass = klass.superclass
+ end while meta.nil? and klass != Object
+ meta.get_signals[index].full_name
+ end
+
+ def Internal.slotAt(qobject, index)
+ klass = qobject.class
+ begin
+ meta = Meta[klass.name]
+ klass = klass.superclass
+ end while meta.nil? and klass != Object
+ meta.get_slots[index].full_name
+ end
+
+ def Internal.getMocArguments(member)
+ argStr = member.sub(/.*\(/, '').sub(/\)$/, '')
+ args = argStr.scan(/([^,]*<[^>]+>)|([^,]+)/)
+ mocargs = allocateMocArguments(args.length)
+ args.each_with_index do |arg, i|
+ arg = arg.to_s
+ a = arg.sub(/^const\s+/, '')
+ a = (a =~ /^(bool|int|double|char\*|QString)&?$/) ? $1 : 'ptr'
+ valid = setMocType(mocargs, i, arg, a)
+ end
+ result = []
+ result << args.length << mocargs
+ result
+ end
+
+ def Internal.makeMetaData(data)
+ return nil if data.nil?
+ tbl = []
+ data.each do |entry|
+ name = entry.name
+ argStr = entry.arg_types
+ params = []
+ args = argStr.scan(/[^,]+/)
+ args.each do |arg|
+ name = '' # umm.. is this the aim?, well. it works. soo... ;-)
+ param = make_QUParameter(name, arg, 0, 1)
+ params << param
+ end
+ method = make_QUMethod(name, params)
+ tbl << make_QMetaData(entry.full_name, method)
+ end
+ make_QMetaData_tbl(tbl)
+ end
+
+ def Internal.getMetaObject(qobject)
+ klass = qobject.class
+ begin
+ meta = Meta[klass.name]
+ klass = klass.superclass
+ end while meta.nil? and klass != Object
+
+ return nil if meta.nil?
+
+ if meta.metaobject.nil? or meta.changed
+ slots = meta.get_slots
+ slotTable = makeMetaData(slots)
+ signals = meta.get_signals
+ signalTable = makeMetaData(signals)
+ meta.metaobject = make_metaObject(qobject.class.name,
+ qobject.staticMetaObject(),
+ slotTable,
+ slots.length,
+ signalTable,
+ signals.length)
+ addSignalMethods(qobject.class, getSignalNames(qobject.class))
+ meta.changed = false
+ end
+
+ meta.metaobject
+ end
+
+ def Internal.connect(src, signal, target, block)
+ signature = (signal =~ /\((.*)\)/) ? $1 : ""
+ return Qt::Object.connect( src,
+ signal,
+ Qt::BlockInvocation.new(target, block, signature),
+ SLOT("invoke(#{signature})") )
+ end
+
+ def Internal.signal_connect(src, signal, block)
+ signature = (signal =~ /\((.*)\)/) ? $1 : ""
+ return Qt::Object.connect( src,
+ signal,
+ Qt::SignalBlockInvocation.new(src, block, signature),
+ SLOT("invoke(#{signature})") )
+ end
+ end # Qt::Internal
+
+ Meta = {}
+
+ # An entry for each signal or slot
+ # Example
+ # foobar(QString,bool)
+ # :name is 'foobar'
+ # :full_name is 'foobar(QString,bool)'
+ # :arg_types is 'QString,bool'
+ QObjectMember = Struct.new :name, :full_name, :arg_types
+
+ class MetaInfo
+ attr_accessor :signals, :slots, :metaobject, :mocargs, :changed
+ def initialize(klass)
+ Meta[klass.name] = self
+ @klass = klass
+ @metaobject = nil
+ @signals = []
+ @slots = []
+ @changed = false
+ Internal.addMetaObjectMethods(klass)
+ end
+
+ def add_signals(signal_list)
+ signal_list.each do |signal|
+ if signal.kind_of? Symbol
+ signal = signal.to_s + "()"
+ end
+ signal = Qt::Object.normalizeSignalSlot(signal)
+ if signal =~ /([^\s]*)\((.*)\)/
+ @signals.push QObjectMember.new($1, signal, $2)
+ else
+ qWarning( "#{@klass.name}: Invalid signal format: '#{signal}'" )
+ end
+ end
+ end
+
+ # Return a list of signals, including inherited ones
+ def get_signals
+ all_signals = []
+ current = @klass
+ while current != Qt::Base
+ meta = Meta[current.name]
+ if !meta.nil?
+ all_signals.concat meta.signals
+ end
+ current = current.superclass
+ end
+ return all_signals
+ end
+
+ def add_slots(slot_list)
+ slot_list.each do |slot|
+ if slot.kind_of? Symbol
+ slot = slot.to_s + "()"
+ end
+ slot = Qt::Object.normalizeSignalSlot(slot)
+ if slot =~ /([^\s]*)\((.*)\)/
+ @slots.push QObjectMember.new($1, slot, $2)
+ else
+ qWarning( "#{@klass.name}: Invalid slot format: '#{slot}'" )
+ end
+ end
+ end
+
+ # Return a list of slots, including inherited ones
+ def get_slots
+ all_slots = []
+ current = @klass
+ while current != Qt::Base
+ meta = Meta[current.name]
+ if !meta.nil?
+ all_slots.concat meta.slots
+ end
+ current = current.superclass
+ end
+ return all_slots
+ end
+ end # Qt::MetaInfo
+
+ IO_Direct = 0x0100
+ IO_Sequential = 0x0200
+ IO_Combined = 0x0300
+ IO_TypeMask = 0x0f00
+ IO_Raw = 0x0040
+ IO_Async = 0x0080
+ IO_ReadOnly = 0x0001
+ IO_WriteOnly = 0x0002
+ IO_ReadWrite = 0x0003
+ IO_Append = 0x0004
+ IO_Truncate = 0x0008
+ IO_Translate = 0x0010
+ IO_ModeMask = 0x00ff
+ IO_Open = 0x1000
+ IO_StateMask = 0xf000
+ IO_Ok = 0
+ IO_ReadError = 1
+ IO_WriteError = 2
+ IO_FatalError = 3
+ IO_ResourceError = 4
+ IO_OpenError = 5
+ IO_ConnectError = 5
+ IO_AbortError = 6
+ IO_TimeOutError = 7
+ IO_UnspecifiedError= 8
+
+end # Qt
+
+class Object
+ def SIGNAL(signal)
+ if signal.kind_of? Symbol
+ return "2" + signal.to_s + "()"
+ else
+ return "2" + signal
+ end
+ end
+
+ def SLOT(slot)
+ if slot.kind_of? Symbol
+ return "1" + slot.to_s + "()"
+ else
+ return "1" + slot
+ end
+ end
+
+ def emit(signal)
+ return signal
+ end
+
+ # See the discussion here: http://eigenclass.org/hiki.rb?instance_exec
+ # about implementations of the ruby 1.9 method instance_exec(). This
+ # version is the one from Rails. It isn't thread safe, but that doesn't
+ # matter for the intended use in invoking blocks as Qt slots.
+ def instance_exec(*arguments, &block)
+ block.bind(self)[*arguments]
+ end
+end
+
+class Proc
+ # Part of the Rails Object#instance_exec implementation
+ def bind(object)
+ block, time = self, Time.now
+ (class << object; self end).class_eval do
+ method_name = "__bind_#{time.to_i}_#{time.usec}"
+ define_method(method_name, &block)
+ method = instance_method(method_name)
+ remove_method(method_name)
+ method
+ end.bind(object)
+ end
+end
+
+class Module
+ alias_method :_constants, :constants
+ alias_method :_instance_methods, :instance_methods
+ alias_method :_protected_instance_methods, :protected_instance_methods
+ alias_method :_public_instance_methods, :public_instance_methods
+
+ private :_constants, :_instance_methods
+ private :_protected_instance_methods, :_public_instance_methods
+
+ def constants
+ qt_methods(_constants, 0x10, true)
+ end
+
+ def instance_methods(inc_super=true)
+ qt_methods(_instance_methods(inc_super), 0x0, inc_super)
+ end
+
+ def protected_instance_methods(inc_super=true)
+ qt_methods(_protected_instance_methods(inc_super), 0x80, inc_super)
+ end
+
+ def public_instance_methods(inc_super=true)
+ qt_methods(_public_instance_methods(inc_super), 0x0, inc_super)
+ end
+
+ private
+ def qt_methods(meths, flags, inc_super=true)
+ if !self.kind_of? Class
+ return meths
+ end
+
+ klass = self
+ classid = 0
+ loop do
+ classid = Qt::Internal::find_pclassid(klass.name)
+ break if classid > 0
+
+ klass = klass.superclass
+ if klass.nil?
+ return meths
+ end
+ end
+
+ # These methods are all defined in Qt::Base, even if they aren't supported by a particular
+ # subclass, so remove them to avoid confusion
+ meths -= ["%", "&", "*", "**", "+", "-", "-@", "/", "<", "<<", "<=", ">", ">=", ">>", "|", "~", "^"]
+ ids = []
+ if inc_super
+ Qt::Internal::getAllParents(classid, ids)
+ end
+ ids << classid
+ ids.each { |c| Qt::Internal::findAllMethodNames(meths, c, flags) }
+ return meths.uniq
+ end
+end
diff --git a/qtruby/rubylib/qtruby/marshall.h b/qtruby/rubylib/qtruby/marshall.h
new file mode 100644
index 00000000..cf20b86d
--- /dev/null
+++ b/qtruby/rubylib/qtruby/marshall.h
@@ -0,0 +1,46 @@
+#ifndef MARSHALL_H
+#define MARSHALL_H
+
+#include <smoke.h>
+#include <ruby.h>
+
+class SmokeType;
+
+class Marshall {
+public:
+ /**
+ * FromVALUE is used for virtual function return values and regular
+ * method arguments.
+ *
+ * ToVALUE is used for method return-values and virtual function
+ * arguments.
+ */
+ typedef void (*HandlerFn)(Marshall *);
+ enum Action { FromVALUE, ToVALUE };
+ virtual SmokeType type() = 0;
+ virtual Action action() = 0;
+ virtual Smoke::StackItem &item() = 0;
+ virtual VALUE * var() = 0;
+ virtual void unsupported() = 0;
+ virtual Smoke *smoke() = 0;
+ /**
+ * For return-values, next() does nothing.
+ * For FromRV, next() calls the method and returns.
+ * For ToRV, next() calls the virtual function and returns.
+ *
+ * Required to reset Marshall object to the state it was
+ * before being called when it returns.
+ */
+ virtual void next() = 0;
+ /**
+ * For FromSV, cleanup() returns false when the handler should free
+ * any allocated memory after next().
+ *
+ * For ToSV, cleanup() returns true when the handler should delete
+ * the pointer passed to it.
+ */
+ virtual bool cleanup() = 0;
+
+ virtual ~Marshall() {}
+};
+#endif
diff --git a/qtruby/rubylib/qtruby/qtruby.h b/qtruby/rubylib/qtruby/qtruby.h
new file mode 100644
index 00000000..66f9fedc
--- /dev/null
+++ b/qtruby/rubylib/qtruby/qtruby.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+ qtruby.h - description
+ -------------------
+ begin : Fri Jul 4 2003
+ copyright : (C) 2003 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 QTRUBY_H
+#define QTRUBY_H
+
+#include "marshall.h"
+
+struct smokeruby_object {
+ bool allocated;
+ Smoke *smoke;
+ int classId;
+ void *ptr;
+};
+
+struct TypeHandler {
+ const char *name;
+ Marshall::HandlerFn fn;
+};
+
+extern int do_debug; // evil
+extern VALUE rv_qapp;
+extern int object_count;
+
+// keep this enum in sync with lib/Qt/debug.pm
+
+enum QtDebugChannel {
+ qtdb_none = 0x00,
+ qtdb_ambiguous = 0x01,
+ qtdb_method_missing = 0x02,
+ qtdb_calls = 0x04,
+ qtdb_gc = 0x08,
+ qtdb_virtual = 0x10,
+ qtdb_verbose = 0x20
+};
+
+void unmapPointer(smokeruby_object *, Smoke::Index, void*);
+smokeruby_object *value_obj_info(VALUE value);
+VALUE getPointerObject(void *ptr);
+
+#endif
diff --git a/qtruby/rubylib/qtruby/smokeruby.h b/qtruby/rubylib/qtruby/smokeruby.h
new file mode 100644
index 00000000..8f152c10
--- /dev/null
+++ b/qtruby/rubylib/qtruby/smokeruby.h
@@ -0,0 +1,321 @@
+#ifndef SMOKERUBY_H
+#define SMOKERUBY_H
+
+#include "smoke.h"
+
+#undef DEBUG
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#ifndef __USE_POSIX
+#define __USE_POSIX
+#endif
+#ifndef __USE_XOPEN
+#define __USE_XOPEN
+#endif
+#include "ruby.h"
+
+#include <qcstring.h>
+
+#include "qtruby.h"
+#include "marshall.h"
+
+
+class SmokeRuby;
+
+class SmokeType {
+ Smoke::Type *_t; // derived from _smoke and _id, but cached
+
+ Smoke *_smoke;
+ Smoke::Index _id;
+public:
+ SmokeType() : _t(0), _smoke(0), _id(0) {}
+ SmokeType(Smoke *s, Smoke::Index i) : _smoke(s), _id(i) {
+ if(_id < 0 || _id > _smoke->numTypes) _id = 0;
+ _t = _smoke->types + _id;
+ }
+ // default copy constructors are fine, this is a constant structure
+
+ // mutators
+ void set(Smoke *s, Smoke::Index i) {
+ _smoke = s;
+ _id = i;
+ _t = _smoke->types + _id;
+ }
+
+ // accessors
+ Smoke *smoke() const { return _smoke; }
+ Smoke::Index typeId() const { return _id; }
+ const Smoke::Type &type() const { return *_t; }
+ unsigned short flags() const { return _t->flags; }
+ unsigned short elem() const { return _t->flags & Smoke::tf_elem; }
+ const char *name() const { return _t->name; }
+ Smoke::Index classId() const { return _t->classId; }
+
+ // tests
+ bool isStack() const { return ((flags() & Smoke::tf_ref) == Smoke::tf_stack); }
+ bool isPtr() const { return ((flags() & Smoke::tf_ref) == Smoke::tf_ptr); }
+ bool isRef() const { return ((flags() & Smoke::tf_ref) == Smoke::tf_ref); }
+ bool isConst() const { return (flags() & Smoke::tf_const); }
+ bool isClass() const {
+ if(elem() == Smoke::t_class)
+ return classId() ? true : false;
+ return false;
+ }
+
+ bool operator ==(const SmokeType &b) const {
+ const SmokeType &a = *this;
+ if(a.name() == b.name()) return true;
+ if(a.name() && b.name() && qstrcmp(a.name(), b.name()) == 0)
+ return true;
+ return false;
+ }
+ bool operator !=(const SmokeType &b) const {
+ const SmokeType &a = *this;
+ return !(a == b);
+ }
+
+};
+
+class SmokeClass {
+ Smoke::Class *_c;
+ Smoke *_smoke;
+ Smoke::Index _id;
+public:
+ SmokeClass(const SmokeType &t) {
+ _smoke = t.smoke();
+ _id = t.classId();
+ _c = _smoke->classes + _id;
+ }
+ SmokeClass(Smoke *smoke, Smoke::Index id) : _smoke(smoke), _id(id) {
+ _c = _smoke->classes + _id;
+ }
+
+ Smoke *smoke() const { return _smoke; }
+ const Smoke::Class &c() const { return *_c; }
+ Smoke::Index classId() const { return _id; }
+ const char *className() const { return _c->className; }
+ Smoke::ClassFn classFn() const { return _c->classFn; }
+ Smoke::EnumFn enumFn() const { return _c->enumFn; }
+ bool operator ==(const SmokeClass &b) const {
+ const SmokeClass &a = *this;
+ if(a.className() == b.className()) return true;
+ if(a.className() && b.className() && qstrcmp(a.className(), b.className()) == 0)
+ return true;
+ return false;
+ }
+ bool operator !=(const SmokeClass &b) const {
+ const SmokeClass &a = *this;
+ return !(a == b);
+ }
+ bool isa(const SmokeClass &sc) const {
+ // This is a sick function, if I do say so myself
+ if(*this == sc) return true;
+ Smoke::Index *parents = _smoke->inheritanceList + _c->parents;
+ for(int i = 0; parents[i]; i++) {
+ if(SmokeClass(_smoke, parents[i]).isa(sc)) return true;
+ }
+ return false;
+ }
+
+ unsigned short flags() const { return _c->flags; }
+ bool hasConstructor() const { return flags() & Smoke::cf_constructor; }
+ bool hasCopy() const { return flags() & Smoke::cf_deepcopy; }
+ bool hasVirtual() const { return flags() & Smoke::cf_virtual; }
+ bool hasFire() const { return !(flags() & Smoke::cf_undefined); }
+};
+
+class SmokeMethod {
+ Smoke::Method *_m;
+ Smoke *_smoke;
+ Smoke::Index _id;
+public:
+ SmokeMethod(Smoke *smoke, Smoke::Index id) : _smoke(smoke), _id(id) {
+ _m = _smoke->methods + _id;
+ }
+
+ Smoke *smoke() const { return _smoke; }
+ const Smoke::Method &m() const { return *_m; }
+ SmokeClass c() const { return SmokeClass(_smoke, _m->classId); }
+ const char *name() const { return _smoke->methodNames[_m->name]; }
+ int numArgs() const { return _m->numArgs; }
+ unsigned short flags() const { return _m->flags; }
+ SmokeType arg(int i) const {
+ if(i >= numArgs()) return SmokeType();
+ return SmokeType(_smoke, _smoke->argumentList[_m->args + i]);
+ }
+ SmokeType ret() const { return SmokeType(_smoke, _m->ret); }
+ Smoke::Index methodId() const { return _id; }
+ Smoke::Index method() const { return _m->method; }
+
+ bool isStatic() const { return flags() & Smoke::mf_static; }
+ bool isConst() const { return flags() & Smoke::mf_const; }
+
+ void call(Smoke::Stack args, void *ptr = 0) const {
+ Smoke::ClassFn fn = c().classFn();
+ (*fn)(method(), ptr, args);
+ }
+};
+
+class Smoke_MAGIC { // to be rewritten
+ SmokeClass _c;
+ void *_ptr;
+ bool _isAllocated;
+public:
+ Smoke_MAGIC(void *p, const SmokeClass &c) :
+ _c(c), _ptr(p), _isAllocated(false) {}
+ const SmokeClass &c() const { return _c; }
+ void *ptr() const { return _ptr; }
+ bool isAllocated() const { return _isAllocated; }
+ void setAllocated(bool isAllocated) { _isAllocated = isAllocated; }
+};
+
+
+/**
+ * SmokeObject is a thin wrapper around VALUE objects. Each SmokeObject instance
+ * increments the refcount of its VALUE for the duration of its existance.
+ *
+ * SmokeObject instances are only returned from SmokeRuby, since the method
+ * of binding data to the scalar must be consistent across all modules.
+ */
+class SmokeObject {
+ VALUE rv;
+ Smoke_MAGIC *m;
+
+public:
+ SmokeObject(VALUE obj, Smoke_MAGIC *mag) : rv(obj), m(mag) {
+ rb_gc_register_address(&rv);
+ }
+
+ ~SmokeObject() {
+ rb_gc_unregister_address(&rv);
+ }
+
+ SmokeObject(const SmokeObject &other) {
+ rv = other.rv;
+ m = other.m;
+ rb_gc_register_address(&rv);
+ }
+
+ SmokeObject &operator =(const SmokeObject &other) {
+ rv = other.rv;
+ m = other.m;
+ rb_gc_register_address(&rv);
+ return *this;
+ }
+
+ const SmokeClass &c() { return m->c(); }
+ Smoke *smoke() { return c().smoke(); }
+ VALUE * var() { return &rv; }
+ void *ptr() { return m->ptr(); }
+ Smoke::Index classId() { return c().classId(); }
+ void *cast(const SmokeClass &toc) {
+ return smoke()->cast(
+ ptr(),
+ classId(),
+ smoke()->idClass(toc.className())
+ );
+ }
+ const char *className() { return c().className(); }
+
+ bool isValid() const { return !NIL_P(rv); }
+ bool isAllocated() const { return m->isAllocated(); }
+ void setAllocated(bool i) { m->setAllocated(i); }
+};
+
+
+/**
+ * Since it's not easy to share functions between Ruby modules, the common
+ * interface between all Smoked libraries and Ruby will be defined in this
+ * class. There will be only one SmokeRuby instance loaded for an entire Ruby
+ * process. It has no data members here -- this is only an abstract interface.
+ */
+
+class SmokeRuby {
+ void *future_extension;
+public:
+ SmokeRuby() : future_extension(0) {}
+
+ // don't need this, we're only defining an interface
+ virtual ~SmokeRuby() = 0;
+
+ /**
+ * Registers a Smoke object
+ */
+ virtual void registerSmoke(const char *name, Smoke *smoke) = 0;
+
+ /**
+ * Gets a smoke object from its name
+ */
+ virtual Smoke *getSmoke(const char *name) = 0;
+
+ /**
+ * Determines if the named smoke is registered.
+ */
+ bool isSmokeRegistered(const char *name) { return getSmoke(name) ? true : false; }
+
+ virtual void registerHandlers(TypeHandler *handlers) = 0;
+
+ /**
+ * Returns a new blessed SV referring to the pointer passed.
+ * Use sv_2mortal() before passing it around.
+ *
+ * @param p pointer to the C++ object. The pointer isn't automatically deleted by SmokePerl.
+ * @param c class of the pointer
+ * @see #getObject
+ * @see #deleteObject
+ */
+ virtual SmokeObject newObject(void *p, const SmokeClass &c) = 0;
+
+ /**
+ * Same as newObject(), except it doesn't treat p as owned by Perl
+ */
+ virtual SmokeObject wrapObject(void *p, const SmokeClass &c) = 0;
+
+ /**
+ * Any SV* created with newObject() on a class with virtual methods can be
+ * retrieved again.
+ */
+ virtual SmokeObject getObject(void *p) = 0;
+
+ /**
+ * Create a SmokeObject from the given VALUE
+ */
+ virtual SmokeObject getObject(VALUE value) = 0;
+};
+
+/*
+ * Type handling by moc is simple.
+ *
+ * If the type name matches /^(?:const\s+)?\Q$types\E&?$/, use the
+ * static_QUType, where $types is join('|', qw(bool int double char* QString);
+ *
+ * Everything else is passed as a pointer! There are types which aren't
+ * Smoke::tf_ptr but will have to be passed as a pointer. Make sure to keep
+ * track of what's what.
+ */
+
+/*
+ * Simply using typeids isn't enough for signals/slots. It will be possible
+ * to declare signals and slots which use arguments which can't all be
+ * found in a single smoke object. Instead, we need to store smoke => typeid
+ * pairs. We also need additional informatation, such as whether we're passing
+ * a pointer to the union element.
+ */
+
+enum MocArgumentType {
+ xmoc_ptr,
+ xmoc_bool,
+ xmoc_int,
+ xmoc_double,
+ xmoc_charstar,
+ xmoc_QString
+};
+
+struct MocArgument {
+ // smoke object and associated typeid
+ SmokeType st;
+ MocArgumentType argType;
+};
+
+#endif // SMOKERUBY_H