Turn your Java apps Gnome-Shell friendly

The Problem

When you try to add a java application as favorite into the Gnome Shell‘s lateral dock and run it you’ll end up having duplicated icons, one for the launcher and one for the running app. This happens b/c the shell uses an application based system for grouping tasks, so the idea is, if you add an application as a favorite launcher and you start it you’ll end having that launcher icon highlighted. Internally the shell matches the running process with the Exec clause of the .desktop file .
This works well except for applications running inside a VM or being interpreted b/c those will share the same running process. On that situation the shell inspects the WM_CLASS X Window property [1] and matches it with the full name of the desktop file. E.g. if your applications has the WM_CLASS set as “mySwingApp”, for this to successfully matched in the dock with its launcher, that launcher must be called mySwingApp.desktop located according XDG.

Note: for inspecting that value on any window you just need to run xprop WM_CLASS and click into the target window

Why is this happening?

Even if you are creating a swing application from scratch there is no easy way to tweak that X Window property using plain and portable APIs. Taking a look into openjdk sources, this is how them manages it

String mainClassName = null;

StackTraceElement trace[] = (new Throwable()).getStackTrace();
int bottom = trace.length - 1;
if (bottom >= 0) {
mainClassName = trace[bottom].getClassName();
}
if (mainClassName == null || mainClassName.equals("")) {
mainClassName = "AWT";
}
awtAppClassName = getCorrectXIDString(mainClassName);

As you may note what is used for this value is the name of the class running the Swing main loop.

Da solution

Digging around the web I founded a java agent and a pretty similar explanation on what’s going on.
So what I did was to fork that agent and improve it a little bit. What I did was to move it into a maven structure and remove its packaging as a fat-jar (I’m radically against fat-jars as you can see in my comments here).

The forked project is located in my github here:
https://github.com/diega/window-matching-agent
and please take a look to the README there

A practical example

My first motivation on doing this was based on IntelliJ IDEA so I’ll paste here my environment.

  • Download the agent-1.0.jar and put it wherever you want (I put it into IntelliJ’s bin/ folder)
  • Edit the file bin/idea.vmoptions adding this line

    -javaagent:agent-1.0.jar=intellij-ultimate

  • Create the file ~/.local/share/applications/intellij-ultimate.desktop with the following content

    [Desktop Entry]
    Version=10.5.1
    Name=IntelliJ IDEA Ultimate Edition
    Comment=The Most Intelligent Java IDE
    Categories=Applications;Development;
    Encoding=UTF-8
    Exec=env IDEA_CLASSPATH\=../lib/asm.jar /home/diego/bin/ideaIU-10.5/bin/idea.sh
    GenericName=IntelliJ
    Icon=/home/diego/bin/ideaIU-10.5/bin/idea128.png
    MimeType=text/x-java
    Terminal=false
    Type=Application
    URL=http://www.jetbrains.com/idea
    

Latest notes

If you download the agent-1.0.jar into another location (or with another name) you must adjust the -javaagent: parameter.
Of course, change the path in the Exec entry to point to your own executable.

Hope this helps somebody, it took me a while to figure out the-right-things-to-do™ :)


[1]: Application Based GNOME 3