SmokeObject * SmokeObject::fromPtr(void *ptr, const Class *klass, bool allocated, bool copy) { if (!klass) error("Attempt to create SmokeObject with NULL class"); if (!ptr) error("Attempt to create SmokeObject with NULL pointer"); SmokeObject *so = instances[ptr]; if (!so) { so = new SmokeObject(ptr, klass, allocated); #ifdef MEM_DEBUG qDebug("%p: created for %p (%s)", so, ptr, klass->name()); #endif // record this ASAP, resolveClassId() needs it for virtual callbacks if (allocated) // do not record unallocated; not informed when deleted instances[so->ptr()] = so; #ifdef MEM_DEBUG else qDebug("%p: unallocated, not registering pointer", so); #endif so->cast(Class::fromSmokeId(so->smoke(), so->module()->resolveClassId(so))); /* it seems that all multiple inheritance in Qt goes through QObject or QEvent, so we can catch offset pointers at run-time */ // FIXME: what happens with other libraries? take QtRuby approach? #ifdef MEM_DEBUG if (allocated && so->klass() != klass) qDebug("%p: class switch %s::%s -> %s::%s", so, klass->smokeBase()->smoke()->moduleName(), klass->name(), so->klass()->smokeBase()->smoke()->moduleName(), so->klass()->name()); #endif if (so->ptr() != ptr) { // must be multiple inheritance, recache SmokeObject *tmp_so = instances[so->ptr()]; #ifdef MEM_DEBUG qDebug("%p: multiple inheritance detected, switch to %p", so, so->ptr()); #endif if (tmp_so) { #ifdef MEM_DEBUG qDebug("%p: replaced with existing %p", so, tmp_so); #endif delete so; so = tmp_so; copy = false; // don't think we every want to copy here } else instances[so->ptr()] = so; instances.remove(ptr); } if (copy) { // copy the data void *tmp_ptr = so->ptr(); so->_ptr = so->clonePtr(); instances[so->ptr()] = so; // update the instances hash after cloning instances.remove(tmp_ptr); #ifdef MEM_DEBUG qDebug("%p: copied to %p", so, so->ptr()); #endif so->_allocated = true; } } return so; }
extern "C" SEXP qt_qmetaInvoke(SEXP x, SEXP s_id, SEXP s_args) { SmokeObject *so = SmokeObject::fromSexp(x); int id = from_sexp<int>(s_id); QObject * qobj = reinterpret_cast<QObject *>(so->castPtr("QObject")); MocMethod method(so->smoke(), qobj->metaObject(), id); SEXP ret = method.invoke(x, s_args); if (method.lastError() > Method::NoError) error("Meta method invocation failed for: '%s::%s'", so->klass()->name(), method.name()); return ret; }
/* We catch all qt_metacall invocations */ extern "C" SEXP qt_qmetacall(SEXP x, SEXP s_call, SEXP s_id, SEXP s_args) { SmokeObject *so = SmokeObject::fromSexp(x); QMetaObject::Call call = enum_from_sexp<QMetaObject::Call>(s_call, SmokeType()); int id = from_sexp<int>(s_id); void **args = reinterpret_cast<void **>(from_sexp<void *>(s_args)); // Assume the target slot is a C++ one Smoke::StackItem i[4]; i[1].s_enum = call; i[2].s_int = id; i[3].s_voidp = args; so->invokeMethod("qt_metacall$$?", i); int ret = i[0].s_int; if (ret < 0) { return ScalarInteger(ret); } if (call != QMetaObject::InvokeMetaMethod) return ScalarInteger(id); QObject * qobj = reinterpret_cast<QObject *>(so->castPtr("QObject")); // get obj metaobject with a virtual call const QMetaObject *metaobject = qobj->metaObject(); // get method count int count = metaobject->methodCount(); QMetaMethod method = metaobject->method(id); if (method.methodType() == QMetaMethod::Signal) { // FIXME: this override of 'activate' is obsolete metaobject->activate(qobj, id, (void**) args); return ScalarInteger(id - count); } DynamicBinding binding(MocMethod(so->smoke(), metaobject, id)); QVector<SmokeType> stackTypes = binding.types(); MocStack mocStack = MocStack(args, stackTypes.size()); SmokeStack smokeStack = mocStack.toSmoke(stackTypes); binding.invoke(so, smokeStack.items()); mocStack.returnFromSmoke(smokeStack, stackTypes[0]); if (binding.lastError() == Method::NoError) warning("Slot invocation failed for %s::%s", so->klass()->name(), binding.name()); return ScalarInteger(id - count); }
Method* MocClass::findMethod(const MethodCall& call) const { Method *method = _delegate->findMethod(call); if (method) return(method); SmokeObject *o = call.target(); /* only QObjects have meta methods */ if (o && o->ptr() && o->instanceOf("QObject") && o->klass() == this) { /* unwrap the call */ QObject * qobject = reinterpret_cast<QObject *>(o->castPtr("QObject")); const QMetaObject * meta = qobject->metaObject(); /* get the method id */ int id = findMethodId(o->smoke(), meta, call.method()->name(), call.args()); if (id >= 0) method = new MocMethod(o->smoke(), meta, id); } return method; }