Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Here's an excerpt taken from one of JDK 1.3's header files that explains the background and the reasons behind the new API:
The AWT native interface allows a native C or C++ application a means by which to access native structures in AWT. This is to facilitate moving legacy C and C++ applications to Java and to target the need ... [for these applications] to do their own native rendering to canvases for performance reasons.
Up until JDK 1.3, there was no defined way for Java programs to access the handles of underlying peer GUI components. With
JDK 1.3, Sun has created a standard mechanism by which developers can allow native GUI APIs and libraries to render inside
a Java AWT Canvas object. This means that there is now an official, supported way to obtain the information that supports this functionality.
And when JDK 1.3 is ported to other platforms, all the ports will expose the same information -- no matter what system is
being used. JDK 1.3 for Windows and JDK 1.3 for Solaris are the first implementations to provide this support.
Sun is introducing this feature for several reasons. First, it allows complex legacy software with third-party dependencies to be migrated to Java before those dependencies themselves complete migration. The second reason is performance; if the native GUI code has been fine-tuned over a long period of time with huge effort, then it makes business sense to leave it unchanged.
In this article, I will introduce the concepts behind this feature. I'll develop a sample widget step by step, which uses the Win32 API to do the rendering. Here is a snapshot of the final widget, a circular window with a smiley face.

The sample widget in action.
MyWindow, say -- that extends Canvas and overrides the paint method. You use the paint method to draw operations for AWT objects, and override it using the keyword native. Overriding it in this way allows you to use your own native code. You must build your native code and compile it into a
dynamic link library (DLL), just as you would with any other JNI application -- we'll call the library MyWindow.DLL in this case. The equivalent for Solaris or Linux would be a shared object/library. You also need to load this library into
your Java class MyWindow, using a System.loadLibrary("MyWindow") call.The two elements you'll need in order to do this are MyWindow.Java, which provides the class that extends the Canvas class, and MyWindow.CPP, which contains the JNI-based entry point for the paint routine. You can find MyWindow.Java, MyWindow.CPP, and a batch file for automating the BUILD.BAT build in the Resources section below.
java.awt.Canvas class. This is why MyWindow extends Canvas, as shown below. MyWindow can be used just like any other Canvas-derived class in your Java application; in our example, I've added MyWindow to Jwindow.
import java.awt.*; import javax.swing.*;
public class MyWindow extends Canvas {
static {
// Load the library that contains the paint code.
System.loadLibrary("MyWindow");
} // native entry point for Painting
public native void paint(Graphics g); public static void main( String[] argv ){
Frame f = new Frame();
f.setSize(300,400); JWindow w = new JWindow(f);
w.setBackground(new Color(0,0,0,255));
w.getContentPane().setBackground(new Color(0,0,0,255));
w.getContentPane().add(new MyWindow());
w.setBounds(300,300,300,300);
w.setVisible(true);
} }
Notice that you load MyWindow.DLL in the static block. This is how your Java application gets access to the native code. (I'll develop that native code momentarily.)
Also notice that the paint method is declared native and has no implementation; this let's the virtual machine know that it is supposed to call the
native method from the DLL loaded in the static block.
javah MyWindow.class. First, you should make sure the class file is in your CLASSPATH. Here's part of the generated MyWindow.h, which shows the function declaration.
/* * Class: MyWindow * Method: paint * Signature: (Ljava/awt/Graphics;)V */ JNIEXPORT void JNICALL Java_MyWindow_paint
(JNIEnv *, jobject, jobject);
MyWindow.CPP, which has the native code for the paint routine needed in MyWindow.Java.#include <windows.h>
#include <assert.h>
#include "jawt_md.h"
#include "MyWindow.h"
#define X(x) (int)(xLeft + (x)*xScale/100) // Scaling macros
#define Y(y) (int)(yTop + (y)*yScale/100) // so scale is 0 - 100
#define CX(x) (int)((x)*xScale/100)
#define CY(y) (int)((y)*yScale/100)
void DrawSmiley(HWND hWnd, HDC hdc);
HRGN hrgn = NULL;
JNIEXPORT void JNICALL
Java_MyWindow_paint(JNIEnv* env, jobject canvas, jobject graphics)
{
JAWT awt;
JAWT_DrawingSurface* ds;
JAWT_DrawingSurfaceInfo* dsi;
JAWT_Win32DrawingSurfaceInfo* dsi_win;
jboolean result;
jint lock;
// Get the AWT
awt.version = JAWT_VERSION_1_3;
result = JAWT_GetAWT(env, &awt);
assert(result != JNI_FALSE);
// Get the drawing surface
ds = awt.GetDrawingSurface(env, canvas);
if(ds == NULL)
return;
// Lock the drawing surface
lock = ds->Lock(ds);
assert((lock & JAWT_LOCK_ERROR) == 0);
// Get the drawing surface info
dsi = ds->GetDrawingSurfaceInfo(ds);
// Get the platform-specific drawing info
dsi_win = (JAWT_Win32DrawingSurfaceInfo*)dsi->platformInfo;
HDC hdc = dsi_win->hdc;
HWND hWnd = dsi_win->hwnd;
//////////////////////////////
// !!! DO PAINTING HERE !!! //
//////////////////////////////
if(hrgn == NULL)
{
RECT rcBounds;
GetWindowRect(hWnd,&rcBounds);
long xLeft = 0; // Use with scaling macros
long yTop = 0;
long xScale = rcBounds.right-rcBounds.left;
long yScale = rcBounds.bottom-rcBounds.top;
hrgn = CreateEllipticRgn(X(10), Y(15), X(90), Y(95));
SetWindowRgn(GetParent(hWnd),hrgn,TRUE);
InvalidateRect(hWnd,NULL,TRUE);
} else {
DrawSmiley(hWnd,hdc);
}
// Free the drawing surface info
ds->FreeDrawingSurfaceInfo(dsi);
// Unlock the drawing surface
ds->Unlock(ds);
// Free the drawing surface
awt.FreeDrawingSurface(ds);
}
void DrawSmiley(HWND hWnd, HDC hdc)
{
RECT rcBounds;
GetWindowRect(hWnd,&rcBounds);
long xLeft = 0; // Use with scaling macros
long yTop = 0;
long xScale = rcBounds.right-rcBounds.left;
long yScale = rcBounds.bottom-rcBounds.top;
// Pen width based on control size
int iPenWidth = max(CX(5), CY(5));
HBRUSH brushBlack;
HBRUSH brushYellow;
HPEN penBlack = CreatePen(PS_SOLID, iPenWidth, RGB(0x00,0x00,0x00));
// Null pen for drawing filled ellipses
HPEN penNull = CreatePen(PS_NULL, 0, (COLORREF)0);
brushBlack = CreateSolidBrush(RGB(0x00,0x00,0x00));
brushYellow = CreateSolidBrush(RGB(0xff,0xff,0x00));
HPEN pPenSave = (HPEN)SelectObject(hdc, penBlack);
HBRUSH pBrushSave = (HBRUSH)SelectObject(hdc,brushYellow);
Ellipse(hdc,X(10), Y(15), X(90), Y(95)); // Head
Arc(hdc,X(25), Y(10), X(75), Y(80), // Smile mouth
X(35), Y(70), X(65), Y(70));
SelectObject(hdc,&penNull); // No draw width
SelectObject(hdc,&brushBlack);
Ellipse(hdc,X(57), Y(35), X(65), Y(50));
Ellipse(hdc,X(35), Y(35), X(43), Y(50)); // Right eye
Ellipse(hdc,X(46), Y(50), X(54), Y(65)); // Nose
SetBkMode(hdc,TRANSPARENT); // Use ForeColor
SelectObject(hdc,pBrushSave);
SelectObject(hdc,pPenSave);
}
The key data structure here is JAWT, which is defined in jawt.h (included with jawt_md.h). It provides access to all the information the native code needs be able to draw on the Java-based GUI component. The first
part of the native method is boilerplate: it populates the JAWT structure, gets a JAWT_Win32DrawingSurfaceInfo structure, locks the surface (only one drawing engine at a time, please!), and then gets a JAWT_DrawingSurfaceInfo structure that contains a pointer (in the platformInfo field) to the necessary platform-specific drawing information. It also includes the bounding rectangle of the drawing surface
and the current clipping region. For more information, dig into jawt.h and jawt_md.h (see the section entitled "Build the environment," below).