2007-02-26

Fixing WM_CLASS for your Java application's windows

X11 windows can have arbitrary properties set on them. There are various conventional properties, and they're read by tools like window managers and task bars and window switchers and the like.

For example, if you have too many open windows on a GNOME desktop, instead of getting one task bar icon per window, you get one per application. Where does the application name come from? From the WM_CLASS property on those windows.

As another example, if you use the screenshot tool in Sun's Java Desktop System release 3 to take a picture of a single window, the default filename contains the application name. Where does the application name come from? From the WM_CLASS property on the window.

So where does the WM_CLASS property come from in a Java application? The fully-qualified name of the class at the bottom of the stack trace when the Toolkit was constructed, with the dots replaced by dashes.

So what's a Java programmer to do to avoid his application appearing to the user to be called org-jessies-app-Main, or something daft like that?

One choice is that you ensure that your main class is in the default package and has the name of your application. But that's ugly, awkward, and a pain if your application's external name doesn't match its internal name.

Another, better, choice would be to override the value that the X11 Toolkit uses for WM_CLASS. Sadly, there's no API for this. No magic property or environment variable you can set. On the bright side, the current implementation caches the value it'll use for all windows when the Toolkit is constructed. So, unlike if it were a private method in default-access class in an undocumented package, you can easily use reflection to override the default:

Toolkit xToolkit = Toolkit.getDefaultToolkit();
java.lang.reflect.Field awtAppClassNameField =
xToolkit.getClass().getDeclaredField("awtAppClassName");
awtAppClassNameField.setAccessible(true);
awtAppClassNameField.set(xToolkit, applicationName);

Surround that with a try/catch and log errors such that if you ever find yourself wondering why your windows have the wrong WM_CLASS (if Sun change this implementation detail in Java 8, say), you'll have a clue lying around.

If your code only ever runs on Mac OS or Windows, you don't need to worry about this (though on Mac OS you'll want to worry about -Xdock:name). But if you're expecting users on Unixes other than Mac OS, this is a worthwhile bit of polish.

I've submitted an RFE. Sun bug 6528430.