/*
* Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.lwawt.macosx;
import java.awt.*;
import java.awt.image.BufferedImage;
@SuppressWarnings("serial") // JDK implementation class
public class CCustomCursor extends Cursor {
static Dimension sMaxCursorSize;
static Dimension getMaxCursorSize() {
if (sMaxCursorSize != null) return sMaxCursorSize;
final Rectangle bounds = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().getBounds();
return sMaxCursorSize = new Dimension(bounds.width / 2, bounds.height / 2);
}
Image fImage;
Point fHotspot;
int fWidth;
int fHeight;
public CCustomCursor(final Image cursor, final Point hotSpot, final String name) throws IndexOutOfBoundsException, HeadlessException {
super(name);
fImage = cursor;
fHotspot = hotSpot;
// This chunk of code is copied from sun.awt.CustomCursor
final Toolkit toolkit = Toolkit.getDefaultToolkit();
// Make sure image is fully loaded.
final Component c = new Canvas(); // for its imageUpdate method
final MediaTracker tracker = new MediaTracker(c);
// MediaTracker loads resolution variants from MultiResolution Toolkit image
tracker.addImage(fImage, 0);
try {
tracker.waitForAll();
} catch (final InterruptedException e) {}
int width = fImage.getWidth(c);
int height = fImage.getHeight(c);
// Fix for bug 4212593 The Toolkit.createCustomCursor does not
// check absence of the image of cursor
// If the image is invalid, the cursor will be hidden (made completely
// transparent).
if (tracker.isErrorAny() || width < 0 || height < 0) {
fHotspot.x = fHotspot.y = 0;
width = height = 1;
fImage = createTransparentImage(width, height);
} else {
// Get the nearest supported cursor size
final Dimension nativeSize = toolkit.getBestCursorSize(width, height);
width = nativeSize.width;
height = nativeSize.height;
}
fWidth = width;
fHeight = height;
// NOTE: this was removed for 3169146, but in 1.5 the JCK tests for an exception and fails if one isn't thrown.
// See what JBuilder does.
// Verify that the hotspot is within cursor bounds.
if (fHotspot.x >= width || fHotspot.y >= height || fHotspot.x < 0 || fHotspot.y < 0) {
throw new IndexOutOfBoundsException("invalid hotSpot");
}
// Must normalize the hotspot
if (fHotspot.x >= width) {
fHotspot.x = width - 1; // it is zero based.
} else if (fHotspot.x < 0) {
fHotspot.x = 0;
}
if (fHotspot.y >= height) {
fHotspot.y = height - 1; // it is zero based.
} else if (fHotspot.y < 0) {
fHotspot.y = 0;
}
}
private static BufferedImage createTransparentImage(int w, int h) {
GraphicsEnvironment ge =
GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
BufferedImage img = gc.createCompatibleImage(w, h, Transparency.BITMASK);
Graphics2D g = (Graphics2D)img.getGraphics();
g.setBackground(new Color(0, 0, 0, 0));
g.clearRect(0, 0, w, h);
g.dispose();
return img;
}
public static Dimension getBestCursorSize(final int preferredWidth, final int preferredHeight) {
// With Panther, cursors have no limit on their size. So give the client their
// preferred size, but no larger than half the dimensions of the main screen
// This will allow large cursors, but not cursors so large that they cover the
// screen. Since solaris nor windows allow cursors this big, this shouldn't be
// a limitation.
// JCK triggers an overflow in the int -- if we get a bizarre value normalize it.
final Dimension maxCursorSize = getMaxCursorSize();
final Dimension d = new Dimension(Math.max(1, Math.abs(preferredWidth)), Math.max(1, Math.abs(preferredHeight)));
return new Dimension(Math.min(d.width, maxCursorSize.width), Math.min(d.height, maxCursorSize.height));
}
// Called from native when the cursor is set
CImage fCImage;
long getImageData() {
if (fCImage != null) {
return fCImage.ptr;
}
try {
fCImage = CImage.getCreator().createFromImage(fImage);
if (fCImage == null) {
// Something unexpected happened: CCustomCursor constructor
// takes care of invalid cursor images, yet createFromImage()
// failed to do its job. Return null to keep the cursor unchanged.
return 0L;
} else {
fCImage.resizeRepresentations(fWidth, fHeight);
return fCImage.ptr;
}
} catch (IllegalArgumentException iae) {
// see comment above
return 0L;
}
}
Point getHotSpot() {
return fHotspot;
}
}