New and Updated Desktop Features in Java SE 6, Part 1

   
By Robert Eckstein, February 2007    

Articles Index

Contents

The final release of the Java Platform, Standard Edition 6 (Java SE 6) has added or updated several features for the Java desktop developer. Note that although previous articles, tech tips, or blog entries have discussed these changes, this article covers the basics from each resource and updates the content to include any changes in the final version of Java SE 6.

Splash Screens

From the article " New Splash-Screen Functionality in Java SE 6" by Oleg Semenov and Dana Nourie

Splash screens are a standard part of any modern graphical user interface (GUI) application. Before Java SE 6, you could use Swing or Abstract Window Toolkit (AWT) to create splash screens in Java technology applications. However, before the splash screen can pop up, the application has to load and initialize the Java Virtual Machine (JVM) *, AWT, usually Swing, and perhaps some application-dependent libraries. The resulting delay of several seconds has made use of a Java technology-based splash screen less than desirable.

Java SE 6 provides a solution that allows the application to show the splash screen much earlier, even before the virtual machine starts. Now, a Java application launcher is able to decode an image and display it in a simple nondecorated window, as Figure 1 shows.

Figure 1. Sample Splash Screen for a Java Technology Application
 

There are two ways to show the native splash screen:

  • If your application is to run from the command line or from a shortcut, use the -splash: Java application launcher option:

    java -splash:filename.gif SplashTest
    
     
  • If your application is packaged in a JAR file, use the SplashScreen-Image option in a manifest file. Place the image in the JAR archive and specify the path in the option. For example, use this code in the manifest.mf file:

         Manifest-Version: 1.0
         Main-Class: SplashTest
         SplashScreen-Image: filename.gif
    
     
    The command-line interface has precedence over the manifest setting.

In certain cases, you might want to dynamically update the splash screen while it is being displayed. The java.awt.SplashScreen class may be used to close the splash screen, change the splash-screen image, get the image position or size, and paint in the splash screen. Note that you cannot use the SplashScreen class to create the splash screen. You should use the command-line or manifest-file option for that.

The following code sample demonstrates the typical process for creating a splash screen.

SplashScreen splash = SplashScreen.getSplashScreen();
Graphics2D g = (Graphics2D)splash.createGraphics();
Dimension size = splash.getDimension();
g.setComposite(AlphaComposite.Clear);
g.fillRect(0, 0, size.width, size.height);
g.setPaintMode();
// Paint a splash screen.
g.update();
 

First, you obtain the SplashScreen object. Then, you obtain a graphic handle with the createGraphics() method. Next, obtain the size of the splash screen, and clear the image. This can be done by setting an AlphaComposite.Clear composite mode and painting a rectangle over the whole splash screen. Next, restore the painting mode and paint the splash screen image on the Graphics context. Lastly, call the update() method to display what you have drawn.

You may change the image in the splash screen with the setImageURL() method. If the user wants to close the splash screen before the first AWT or Swing window is displayed, or in the rare case that AWT or Swing is not used for the application GUI, this may be done with the SplashScreen.close() method.

The following application is an example of how the new splash screen works.

import java.awt.*;
import java.awt.event.*;

public class SplashTest extends Frame implements ActionListener {
    static void renderSplashFrame(Graphics2D g, int frame) {
        final String[] comps = {"foo", "bar", "baz"};
        g.setComposite(AlphaComposite.Clear);
        g.fillRect(130,250,280,40);
        g.setPaintMode();
        g.setColor(Color.BLACK);
        g.drawString("Loading "+comps[(frame/5)%3]+"...", 130, 260);
        g.fillRect(130,270,(frame*10)%280,20);
    }
    public SplashTest() {
        super("SplashScreen demo");
        setSize(500, 300);
        setLayout(new BorderLayout());
        Menu m1 = new Menu("File");
        MenuItem mi1 = new MenuItem("Exit");
        m1.add(mi1);
        mi1.addActionListener(this);

        MenuBar mb = new MenuBar();
        setMenuBar(mb);
        mb.add(m1);
        final SplashScreen splash = SplashScreen.getSplashScreen();
        if (splash == null) {
            System.out.println("SplashScreen.getSplashScreen() returned null");
            return;
        }
        Graphics2D g = (Graphics2D)splash.createGraphics();
        if (g == null) {
            System.out.println("g is null");
            return;
        }
        for(int i=0; i<100; i++) {
            renderSplashFrame(g, i);
            splash.update();
            try {
                Thread.sleep(200);
            }
            catch(InterruptedException e) {
            }
        }
        splash.close();
        setVisible(true);
        toFront();
    }
    public void actionPerformed(ActionEvent ae) {
        System.exit(0);
    }
    public static void main (String args[]) {
        SplashTest test = new SplashTest();
    }
}
 

Note that createGraphics() creates and returns a graphics context -- as a Graphics object -- for a splash-screen overlay image. This allows you to draw over the splash screen. Rather than drawing on the main image, you draw on the image that is displayed over the main image, using alpha blending. Also note that simply drawing on the overlay image does not necessarily update the contents of the splash-screen window. You should call the update() method on the SplashScreen when you want the splash screen to be updated immediately.

System Tray

From the article " New System Tray Functionality in Java SE 6" by Robert Eckstein

Java SE 6 lets you access the system tray in Java technology with the help of two separate classes in the java.awt package: SystemTray and TrayIcon. These classes give you the ability to add graphics, pop-up menus, and floating tip functionality to the system tray.

The system tray is a specialized area, typically at the bottom of the desktop, where users can access continually running programs. On Microsoft Windows and the Gnome desktop, the system tray is often referred to as the notification area. On KDE, it is referred to as the system tray. On each system, all applications running on the desktop share this tray area.

Figures 2 and 3 show the system tray on both Windows and Gnome. In both cases, the system tray resides by default in the lower right corner of the screen.

Figure 2. Windows Notification Area
 
Figure 3. Gnome System Tray
 

The java.awt.SystemTray class represents the system tray for a desktop. You can access the system tray by calling the static SystemTray.getSystemTray() method. Before doing so, however, the application should always use the static SystemTray.isSupported() method to check whether the system tray is supported. If the system tray is not present or supported on this platform, the isSupported() method returns false. If the application attempts to call getSystemTray() in such a case, the method will throw a java.lang.UnsupportedOperationException.

Every Java application has a single SystemTray instance. Hence, an application cannot create its own instance of SystemTray. Instead, it must obtain the current one using the getSystemTray() method.

The SystemTray contains one or more TrayIcons, which are added to the tray using the add() method and which are removed when no longer needed with the remove() method. Note that the add() method can throw an AWTException if the operating system or the Java runtime determines that the icon cannot be added to the system tray. For example, an AWTException will be thrown by X Windows desktops if the system tray does not exist.

The following code sample demonstrates how to access and customize the system tray:

final TrayIcon trayIcon;

if (SystemTray.isSupported()) {

    SystemTray tray = SystemTray.getSystemTray();
    Image image = Toolkit.getDefaultToolkit().getImage("tray.gif");

    MouseListener mouseListener = new MouseListener() {
                
        public void mouseClicked(MouseEvent e) {
            System.out.println("Tray Icon - Mouse clicked!");                 
        }

        public void mouseEntered(MouseEvent e) {
            System.out.println("Tray Icon - Mouse entered!");                 
        }

        public void mouseExited(MouseEvent e) {
            System.out.println("Tray Icon - Mouse exited!");                 
        }

        public void mousePressed(MouseEvent e) {
            System.out.println("Tray Icon - Mouse pressed!");                 
        }

        public void mouseReleased(MouseEvent e) {
            System.out.println("Tray Icon - Mouse released!");                 
        }
    };

    ActionListener exitListener = new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            System.out.println("Exiting...");
            System.exit(0);
        }
    };
            
    PopupMenu popup = new PopupMenu();
    MenuItem defaultItem = new MenuItem("Exit");
    defaultItem.addActionListener(exitListener);
    popup.add(defaultItem);

    trayIcon = new TrayIcon(image, "Tray Demo", popup);

    ActionListener actionListener = new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            trayIcon.displayMessage("Action Event", 
                "An Action Event Has Been Performed!",
                TrayIcon.MessageType.INFO);
        }
    };
            
    trayIcon.setImageAutoSize(true);
    trayIcon.addActionListener(actionListener);
    trayIcon.addMouseListener(mouseListener);

    try {
        tray.add(trayIcon);
    } catch (AWTException e) {
        System.err.println("TrayIcon could not be added.");
    }

} else {

    //  System Tray is not supported.

}
 
Gray Rect Fix

Compiled from the blog entries " Swing Painting Improvements: No More Gray Rect!" by Scott Violet and " Swing Update: No More Gray Rect" by Chet Haase

In scoping out various performance-related projects for JDK 6, the Swing team wanted to tackle one of Swing's long-standing problem areas that has contributed to bad perceived performance. This is called the gray rect problem. That is, when a Swing-based application is exposed after being hidden by another application, there is a noticeable delay between when the background of the window is erased and when the actual contents are painted. With JDK 6, this problem has been fixed.

The fix involves adding true double-buffering support to Swing. That is, each application window now has an offscreen duplicate image, known as a back buffer, that is kept synchronized with the onscreen window. When a window is exposed, Swing simply copies directly from the offscreen image, on the toolkit thread, to the screen. An added bonus of this fix is that if your application is blocking the event dispatch thread -- perhaps you're contacting a server, and a user hides your window and then exposes it -- the application will still repaint itself.

Swing's original buffering mechanism was created in a time when system memory was a constrained resource, so sharing this back buffer with all Swing windows was important. Instead of a buffer that acts as a backup for the contents on the screen, as back buffers typically do, the Swing buffer acted more as a "scratch buffer" for any pending operations. Whenever an update needed to occur on the Swing window, Swing would render that region into the upper left area of the back buffer and then copy that region into the proper location in the window.

The end result was that the contents in the back buffer were not persistent, nor did they typically reflect the contents in the Swing window. For example, if another window was dragged across the Swing window and caused that window to be updated, then Swing would have to repaint that entire area again, because it didn't know what used to be there.

With this new approach, Swing now has a separate buffer for each Swing window on the screen, and those buffers' contents are kept synchronized with the graphics in the actual window. So now, if you drag a window across the Swing application window, Swing can simply copy from the back buffer to the screen and save all the work of erasing and then repainting that area.

What's more, Swing does this fast-copy operation on the native event thread, which means that there is an immediate response.

Figure 4 shows the relative speeds of NetBeans IDE window validations with different JDK releases.

Figure 4. NetBeans IDE Window Validations With Different JDK Releases
 
LCD Text

From the blog entry " Phil's Font Fixes" by Chet Haase and Phil Race

One of the most frequently requested features has been for JDK 6 to support subpixel text. This is an optimization for LCD displays that uses subpixel striping to increase the text resolution. Because of the way users apply and configure it, subpixel text is often considered a form of text antialiasing.

The good news is that JDK 6 implements this feature. Whether you use the look and feel of Metal, Microsoft Windows, or GTK, you will get the same antialiasing behavior for fonts in Java technology-based applications as you do in native applications. Best of all, you don't have to do anything -- it just works out of the box.

In order to achieve this, the look and feel of Windows and of GTK have also been updated to track the user's desktop preferences and update any preference changes in real time. Also, the default Java technology look and feel, Metal, now reads the user's desktop text-antialiasing preferences on startup and applies them to the JDK fonts. When used together with the Metal "Ocean" theme, which uses plain fonts instead of bold, the result is quite pleasing to the eye, as shown in Figure 5.

Figure 5. Java Metalworks Demo (Ocean Theme)
Click here for a larger image
 

Swing supports five new values for java.awt.RenderingHints.KEY_TEXT_ANTIALIASING on all platforms:

  • VALUE_TEXT_ANTIALIAS_LCD_HRGB
  • VALUE_TEXT_ANTIALIAS_LCD_HBGR
  • VALUE_TEXT_ANTIALIAS_LCD_VRGB
  • VALUE_TEXT_ANTIALIAS_LCD_VBGR
  • VALUE_TEXT_ANTIALIAS_GASP

The first four correspond to the four possible LCD-subpixel configurations. Native GTK applications support all four of these. On Windows, you will need at least XP to get LCD text support in native applications, although Microsoft only supports HRGB on Windows XP, and the company added HBGR in XP Service Pack 1 (SP1). The JDK supports LCD text on all Windows versions.

The JDK uses the final hint value, VALUE_TEXT_ANTIALIAS_GASP, to precisely emulate the "standard" font smoothing in Windows, which is what users with older CRTs need. Note that with this setting, not all text is antialiased. Instead, this setting uses a table in the font, called the GASP table, which stipulates the sizes at which smoothing should be done.

To demonstrate this, look at the JTable demo tab from the SwingSet2 demo. Figure 6 shows it without LCD text.

Figure 6. SwingSet2 Demo Without LCD Text
Click here for a larger image
 

Figure 7 shows it with LCD text.

Figure 7. SwingSet2 Demo With LCD Text
Click here for a larger image
 

The screen capture in Figure 8 shows the same fonts and text as they are rendered with Windows WordPad on the left and with a small JDK application on the right. The fonts used here are ones that users typically see in Windows applications.

Figure 8. LCD Fonts in WordPad and JDK
Click here for a larger image
 

Figure 9 is a screen capture that compares some of the more common fonts seen in Gnome applications on Linux alongside the JDK rendering of these fonts. The Gnome text was rendered on Fedora Core in the gedit application. Because gedit can use only one font at a time, several screens of text were captured and stitched together using the GNU Image Manipulation Program (GIMP).

Figure 9. LCD Fonts Using gedit in Fedora Core
Click here for a larger image
 

A few notes:

  • First, these images are prepared for viewing on an HRGB LCD display. That is by far the most common type of LCD display. If you are using a CRT, don't expect to see much improvement. In addition, if your LCD display is connected by a VGA connector instead of a DVI, you won't see the best display either. A VGA connector just doesn't have the precise addressability needed to obtain good results from this.

  • In addition, automatic image scaling in your browser may alter the images. If they look odd, try disabling automatic image resizing or just saving the images and loading them with a local image-viewing application instead.

Single-Threaded Rendering

Compiled from the blog entries " STR-Crazy: Improving the OpenGL-based Java 2D Pipeline" and " STR-Crazier: Performance Improvements in JDK 6" by Chris Campbell

Until now, Java 2D rendered its graphics on arbitrary Java threads. With single-threaded rendering (STR), requests are now queued at the Java platform level, then executed at the native operating system (OS) level on a single thread. However, this feature is not as visible as many others in JDK 6. At present, STR is implemented only in the OpenGL rendering pipeline, which is not enabled by default due to various driver and hardware issues.

Besides being extremely useful from a graphics-software perspective, STR offers significant improvements both for the current OpenGL pipeline and for future rendering pipelines that will use this approach.

OpenGL rendering offers benefits both in robustness, as multithreaded rendering in OpenGL tends to cause problems for many video cards, and in performance, as the batching of rendering requests saves significantly in overhead in both the Java Native Interface (JNI) and the OpenGL API. Future Java SE releases will likely use the STR approach in other rendering pipelines, such as the default DirectX renderer on Windows, and provide similar benefits.

As most developers are already aware, JDK 5.0 included an OpenGL-based Java 2D pipeline to improve rendering performance. Although the OGL pipeline was a big step forward for rendering performance of complex operations such as transforms, compositing, and gradients, it was not nearly as robust as the existing X11- and DirectX-based pipelines. This meant that users evaluating their Java technology-based applications with the OGL pipeline enabled would see frequent crashes and rendering artifacts.

What was causing these crashes? If you're familiar with OpenGL, you probably know that it's important to do all your rendering from a single thread. Although it is possible to render from other threads, OpenGL drivers are optimized for the single-threaded case. Developers are not quite as lucky in Java 2D. Rendering requests can come from any number of threads, including the event-dispatching thread or a user thread.

In JDK 5.0, the Java platform dealt with this by taking precautions such as these:

  • Ensuring that only one thread is calling an OpenGL method at any given time
  • Using OpenGL rendering contexts only from the thread on which they were created

This makes OpenGL drivers reasonably functional, but it requires more labor from the Java technology, which means reduced performance. And despite all efforts, drivers can still crash when there are many rendering threads in use by an application.

Clearly, something needed to be done if the OGL pipeline was ever to become reliable enough for day-to-day use by end users. For the past couple of years, several people on the Swing team have discussed the idea of single-threaded rendering, which would allow the Java libraries to interact with native graphics libraries, such as OpenGL, from a single thread.

The idea originally came up as a possible solution to a number of threading problems that the Swing team had dealt with in the past on the Windows side. But what better way to test these ideas than to implement them using the OGL pipeline? So that's what the team set out to do in JDK 6. Instead of the scenario in Figure 10, in which multiple threads touch the native graphics layer, a more elegant solution appears in Figure 11.

Figure 10. Multithreaded Rendering
 
Figure 11. Single-Threaded Rendering
 

Here are some quick numbers from a test Linux configuration (JDS, 2x 2.6GHz P4, Nvidia GeForce FX 5600). The numbers look similar on the Solaris Operating System and on Windows:

  • SwingMark, an internal Swing benchmark, is approximately 15 percent faster.

  • The drawString() method is about 250 percent faster, according to J2DBench.

  • The fillRect() and drawLine() methods are up to 2500 percent faster, according to J2DBench.

  • FireStarter, an internal demo, renders about 2600 transformed, filtered, blended sprites per frame at 30 frames per second, as opposed to only 1600 sprites before STR.

In JDK 6, the Swing team also set out to reduce the overhead of small rendering operations, where small refers to operations in which only a few pixels are touched -- for example a 10x10 pixel fillRect() operation. Reducing overhead in these cases is very important in improving overall Swing performance because Swing typically touches small areas at a time. For example, if you click a JButton, a small area is filled with a color or gradient, then a few lines and some text are rendered on top of that. Anything that can get those pixels on the screen sooner will improve users' perception of the responsiveness of Swing applications.

Many of the overhead reductions came with the following bug fixes:

  • 6255545: OGL: avoid redundant texture state-setting calls
  • 6280588: OGL: avoid enable/disable GL_TEXTURE_2D around every texturing operation
  • 6273431: OGL: improve performance of parameter queuing

With those fixes integrated in JDK 6, it's a good time to step back and chart how much progress the Swing team has made. Figure 12 shows the chart.

Figure 12. OpenGL Pipeline Improvements in Java SE 6
 

Here are the big takeaways:

  • The chart in Figure 12 shows the performance improvements made to the OGL-based Java 2D pipeline in JDK 6 (blue bars), compared to the OGL pipeline in JDK 5.0 (orange bars) and the default X11 pipeline in JDK 6 (green bars).

  • Of course, this is just a small representative sampling of operations. Hundreds of other operations are now much faster when the OGL pipeline is enabled, some just a few percent better than X11, and others are 10 to 40 times faster.

  • These performance wins are similar across all platforms: Windows, Linux, and Solaris OS.

  • Many of the improvements can be attributed to the STR project and the overhead reductions for small rendering operations.

  • Because these operations are accelerated in graphics hardware, CPU utilization can be significantly lower when the OGL pipeline is enabled.

Even with these improvements, the X11 pipeline still beats the pants off the OGL pipeline in a few operations, due to some highly optimized loops in the Xserver -- for example, small filled ovals. The Swing team will continue to address the most important cases, so ideally the OGL pipeline will close that performance gap.

Native Look and Feel

From the blog entry " Hi-Fi Swing (Or Improving the Native Fidelity of Swing System L&Fs)" by Bino George

One of Swing's biggest strengths is its lack of a rigid coupling between the underlying platform toolkit and the Swing API. The Swing API was designed to be extensible and free from platform limitations. However, the freedom from platform restrictions comes at some cost in terms of engineering the Swing toolkit. Swing engineers have to make conscious trade-offs between native fidelity and platform independence. Over the years, users have requested that the Swing team provide the absolute best fidelity for system look-and-feel user interfaces.

Theming the Windows desktop has been popular for many years. For example, PC manufacturers such as Sony or Gateway have shipped custom Windows themes that provide a branded look that identifies the desktop with the system manufacturer. In addition, many users like the power and flexibility of customizing the desktop.

One of the most popular theming applications for Windows is WindowBlinds. In fact, WindowBlinds was so popular that Microsoft worked with the product's author to develop a new API that exposes the rendering of Windows controls: the UxTheme API. Windows XP provides a new default XP look and feel, based on UxTheme, that users can extend using the UxTheme API.

In JDK 5.0, the Swing team provided support for the Windows XP look and feel. The mechanism used to provide this support was based on reading the resources embedded in the XP Styles files and using those icons and colors to render the Windows look and feel. Unfortunately, Microsoft has changed the Styles files in Windows Vista so that the resources are no longer visible using the mechanism in JDK 5.0. So naturally when the developers ran the current JDK under Windows Vista, their applications fell back to the Windows classic look and feel used in Windows 2000. Swing will always fall back to this look and feel if it is unable to load the XP look and feel.

After some discussions between engineers from the Swing team and from Microsoft's graphics team, the Microsoft team suggested that the way to work with the Windows Vista themes was to use the UxTheme API. So a few Swing-Windows look-and-feel authors prototyped a version of the Windows XP look and feel that uses the UxTheme engine to perform the rendering of Swing components. The authors then tested the prototype under Windows Vista and found that the rendering of the Vista theme was pixel perfect with UxTheme. This lead us to the re-implementation of the Windows look and feel using UxTheme, and this new implementation is available in JDK 6.

A Look Ahead

Part 2 of this article will discuss additional new and updated features in Java SE 6: table sorting and filtering, improvements to the Image I/O library, the new modality model, and the desktop API.

_______
* As used on this web site, the terms "Java Virtual Machine" or "JVM" mean a virtual machine for the Java platform.

For More Information

Overall:

Splash Screens

System Tray

Look and Feel

  • JavooToo contains a nice list of custom look and feel designs.  

Java Platform

Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
Your email address (no reply is possible without an address):
Sun Privacy Policy

Note: We are not able to respond to all submitted comments.