Monday, December 5, 2011

Eclipse Unity Integration - without JNA

As I have explained in my previous post, it is very easy to access native libraries when you use JNA. This approach has, however, two major drawbacks: it uses LGPL, which is allowed in Eclipse Foundation only in very border situations, and it requires almost 2MB of jars. That's a lot.

In this post I am going to show you how to write java code that manipulates Ubuntu Unity Launcher using pure JNI. I will use for that Eclipse with JDT and CDT installed.

To prepare environment, it is necessary to install all the required dev linux packages. The command that do that is:

sudo apt-get install libunity-dev

After downloading the whole package (nearly 70MB), you are ready to start coding. So, let's create a java  project, and create following class, which more or less corresponds to native methods.

  If you compare that code with the approach described in my previous post, you will notice that pointer to launcher structures has been replaced with a long type. I do not care what is stored in the C structure, so let's make a handle from it.

Now it is time to launch a terminal, go to the bin/ folder and generate a C header file. Yes, the java command that generates headers operates on class files, so it is necessary to have the java project compiled. Then we can invoke following command (you may need to adjust your class name):

javah -jni org.eclipse.ubuntu.UnityLauncher

The generated code will make most of the java developers shiver:

Since now we are C developers, it is time to use CDT and add a C/C++ nature to the java project - we will keep everything together. The conversion can be performed by selecting 'New'->'Convert to a C/C++ Project (Adds C/C++ Nature)', and then 'Shared Library', because this is what we want to create - a library that can be loaded by jvm.

Newly converted C project requires some setup - especially we need to inform compiler and linker about existing Ubuntu headers & libraries. On the screenshots below you can find my settings:

There is one more option that needs to be set - fPIC:

I do not know what it actually means, but compiler instructed me to add this if I wanted to have a library that could be shared ;).

After setting the C project, put the header file into the C source folder, and then create a new c file:

This code requires almost no explanation - we use a long variable to store a pointer to the actual structure, and do some small native operation to get char* from String. Nothing really big.

At this point it is necessary to hit the 'Build All' button. A .so library should be created in our project. The library needs to be added to java path, so we go to the project build path, and add native library:

That's almost it. We need two more things - first of all it is necessary to load the shared library into vm, so let's modify UnityLauncher

The second thing to do is to write a small SWT application - because it is impossible to modify any gtk widget without starting the gtk loop - and that task can be safely delegated to swt main loop. So our test class looks like that:

The result is expected (and nice):

We have reduced the size of the required libraries about 10 times (now it is more or less 200kb), and we are 100% EPL compliant.

There is much more work to be done - first of all the java project needs to be converted into a linux-specific plugin and hooked into jobs framework, although the latter is not a very complicated task.

I'm curious if it is possible to configure P2 in such a way that it will create an eclipse.desktop file when my plugin is installed?

I hope this long post will help somebody ;-). And I plan to release sources of my plugin as soon as I clean up the code :).

No comments:

Post a Comment