001 /*
002 * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025 package java.awt;
026
027 import java.awt.AWTException;
028 import java.awt.Point;
029 import java.awt.Toolkit;
030
031 import java.io.File;
032 import java.io.FileInputStream;
033
034 import java.beans.ConstructorProperties;
035 import java.util.Hashtable;
036 import java.util.Properties;
037 import java.util.StringTokenizer;
038
039 import java.security.AccessController;
040
041 import sun.awt.DebugHelper;
042
043 /**
044 * A class to encapsulate the bitmap representation of the mouse cursor.
045 *
046 * @see Component#setCursor
047 * @version 1.51, 05/05/07
048 * @author Amy Fowler
049 */
050 public class Cursor implements java.io.Serializable {
051
052 /**
053 * The default cursor type (gets set if no cursor is defined).
054 */
055 public static final int DEFAULT_CURSOR = 0;
056
057 /**
058 * The crosshair cursor type.
059 */
060 public static final int CROSSHAIR_CURSOR = 1;
061
062 /**
063 * The text cursor type.
064 */
065 public static final int TEXT_CURSOR = 2;
066
067 /**
068 * The wait cursor type.
069 */
070 public static final int WAIT_CURSOR = 3;
071
072 /**
073 * The south-west-resize cursor type.
074 */
075 public static final int SW_RESIZE_CURSOR = 4;
076
077 /**
078 * The south-east-resize cursor type.
079 */
080 public static final int SE_RESIZE_CURSOR = 5;
081
082 /**
083 * The north-west-resize cursor type.
084 */
085 public static final int NW_RESIZE_CURSOR = 6;
086
087 /**
088 * The north-east-resize cursor type.
089 */
090 public static final int NE_RESIZE_CURSOR = 7;
091
092 /**
093 * The north-resize cursor type.
094 */
095 public static final int N_RESIZE_CURSOR = 8;
096
097 /**
098 * The south-resize cursor type.
099 */
100 public static final int S_RESIZE_CURSOR = 9;
101
102 /**
103 * The west-resize cursor type.
104 */
105 public static final int W_RESIZE_CURSOR = 10;
106
107 /**
108 * The east-resize cursor type.
109 */
110 public static final int E_RESIZE_CURSOR = 11;
111
112 /**
113 * The hand cursor type.
114 */
115 public static final int HAND_CURSOR = 12;
116
117 /**
118 * The move cursor type.
119 */
120 public static final int MOVE_CURSOR = 13;
121
122 protected static Cursor predefined[] = new Cursor[14];
123
124 /* Localization names and default values */
125 static final String[][] cursorProperties = {
126 { "AWT.DefaultCursor", "Default Cursor" },
127 { "AWT.CrosshairCursor", "Crosshair Cursor" },
128 { "AWT.TextCursor", "Text Cursor" },
129 { "AWT.WaitCursor", "Wait Cursor" },
130 { "AWT.SWResizeCursor", "Southwest Resize Cursor" },
131 { "AWT.SEResizeCursor", "Southeast Resize Cursor" },
132 { "AWT.NWResizeCursor", "Northwest Resize Cursor" },
133 { "AWT.NEResizeCursor", "Northeast Resize Cursor" },
134 { "AWT.NResizeCursor", "North Resize Cursor" },
135 { "AWT.SResizeCursor", "South Resize Cursor" },
136 { "AWT.WResizeCursor", "West Resize Cursor" },
137 { "AWT.EResizeCursor", "East Resize Cursor" },
138 { "AWT.HandCursor", "Hand Cursor" },
139 { "AWT.MoveCursor", "Move Cursor" }, };
140
141 /**
142 * The chosen cursor type initially set to
143 * the <code>DEFAULT_CURSOR</code>.
144 *
145 * @serial
146 * @see #getType()
147 */
148 int type = DEFAULT_CURSOR;
149
150 /**
151 * The type associated with all custom cursors.
152 */
153 public static final int CUSTOM_CURSOR = -1;
154
155 /*
156 * hashtable, filesystem dir prefix, filename, and properties for custom cursors support
157 */
158
159 private static final Hashtable systemCustomCursors = new Hashtable(
160 1);
161 private static final String systemCustomCursorDirPrefix = initCursorDir();
162
163 private static String initCursorDir() {
164 String jhome = (String) java.security.AccessController
165 .doPrivileged(new sun.security.action.GetPropertyAction(
166 "java.home"));
167 return jhome + File.separator + "lib" + File.separator
168 + "images" + File.separator + "cursors"
169 + File.separator;
170 }
171
172 private static final String systemCustomCursorPropertiesFile = systemCustomCursorDirPrefix
173 + "cursors.properties";
174
175 private static Properties systemCustomCursorProperties = null;
176
177 private static final String CursorDotPrefix = "Cursor.";
178 private static final String DotFileSuffix = ".File";
179 private static final String DotHotspotSuffix = ".HotSpot";
180 private static final String DotNameSuffix = ".Name";
181
182 /*
183 * JDK 1.1 serialVersionUID
184 */
185 private static final long serialVersionUID = 8028237497568985504L;
186
187 private static final DebugHelper dbg = DebugHelper
188 .create(Cursor.class);
189
190 static {
191 /* ensure that the necessary native libraries are loaded */
192 Toolkit.loadLibraries();
193 if (!GraphicsEnvironment.isHeadless()) {
194 initIDs();
195 }
196 }
197
198 /**
199 * Initialize JNI field and method IDs for fields that may be
200 * accessed from C.
201 */
202 private static native void initIDs();
203
204 /**
205 * Hook into native data.
206 */
207 private transient long pData;
208
209 private transient Object anchor = new Object();
210
211 static class CursorDisposer implements sun.java2d.DisposerRecord {
212 volatile long pData;
213
214 public CursorDisposer(long pData) {
215 this .pData = pData;
216 }
217
218 public void dispose() {
219 if (pData != 0) {
220 finalizeImpl(pData);
221 }
222 }
223 }
224
225 transient CursorDisposer disposer;
226
227 private void setPData(long pData) {
228 this .pData = pData;
229 if (GraphicsEnvironment.isHeadless()) {
230 return;
231 }
232 if (disposer == null) {
233 disposer = new CursorDisposer(pData);
234 // anchor is null after deserialization
235 if (anchor == null) {
236 anchor = new Object();
237 }
238 sun.java2d.Disposer.addRecord(anchor, disposer);
239 } else {
240 disposer.pData = pData;
241 }
242 }
243
244 /**
245 * The user-visible name of the cursor.
246 *
247 * @serial
248 * @see #getName()
249 */
250 protected String name;
251
252 /**
253 * Returns a cursor object with the specified predefined type.
254 *
255 * @param type the type of predefined cursor
256 * @return the specified predefined cursor
257 * @throws IllegalArgumentException if the specified cursor type is
258 * invalid
259 */
260 static public Cursor getPredefinedCursor(int type) {
261 if (type < Cursor.DEFAULT_CURSOR || type > Cursor.MOVE_CURSOR) {
262 throw new IllegalArgumentException("illegal cursor type");
263 }
264 if (predefined[type] == null) {
265 predefined[type] = new Cursor(type);
266 }
267 return predefined[type];
268 }
269
270 /**
271 * Returns a system-specific custom cursor object matching the
272 * specified name. Cursor names are, for example: "Invalid.16x16"
273 *
274 * @param name a string describing the desired system-specific custom cursor
275 * @return the system specific custom cursor named
276 * @exception HeadlessException if
277 * <code>GraphicsEnvironment.isHeadless</code> returns true
278 */
279 static public Cursor getSystemCustomCursor(final String name)
280 throws AWTException, HeadlessException {
281 GraphicsEnvironment.checkHeadless();
282 Cursor cursor = (Cursor) systemCustomCursors.get(name);
283
284 if (cursor == null) {
285 synchronized (systemCustomCursors) {
286 if (systemCustomCursorProperties == null)
287 loadSystemCustomCursorProperties();
288 }
289
290 String prefix = CursorDotPrefix + name;
291 String key = prefix + DotFileSuffix;
292
293 if (!systemCustomCursorProperties.containsKey(key)) {
294 if (dbg.on) {
295 dbg.println("Cursor.getSystemCustomCursor(" + name
296 + ") returned null");
297 }
298 return null;
299 }
300
301 final String fileName = systemCustomCursorProperties
302 .getProperty(key);
303
304 String localized = (String) systemCustomCursorProperties
305 .getProperty(prefix + DotNameSuffix);
306
307 if (localized == null)
308 localized = name;
309
310 String hotspot = (String) systemCustomCursorProperties
311 .getProperty(prefix + DotHotspotSuffix);
312
313 if (hotspot == null)
314 throw new AWTException(
315 "no hotspot property defined for cursor: "
316 + name);
317
318 StringTokenizer st = new StringTokenizer(hotspot, ",");
319
320 if (st.countTokens() != 2)
321 throw new AWTException(
322 "failed to parse hotspot property for cursor: "
323 + name);
324
325 int x = 0;
326 int y = 0;
327
328 try {
329 x = Integer.parseInt(st.nextToken());
330 y = Integer.parseInt(st.nextToken());
331 } catch (NumberFormatException nfe) {
332 throw new AWTException(
333 "failed to parse hotspot property for cursor: "
334 + name);
335 }
336
337 try {
338 final int fx = x;
339 final int fy = y;
340 final String flocalized = localized;
341
342 cursor = (Cursor) java.security.AccessController
343 .doPrivileged(new java.security.PrivilegedExceptionAction() {
344 public Object run() throws Exception {
345 Toolkit toolkit = Toolkit
346 .getDefaultToolkit();
347 Image image = toolkit
348 .getImage(systemCustomCursorDirPrefix
349 + fileName);
350 return toolkit.createCustomCursor(
351 image, new Point(fx, fy),
352 flocalized);
353 }
354 });
355 } catch (Exception e) {
356 throw new AWTException("Exception: " + e.getClass()
357 + " " + e.getMessage()
358 + " occurred while creating cursor " + name);
359 }
360
361 if (cursor == null) {
362 if (dbg.on) {
363 dbg.println("Cursor.getSystemCustomCursor(" + name
364 + ") returned null");
365 }
366 } else {
367 systemCustomCursors.put(name, cursor);
368 }
369 }
370
371 return cursor;
372 }
373
374 /**
375 * Return the system default cursor.
376 */
377 static public Cursor getDefaultCursor() {
378 return getPredefinedCursor(Cursor.DEFAULT_CURSOR);
379 }
380
381 /**
382 * Creates a new cursor object with the specified type.
383 * @param type the type of cursor
384 * @throws IllegalArgumentException if the specified cursor type
385 * is invalid
386 */
387 @ConstructorProperties({"type"})
388 public Cursor(int type) {
389 if (type < Cursor.DEFAULT_CURSOR || type > Cursor.MOVE_CURSOR) {
390 throw new IllegalArgumentException("illegal cursor type");
391 }
392 this .type = type;
393
394 // Lookup localized name.
395 name = Toolkit.getProperty(cursorProperties[type][0],
396 cursorProperties[type][1]);
397 }
398
399 /**
400 * Creates a new custom cursor object with the specified name.<p>
401 * Note: this constructor should only be used by AWT implementations
402 * as part of their support for custom cursors. Applications should
403 * use Toolkit.createCustomCursor().
404 * @param name the user-visible name of the cursor.
405 * @see java.awt.Toolkit#createCustomCursor
406 */
407 protected Cursor(String name) {
408 this .type = Cursor.CUSTOM_CURSOR;
409 this .name = name;
410 }
411
412 /**
413 * Returns the type for this cursor.
414 */
415 public int getType() {
416 return type;
417 }
418
419 /**
420 * Returns the name of this cursor.
421 * @return a localized description of this cursor.
422 * @since 1.2
423 */
424 public String getName() {
425 return name;
426 }
427
428 /**
429 * Returns a string representation of this cursor.
430 * @return a string representation of this cursor.
431 * @since 1.2
432 */
433 public String toString() {
434 return getClass().getName() + "[" + getName() + "]";
435 }
436
437 /*
438 * load the cursor.properties file
439 */
440 private static void loadSystemCustomCursorProperties()
441 throws AWTException {
442 synchronized (systemCustomCursors) {
443 systemCustomCursorProperties = new Properties();
444
445 try {
446 AccessController
447 .doPrivileged(new java.security.PrivilegedExceptionAction() {
448 public Object run() throws Exception {
449 FileInputStream fis = null;
450 try {
451 fis = new FileInputStream(
452 systemCustomCursorPropertiesFile);
453 systemCustomCursorProperties
454 .load(fis);
455 } finally {
456 if (fis != null)
457 fis.close();
458 }
459 return null;
460 }
461 });
462 } catch (Exception e) {
463 systemCustomCursorProperties = null;
464 throw new AWTException("Exception: " + e.getClass()
465 + " " + e.getMessage()
466 + " occurred while loading: "
467 + systemCustomCursorPropertiesFile);
468 }
469 }
470 }
471
472 private native static void finalizeImpl(long pData);
473 }
|