Open source Java projects: Java Native Access

An easier way to access native code

1 2 3 4 5 Page 5
Page 5 of 5

Transparent windows

The previous article in this series focused on Bernhard Pauler's balloontip project. For that article, I built an application GUI, called VerifyAge, that included a balloon tip. Figure 1 reveals one small problem with the GUI: the balloon tip's undecorated dialog container hides part of the window's frame, preventing access to the frame's Minimize and Maximize buttons, and making the overall GUI look unsightly.

It is not possible to minimize the GUI when the balloon tip is displayed.
Figure 1. It is not possible to minimize the GUI when the balloon tip is displayed

Although it would have been better to render that part of the undecorated dialog not presenting the balloon tip transparent, Java does not support transparent windows. Fortunately, we can solve this problem using the com.sun.jna.examples.WindowUtils class located in JNA's examples.jar file.

WindowUtils provides utility methods that use JNA to achieve transparent windows on Unix, Linux, Mac OS X, and Windows platforms. For example, public static void setWindowMask(final Window w, Icon mask) lets you choose which part of a window to make transparent based on pixels not defined by its mask argument. This task is demonstrated in Listing 10.

Listing 10. Using JNA to render a window transparent

// Create a mask for this dialog. This mask has the same shape as the
// dialog's rounded balloon tip and ensures that only the balloon tip
// part of the dialog will be visible. All other dialog pixels will
// disappear because they correspond to transparent mask pixels.

// Note: The drawing code is based on the drawing code in
// RoundedBalloonBorder.

Rectangle bounds = getBounds ();
BufferedImage bi = new BufferedImage (bounds.width, bounds.height,
                                      BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.createGraphics ();
g.fillRoundRect (0, 0, bounds.width, bounds.height-VERT_OFFSET,
                 ARC_WIDTH*2, ARC_HEIGHT*2);
g.drawRoundRect (0, 0, bounds.width-1, bounds.height-VERT_OFFSET-1,
                 ARC_WIDTH*2, ARC_HEIGHT*2);
int [] xPoints = { HORZ_OFFSET, HORZ_OFFSET+VERT_OFFSET, HORZ_OFFSET };
int [] yPoints = { bounds.height-VERT_OFFSET-1, bounds.height-VERT_OFFSET
                   -1, bounds.height-1 };
g.fillPolygon (xPoints, yPoints, 3);
g.drawLine (xPoints [0], yPoints [0], xPoints [2], yPoints [2]);
g.drawLine (xPoints [1], yPoints [1], xPoints [2], yPoints [2]);
g.dispose ();
WindowUtils.setWindowMask (this, new ImageIcon (bi));

The code fragment in Listing 10 is an excerpt from the end of the TipFrame constructor in an enhanced VerifyAge2 application, which is included in this article's code archive. The constructor defines a mask in the shape of the rounded balloon tip, where only drawn pixels are non-transparent.

Assuming that your current directory contains examples.jar, jna.jar, and VerifyAge2.java, invoke javac -cp examples.jar;balloontip.jar VerifyAge2.java to compile the source code. Then invoke java -Dsun.java2d.noddraw=true -cp examples.jar;balloontip.jar;. VerifyAge2 to run the application. Figure 2 reveals transparency.

You can now minimize the GUI when a balloon tip appears.
Figure 2. You can now minimize the GUI when a balloon tip appears

In conclusion

JNA is a project with a long history (stretching back to 1999) but it was first released in November 2006. Since then it has been slowly gaining the attention of developers who need to integrate native C code into Java-based projects. JNA has also made some waves among JRuby programmers because it can be used to work around one of JRuby's pervasive problems, lack of support for POSIX calls. JNA has also been proposed as a solution for extending Ruby with low-level C code.

I enjoyed working with JNA and believe you will find it easier and safer to use than JNI for accessing native code. Needless to say, there is more to JNA than I could cover in a single article. See the Resources section to learn more about this open source Java project. Experiment with it and share your experiences in the discussion forum for this series. I'll be back next month with another lesser known open source project that could benefit your everyday Java development.

Addendum: An alternative to WindowUtils.setWindowMask()

Shortly after writing this article I discovered that Java supports translucent and shaped windows as of the 6u10 build. After reading about this topic in Kirill Grouchnikov's blog, I modified VerifyAge2 to use this new alternative to WindowUtils.setWindowMask(), as follows:

// Create and install a balloon tip shape to ensure that only this part
// of the dialog will be visible.

Rectangle bounds = getBounds ();
GeneralPath gp;
gp = new GeneralPath (new RoundRectangle2D.Double (bounds.x, bounds.y,
                                                   bounds.width,
                                                   bounds.height-
                                                   VERT_OFFSET,
                                                   ARC_WIDTH*2-1,
                                                   ARC_HEIGHT*2-1));
gp.moveTo (HORZ_OFFSET, bounds.height-VERT_OFFSET);
gp.lineTo (HORZ_OFFSET, bounds.height);
gp.lineTo (HORZ_OFFSET+VERT_OFFSET+1, bounds.height-VERT_OFFSET);
AWTUtilities.setWindowShape (this, gp);

This code uses the new AWTUtilities class (located in the com.sun.awt package) and its public void setWindowShape(Window w, Shape s) method to reshape the TipFrame JDialog window into a balloon shape.

Jeff Friesen is a freelance software developer and educator who specializes in Java technology. Check out his javajeff.mb.ca website to discover all of his published Java articles and more.

Learn more about this topic

1 2 3 4 5 Page 5
Page 5 of 5