1. /*
  2. * @(#)Cursor.java 1.30 00/02/02
  3. *
  4. * Copyright 1996-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package java.awt;
  11. import java.awt.AWTException;
  12. import java.awt.Point;
  13. import java.awt.Toolkit;
  14. import java.io.File;
  15. import java.io.FileInputStream;
  16. import java.util.Enumeration;
  17. import java.util.Hashtable;
  18. import java.util.Properties;
  19. import java.util.StringTokenizer;
  20. import java.security.AccessController;
  21. /**
  22. * A class to encapsulate the bitmap representation of the mouse cursor.
  23. *
  24. * @see Component#setCursor
  25. * @version 1.30, 02/02/00
  26. * @author Amy Fowler
  27. */
  28. public class Cursor implements java.io.Serializable {
  29. /**
  30. * The default cursor type (gets set if no cursor is defined).
  31. */
  32. public static final int DEFAULT_CURSOR = 0;
  33. /**
  34. * The crosshair cursor type.
  35. */
  36. public static final int CROSSHAIR_CURSOR = 1;
  37. /**
  38. * The text cursor type.
  39. */
  40. public static final int TEXT_CURSOR = 2;
  41. /**
  42. * The wait cursor type.
  43. */
  44. public static final int WAIT_CURSOR = 3;
  45. /**
  46. * The south-west-resize cursor type.
  47. */
  48. public static final int SW_RESIZE_CURSOR = 4;
  49. /**
  50. * The south-east-resize cursor type.
  51. */
  52. public static final int SE_RESIZE_CURSOR = 5;
  53. /**
  54. * The north-west-resize cursor type.
  55. */
  56. public static final int NW_RESIZE_CURSOR = 6;
  57. /**
  58. * The north-east-resize cursor type.
  59. */
  60. public static final int NE_RESIZE_CURSOR = 7;
  61. /**
  62. * The north-resize cursor type.
  63. */
  64. public static final int N_RESIZE_CURSOR = 8;
  65. /**
  66. * The south-resize cursor type.
  67. */
  68. public static final int S_RESIZE_CURSOR = 9;
  69. /**
  70. * The west-resize cursor type.
  71. */
  72. public static final int W_RESIZE_CURSOR = 10;
  73. /**
  74. * The east-resize cursor type.
  75. */
  76. public static final int E_RESIZE_CURSOR = 11;
  77. /**
  78. * The hand cursor type.
  79. */
  80. public static final int HAND_CURSOR = 12;
  81. /**
  82. * The move cursor type.
  83. */
  84. public static final int MOVE_CURSOR = 13;
  85. protected static Cursor predefined[] = new Cursor[14];
  86. /* Localization names and default values */
  87. static final String[][] cursorProperties = {
  88. { "AWT.DefaultCursor", "Default Cursor" },
  89. { "AWT.CrosshairCursor", "Crosshair Cursor" },
  90. { "AWT.TextCursor", "Text Cursor" },
  91. { "AWT.WaitCursor", "Wait Cursor" },
  92. { "AWT.SWResizeCursor", "Southwest Resize Cursor" },
  93. { "AWT.SEResizeCursor", "Southeast Resize Cursor" },
  94. { "AWT.NWResizeCursor", "Northwest Resize Cursor" },
  95. { "AWT.NEResizeCursor", "Northeast Resize Cursor" },
  96. { "AWT.NResizeCursor", "North Resize Cursor" },
  97. { "AWT.SResizeCursor", "South Resize Cursor" },
  98. { "AWT.WResizeCursor", "West Resize Cursor" },
  99. { "AWT.EResizeCursor", "East Resize Cursor" },
  100. { "AWT.HandCursor", "Hand Cursor" },
  101. { "AWT.MoveCursor", "Move Cursor" },
  102. };
  103. /**
  104. * The chosen cursor type initially set to
  105. * the <code>DEFAULT_CURSOR</code>.
  106. *
  107. * @serial
  108. * @see getType()
  109. */
  110. int type = DEFAULT_CURSOR;
  111. /**
  112. * The type associated with all custom cursors.
  113. */
  114. public static final int CUSTOM_CURSOR = -1;
  115. /*
  116. * hashtable, filesystem dir prefix, filename, and properties for custom cursors support
  117. */
  118. private static final Hashtable systemCustomCursors = new Hashtable(1);
  119. private static final String systemCustomCursorDirPrefix = initCursorDir();
  120. private static String initCursorDir() {
  121. String jhome = (String) java.security.AccessController.doPrivileged(
  122. new sun.security.action.GetPropertyAction("java.home"));
  123. return jhome +
  124. File.separator + "lib" + File.separator + "images" +
  125. File.separator + "cursors" + File.separator;
  126. }
  127. private static final String systemCustomCursorPropertiesFile = systemCustomCursorDirPrefix + "cursors.properties";
  128. private static Properties systemCustomCursorProperties = null;
  129. private static final String CursorDotPrefix = "Cursor.";
  130. private static final String DotFileSuffix = ".File";
  131. private static final String DotHotspotSuffix = ".HotSpot";
  132. private static final String DotNameSuffix = ".Name";
  133. /*
  134. * JDK 1.1 serialVersionUID
  135. */
  136. private static final long serialVersionUID = 8028237497568985504L;
  137. static {
  138. /* ensure that the necessary native libraries are loaded */
  139. Toolkit.loadLibraries();
  140. initIDs();
  141. }
  142. /**
  143. * Initialize JNI field and method IDs for fields that may be
  144. accessed from C.
  145. */
  146. private static native void initIDs();
  147. /**
  148. * Hook into native data.
  149. */
  150. private transient long pData;
  151. /**
  152. * The user-visible name of the cursor.
  153. *
  154. * @serial
  155. * @see #getName()
  156. */
  157. protected String name;
  158. /**
  159. * Returns a cursor object with the specified predefined type.
  160. * @param type the type of predefined cursor
  161. */
  162. static public Cursor getPredefinedCursor(int type) {
  163. if (type < Cursor.DEFAULT_CURSOR || type > Cursor.MOVE_CURSOR) {
  164. throw new IllegalArgumentException("illegal cursor type");
  165. }
  166. if (predefined[type] == null) {
  167. predefined[type] = new Cursor(type);
  168. }
  169. return predefined[type];
  170. }
  171. /**
  172. * @return the system specific custom Cursor named
  173. *
  174. * Cursor names are, for example: "Invalid.16x16"
  175. */
  176. static public Cursor getSystemCustomCursor(final String name)
  177. throws AWTException {
  178. Cursor cursor = (Cursor)systemCustomCursors.get(name);
  179. if (cursor == null) {
  180. synchronized(systemCustomCursors) {
  181. if (systemCustomCursorProperties == null)
  182. loadSystemCustomCursorProperties();
  183. }
  184. String prefix = CursorDotPrefix + name;
  185. String key = prefix + DotFileSuffix;
  186. if (!systemCustomCursorProperties.containsKey(key)) {
  187. System.err.println("Cursor.getSystemCustomCursor(" + name + ") returned null");
  188. return null;
  189. }
  190. final String fileName =
  191. systemCustomCursorProperties.getProperty(key);
  192. String localized = (String)systemCustomCursorProperties.getProperty(prefix + DotNameSuffix);
  193. if (localized == null) localized = name;
  194. String hotspot = (String)systemCustomCursorProperties.getProperty(prefix + DotHotspotSuffix);
  195. if (hotspot == null)
  196. throw new AWTException("no hotspot property defined for cursor: " + name);
  197. StringTokenizer st = new StringTokenizer(hotspot, ",");
  198. if (st.countTokens() != 2)
  199. throw new AWTException("failed to parse hotspot property for cursor: " + name);
  200. int x = 0;
  201. int y = 0;
  202. try {
  203. x = Integer.parseInt(st.nextToken());
  204. y = Integer.parseInt(st.nextToken());
  205. } catch (NumberFormatException nfe) {
  206. throw new AWTException("failed to parse hotspot property for cursor: " + name);
  207. }
  208. try {
  209. final int fx = x;
  210. final int fy = y;
  211. final String flocalized = localized;
  212. cursor = (Cursor) java.security.AccessController.doPrivileged(
  213. new java.security.PrivilegedExceptionAction() {
  214. public Object run() throws Exception {
  215. Toolkit toolkit = Toolkit.getDefaultToolkit();
  216. Image image = toolkit.getImage(
  217. systemCustomCursorDirPrefix + fileName);
  218. return toolkit.createCustomCursor(
  219. image, new Point(fx,fy), flocalized);
  220. }
  221. });
  222. } catch (Exception e) {
  223. throw new AWTException(
  224. "Exception: " + e.getClass() + " " + e.getMessage() +
  225. " occurred while creating cursor " + name);
  226. }
  227. if (cursor == null) {
  228. System.err.println("Cursor.getSystemCustomCursor(" + name + ") returned null");
  229. } else {
  230. systemCustomCursors.put(name, cursor);
  231. }
  232. }
  233. return cursor;
  234. }
  235. /**
  236. * Return the system default cursor.
  237. */
  238. static public Cursor getDefaultCursor() {
  239. return getPredefinedCursor(Cursor.DEFAULT_CURSOR);
  240. }
  241. /**
  242. * Creates a new cursor object with the specified type.
  243. * @param type the type of cursor
  244. */
  245. public Cursor(int type) {
  246. if (type < Cursor.DEFAULT_CURSOR || type > Cursor.MOVE_CURSOR) {
  247. throw new IllegalArgumentException("illegal cursor type");
  248. }
  249. this.type = type;
  250. // Lookup localized name.
  251. name = Toolkit.getProperty(cursorProperties[type][0],
  252. cursorProperties[type][1]);
  253. }
  254. /**
  255. * Creates a new custom cursor object with the specified name.<p>
  256. * Note: this constructor should only be used by AWT implementations
  257. * as part of their support for custom cursors. Applications should
  258. * use Toolkit.createCustomCursor().
  259. * @param name the user-visible name of the cursor.
  260. * @see java.awt.Toolkit#createCustomCursor
  261. */
  262. protected Cursor(String name) {
  263. this.type = Cursor.CUSTOM_CURSOR;
  264. this.name = name;
  265. }
  266. /**
  267. * Returns the type for this cursor.
  268. */
  269. public int getType() {
  270. return type;
  271. }
  272. /**
  273. * Returns the name of this cursor.
  274. * @return a localized description of this cursor.
  275. * @since 1.2
  276. */
  277. public String getName() {
  278. return name;
  279. }
  280. /**
  281. * Returns a string representation of this cursor.
  282. * @return a string representation of this cursor.
  283. * @since 1.2
  284. */
  285. public String toString() {
  286. return getClass().getName() + "[" + getName() + "]";
  287. }
  288. /*
  289. * load the cursor.properties file
  290. */
  291. private static void loadSystemCustomCursorProperties() throws AWTException {
  292. synchronized(systemCustomCursors) {
  293. systemCustomCursorProperties = new Properties();
  294. try {
  295. AccessController.doPrivileged(
  296. new java.security.PrivilegedExceptionAction() {
  297. public Object run() throws Exception {
  298. FileInputStream fis = null;
  299. try {
  300. fis = new FileInputStream(
  301. systemCustomCursorPropertiesFile);
  302. systemCustomCursorProperties.load(fis);
  303. } finally {
  304. if (fis != null)
  305. fis.close();
  306. }
  307. return null;
  308. }
  309. });
  310. } catch (Exception e) {
  311. systemCustomCursorProperties = null;
  312. throw new AWTException("Exception: " + e.getClass() + " " +
  313. e.getMessage() + " occurred while loading: " +
  314. systemCustomCursorPropertiesFile);
  315. }
  316. }
  317. }
  318. // This won't really throw an exception, but it must match the
  319. // signature of Object.finalize
  320. protected native void finalize() throws Throwable;
  321. }