JDK-6528430 : need system property to override default WM_CLASS
  • Type: Enhancement
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 6
  • Priority: P5
  • Status: Open
  • Resolution: Unresolved
  • OS: linux
  • CPU: x86
  • Submitted: 2007-02-26
  • Updated: 2012-05-10
Description
A DESCRIPTION OF THE REQUEST :
i'd like to just set the "java.awt.WM_CLASS" property to choose my own WM_CLASS, rather than have XToolkit's default guess.

JUSTIFICATION :
http://elliotth.blogspot.com/2007/02/fixing-wmclass-for-your-java.html

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.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
i'd like to just set the "java.awt.WM_CLASS" property.
ACTUAL -
i have to hack about with the internals of XToolkit.

---------- BEGIN SOURCE ----------
any Java application that doesn't use my work-around.

here's my suggested patch, for which there is no separate text field (you need to update the combo boxes so i can say that this is a problem in the final Java 6 release, too!):

--- XToolkit.java.orig  2007-02-25 21:04:24.000000000 -0800
+++ XToolkit.java       2007-02-25 21:06:01.000000000 -0800
@@ -285,17 +285,19 @@
         }
 
         if (!GraphicsEnvironment.isHeadless()) {
-            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 = getSystemProperty("java.awt.WM_CLASS");
+            if (awtAppClassName == null) {
+                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);
             }
-            awtAppClassName = getCorrectXIDString(mainClassName);
 
             init();
             XWM.init();

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
  Toolkit xToolkit = Toolkit.getDefaultToolkit();
  java.lang.reflect.Field awtAppClassNameField =
      xToolkit.getClass().getDeclaredField("awtAppClassName");
  awtAppClassNameField.setAccessible(true);
  awtAppClassNameField.set(xToolkit, applicationName);
Another symptom is that every JNLP app is displayed as "com-sun-javaws-Main".

Comments
WORK AROUND NetBeans workaround: http://hg.netbeans.org/core-main/rev/5832261b8434
10-05-2012

EVALUATION A pretty good solution for the problem.
27-01-2011