Skip to main content

Java, Linux and using the desktop's stock icons in a Swing GUI

Posted in

Well, Java is cross platform, granted. But if you want your application to look native to the user's desktop environment, you have to jump through a lot of hoops (and some of them are burning, too). Take icons, for example. Nowadays, an application is expected to use icons in menuentries and on the toolbar to increase usability. Nothing wrong with that, except that Swing does not ship with any. You have to provide your own and you have to bundle them with your application. For Windows and MacOS, that's ok. On Linux, however, applications are suppose to use stock icons, provided by the desktop environment. Big problem: how are you suppose to access them from Java? How are you even suppose to figure out, which icon theme the user is currently using? Guessing and poking around in config files is hardly appealing.

The solution to loading the correct icons under Linux is buried deep inside the JRE and unfortunately, also in the sun.awt package. Using a proprietary API is most certainly no more appealing than digging around in config files, but at least it gets the job done with less hassle:

import sun.awt.*;
import java.awt.*;
import java.awt.image.*;
 
public class HackLoader {
 
  public Icon loadIcon() {
    ImageIcon icon;
    try {
      int widget = -1; // Go with the default
      String id = "gtk-new";    
      int dir = 1; // NONE=0 ; LTR=1; RTL=2;
      int size = 1;
      
      UNIXToolkit utk = (UNIXToolkit)Toolkit.getDefaultToolkit();
      BufferedImage img = utk.getStockIcon(-1,id,size,dir,null);                                       
      icon = new ImageIcon(img); // Will throw if img==null
    }
    catch (NoClassDefFoundError e) {
      // Ok, the API is not available at all.
    }
    catch (Exception e) {
      // We are not on a GTK system
    }
    finally {
      // Load a bundled icon here
    }
    return icon;
  }
} 

Now, id andsize need an explanation. These are constants, coming from various GTK header files. Most important is certainly the id parameter which determines which icon the load. This constant string can be looked up in the GTK stock items list. The image size comes from gtk/gtkenums.h and is defined by the following enum:

typedef enum
{
  GTK_ICON_SIZE_INVALID,
  GTK_ICON_SIZE_MENU,
  GTK_ICON_SIZE_SMALL_TOOLBAR,
  GTK_ICON_SIZE_LARGE_TOOLBAR,
  GTK_ICON_SIZE_BUTTON,
  GTK_ICON_SIZE_DND,
  GTK_ICON_SIZE_DIALOG
} GtkIconSize;

Java mirrors these constants in the com.sun.java.swing.plaf.gtk.GTKConstants.TextDirection class, so they can accessed in the "pure" way, but since that class is also proprietary, it means just more compiler warnings.