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