[Kde-bindings] QtJava rewritten as a SMOKE adaptor?
Richard Dale
Richard_Dale at tipitina.demon.co.uk
Thu Aug 7 16:27:10 UTC 2003
I've spent the last month or so implementing QtRuby, which interfaces with
Ashley Winter's language independent SMOKE bindings for Qt. It went really
well, and already QtRuby can do things that QtJava can't - such as override
all virtual methods, rather than just some of them. The advantage of using
SMOKE is that you only need to write a relatively simple 'adaptor' for a new
language. You don't have to start all over everytime and generate all the
'bridge' C++ classes that actually call the Qt C++ methods, and do virtual
method callbacks to the target language - that's all in the SMOKE library.
The existing QtJava/Koala java bindings work well enough, but are quite hard
to extend for things like adding all the missing virtual method callbacks,
java serialization or dynamic DCOP support.
So I've been thinking about how to implement the same thing for QtJava for the
past couple of days, and can see how it might work now. At the moment each Qt
C++ method has a corresponding java native method, and the code in the JNI
method calls the C++ one like this:
In QApplication.java:
public native int exec();
In QApplication.cpp:
JNIEXPORT jint JNICALL
Java_org_kde_qt_QApplication_exec(JNIEnv *env, jobject obj)
{
return (jint) ((QApplication*) QtSupport::getQt(env, obj))->exec();
}
The getQt() call just gets the corresponding C++ instance for the java one,
and calls QApplication::exec() with it.
The new SMOKE approach will do away with the need to generate all the C++ JNI
based sources like QApplication.cpp/QApplication.h and so on - a BIG plus.
The current 90000 lines of C++ code in the project will drop to about 3000.
Instead, exec() in QApplication.java will look like this:
public int exec() {
return proxy.exec().intValue();
}
Rather than directly use a native JNI method, the call to exec is handed off
to a java.lang.reflect.Proxy instance - 'proxy'. Java Proxies only implement
one method to do anything, called invoke(), and the exec() call is translated
into an invoke() one via reflection machinery in Proxy.
public Object invoke(Object proxy, Method method, Object[] args);
invoke() will then call a single global JNI function which actually marshalls
the java argument values onto the C++ smoke stack, and invokes the target C++
method via the SMOKE runtime.
The 'proxy' instance variables will need to be created in the constructors.
Every Qt class like QApplication.java will need to have a corresponding
interface QApplicationInterface.java so that all the methods the proxy
expects to handle can be given via an array of these interface classes (for
the current class and its parents).
QApplicationInterface proxy;
...
proxy = (QApplicationInterface) Proxy.newProxyInstance(
QApplication.class.getClassLoader(),
new Class[] { QApplicationInterface.class },
new QtProxy() );
I don't know if this makes sense, but I thought it would be a good idea to at
least start discussing what to do about QtJava/Koala for KDE 3.2.
-- Richard
More information about the Kde-bindings
mailing list