It could be that the drivers or X server doesn’t support hw cursors with more than 2 colors.
You can pretty easily render the cursor yourself: set an empty cursor (or 1x1 translucent one) to hide the default cursor, register a MouseMotionListener, and render whatever your want at the mouse coordinates.
The benefit is that you have full control at what you want to render, it could be an image, a bunch of images (like a snake or something), etc, and it will work the same on all platforms.
Here’s a little something I came up with one winter evenining poking around with the Balls demo. It’s not going to work out of the box, but you can kind of get the idea. (sorry for the formatting)
/**
* Simple custom cursor implementation.
*/
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;
import java.util.Arrays;
public class CustomCursor {
static final int CURSOR_TAIL_LENGTH = 5;
static final int MAX_CURSOR_TAIL_DISTANCE = 15;
static final int TAIL_CATCHUP_SPEED = 3;
Image cursorImage;
Point lastMousePosition;
Point cursorPositions[];
int currentTailDistance;
int lastUnchangedPosition;
Timer cursorTimer;
public CustomCursor(GameFrame parent, BufferedImage bi) {
initCursorTail(bi, parent.getGraphicsConfig());
parent.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
synchronized (cursorPositions) {
cursorTimer.stop();
currentTailDistance = MAX_CURSOR_TAIL_DISTANCE;
lastMousePosition = e.getPoint();
System.arraycopy(cursorPositions, 0,
cursorPositions, 1,
cursorPositions.length - 1);
cursorPositions[0] = lastMousePosition;
lastUnchangedPosition = 0;
}
}
});
}
void initCursorTail(BufferedImage image, GraphicsConfiguration gc) {
lastMousePosition = new Point(0, 0);
currentTailDistance = MAX_CURSOR_TAIL_DISTANCE;
lastUnchangedPosition = 0;
cursorPositions = new Point[CURSOR_TAIL_LENGTH*MAX_CURSOR_TAIL_DISTANCE];
Arrays.fill(cursorPositions, lastMousePosition);
cursorImage = gc.createCompatibleImage(image.getWidth(), image.getHeight(),
Transparency.BITMASK);
Graphics g = cursorImage.getGraphics();
g.drawImage(image, 0, 0, null);
cursorTimer = new Timer(30, new ActionListener() {
public void actionPerformed(ActionEvent e) {
synchronized (cursorPositions) {
int newLastPos = lastUnchangedPosition + TAIL_CATCHUP_SPEED;
if (newLastPos < cursorPositions.length) {
System.arraycopy(cursorPositions, lastUnchangedPosition,
cursorPositions, newLastPos,
cursorPositions.length - newLastPos);
Arrays.fill(cursorPositions,
lastUnchangedPosition,
newLastPos,
cursorPositions[lastUnchangedPosition]);
lastUnchangedPosition = newLastPos;
} else {
cursorTimer.stop();
}
}
}
});
}
public void render(Graphics g) {
synchronized (cursorPositions) {
float scale = 1f;
int lastCursorPosition = currentTailDistance * CURSOR_TAIL_LENGTH - 1;
for (int i = lastCursorPosition; i >= 0 ; i -= currentTailDistance) {
// scale on the fly, this may be optimized to
// render prescaled images
g.drawImage(cursorImage,
(int)cursorPositions[i].getX(),
(int)cursorPositions[i].getY(),
(int)(cursorImage.getWidth(null) * scale),
(int)(cursorImage.getHeight(null) * scale),
null);
scale -= .15;
}
cursorTimer.start();
}
}
public void dispose() {
cursorTimer.stop();
cursorTimer = null;
}
}