Thursday, June 26, 2008

XGetWindowAttributes and You

Right at the end of a project I've been working on, I run into a very weird issue. As per the title of this post, it's with XGetWindowAttributes and the XWindowAttributes struct.

Reference page:
XGetWindowAttributes

The main reason I'm looking to use this function is for XWindowAttributes.class, which will tell me if the window I have is InputOutput (visible) or InputOnly (not visible). If there's a simpler way to detect a window's visibility, I couldn't find it.

Anyway, in my coding I have this:


XWindowAttributes attr;
XGetWindowAttributes(display, hwnd, &attr);
if(attr.class == InputOutput){
[...]
}else{
[...]
}


Looks fine, yes? Well, it won't compile.

error: expected unqualified-id before class
error: expected `)' before class

Some research on the error turns up next to nothing; just a bunch of people saying that switching header include orders fixes it. Didn't fix it for me.

So then I figure, perhaps the documentation is old, and "class" has been removed. Changing "class" to a random string returns a different error, so that's not it. So I looked at the newest documentation I could find - the source. Turns out that it WAS changed, and here it is (abbridged):


typedef struct {
int x, y; /* location of window */
[...]
Window root; /* root of screen containing window */
#if defined(__cplusplus) || defined(c_plusplus)
int c_class; /* C++ InputOutput, InputOnly*/
#else
int class; /* InputOutput, InputOnly*/
#endif
int bit_gravity; /* one of bit gravity values */
[...]
Screen *screen; /* back pointer to correct screen */
} XWindowAttributes;


As it turns out, my code is C++, and apparently there's a different member for C and C++ (whoever heard of doing that? I fail to see the reasoning - though I'm sure there is some).

Anyway, a simple change of variable name to c_class fixed the errors, and it compiles successfully. Mark another one up for non-deterministic error messages.

Tuesday, June 24, 2008

Wider Posts!

I've edited the template a little, and now it seems a little less cramped. Of course, I'm on a widescreen so it still looks like text crunched into the middle of the screen, but I tried to keep it at a width of 800px for easy viewing on older machines (sometimes I wish they'd all just burn up and get replaced). Anyway, I checked it on a couple browsers, and it looks fine, but let me know if there's an issue.

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);
}
}

Sunday, June 22, 2008

Intro to JNI on Linux

Today (as the title says) I'm going to go over a few things dealing with JNI compilation for Linux. I recommend you read my previous post for JNI on Windows if you've never used it before, this just deals with the quick and dirty details.

Let's get to some simple code:

myNativeMethod.cpp:

#include "myClass.h"

JNIEXPORT void JNICALL Java_myClass_myNativeMethod(JNIEnv *env, jobject obj){
printf("well hello there!\n");
}



Easy stuff. As always, myClass.h is generated after the java code is compiled and run through javah. Our native method is defined in the java source as:


...
private native void myNativeMethod();
static {
System.loadLibrary("myNativeLibrary");
}
...


NOTE: System.loadLibrary expects a certain filename. On Linux, it prepends "lib" and appends ".so" - so the above call looks for "libmyNativeLibrary.so" on Linux, just as it would look for "myNativeLibrary.dll" on Windows.

Let's compile! Of course, your include paths will probably be different, but that shouldn't be hard to fix.


g++ -shared -o libmyNativeLibrary.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 myNativeMethod.cpp


Viola! We have compiled our library.

Now, when you try to use it, sometimes you'll get am UnsatisfiedLinkError if everything's not exactly right. This is caused from a couple things:

1) You didn't name it lib[name].so!
2) You didn't use the right method signature - the header signature and your own signature should be EXACTLY the same.
3) It's simply not in Java's library search path. The quick and dirty way to force it in is to run:

java -Djava.library.path=./ myClass

Unfortunately, the library path that overwrites usually has stuff in it that is needed - which results in more Unsatisfied Link Errors. The next quick and dirty way is to just move libmyNativeLibrary.so to /lib or somewhere else in the library path.

Gatta run, I may add more later.

Saturday, June 21, 2008

JNI's NewStringUTF and Memory Use

After a few crashes and debugging returning the error location being a malloc call, I did some research on NewStringUTF usage.

It was difficult to find, but it appears that a returned jstring (made by NewStringUTF) is copied by Java into its own heap space. This contradicts my previous assumption that it just kept the memory pointer. In my previous code I had similar to:



JNIEXPORT jstring JNICALL Java_myClass_myMethod(JNIEnv *env, jobject obj){
...
LPTSTR buffer = (LPTSTR)malloc(200*sizeof(TCHAR));
...
return env->NewStringUTF(buffer);
}


Obviously this doesn't free the memory allocated and pointed to by "buffer" - which I'd previously thought was correct, assuming the Java garbage collector would clean it up. It appears that was incorrect, though - so (in my situation) the best solution was to make a global buffer and use it over and over.


LPTSTR buffer = (LPTSTR)malloc(200*sizeof(TCHAR));
JNIEXPORT jstring JNICALL Java_nimbus_getForegroundWindow(JNIEnv *env, jobject obj){
...
return env->NewStringUTF(buffer);
}


This ensures that memory isn't constantly allocated and not deleted. Hopefully in the future the Sun JNI examples will note this better.

Wednesday, June 18, 2008

Messing with X11

My latest foray into X windowing got me stuck in a couple places. I'll give a brief overview today of my issues and resolutions, and perhaps if I find some time I'll go through in more detail later.

Issue: Finding a call to locate the focused window.
Resolution: XGetInputFocus

Issue: Finding a call to get the window title.
Resolution1: XGetWindowProperty
Resolution2: XFetchName (much much easier)

Issue: Window title is null?
Reason: There appears to be an invisible window overlayed on it. Often "FocusProxy".
Resolution: XQueryTree to find the parent. This resolution is iffy.

Issue: Finding a call to get a process ID from a window.
Resolution: XGetWindowProperty -> _NET_WM_PID (though it's not always set)

Wednesday, June 11, 2008

X System Calls

Lately I've been searching for a couple calls under X that have been evading me. The one in particular that I need is a call to determine the process ID of the foreground window.

I've found some very interesting info, lots of stuff that would be useful if I were implementing a complete window manager:

Inter-client Communication Conventions Manual
Window ID -> Process ID
Wikipedia's Xlib Article

I have a feeling that what I need is in Xlib, but I haven't had time to go through it completely yet.

What worries me, though, is that I've read a couple places that going from window ID to process ID is (almost?) nondeterministic in X. There HAS to be a way though... right? I just don't know enough about window managers and X I guess.

Edit/Update:

This:

Xlib Programming Manual: Input Focus Events

has some potential for helping.

XGetInputFocus

Promising!

"A C++ program to generate every possible X11 request"

Very useful.

Thursday, June 5, 2008

Batch File Issue

If anyone has an answer to why it's doing this, please let me know. I'm not too concerned about it, so I haven't gone digging, but figured I'd put it out there for all to see.

So I've got this batch file I've been using to build these simple JNI projects. Nothing fancy:

[make.bat]

call clean.bat
javac javaclass.java
javah -jni javaclass
call "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat" amd64
cl -I"c:\program files\java\jdk1.6.0_06\include" -I"c:\program files\java\jdk1.6.0_06\include\win32" -I"." -MD -LD javanative.cpp -Fejavanative.dll user32.lib
mt -manifest javanative.dll.manifest -outputresource:javanative.dll;2


Every, say, 12 builds in the same console window, and I get this error message:


The input line is too long.
The syntax of the command is incorrect.


The message comes from the Visual Studio batch file or the compiler, not sure which - the batch file prints out a message saying it's configured as normal, and that's when it dies.

Anyway, from then on it fails to build, and the only way to fix it is to open a new console window. Nothing big, just annoying sometimes.

user32.dll Functions in JNI

UPDATE NOTE:
Please read this post explaining a small issue with the code used in this article.


If you've never used JNI before, please read my previous post first.

In this post I'm going to go over how to use some windows functions with JNI. Specifically, two which have caused me frustration recently: GetForegroundWindow and GetWindowText.

Reference Pages:
GetForegroundWindow
GetWindowText
GetWindowTextLength
GetLastError
C++ JNI Types/Functions

To the code! This is similar to my initial code - there is a problem with it. Hopefully you don't see it, so as to keep my programming ego intact. Again, this code DOES NOT WORK - if you're just here for the code look down further.

[javanative.cpp]

#include "windows.h"
#include "winuser.h"
#include "jni.h"
#include "javaclass.h" // generated header file

JNIEXPORT jstring JNICALL Java_javaclass_getForegroundWindow(JNIEnv *env, jobject obj){
HWND hwnd = GetForegroundWindow();
if(hwnd == 0){
return NULL;
}
int length = GetWindowLength(hwnd);
LPTSTR buffer = "xxxxxxxxxxxxxxxxxxxx"; // this is how I found a few examples online
int textLength = GetWindowText(hwnd, buffer, 20);
return env->NewStringUTF(buffer); // this too - memory leak. see code below
}

Note that the functions (GetWindowText, etc.) are in user32.dll; in order to use them, you must include the user32.lib library during compilation. The method to do this depends on your compiler; with the Visual Studio command-line compiler, you just append the libraries to the end (as you'll see below).

Compilation:

javac javaclass.java
javah -jni javaclass
call "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat" amd64
cl -I"c:\program files\java\jdk1.6.0_06\include" -I"c:\program files\java\jdk1.6.0_06\include\win32" -I"." -MT -LD javanative.cpp -Fejavanative.dll user32.lib



Now then, it compiles - but it doesn't work. It returns the "xxxx..." string as the name every time. After some debugging, I found that GetWindowText was returning an error code of 1400 - and that code means that the window does not exist. Some more testing confirmed that the window DID exist - IsWindow returned true, etc. So, what's the problem?

As you probably guessed (the only commented line in the code):


LPTSTR buffer = "xxxxxxxxxxxxxxxxxxxx"; // this is how I found a few examples online


Apparently, having the buffer on the stack makes the call return 1400 - a completely wrong error code. The correct way to do it is to put the buffer on the heap.


int length = GetWindowTextLength(hwnd);
// make some heap space - lots of ways to do this.
LPTSTR buffer = (LPTSTR)malloc(length * sizeof(TCHAR));


It works!

Here's the full, working code:

#include "windows.h"
#include "winuser.h"
#include "jni.h"
#include "javaclass.h"

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

HWND hwnd = GetForegroundWindow();
if(hwnd == 0){
return NULL;
}
int length = GetWindowTextLength(hwnd);
LPTSTR buffer = (LPTSTR)malloc(length * sizeof(TCHAR));
int textLength = GetWindowText(hwnd, buf, length);
DWORD lasterror = GetLastError();
jstring jstr = env->NewStringUTF(buffer);
free(buffer);
return jstr;
}
Note that even though we allocate heap space, we don't want to free it ourselves. This is not a memory leak, Java's GC will deallocate it when it's no longer in use.

And there you have it. Calling getForegroundWindow() in your java source now returns the caption of the foreground window.

Introduction to JNI

As my first technical post, I'm going to overview how to use JNI with C++.

My platform:
Windows Vista Ultimate
AMD Athlon64 X2 6000+
5GB DDR2
Java 1.6.0_06 64-bit
Microsoft Visual Studio 2008

Straight to the code:

[HelloWorld.java]

class HelloWorld {
public static native void HelloNative(String s);
static {
System.loadLibrary("HelloDLL");
}
public static void main(String[] Args){
HelloNative("Hello, world!");
}
}

Things to note:
- The method we're going to create in the DLL is declared as "native" but not defined.
- To load the methods from the DLL, we call System.loadLibrary("library");
- Do not put the extension in the call - our DLL will be HelloDLL.dll, so we call with "HelloDLL"
- After that, we can use the function just as normal.

[HelloWorld.cpp (here's where it gets messy)]

#include "HelloWorld.h"
JNIEXPORT void JNICALL Java_HelloWorld_HelloNative(JNIEnv *env, jobject obj, jstring javaString){
const char *input = env->GetStringUTFChars(javaString, 0);
printf("%s\n", input);
env->ReleaseStringUTFChars(javaString, input);
}


Things to note:
-The header "HelloWorld.h" will be generated by javah as we'll see in a bit.
-The function name must be Java_ClassName_MethodName
-The function parameters must start with a JNIEnv* and a jobject, after that come your own.
-To use the jstring you passed in as a character array, you have to call GetStringUTFChars
-You MUST call ReleaseStringUTFChars after calling GetStringUTFChars once you're done

Putting it all together:

javac HelloWorld.java
javah -jni HelloWorld

[Here you can use a C++ compiler of your choice, as long as you know how to use it to create a DLL. This example is with Visual Studio 2008]

call "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat" amd64

cl -I"c:\program files\java\jdk1.6.0_06\include" -I"c:\program files\java\jdk1.6.0_06\include\win32" -I"." -MT -LD HelloWorld.cpp -FeHelloDLL.dll


All done!
Let's go over the compilation.

You'd better know what javac does already; javah creates the header file for the class, which we already included in our cpp file (HelloWorld.h).

The first Visual Studio command is a batch file, with an architecture parameter. I'm compiling to amd64. The batch file sets the paths and settings necessary for compilation, makes things easy. I don't believe the standard install of Visual Studio comes with the different architectures - you have to enable it during install (you can go to reinstall and add it without reinstalling the whole thing). Visual Studio Express may not have it - you'll have to install the Windows SDK to get them. There's a help page on the MSDN somewhere about that.

cl is the command-line compiler for Visual Studio. I'm adding include paths to Java's includes directories, as well as the current directory. Some extra switches for good measure, the source file, and the output file.

Viola! You now have your DLL.


Important Note:

With Visual Studio, you can either compile with -MT or -MD. I believe default is MD. the difference is that MT adds the library code directly (statically) to your DLL, while MD links it dynamically. If you use MD, your program is now dependent on msvcr90.dll (or whatever version of Visual Studio you're using). If it fails to run, you need to grab this DLL. I chose to just put it in with my own DLL, as not everyone is going to have it. If you don't, you can find it easily online, or if you have Visual Studio it should be at:

C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\redist\somewheredownthere

I prefer to use MT, so that I don't have to worry about distributing extra static libraries. There are up and downsides to using both. Static will make your DLL a little larger, will MD will make your DLL rely on other libraries. You also may have to embed the manifest file into your DLL if you use MD.

Also note that there are different versions of msvcr90.dll for different architectures, if you choose to use dynamic linking. You can't use the wrong one. Don't worry, it should tell you if you have the wrong one.

Anyway...
That's the end of my first post. Hope you enjoyed.

So last night...

... while I couldn't sleep after an afternoon of frustrations, I thought it might be beneficial to both myself and others if I had somewhere to keep notes on the general "quirks and quandaries" I run into while programming. Of course, I'll also try to post examples of things I found difficult to find, for the betterment of the learning community.

Anyway, I hope at least some of what I do is useful to someone.