jdk/src/share/classes/java/awt/Cursor.java
changeset 2 90ce3da70b43
child 3445 39d00a6cac5e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/awt/Cursor.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,448 @@
+/*
+ * Copyright 1996-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package java.awt;
+
+import java.awt.AWTException;
+import java.awt.Point;
+import java.awt.Toolkit;
+
+import java.io.File;
+import java.io.FileInputStream;
+
+import java.beans.ConstructorProperties;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import java.util.logging.*;
+
+import java.security.AccessController;
+
+/**
+ * A class to encapsulate the bitmap representation of the mouse cursor.
+ *
+ * @see Component#setCursor
+ * @author      Amy Fowler
+ */
+public class Cursor implements java.io.Serializable {
+
+    /**
+     * The default cursor type (gets set if no cursor is defined).
+     */
+    public static final int     DEFAULT_CURSOR                  = 0;
+
+    /**
+     * The crosshair cursor type.
+     */
+    public static final int     CROSSHAIR_CURSOR                = 1;
+
+    /**
+     * The text cursor type.
+     */
+    public static final int     TEXT_CURSOR                     = 2;
+
+    /**
+     * The wait cursor type.
+     */
+    public static final int     WAIT_CURSOR                     = 3;
+
+    /**
+     * The south-west-resize cursor type.
+     */
+    public static final int     SW_RESIZE_CURSOR                = 4;
+
+    /**
+     * The south-east-resize cursor type.
+     */
+    public static final int     SE_RESIZE_CURSOR                = 5;
+
+    /**
+     * The north-west-resize cursor type.
+     */
+    public static final int     NW_RESIZE_CURSOR                = 6;
+
+    /**
+     * The north-east-resize cursor type.
+     */
+    public static final int     NE_RESIZE_CURSOR                = 7;
+
+    /**
+     * The north-resize cursor type.
+     */
+    public static final int     N_RESIZE_CURSOR                 = 8;
+
+    /**
+     * The south-resize cursor type.
+     */
+    public static final int     S_RESIZE_CURSOR                 = 9;
+
+    /**
+     * The west-resize cursor type.
+     */
+    public static final int     W_RESIZE_CURSOR                 = 10;
+
+    /**
+     * The east-resize cursor type.
+     */
+    public static final int     E_RESIZE_CURSOR                 = 11;
+
+    /**
+     * The hand cursor type.
+     */
+    public static final int     HAND_CURSOR                     = 12;
+
+    /**
+     * The move cursor type.
+     */
+    public static final int     MOVE_CURSOR                     = 13;
+
+    protected static Cursor predefined[] = new Cursor[14];
+
+    /* Localization names and default values */
+    static final String[][] cursorProperties = {
+        { "AWT.DefaultCursor", "Default Cursor" },
+        { "AWT.CrosshairCursor", "Crosshair Cursor" },
+        { "AWT.TextCursor", "Text Cursor" },
+        { "AWT.WaitCursor", "Wait Cursor" },
+        { "AWT.SWResizeCursor", "Southwest Resize Cursor" },
+        { "AWT.SEResizeCursor", "Southeast Resize Cursor" },
+        { "AWT.NWResizeCursor", "Northwest Resize Cursor" },
+        { "AWT.NEResizeCursor", "Northeast Resize Cursor" },
+        { "AWT.NResizeCursor", "North Resize Cursor" },
+        { "AWT.SResizeCursor", "South Resize Cursor" },
+        { "AWT.WResizeCursor", "West Resize Cursor" },
+        { "AWT.EResizeCursor", "East Resize Cursor" },
+        { "AWT.HandCursor", "Hand Cursor" },
+        { "AWT.MoveCursor", "Move Cursor" },
+    };
+
+    /**
+     * The chosen cursor type initially set to
+     * the <code>DEFAULT_CURSOR</code>.
+     *
+     * @serial
+     * @see #getType()
+     */
+    int type = DEFAULT_CURSOR;
+
+    /**
+     * The type associated with all custom cursors.
+     */
+    public static final int     CUSTOM_CURSOR                   = -1;
+
+    /*
+     * hashtable, filesystem dir prefix, filename, and properties for custom cursors support
+     */
+
+    private static final Hashtable  systemCustomCursors         = new Hashtable(1);
+    private static final String systemCustomCursorDirPrefix = initCursorDir();
+
+    private static String initCursorDir() {
+        String jhome =  (String) java.security.AccessController.doPrivileged(
+               new sun.security.action.GetPropertyAction("java.home"));
+        return jhome +
+            File.separator + "lib" + File.separator + "images" +
+            File.separator + "cursors" + File.separator;
+    }
+
+    private static final String     systemCustomCursorPropertiesFile = systemCustomCursorDirPrefix + "cursors.properties";
+
+    private static       Properties systemCustomCursorProperties = null;
+
+    private static final String CursorDotPrefix  = "Cursor.";
+    private static final String DotFileSuffix    = ".File";
+    private static final String DotHotspotSuffix = ".HotSpot";
+    private static final String DotNameSuffix    = ".Name";
+
+    /*
+     * JDK 1.1 serialVersionUID
+     */
+    private static final long serialVersionUID = 8028237497568985504L;
+
+    private static final Logger log = Logger.getLogger("java.awt.Cursor");
+
+    static {
+        /* ensure that the necessary native libraries are loaded */
+        Toolkit.loadLibraries();
+        if (!GraphicsEnvironment.isHeadless()) {
+            initIDs();
+        }
+    }
+
+    /**
+     * Initialize JNI field and method IDs for fields that may be
+     * accessed from C.
+     */
+    private static native void initIDs();
+
+    /**
+     * Hook into native data.
+     */
+    private transient long pData;
+
+    private transient Object anchor = new Object();
+
+    static class CursorDisposer implements sun.java2d.DisposerRecord {
+        volatile long pData;
+        public CursorDisposer(long pData) {
+            this.pData = pData;
+        }
+        public void dispose() {
+            if (pData != 0) {
+                finalizeImpl(pData);
+            }
+        }
+    }
+    transient CursorDisposer disposer;
+    private void setPData(long pData) {
+        this.pData = pData;
+        if (GraphicsEnvironment.isHeadless()) {
+            return;
+        }
+        if (disposer == null) {
+            disposer = new CursorDisposer(pData);
+            // anchor is null after deserialization
+            if (anchor == null) {
+                anchor = new Object();
+            }
+            sun.java2d.Disposer.addRecord(anchor, disposer);
+        } else {
+            disposer.pData = pData;
+        }
+    }
+
+    /**
+     * The user-visible name of the cursor.
+     *
+     * @serial
+     * @see #getName()
+     */
+    protected String name;
+
+    /**
+     * Returns a cursor object with the specified predefined type.
+     *
+     * @param type the type of predefined cursor
+     * @return the specified predefined cursor
+     * @throws IllegalArgumentException if the specified cursor type is
+     *         invalid
+     */
+    static public Cursor getPredefinedCursor(int type) {
+        if (type < Cursor.DEFAULT_CURSOR || type > Cursor.MOVE_CURSOR) {
+            throw new IllegalArgumentException("illegal cursor type");
+        }
+        if (predefined[type] == null) {
+            predefined[type] = new Cursor(type);
+        }
+        return predefined[type];
+    }
+
+    /**
+     * Returns a system-specific custom cursor object matching the
+     * specified name.  Cursor names are, for example: "Invalid.16x16"
+     *
+     * @param name a string describing the desired system-specific custom cursor
+     * @return the system specific custom cursor named
+     * @exception HeadlessException if
+     * <code>GraphicsEnvironment.isHeadless</code> returns true
+     */
+    static public Cursor getSystemCustomCursor(final String name)
+        throws AWTException, HeadlessException {
+        GraphicsEnvironment.checkHeadless();
+        Cursor cursor = (Cursor)systemCustomCursors.get(name);
+
+        if (cursor == null) {
+            synchronized(systemCustomCursors) {
+                if (systemCustomCursorProperties == null)
+                    loadSystemCustomCursorProperties();
+            }
+
+            String prefix = CursorDotPrefix + name;
+            String key    = prefix + DotFileSuffix;
+
+            if (!systemCustomCursorProperties.containsKey(key)) {
+                if (log.isLoggable(Level.FINER)) {
+                    log.log(Level.FINER, "Cursor.getSystemCustomCursor(" + name + ") returned null");
+                }
+                return null;
+            }
+
+            final String fileName =
+                systemCustomCursorProperties.getProperty(key);
+
+            String localized = (String)systemCustomCursorProperties.getProperty(prefix + DotNameSuffix);
+
+            if (localized == null) localized = name;
+
+            String hotspot = (String)systemCustomCursorProperties.getProperty(prefix + DotHotspotSuffix);
+
+            if (hotspot == null)
+                throw new AWTException("no hotspot property defined for cursor: " + name);
+
+            StringTokenizer st = new StringTokenizer(hotspot, ",");
+
+            if (st.countTokens() != 2)
+                throw new AWTException("failed to parse hotspot property for cursor: " + name);
+
+            int x = 0;
+            int y = 0;
+
+            try {
+                x = Integer.parseInt(st.nextToken());
+                y = Integer.parseInt(st.nextToken());
+            } catch (NumberFormatException nfe) {
+                throw new AWTException("failed to parse hotspot property for cursor: " + name);
+            }
+
+            try {
+                final int fx = x;
+                final int fy = y;
+                final String flocalized = localized;
+
+                cursor = (Cursor) java.security.AccessController.doPrivileged(
+                    new java.security.PrivilegedExceptionAction() {
+                    public Object run() throws Exception {
+                        Toolkit toolkit = Toolkit.getDefaultToolkit();
+                        Image image = toolkit.getImage(
+                           systemCustomCursorDirPrefix + fileName);
+                        return toolkit.createCustomCursor(
+                                    image, new Point(fx,fy), flocalized);
+                    }
+                });
+            } catch (Exception e) {
+                throw new AWTException(
+                    "Exception: " + e.getClass() + " " + e.getMessage() +
+                    " occurred while creating cursor " + name);
+            }
+
+            if (cursor == null) {
+                if (log.isLoggable(Level.FINER)) {
+                    log.log(Level.FINER, "Cursor.getSystemCustomCursor(" + name + ") returned null");
+                }
+            } else {
+                systemCustomCursors.put(name, cursor);
+            }
+        }
+
+        return cursor;
+    }
+
+    /**
+     * Return the system default cursor.
+     */
+    static public Cursor getDefaultCursor() {
+        return getPredefinedCursor(Cursor.DEFAULT_CURSOR);
+    }
+
+    /**
+     * Creates a new cursor object with the specified type.
+     * @param type the type of cursor
+     * @throws IllegalArgumentException if the specified cursor type
+     * is invalid
+     */
+    @ConstructorProperties({"type"})
+    public Cursor(int type) {
+        if (type < Cursor.DEFAULT_CURSOR || type > Cursor.MOVE_CURSOR) {
+            throw new IllegalArgumentException("illegal cursor type");
+        }
+        this.type = type;
+
+        // Lookup localized name.
+        name = Toolkit.getProperty(cursorProperties[type][0],
+                                   cursorProperties[type][1]);
+    }
+
+    /**
+     * Creates a new custom cursor object with the specified name.<p>
+     * Note:  this constructor should only be used by AWT implementations
+     * as part of their support for custom cursors.  Applications should
+     * use Toolkit.createCustomCursor().
+     * @param name the user-visible name of the cursor.
+     * @see java.awt.Toolkit#createCustomCursor
+     */
+    protected Cursor(String name) {
+        this.type = Cursor.CUSTOM_CURSOR;
+        this.name = name;
+    }
+
+    /**
+     * Returns the type for this cursor.
+     */
+    public int getType() {
+        return type;
+    }
+
+    /**
+     * Returns the name of this cursor.
+     * @return    a localized description of this cursor.
+     * @since     1.2
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns a string representation of this cursor.
+     * @return    a string representation of this cursor.
+     * @since     1.2
+     */
+    public String toString() {
+        return getClass().getName() + "[" + getName() + "]";
+    }
+
+    /*
+     * load the cursor.properties file
+     */
+    private static void loadSystemCustomCursorProperties() throws AWTException {
+        synchronized(systemCustomCursors) {
+            systemCustomCursorProperties = new Properties();
+
+            try {
+                AccessController.doPrivileged(
+                      new java.security.PrivilegedExceptionAction() {
+                    public Object run() throws Exception {
+                        FileInputStream fis = null;
+                        try {
+                            fis = new FileInputStream(
+                                           systemCustomCursorPropertiesFile);
+                            systemCustomCursorProperties.load(fis);
+                        } finally {
+                            if (fis != null)
+                                fis.close();
+                        }
+                        return null;
+                    }
+                });
+            } catch (Exception e) {
+                systemCustomCursorProperties = null;
+                 throw new AWTException("Exception: " + e.getClass() + " " +
+                   e.getMessage() + " occurred while loading: " +
+                                        systemCustomCursorPropertiesFile);
+            }
+        }
+    }
+
+    private native static void finalizeImpl(long pData);
+}