comparison dwt/graphics/Device.d @ 0:380af2bdd8e5

Upload of whole dwt tree
author Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com>
date Sat, 09 Aug 2008 17:00:02 +0200
parents
children ab8b5765e3d1 2952d5604c0a
comparison
equal deleted inserted replaced
-1:000000000000 0:380af2bdd8e5
1 /*******************************************************************************
2 * Copyright (c) 2000, 2007 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 module dwt.graphics.Device;
12
13 import dwt.dwthelper.utils;
14
15 import dwt.DWT;
16 import dwt.DWTException;
17 import dwt.internal.Compatibility;
18 import dwt.internal.cocoa.NSArray;
19 import dwt.internal.cocoa.NSDictionary;
20 import dwt.internal.cocoa.NSFont;
21 import dwt.internal.cocoa.NSFontManager;
22 import dwt.internal.cocoa.NSRect;
23 import dwt.internal.cocoa.NSScreen;
24 import dwt.internal.cocoa.NSSize;
25 import dwt.internal.cocoa.NSString;
26 import dwt.internal.cocoa.NSValue;
27 import dwt.internal.cocoa.OS;
28 import dwt.internal.cocoa.id;
29
30 /**
31 * This class is the abstract superclass of all device objects,
32 * such as the Display device and the Printer device. Devices
33 * can have a graphics context (GC) created for them, and they
34 * can be drawn on by sending messages to the associated GC.
35 */
36 public abstract class Device implements Drawable {
37
38 /* Debugging */
39 public static bool DEBUG;
40 bool debug = DEBUG;
41 bool tracking = DEBUG;
42 Error [] errors;
43 Object [] objects;
44 Object trackingLock;
45
46 /* Disposed flag */
47 bool disposed, warnings;
48
49 Color COLOR_BLACK, COLOR_DARK_RED, COLOR_DARK_GREEN, COLOR_DARK_YELLOW, COLOR_DARK_BLUE;
50 Color COLOR_DARK_MAGENTA, COLOR_DARK_CYAN, COLOR_GRAY, COLOR_DARK_GRAY, COLOR_RED;
51 Color COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE;
52
53 /* System Font */
54 Font systemFont;
55
56 /*
57 * TEMPORARY CODE. When a graphics object is
58 * created and the device parameter is null,
59 * the current Display is used. This presents
60 * a problem because DWT graphics does not
61 * reference classes in DWT widgets. The correct
62 * fix is to remove this feature. Unfortunately,
63 * too many application programs rely on this
64 * feature.
65 *
66 * This code will be removed in the future.
67 */
68 protected static Device CurrentDevice;
69 protected static Runnable DeviceFinder;
70 static {
71 try {
72 Class.forName ("dwt.widgets.Display");
73 } catch (Throwable e) {}
74 }
75
76 /*
77 * TEMPORARY CODE.
78 */
79 static synchronized Device getDevice () {
80 if (DeviceFinder !is null) DeviceFinder.run();
81 Device device = CurrentDevice;
82 CurrentDevice = null;
83 return device;
84 }
85
86 /**
87 * Constructs a new instance of this class.
88 * <p>
89 * You must dispose the device when it is no longer required.
90 * </p>
91 *
92 * @see #create
93 * @see #init
94 *
95 * @since 3.1
96 */
97 public Device() {
98 this(null);
99 }
100
101 /**
102 * Constructs a new instance of this class.
103 * <p>
104 * You must dispose the device when it is no longer required.
105 * </p>
106 *
107 * @param data the DeviceData which describes the receiver
108 *
109 * @see #create
110 * @see #init
111 * @see DeviceData
112 */
113 public Device(DeviceData data) {
114 synchronized (Device.class) {
115 if (data !is null) {
116 debug = data.debug;
117 tracking = data.tracking;
118 }
119 if (tracking) {
120 errors = new Error [128];
121 objects = new Object [128];
122 trackingLock = new Object ();
123 }
124 create (data);
125 init ();
126 }
127 }
128
129 /**
130 * Throws an <code>DWTException</code> if the receiver can not
131 * be accessed by the caller. This may include both checks on
132 * the state of the receiver and more generally on the entire
133 * execution context. This method <em>should</em> be called by
134 * device implementors to enforce the standard DWT invariants.
135 * <p>
136 * Currently, it is an error to invoke any method (other than
137 * <code>isDisposed()</code> and <code>dispose()</code>) on a
138 * device that has had its <code>dispose()</code> method called.
139 * </p><p>
140 * In future releases of DWT, there may be more or fewer error
141 * checks and exceptions may be thrown for different reasons.
142 * <p>
143 *
144 * @exception DWTException <ul>
145 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
146 * </ul>
147 */
148 protected void checkDevice () {
149 if (disposed) DWT.error(DWT.ERROR_DEVICE_DISPOSED);
150 }
151
152 /**
153 * Creates the device in the operating system. If the device
154 * does not have a handle, this method may do nothing depending
155 * on the device.
156 * <p>
157 * This method is called before <code>init</code>.
158 * </p><p>
159 * Subclasses are supposed to reimplement this method and not
160 * call the <code>super</code> implementation.
161 * </p>
162 *
163 * @param data the DeviceData which describes the receiver
164 *
165 * @see #init
166 */
167 protected void create (DeviceData data) {
168 }
169
170 /**
171 * Disposes of the operating system resources associated with
172 * the receiver. After this method has been invoked, the receiver
173 * will answer <code>true</code> when sent the message
174 * <code>isDisposed()</code>.
175 *
176 * @see #release
177 * @see #destroy
178 * @see #checkDevice
179 */
180 public void dispose () {
181 synchronized (Device.class) {
182 if (isDisposed()) return;
183 checkDevice ();
184 release ();
185 destroy ();
186 disposed = true;
187 if (tracking) {
188 synchronized (trackingLock) {
189 objects = null;
190 errors = null;
191 trackingLock = null;
192 }
193 }
194 }
195 }
196
197 void dispose_Object (Object object) {
198 synchronized (trackingLock) {
199 for (int i=0; i<objects.length; i++) {
200 if (objects [i] is object) {
201 objects [i] = null;
202 errors [i] = null;
203 return;
204 }
205 }
206 }
207 }
208
209 /**
210 * Destroys the device in the operating system and releases
211 * the device's handle. If the device does not have a handle,
212 * this method may do nothing depending on the device.
213 * <p>
214 * This method is called after <code>release</code>.
215 * </p><p>
216 * Subclasses are supposed to reimplement this method and not
217 * call the <code>super</code> implementation.
218 * </p>
219 *
220 * @see #dispose
221 * @see #release
222 */
223 protected void destroy () {
224 }
225
226 /**
227 * Returns a rectangle describing the receiver's size and location.
228 *
229 * @return the bounding rectangle
230 *
231 * @exception DWTException <ul>
232 * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
233 * </ul>
234 */
235 public Rectangle getBounds () {
236 checkDevice ();
237 NSScreen screen = NSScreen.mainScreen();
238 NSRect rect = screen.frame();
239 return new Rectangle((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
240 }
241
242 /**
243 * Returns a <code>DeviceData</code> based on the receiver.
244 * Modifications made to this <code>DeviceData</code> will not
245 * affect the receiver.
246 *
247 * @return a <code>DeviceData</code> containing the device's data and attributes
248 *
249 * @exception DWTException <ul>
250 * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
251 * </ul>
252 *
253 * @see DeviceData
254 */
255 public DeviceData getDeviceData () {
256 checkDevice();
257 DeviceData data = new DeviceData ();
258 data.debug = debug;
259 data.tracking = tracking;
260 if (tracking) {
261 synchronized (trackingLock) {
262 int count = 0, length = objects.length;
263 for (int i=0; i<length; i++) {
264 if (objects [i] !is null) count++;
265 }
266 int index = 0;
267 data.objects = new Object [count];
268 data.errors = new Error [count];
269 for (int i=0; i<length; i++) {
270 if (objects [i] !is null) {
271 data.objects [index] = objects [i];
272 data.errors [index] = errors [i];
273 index++;
274 }
275 }
276 }
277 } else {
278 data.objects = new Object [0];
279 data.errors = new Error [0];
280 }
281 return data;
282 }
283
284 /**
285 * Returns a rectangle which describes the area of the
286 * receiver which is capable of displaying data.
287 *
288 * @return the client area
289 *
290 * @exception DWTException <ul>
291 * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
292 * </ul>
293 *
294 * @see #getBounds
295 */
296 public Rectangle getClientArea () {
297 checkDevice ();
298 NSScreen screen = NSScreen.mainScreen();
299 NSRect rect = screen.visibleFrame();
300 return new Rectangle((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
301 }
302
303 /**
304 * Returns the bit depth of the screen, which is the number of
305 * bits it takes to represent the number of unique colors that
306 * the screen is currently capable of displaying. This number
307 * will typically be one of 1, 8, 15, 16, 24 or 32.
308 *
309 * @return the depth of the screen
310 *
311 * @exception DWTException <ul>
312 * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
313 * </ul>
314 */
315 public int getDepth () {
316 checkDevice ();
317 return OS.NSBitsPerPixelFromDepth(NSScreen.mainScreen().depth());
318 }
319
320 /**
321 * Returns a point whose x coordinate is the horizontal
322 * dots per inch of the display, and whose y coordinate
323 * is the vertical dots per inch of the display.
324 *
325 * @return the horizontal and vertical DPI
326 *
327 * @exception DWTException <ul>
328 * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
329 * </ul>
330 */
331 public Point getDPI () {
332 checkDevice ();
333 NSDictionary dictionary = NSScreen.mainScreen().deviceDescription();
334 NSValue value = new NSValue(dictionary.objectForKey(new id(OS.NSDeviceResolution())).id);
335 NSSize size = value.sizeValue();
336 return new Point((int)size.width, (int)size.height);
337 }
338
339 /**
340 * Returns <code>FontData</code> objects which describe
341 * the fonts that match the given arguments. If the
342 * <code>faceName</code> is null, all fonts will be returned.
343 *
344 * @param faceName the name of the font to look for, or null
345 * @param scalable if true only scalable fonts are returned, otherwise only non-scalable fonts are returned.
346 * @return the matching font data
347 *
348 * @exception DWTException <ul>
349 * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
350 * </ul>
351 */
352 public FontData[] getFontList (String faceName, bool scalable) {
353 checkDevice ();
354 if (!scalable) return new FontData[0];
355 NSArray fonts = NSFontManager.sharedFontManager().availableFonts();
356 int count = 0;
357 FontData[] fds = new FontData[fonts.count()];
358 for (int i = 0; i < fds.length; i++) {
359 NSString str = new NSString(fonts.objectAtIndex(i));
360 char[] buffer = new char[str.length()];
361 str.getCharacters_(buffer);
362 String nsName = new String(buffer);
363 String name = nsName;
364 int index = nsName.indexOf('-');
365 if (index !is -1) name = name.substring(0, index);
366 int style = DWT.NORMAL;
367 if (nsName.indexOf("Italic") !is -1) style |= DWT.ITALIC;
368 if (nsName.indexOf("Bold") !is -1) style |= DWT.BOLD;
369 if (faceName is null || Compatibility.equalsIgnoreCase(faceName, name)) {
370 FontData data = new FontData(name, 0, style);
371 data.nsName = nsName;
372 fds[count++] = data;
373 }
374 }
375 if (count is fds.length) return fds;
376 FontData[] result = new FontData[count];
377 System.arraycopy(fds, 0, result, 0, count);
378 return result;
379 }
380
381 /**
382 * Returns the matching standard color for the given
383 * constant, which should be one of the color constants
384 * specified in class <code>DWT</code>. Any value other
385 * than one of the DWT color constants which is passed
386 * in will result in the color black. This color should
387 * not be freed because it was allocated by the system,
388 * not the application.
389 *
390 * @param id the color constant
391 * @return the matching color
392 *
393 * @exception DWTException <ul>
394 * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
395 * </ul>
396 *
397 * @see DWT
398 */
399 public Color getSystemColor (int id) {
400 checkDevice ();
401 switch (id) {
402 case DWT.COLOR_BLACK: return COLOR_BLACK;
403 case DWT.COLOR_DARK_RED: return COLOR_DARK_RED;
404 case DWT.COLOR_DARK_GREEN: return COLOR_DARK_GREEN;
405 case DWT.COLOR_DARK_YELLOW: return COLOR_DARK_YELLOW;
406 case DWT.COLOR_DARK_BLUE: return COLOR_DARK_BLUE;
407 case DWT.COLOR_DARK_MAGENTA: return COLOR_DARK_MAGENTA;
408 case DWT.COLOR_DARK_CYAN: return COLOR_DARK_CYAN;
409 case DWT.COLOR_GRAY: return COLOR_GRAY;
410 case DWT.COLOR_DARK_GRAY: return COLOR_DARK_GRAY;
411 case DWT.COLOR_RED: return COLOR_RED;
412 case DWT.COLOR_GREEN: return COLOR_GREEN;
413 case DWT.COLOR_YELLOW: return COLOR_YELLOW;
414 case DWT.COLOR_BLUE: return COLOR_BLUE;
415 case DWT.COLOR_MAGENTA: return COLOR_MAGENTA;
416 case DWT.COLOR_CYAN: return COLOR_CYAN;
417 case DWT.COLOR_WHITE: return COLOR_WHITE;
418 }
419 return COLOR_BLACK;
420 }
421
422 /**
423 * Returns a reasonable font for applications to use.
424 * On some platforms, this will match the "default font"
425 * or "system font" if such can be found. This font
426 * should not be freed because it was allocated by the
427 * system, not the application.
428 * <p>
429 * Typically, applications which want the default look
430 * should simply not set the font on the widgets they
431 * create. Widgets are always created with the correct
432 * default font for the class of user-interface component
433 * they represent.
434 * </p>
435 *
436 * @return a font
437 *
438 * @exception DWTException <ul>
439 * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
440 * </ul>
441 */
442 public Font getSystemFont () {
443 checkDevice ();
444 return systemFont;
445 }
446
447 /**
448 * Returns <code>true</code> if the underlying window system prints out
449 * warning messages on the console, and <code>setWarnings</code>
450 * had previously been called with <code>true</code>.
451 *
452 * @return <code>true</code>if warnings are being handled, and <code>false</code> otherwise
453 *
454 * @exception DWTException <ul>
455 * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
456 * </ul>
457 */
458 public bool getWarnings () {
459 checkDevice ();
460 return warnings;
461 }
462
463 /**
464 * Initializes any internal resources needed by the
465 * device.
466 * <p>
467 * This method is called after <code>create</code>.
468 * </p><p>
469 * If subclasses reimplement this method, they must
470 * call the <code>super</code> implementation.
471 * </p>
472 *
473 * @see #create
474 */
475 protected void init () {
476 /* Create the standard colors */
477 COLOR_BLACK = new Color (this, 0,0,0);
478 COLOR_DARK_RED = new Color (this, 0x80,0,0);
479 COLOR_DARK_GREEN = new Color (this, 0,0x80,0);
480 COLOR_DARK_YELLOW = new Color (this, 0x80,0x80,0);
481 COLOR_DARK_BLUE = new Color (this, 0,0,0x80);
482 COLOR_DARK_MAGENTA = new Color (this, 0x80,0,0x80);
483 COLOR_DARK_CYAN = new Color (this, 0,0x80,0x80);
484 COLOR_GRAY = new Color (this, 0xC0,0xC0,0xC0);
485 COLOR_DARK_GRAY = new Color (this, 0x80,0x80,0x80);
486 COLOR_RED = new Color (this, 0xFF,0,0);
487 COLOR_GREEN = new Color (this, 0,0xFF,0);
488 COLOR_YELLOW = new Color (this, 0xFF,0xFF,0);
489 COLOR_BLUE = new Color (this, 0,0,0xFF);
490 COLOR_MAGENTA = new Color (this, 0xFF,0,0xFF);
491 COLOR_CYAN = new Color (this, 0,0xFF,0xFF);
492 COLOR_WHITE = new Color (this, 0xFF,0xFF,0xFF);
493
494 /* Initialize the system font slot */
495 NSFont font = NSFont.systemFontOfSize(NSFont.systemFontSize());
496 systemFont = Font.cocoa_new(this, font);
497 }
498
499 /**
500 * Invokes platform specific functionality to allocate a new GC handle.
501 * <p>
502 * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
503 * API for <code>Device</code>. It is marked public only so that it
504 * can be shared within the packages provided by DWT. It is not
505 * available on all platforms, and should never be called from
506 * application code.
507 * </p>
508 *
509 * @param data the platform specific GC data
510 * @return the platform specific GC handle
511 */
512 public abstract int internal_new_GC (GCData data);
513
514 /**
515 * Invokes platform specific functionality to dispose a GC handle.
516 * <p>
517 * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
518 * API for <code>Device</code>. It is marked public only so that it
519 * can be shared within the packages provided by DWT. It is not
520 * available on all platforms, and should never be called from
521 * application code.
522 * </p>
523 *
524 * @param hDC the platform specific GC handle
525 * @param data the platform specific GC data
526 */
527 public abstract void internal_dispose_GC (int handle, GCData data);
528
529 /**
530 * Returns <code>true</code> if the device has been disposed,
531 * and <code>false</code> otherwise.
532 * <p>
533 * This method gets the dispose state for the device.
534 * When a device has been disposed, it is an error to
535 * invoke any other method using the device.
536 *
537 * @return <code>true</code> when the device is disposed and <code>false</code> otherwise
538 */
539 public bool isDisposed () {
540 synchronized (Device.class) {
541 return disposed;
542 }
543 }
544
545 /**
546 * Loads the font specified by a file. The font will be
547 * present in the list of fonts available to the application.
548 *
549 * @param path the font file path
550 * @return whether the font was successfully loaded
551 *
552 * @exception DWTException <ul>
553 * <li>ERROR_NULL_ARGUMENT - if path is null</li>
554 * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
555 * </ul>
556 *
557 * @see Font
558 *
559 * @since 3.3
560 */
561 public bool loadFont (String path) {
562 checkDevice();
563 if (path is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
564 bool result = false;
565 char [] chars = new char [path.length ()];
566 path.getChars (0, chars.length, chars, 0);
567 return result;
568 }
569
570 void new_Object (Object object) {
571 synchronized (trackingLock) {
572 for (int i=0; i<objects.length; i++) {
573 if (objects [i] is null) {
574 objects [i] = object;
575 errors [i] = new Error ();
576 return;
577 }
578 }
579 Object [] newObjects = new Object [objects.length + 128];
580 System.arraycopy (objects, 0, newObjects, 0, objects.length);
581 newObjects [objects.length] = object;
582 objects = newObjects;
583 Error [] newErrors = new Error [errors.length + 128];
584 System.arraycopy (errors, 0, newErrors, 0, errors.length);
585 newErrors [errors.length] = new Error ();
586 errors = newErrors;
587 }
588 }
589
590 /**
591 * Releases any internal resources back to the operating
592 * system and clears all fields except the device handle.
593 * <p>
594 * When a device is destroyed, resources that were acquired
595 * on behalf of the programmer need to be returned to the
596 * operating system. For example, if the device allocated a
597 * font to be used as the system font, this font would be
598 * freed in <code>release</code>. Also,to assist the garbage
599 * collector and minimize the amount of memory that is not
600 * reclaimed when the programmer keeps a reference to a
601 * disposed device, all fields except the handle are zero'd.
602 * The handle is needed by <code>destroy</code>.
603 * </p>
604 * This method is called before <code>destroy</code>.
605 * </p><p>
606 * If subclasses reimplement this method, they must
607 * call the <code>super</code> implementation.
608 * </p>
609 *
610 * @see #dispose
611 * @see #destroy
612 */
613 protected void release () {
614 COLOR_BLACK = COLOR_DARK_RED = COLOR_DARK_GREEN = COLOR_DARK_YELLOW = COLOR_DARK_BLUE =
615 COLOR_DARK_MAGENTA = COLOR_DARK_CYAN = COLOR_GRAY = COLOR_DARK_GRAY = COLOR_RED =
616 COLOR_GREEN = COLOR_YELLOW = COLOR_BLUE = COLOR_MAGENTA = COLOR_CYAN = COLOR_WHITE = null;
617 }
618
619 /**
620 * If the underlying window system supports printing warning messages
621 * to the console, setting warnings to <code>false</code> prevents these
622 * messages from being printed. If the argument is <code>true</code> then
623 * message printing is not blocked.
624 *
625 * @param warnings <code>true</code>if warnings should be printed, and <code>false</code> otherwise
626 *
627 * @exception DWTException <ul>
628 * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
629 * </ul>
630 */
631 public void setWarnings (bool warnings) {
632 checkDevice ();
633 this.warnings = warnings;
634 }
635
636 }