Wednesday, September 12, 2007

Run your Java program as an NT service

Thomas Boerkel has contributed some mappings and code to the JNA project to facilitate access to Windows' user accounts, registry, and NT services. Included is an abstract class which is capable of installing, uninstalling, and running itself as an NT service. What sets this little gem apart from most available wrappers is that you don't need a Windows executable stub; the complete Windows service API is available to your Java program, including all system events and callbacks.

You can browse the source here. A NetBeans project is included.

I was working on an abstract service class as well but Thomas beat me to completion. Great work, Thomas!

Update: Make sure your classpath and classes are accessible by the local system account, or the service won't be able to start. To see if this is the issue, you can temporarily change the service to start using your user identity; if it works, then the problem is that the local system account doesn't have access.

Thursday, September 06, 2007

Is final not final, or just not the final I wanted?

While adding some VM crash protection to JNA, I ran into this situation:


public class Pointer {
public static final int SIZE = Native.POINTER_SIZE;
}

public class Native {
public static final int POINTER_SIZE;
static {
initIDs();
POINTER_SIZE = pointerSize();
}
private static native int pointerSize();
}


I had just moved the native initialization code from Pointer to Native. All the native methods were private, so the only changes were to update those two classes and rename the native methods. But when I reran the test suite, I started getting a host of errors.


There errors were all caused by Pointer.SIZE having a zero value. I figured that since Pointer.SIZE was final, the value it was assigned from must also have been zero. A quick inspection on Native.POINTER_SIZE, however, showed that it was propertly initialized and non-zero. How, then, could Pointer.SIZE be zero if Native.POINTER_SIZE was not?


Anyone who has done any JNI is probably aware that Java access modifiers don't mean anything to native code. My first thought was that perhaps "final" modifiers don't mean anything either. Only problem is that I was never touching that Pointer.SIZE field in native code. Never even accessed it.


Scanning though the native initialization code, I noticed that, among a host of standard JRE classes, a reference to the Pointer class was being created. This turns out to be the cause of my problem: during Native class initialization, the Pointer class was loaded from JNI. When the pointer final field was initialized, it got the value from a not-yet-initialized Native class.


Turns out, this can be duplicated with pure Java code:


public class LoadTest {
public static final int VALUE;
static {
System.out.println("value=" + Secondary.VALUE);
VALUE = 1;
System.out.println("value=" + Secondary.VALUE);
}
}

class Secondary {
public static final int VALUE = LoadTest.VALUE;
}


When loaded, the class prints "value=0" twice, so final is final, just not the value I intended. Here, the problem is more apparent because the class dependency is clearly visible, which wasn't the case with the JNI initialization.


Maybe I'll call this antipattern something curiously obscure, like "Law of the Polygamist's Second Wife".

Monday, July 23, 2007

Demo sources

All source for demos in previous blog entries is now available via SVN on SourceForge. The project page is here.

All sources are provided under the LGPL.

Wednesday, June 27, 2007

Improved Window Shaping

Thanks to contributions from Olivier Chafik and Chris Deckers, the overhead for setting a window shape mask has been reduced by about two orders of magnitude. In this case, the balloon tip windows no longer have such a noticeable delay before showing.

Linux users should also have fewer issues with this version; some of the library setup previously required is now taken care of automatically by the JNA library.



Saturday, May 12, 2007

Easier Alpha Masks

The per-pixel alpha masking in this post has been codified into a simple API.

WindowUtils.setWindowTransparent(Window w, boolean transparent);

This effectively gives the window a transparent background. The alpha levels of the window's contents are preserved.

The demo is similar to the previous one but adds a few standard components to the mix.



UPDATE If you have a linux system and this for some reason doesn't work, please post a comment to that effect, or post a message to users@jna.dev.java.net so we can ensure this works reliably across all linux systems (64-bit is in the works).

Wednesday, April 25, 2007

Improved Drag Images

A while back I posted some drag/drop handling code that included drag images that were closer to real drag image support, but were restricted to only showing up on windows belonging to the same VM.

Now, thanks to the window masking and transparency utilities provided by JNA, the drag images can escape the bounds of java windows.





This wasn't quite as easy as expected, even with the shaped, transparent windows already taken care of.

First, I had intended to use Swing's built-in drag support, given that Shannon Hickey has put so much work into improving it. Unfortunately, that built-in support, while making some operations very easy, makes others impossible. Namely, drag image support requires updating the image's location in response to cursor motion. While it's technically possible to listen for motion outside the drag operation using a global DragSource listener, that's a hacky workaround. So instead, I fall back to raw DnD with DragGestureListener, DragSourceListener, et al. These provide the necessary hooks to move the drag image, and I already have some abstract base classes that provide a basic, customizable implementation.

Next, I uncovered a bug in the JNA example code converting an Icon into a region mask. It turns out that a BufferedImage of type TYPE_BYTE_BINARY applies something like a 50% luminance threshold, when what I really wanted was a zero/non-zero threshold based on the alpha component of the icon's pixels. I tried writing my own binary Composite to do just that, but wound up with errors downstream of the actual composite operation. Fortunately, BufferedImage.getAlphaRaster on a standard ARGB image gives me pretty much what I want.

Finally, once I instantiated a window under the current drag operation, I could no longer drop anywhere. Which makes sense when you consider there is now a window in between the cursor and any place you'd like to drop. I almost gave up thinking this was an intractable problem given that DnD is so tightly wound up with native implementations, but I'm always game for one more variation. Remember that a window region can have holes in it, where events pass through to whatever lies beneath. Well, what if we put a hole right where the cursor is? Since it's directly under the cursor, it's not really apparent, but it allows events to pass through to the underlying drop target. We only need a single pixel, because that's all the DnD system cares about (I initially made it much bigger just so I could be sure I put it in the right place). Voila! It works.

Wednesday, April 18, 2007

Alpha-mask Transparency for a Window

Finally got per-pixel alpha mask working on w32. The included image isn't the greatest for showing an antialiased edge (it does have one), but if you have something with a drop shadow lying about, just drop it on the demo window and that'll be used instead.

Update This demo works on Windows, OSX and Linux (Linux requires JRE1.5+).



Update Here's another image to drop on the demo window, which better demonstrates the alpha blending, in case you don't have any handy


I've got some working X11 code, too, but I need to figure out a decent API to make it happen. OSX lets you just set the window background pixel transparent and then everything you paint in the window is automatically composited with whatever alpha mask you paint with. That could probably work with Swing as well, but you have to magically drop anything with a default background. OSX does this by checking for a magic UIResource color; anything painted with that color is fully transparent.

Update Source is available on BRANCH_V2 from JNA.

I realize I may be an utter dolt, but I find it really hard to follow Microsoft APIs. I've worked with Qt, X11/Xt, and Mac, each of which has its peculiarities of architecture, but those have a consistency (might I say design) that spans more than two or three functions.

Friday, April 13, 2007

Java Transparent Windows (X11 update)





Update: If your X11 setup supports it (XFCE, metacity + xcompmgr, compiz, etc), the JNA shaped window demo now has window transparency.

Thanks to Romain Guy for some initial testing and VMWare for making experimental linux installations easier.

Update: BTW, the linux setup I used was ubuntu (after installing xubuntu packages to get xfce; should have started with xubuntu). Note that the transparency is similar to that on OS X and w32, i.e. a single alpha level for the entire window. Next up is to apply a per-pixel alpha mask, if I can scrounge up some samples of how to do it on each platform.

I added some features to JNA to facilitate working with the X11 visual lookups (it returns an array of structures), so a few more files got changed than just the examples jar. If you want the latest and greatest, you'll need to check out from CVS and do 'ant examples-jar'.

Thursday, April 05, 2007

Another thing that sucks about applets...

You can't easily make the background color match the web page. You'd think that Applet.setBackground() would just Do the Right Thing.

You don't necessarily want to hard-code a value into the applet, but even if you set a value via javascript/livescript, you've got to do extra work to make it propagate down the hierarchy.

This is also applicable to Swing; you can't set a background color on a parent component and have it propagate to descendants. The first non-opaque component you run into is going to get its background from the UIManager. I really don't want to have to figure out which UIManager colors I have to override just to set the bloody background color of my app.

Maybe the new JSR 296 will do something about this, maybe not, but it'd be nice to have something akin to the old X toolkit's resource specifiction:

*.background: red
*.JCheckBox.background: red
JApplet.*.background: red
named-applet.*.background: red

The idea is that you can isolate or aggregate just about anything in the hierarchy by name or by class, and apply a resource setting to it (I guess they're calling it "injection" these days).

Animated Per-panel Options Pane

Here's another example in the search for an unobtrusive property editor. This one looks a little like the Google Maps thumbnail navigator (at least with respect to its activator).


Contents




The API is simple:


// This component's preferred size will normally be that of its content
container.add(new OptionsPanel(content, options));


The purpose of this component is to unobtrusively associate a nontrivial set of options with some content whose display is typically larger than the options themselves. The options display is kept close the the content it modifies, which avoids the user having to go search through menus or play dialog positioning games. Since the options are hidden by default, you also don't have them always using up screen real estate. This sort of thing is often wedged into a docking solution, which is inappropriate if the information doesn't need to be visible at all times. A docking solution also insists on allocating the whole edge of the dock, so if you don't have other junk that has to be in there, you're wasting a lot of space.

The OptionsPane component wraps the content in the center of a BorderLayout and keeps the PAGE_END slot available for the options themselves.

Toggle Button Positioning


Notice that the toggle button isn't affected by the border layout (or any other content, for that matter). The toggle button has been placed in a layer above the rest of the content, so it's always visible and doesn't contribute to any layout complexity.

JRootPane root = SwingUtilities.getRootPane(this);
if (root != null) {
layered = root.getLayeredPane();
if (layered != null) {
int layer = JLayeredPane.DEFAULT_LAYER.intValue();
layered.add(toggle, new Integer(layer + 1));
updateButtonLocation();
}
}

We also want to update the button location whenever the OptionsPane moves. While we could use a ComponentListener, that would update the button's location after the OptionsPane was moved/resized, resulting in some jerkiness to the display. So instead, the button gets moved at the same time as the parent component:

public void setBounds(int x, int y, int w, int h) {
super.setBounds(x, y, w, h);
updateButtonLocation();
}


Layout Animation


Rather than instantly making the options visible and doing a single relayout, we use a javax.swing.Timer to gradually grow the options from the lower right corner into its final position. The bottom slot of BorderLayout will respect a component's height, but stretch or squash the component to the pane's current width. So changing the height gradually will work, but changing the width will have no effect (the component simply appears to rise from the bottom of the panel, rather than from the lower right).

Rather than changing the width, we use an empty border in a JPanel wrapped around the options component. By changing the width of the left border, the options appear to grow from the left to the right.

The animation increment is simple (move half the remaining distance), which is pretty good for most purposes. This is the Timer configuration in response to the expansion button click:

final int INTERVAL = 50;
final int FRACTION = 2;
final boolean expanded = isExpanded;
Timer timer = new Timer(INTERVAL, new ActionListener() {
public void actionPerformed(ActionEvent e) {
Insets insets = optionsBox.getInsets();
Insets delta = targetInsets(expanded);
Dimension targetSize = targetSize(expanded);
int dx = (delta.left - insets.left)/FRACTION;
if (dx != 0) {
insets.left += dx;
optionsBox.setBorder(new EmptyBorder(insets));
optionsBox.revalidate();
repaint();
}
int dy = (targetSize.height - optionsBox.getHeight())/FRACTION;
if (dy != 0) {
Dimension size = optionsBox.getSize();
size.height += dy;
optionsBox.setPreferredSize(size);
optionsBox.revalidate();
revalidate();
repaint();
}
if (Math.abs(dx) <= 1 && Math.abs(dy) <= 1) {
((Timer)e.getSource()).stop();
toggle.setEnabled(true);
if (!expanded) {
remove(optionsBox);
}
revalidate();
repaint();
}
}
});
timer.setRepeats(true);
timer.start();

You can play around with the FRACTION and INTERVAL constants to see the effect it has on the animation.

Source is available in the applet jar file in the article link.

Monday, April 02, 2007

Speech Bubble Update (with Drop Shadow)


I added a drop shadow to the speech bubble. You don't need it on OSX (OSX provides one automatically), and I don't have compiz or similar compositing window manager installed on linux at the moment (although if anyone is willing to submit/test the corresponding code, I'm happy to include it).

Nothing fancy, just black with 50% alpha. The shadow mask is just the original mask, sheared, scaled, and offset. The drop shadow would probably look nicer with a blurred edge, but that likely requires a variable alpha setting for the window (although you might be able to fake it by varying the edge color). Applying per-pixel alpha masks prior to Windows Vista seems to be non-trivial (this example uses a single alpha value for the entire window).

The JNA function definitions are trivial:


int GetWindowLongA(Pointer hWnd, int nIndex);
int SetWindowLongA(Pointer hWnd, int nIndex, int dwNewLong);
boolean SetLayeredWindowAttributes(Pointer hwnd, int crKey,
byte bAlpha, int dwFlags);


As is the actual usage:


Pointer hWnd = getHWnd(w);
User32 user = User32.INSTANCE;
int flags = user.GetWindowLongA(hWnd, User32.GWL_EXSTYLE) | User32.WS_EX_LAYERED;
user.SetWindowLongA(hWnd, User32.GWL_EXSTYLE, flags);
user.SetLayeredWindowAttributes(hWnd, 0, (byte)(255*alpha), User32.LWA_ALPHA);


The only real trick is that DirectDraw must be disabled in order to get the transparency effect and avoid leaving behind painting artifacts.

java -Dsun.java2d.noddraw=true ...

NOTE: thanks to l2fprod for the hint and the original round, transparent clock!

Update: Demo is now available from the JNA homepage.

Wednesday, March 28, 2007

Give your application a speech bubble

As a result of an argument about the best way to present meta-information about complex application objects presented to the user, I had to come up with some concrete alternatives.

The problem is that for a given item in the application (in this case an SVN-based revision control client that aggregates and presents large amounts of meta-information about the repository), there may exist information that just doesn't fit in the display. You want to provide the user with a route to the desired information with as few inputs as possible.

Tooltips is one alternative, but aren't always appropriate. While you can set (globally) the delay before appearance and the time before dismissal, dismissing them is implicit. In my application, I need the meta information to be displayed or hidden explicitly, so that rules out tooltips (at least without substantial modification of the tooltip manager).

A dedicated "inspector" window is another alternative, but kind of heavyweight. We definitely don't want a component that can be activated, since that introduces focus issues. I also didn't want to make it appear to the user that there was a generic "container" that kept resizing and moving, as if it were a tool palette that couldn't decide on its purpose. At a minimum the window has to be undecorated and pretty much behave like a tooltip.

What I really wanted was something in between the two. A simple Popup with a unique appearance which could be shown or hidden at will. Apple introduced something like this as Balloon Help years ago, although I think the main problem was that they didn't get the trigger quite right. One reason a lot of expert users don't like tooltips (or balloon help) is that they show up when you don't expect it and you have to wave the mouse to make them go away (usually causing another one to be triggered).

Google maps does a nice job with their balloon tips. The trigger is obvious, and the tip itself provides a close button (and now I notice a maximize button as well).

So I started out with Popups via PopupFactory and wound up with another demonstration of non-rectangular clipping, brought to you by the JNA project. The API is pretty simple:


Component myComponent;
Component myBubble;
Point where; // location relative to myComponent
final Popup popup = BalloonManager.getBalloon(myComponent, myBubble, where.x, where.y);
popup.show();
// Hide the popup on mouse clicks
myBubble.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
popup.hide();
}
});


The balloon is a simple rounded rectangle with a triangle stuck to the bottom, with the corresponding Area used as the window mask.

I originally tried using PopupFactory directly, but it doesn't provide enough control over the intermediate components (the ancestors of the content that you don't really see; there's a pesky medium-weight popup that uses java.awt.Panel, which can't be easily masked). This implementation uses a window for any popup, regardless of whether its fully contained within the parent component.

Drop shadows would be nice (maybe someone wants to contribute some compositing code?).




Tuesday, March 13, 2007

Building w32 JNI DLLs with gcc

After a bit of trial and error, I got JNA's native shared library to build (and run, and run tests) using gcc. Unfortunately the available documentation didn't quite work for me (might be a problem with my cygwin installation, but I wasn't the only one with an issue).

gcc-mingw is a version of cygwin gcc that can compile directly to the w32 api, without any of the cygwin emulation layer.


% gcc -dumpspecs | sed s%dllcrt2%/lib/mingw/dllcrt2%g > specs.new
% gcc -mno-cygwin -D_REENTRANT -D_GNU_SOURCE \
-D__int64="long long" -D_JNI_IMPLEMENTATION \
-o
-shared -Wl,--kill-at -specs specs.new -L /lib/mingw


The -mno-cygwin flag tells the compiler to run in mingw mode, i.e. omit all the cygwin unix compatibility layer and compile directly against the w32 api.

GCC's built-in 64-bit type is long long, so we map the type used in the JNI headers, __int64, to that type. Defining _JNI_IMPLEMENTATION ensures the JNI implementation exports its native method declarations.

Defining _REENTRANT and _GNU_SOURCE cause certain additional declarations of C library functions to be included. If you've never heard of them, most likely you don't need them.

The --kill-at flag to the linker ensures all symbols are exported undecorated, i.e. _my_func instead of _my_func@NN, which is the default when a function is declared as __stdcall. You could also use --add-stdcall-alias, which includes both versions of the symbol.

The GCC specs need tweaking or gcc-mingw doesn't find its initialization code for dlls, dllcrt2.o. We also have to nudge gcc-mingw to find the mingw libraries. Normally this is taken care of automatically by gcc, but for some reason my installation of cygwin gcc wouldn't find them, and no amount of -L or explicit object linkage would fix it.

Anyhow, with that out of the way, you don't have to have Microsoft's tools to build JNA or any other JNI library on w32.

I have noted that GCC apparently handles floating point a little differently, since the JNA tests that use FP return values/arguments are failing with the GCC-build dll.

Tuesday, February 27, 2007

Non-rectangular Windows Update




Updated to include support for OSX and linux.

While OSX doesn't actually use any native code to do the window mask, JNA support is there if it needed to. Source (and per-platform binaries) is available at http://jna.dev.java.net.

Update
Transparent version of the demo is available here.

Friday, February 23, 2007

Non-rectangular Windows

I've been meaning to play around with shaped windows for a while, but didn't relish the thought of walking through the tedium of JNI configurations and builds. Doing it on one platform is bad enough, but on several? No thanks.

So I thought I'd write a little scriptable shared library access stub once and be done with JNI entirely. Well, turns out it's already been done. Several times.

JNative
NLink
JNA

JNative has some interesting features not found in the others, but actually using it is only slightly better than JNI. NLink is currently w32-only, and has a bit of a COM bent. JNA fit most closely with my objectives, already had implementations for w32 and solaris, and was already platform-agnostic. So I took a couple days to hack in some more features (mostly to get an understanding of the codebase), and here is what I got. The following code is what it takes to make a frame take an arbitrary shape.

User32 user32 = User32.INSTANCE;
GDI32 gdi32 = GDI32.INSTANCE;
JFrame frame = new JFrame(getName());
Pointer p = gdi32.CreateRoundRectRgn(0, -150, 300, 300, 300, 300);
int hWnd = user32.FindWindowA(null, getName());
user32.SetWindowRgn(hWnd, p, true);

Looking up the appropriate w32 calls probably took the most time. How are the w32 libraries defined? How is this for trivial:

public interface User32 extends StdCallLibarary {
User32 INSTANCE = (User32)Native.loadLibary("user32", User32.class);
int FindWindowA(String winClass, String title);
void setWindowRgn(int hWnd, Pointer p, boolean redraw);
}
public interface GDI32 extends StdCallLibrary {
GDI32 INSTANCE = (GDI32)Native.loadLibrary("gdi32", GDI32.class);
Pointer CreateRoundRectRgn(int left, int top, int right, int bottom, int w, int h);
}

Now, somebody's probably going to point me to how SWT has had this functionality for years (does it?), but this is nicely abstracted and based on a very small number of classes. I'll be updating the code at jna.dev.java.net (or maybe opening a new location if I can't get the existing project moved to subversion), but for now, check out the demo by clicking on everyone's favorite orange launch button.




Permissions required, because this runs some custom native code.

Oh, BTW, this is windows-only for the moment. I'll do X11 next and anyone's free to send me some code snippets for setting window masks on other platforms. I could also use some help porting to PPC and other platforms (a very small amount of native ASM to push arguments to the stack, not too hard).

Friday, February 16, 2007

JDK 1.6 Applet Madness

I had a few applets on the main page showing some interesting eye candy. Then I upgraded my JDK to 1.6 and they lock up the java plugin (IE or firefox). If anyone has encountered a similar issue, please let me know, I'd really like to fix it.

I've gotten a variety of errors, but I can't seem to come up with an effective workaround or consistent analysis (JDK 1.6 doesn't let you pick a different VM to use for applets).