Tuesday, June 24, 2008

Using Xlib with JNI

Quick tutorial today on using Xlib with JNI (obviously).

Check my previous posts tagged with Xlib and X11 for reference material. If you've never used JNI before, you're probably going to need to do some basic tutorials first - again, previous posts here may help.

Let's get started! The first thing you're going to need is the X11 development headers. On my machine:


apt-cache search libx11-dev
libx11-dev - X11 client-side library (development headers)

apt-get install libx11-dev


Your java source is your own to deal with, seeing as all that's relevant here is the method and class name. We'll use String JXTest.doSomething();

JXTest.cpp:

#include "/usr/include/X11/Xlib.h"
#include "JXTest.h"

// open the current display. NULL means check the DISPLAY shell variable
Display *display = XOpenDisplay(NULL);
Window hwnd;
int revert_to;
char title[80];

JNIEXPORT jstring JNICALL Java_JXTest_doSomething(JNIEnv *env, jobject obj){

// make sure we're connected to an X display
if(display == NULL){
printf("Could not open display\n");
return NULL;
}

// now we get to do stuff!
// let's keep with previous posts, and go with getting the focused window's title
// check the reference pages on these functions for more information

XGetInputFocus(display, &hwnd, &revert_to);

char* retval;
if(XFetchName(display, hwnd, &retval)) != 0){
// we have to free the string, so let's copy it into our own
// note that title is global so that we're not allocating new memory each time
strcpy(title, retval);
XFree(retval);
printf("Our window title is %s\n", title);

// as per a previous post, NewStringUTF does not preserve the pointer, so we can reuse title later
return env->NewStringUTF(title);
}
printf("Could not get window title!\n");
return null;

}



g++ -lX11 -shared -o libtestlibrary.so -I/usr/lib/jvm/java-6-sun-1.6.0.00/include/ -I/usr/lib/jvm/java-6-sun-1.6.0.00/include/linux -I/usr/includes/X11/ nimbusLinux.cpp


-lX11 links the library to X11 and includes the X11 headers
-o is the output file name - remember that System.loadLbrary translates "testlibrary" to "libtestlibrary.so" automatically
-I are include paths - you'll probably hae to modify these to suit your own system

If all goes well, you should now have a program that interacts with X to get the currently-focused window's title!

Note that under some window managers the currently-focused window has an invisible "FocusProxy" over it - see my post here for information on that and a couple other issues.

One last note: on Linux, I've had issues with library loading with System.loadLibrary. This should help, and it's cross-platform:


static {
try{
File pwd = new File(".");
System.load(pwd.getCanonicalPath() + "/" + System.mapLibraryName("libraryname"));
}catch(Exception e){
e.printStackTrace();
System.exit(1);
}
}

No comments: