View Javadoc
1   /*
2    * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  
27  package java.awt;
28  
29  import java.awt.image.ColorModel;
30  
31  import sun.awt.AWTAccessor;
32  import sun.awt.AppContext;
33  import sun.awt.SunToolkit;
34  
35  /**
36   * The <code>GraphicsDevice</code> class describes the graphics devices
37   * that might be available in a particular graphics environment.  These
38   * include screen and printer devices. Note that there can be many screens
39   * and many printers in an instance of {@link GraphicsEnvironment}. Each
40   * graphics device has one or more {@link GraphicsConfiguration} objects
41   * associated with it.  These objects specify the different configurations
42   * in which the <code>GraphicsDevice</code> can be used.
43   * <p>
44   * In a multi-screen environment, the <code>GraphicsConfiguration</code>
45   * objects can be used to render components on multiple screens.  The
46   * following code sample demonstrates how to create a <code>JFrame</code>
47   * object for each <code>GraphicsConfiguration</code> on each screen
48   * device in the <code>GraphicsEnvironment</code>:
49   * <pre>{@code
50   *   GraphicsEnvironment ge = GraphicsEnvironment.
51   *   getLocalGraphicsEnvironment();
52   *   GraphicsDevice[] gs = ge.getScreenDevices();
53   *   for (int j = 0; j < gs.length; j++) {
54   *      GraphicsDevice gd = gs[j];
55   *      GraphicsConfiguration[] gc =
56   *      gd.getConfigurations();
57   *      for (int i=0; i < gc.length; i++) {
58   *         JFrame f = new
59   *         JFrame(gs[j].getDefaultConfiguration());
60   *         Canvas c = new Canvas(gc[i]);
61   *         Rectangle gcBounds = gc[i].getBounds();
62   *         int xoffs = gcBounds.x;
63   *         int yoffs = gcBounds.y;
64   *         f.getContentPane().add(c);
65   *         f.setLocation((i*50)+xoffs, (i*60)+yoffs);
66   *         f.show();
67   *      }
68   *   }
69   * }</pre>
70   * <p>
71   * For more information on full-screen exclusive mode API, see the
72   * <a href="http://docs.oracle.com/javase/tutorial/extra/fullscreen/index.html">
73   * Full-Screen Exclusive Mode API Tutorial</a>.
74   *
75   * @see GraphicsEnvironment
76   * @see GraphicsConfiguration
77   */
78  public abstract class GraphicsDevice {
79  
80      private Window fullScreenWindow;
81      private AppContext fullScreenAppContext; // tracks which AppContext
82                                               // created the FS window
83      // this lock is used for making synchronous changes to the AppContext's
84      // current full screen window
85      private final Object fsAppContextLock = new Object();
86  
87      private Rectangle windowedModeBounds;
88  
89      /**
90       * This is an abstract class that cannot be instantiated directly.
91       * Instances must be obtained from a suitable factory or query method.
92       * @see GraphicsEnvironment#getScreenDevices
93       * @see GraphicsEnvironment#getDefaultScreenDevice
94       * @see GraphicsConfiguration#getDevice
95       */
96      protected GraphicsDevice() {
97      }
98  
99      /**
100      * Device is a raster screen.
101      */
102     public final static int TYPE_RASTER_SCREEN          = 0;
103 
104     /**
105      * Device is a printer.
106      */
107     public final static int TYPE_PRINTER                = 1;
108 
109     /**
110      * Device is an image buffer.  This buffer can reside in device
111      * or system memory but it is not physically viewable by the user.
112      */
113     public final static int TYPE_IMAGE_BUFFER           = 2;
114 
115     /**
116      * Kinds of translucency supported by the underlying system.
117      *
118      * @see #isWindowTranslucencySupported
119      *
120      * @since 1.7
121      */
122     public static enum WindowTranslucency {
123         /**
124          * Represents support in the underlying system for windows each pixel
125          * of which is guaranteed to be either completely opaque, with
126          * an alpha value of 1.0, or completely transparent, with an alpha
127          * value of 0.0.
128          */
129         PERPIXEL_TRANSPARENT,
130         /**
131          * Represents support in the underlying system for windows all of
132          * the pixels of which have the same alpha value between or including
133          * 0.0 and 1.0.
134          */
135         TRANSLUCENT,
136         /**
137          * Represents support in the underlying system for windows that
138          * contain or might contain pixels with arbitrary alpha values
139          * between and including 0.0 and 1.0.
140          */
141         PERPIXEL_TRANSLUCENT;
142     }
143 
144     /**
145      * Returns the type of this <code>GraphicsDevice</code>.
146      * @return the type of this <code>GraphicsDevice</code>, which can
147      * either be TYPE_RASTER_SCREEN, TYPE_PRINTER or TYPE_IMAGE_BUFFER.
148      * @see #TYPE_RASTER_SCREEN
149      * @see #TYPE_PRINTER
150      * @see #TYPE_IMAGE_BUFFER
151      */
152     public abstract int getType();
153 
154     /**
155      * Returns the identification string associated with this
156      * <code>GraphicsDevice</code>.
157      * <p>
158      * A particular program might use more than one
159      * <code>GraphicsDevice</code> in a <code>GraphicsEnvironment</code>.
160      * This method returns a <code>String</code> identifying a
161      * particular <code>GraphicsDevice</code> in the local
162      * <code>GraphicsEnvironment</code>.  Although there is
163      * no public method to set this <code>String</code>, a programmer can
164      * use the <code>String</code> for debugging purposes.  Vendors of
165      * the Java&trade; Runtime Environment can
166      * format the return value of the <code>String</code>.  To determine
167      * how to interpret the value of the <code>String</code>, contact the
168      * vendor of your Java Runtime.  To find out who the vendor is, from
169      * your program, call the
170      * {@link System#getProperty(String) getProperty} method of the
171      * System class with "java.vendor".
172      * @return a <code>String</code> that is the identification
173      * of this <code>GraphicsDevice</code>.
174      */
175     public abstract String getIDstring();
176 
177     /**
178      * Returns all of the <code>GraphicsConfiguration</code>
179      * objects associated with this <code>GraphicsDevice</code>.
180      * @return an array of <code>GraphicsConfiguration</code>
181      * objects that are associated with this
182      * <code>GraphicsDevice</code>.
183      */
184     public abstract GraphicsConfiguration[] getConfigurations();
185 
186     /**
187      * Returns the default <code>GraphicsConfiguration</code>
188      * associated with this <code>GraphicsDevice</code>.
189      * @return the default <code>GraphicsConfiguration</code>
190      * of this <code>GraphicsDevice</code>.
191      */
192     public abstract GraphicsConfiguration getDefaultConfiguration();
193 
194     /**
195      * Returns the "best" configuration possible that passes the
196      * criteria defined in the {@link GraphicsConfigTemplate}.
197      * @param gct the <code>GraphicsConfigTemplate</code> object
198      * used to obtain a valid <code>GraphicsConfiguration</code>
199      * @return a <code>GraphicsConfiguration</code> that passes
200      * the criteria defined in the specified
201      * <code>GraphicsConfigTemplate</code>.
202      * @see GraphicsConfigTemplate
203      */
204     public GraphicsConfiguration
205            getBestConfiguration(GraphicsConfigTemplate gct) {
206         GraphicsConfiguration[] configs = getConfigurations();
207         return gct.getBestConfiguration(configs);
208     }
209 
210     /**
211      * Returns <code>true</code> if this <code>GraphicsDevice</code>
212      * supports full-screen exclusive mode.
213      * If a SecurityManager is installed, its
214      * <code>checkPermission</code> method will be called
215      * with <code>AWTPermission("fullScreenExclusive")</code>.
216      * <code>isFullScreenSupported</code> returns true only if
217      * that permission is granted.
218      * @return whether full-screen exclusive mode is available for
219      * this graphics device
220      * @see java.awt.AWTPermission
221      * @since 1.4
222      */
223     public boolean isFullScreenSupported() {
224         return false;
225     }
226 
227     /**
228      * Enter full-screen mode, or return to windowed mode.  The entered
229      * full-screen mode may be either exclusive or simulated.  Exclusive
230      * mode is only available if <code>isFullScreenSupported</code>
231      * returns <code>true</code>.
232      * <p>
233      * Exclusive mode implies:
234      * <ul>
235      * <li>Windows cannot overlap the full-screen window.  All other application
236      * windows will always appear beneath the full-screen window in the Z-order.
237      * <li>There can be only one full-screen window on a device at any time,
238      * so calling this method while there is an existing full-screen Window
239      * will cause the existing full-screen window to
240      * return to windowed mode.
241      * <li>Input method windows are disabled.  It is advisable to call
242      * <code>Component.enableInputMethods(false)</code> to make a component
243      * a non-client of the input method framework.
244      * </ul>
245      * <p>
246      * The simulated full-screen mode places and resizes the window to the maximum
247      * possible visible area of the screen. However, the native windowing system
248      * may modify the requested geometry-related data, so that the {@code Window} object
249      * is placed and sized in a way that corresponds closely to the desktop settings.
250      * <p>
251      * When entering full-screen mode, if the window to be used as a
252      * full-screen window is not visible, this method will make it visible.
253      * It will remain visible when returning to windowed mode.
254      * <p>
255      * When entering full-screen mode, all the translucency effects are reset for
256      * the window. Its shape is set to {@code null}, the opacity value is set to
257      * 1.0f, and the background color alpha is set to 255 (completely opaque).
258      * These values are not restored when returning to windowed mode.
259      * <p>
260      * It is unspecified and platform-dependent how decorated windows operate
261      * in full-screen mode. For this reason, it is recommended to turn off
262      * the decorations in a {@code Frame} or {@code Dialog} object by using the
263      * {@code setUndecorated} method.
264      * <p>
265      * When returning to windowed mode from an exclusive full-screen window,
266      * any display changes made by calling {@code setDisplayMode} are
267      * automatically restored to their original state.
268      *
269      * @param w a window to use as the full-screen window; {@code null}
270      * if returning to windowed mode.  Some platforms expect the
271      * fullscreen window to be a top-level component (i.e., a {@code Frame});
272      * therefore it is preferable to use a {@code Frame} here rather than a
273      * {@code Window}.
274      *
275      * @see #isFullScreenSupported
276      * @see #getFullScreenWindow
277      * @see #setDisplayMode
278      * @see Component#enableInputMethods
279      * @see Component#setVisible
280      * @see Frame#setUndecorated
281      * @see Dialog#setUndecorated
282      *
283      * @since 1.4
284      */
285     public void setFullScreenWindow(Window w) {
286         if (w != null) {
287             if (w.getShape() != null) {
288                 w.setShape(null);
289             }
290             if (w.getOpacity() < 1.0f) {
291                 w.setOpacity(1.0f);
292             }
293             if (!w.isOpaque()) {
294                 Color bgColor = w.getBackground();
295                 bgColor = new Color(bgColor.getRed(), bgColor.getGreen(),
296                                     bgColor.getBlue(), 255);
297                 w.setBackground(bgColor);
298             }
299             // Check if this window is in fullscreen mode on another device.
300             final GraphicsConfiguration gc = w.getGraphicsConfiguration();
301             if (gc != null && gc.getDevice() != this
302                     && gc.getDevice().getFullScreenWindow() == w) {
303                 gc.getDevice().setFullScreenWindow(null);
304             }
305         }
306         if (fullScreenWindow != null && windowedModeBounds != null) {
307             // if the window went into fs mode before it was realized it may
308             // have (0,0) dimensions
309             if (windowedModeBounds.width  == 0) windowedModeBounds.width  = 1;
310             if (windowedModeBounds.height == 0) windowedModeBounds.height = 1;
311             fullScreenWindow.setBounds(windowedModeBounds);
312         }
313         // Set the full screen window
314         synchronized (fsAppContextLock) {
315             // Associate fullscreen window with current AppContext
316             if (w == null) {
317                 fullScreenAppContext = null;
318             } else {
319                 fullScreenAppContext = AppContext.getAppContext();
320             }
321             fullScreenWindow = w;
322         }
323         if (fullScreenWindow != null) {
324             windowedModeBounds = fullScreenWindow.getBounds();
325             // Note that we use the graphics configuration of the device,
326             // not the window's, because we're setting the fs window for
327             // this device.
328             final GraphicsConfiguration gc = getDefaultConfiguration();
329             final Rectangle screenBounds = gc.getBounds();
330             if (SunToolkit.isDispatchThreadForAppContext(fullScreenWindow)) {
331                 // Update graphics configuration here directly and do not wait
332                 // asynchronous notification from the peer. Note that
333                 // setBounds() will reset a GC, if it was set incorrectly.
334                 fullScreenWindow.setGraphicsConfiguration(gc);
335             }
336             fullScreenWindow.setBounds(screenBounds.x, screenBounds.y,
337                                        screenBounds.width, screenBounds.height);
338             fullScreenWindow.setVisible(true);
339             fullScreenWindow.toFront();
340         }
341     }
342 
343     /**
344      * Returns the <code>Window</code> object representing the
345      * full-screen window if the device is in full-screen mode.
346      *
347      * @return the full-screen window, or <code>null</code> if the device is
348      * not in full-screen mode.
349      * @see #setFullScreenWindow(Window)
350      * @since 1.4
351      */
352     public Window getFullScreenWindow() {
353         Window returnWindow = null;
354         synchronized (fsAppContextLock) {
355             // Only return a handle to the current fs window if we are in the
356             // same AppContext that set the fs window
357             if (fullScreenAppContext == AppContext.getAppContext()) {
358                 returnWindow = fullScreenWindow;
359             }
360         }
361         return returnWindow;
362     }
363 
364     /**
365      * Returns <code>true</code> if this <code>GraphicsDevice</code>
366      * supports low-level display changes.
367      * On some platforms low-level display changes may only be allowed in
368      * full-screen exclusive mode (i.e., if {@link #isFullScreenSupported()}
369      * returns {@code true} and the application has already entered
370      * full-screen mode using {@link #setFullScreenWindow}).
371      * @return whether low-level display changes are supported for this
372      * graphics device.
373      * @see #isFullScreenSupported
374      * @see #setDisplayMode
375      * @see #setFullScreenWindow
376      * @since 1.4
377      */
378     public boolean isDisplayChangeSupported() {
379         return false;
380     }
381 
382     /**
383      * Sets the display mode of this graphics device. This is only allowed
384      * if {@link #isDisplayChangeSupported()} returns {@code true} and may
385      * require first entering full-screen exclusive mode using
386      * {@link #setFullScreenWindow} providing that full-screen exclusive mode is
387      * supported (i.e., {@link #isFullScreenSupported()} returns
388      * {@code true}).
389      * <p>
390      *
391      * The display mode must be one of the display modes returned by
392      * {@link #getDisplayModes()}, with one exception: passing a display mode
393      * with {@link DisplayMode#REFRESH_RATE_UNKNOWN} refresh rate will result in
394      * selecting a display mode from the list of available display modes with
395      * matching width, height and bit depth.
396      * However, passing a display mode with {@link DisplayMode#BIT_DEPTH_MULTI}
397      * for bit depth is only allowed if such mode exists in the list returned by
398      * {@link #getDisplayModes()}.
399      * <p>
400      * Example code:
401      * <pre><code>
402      * Frame frame;
403      * DisplayMode newDisplayMode;
404      * GraphicsDevice gd;
405      * // create a Frame, select desired DisplayMode from the list of modes
406      * // returned by gd.getDisplayModes() ...
407      *
408      * if (gd.isFullScreenSupported()) {
409      *     gd.setFullScreenWindow(frame);
410      * } else {
411      *    // proceed in non-full-screen mode
412      *    frame.setSize(...);
413      *    frame.setLocation(...);
414      *    frame.setVisible(true);
415      * }
416      *
417      * if (gd.isDisplayChangeSupported()) {
418      *     gd.setDisplayMode(newDisplayMode);
419      * }
420      * </code></pre>
421      *
422      * @param dm The new display mode of this graphics device.
423      * @exception IllegalArgumentException if the <code>DisplayMode</code>
424      * supplied is <code>null</code>, or is not available in the array returned
425      * by <code>getDisplayModes</code>
426      * @exception UnsupportedOperationException if
427      * <code>isDisplayChangeSupported</code> returns <code>false</code>
428      * @see #getDisplayMode
429      * @see #getDisplayModes
430      * @see #isDisplayChangeSupported
431      * @since 1.4
432      */
433     public void setDisplayMode(DisplayMode dm) {
434         throw new UnsupportedOperationException("Cannot change display mode");
435     }
436 
437     /**
438      * Returns the current display mode of this
439      * <code>GraphicsDevice</code>.
440      * The returned display mode is allowed to have a refresh rate
441      * {@link DisplayMode#REFRESH_RATE_UNKNOWN} if it is indeterminate.
442      * Likewise, the returned display mode is allowed to have a bit depth
443      * {@link DisplayMode#BIT_DEPTH_MULTI} if it is indeterminate or if multiple
444      * bit depths are supported.
445      * @return the current display mode of this graphics device.
446      * @see #setDisplayMode(DisplayMode)
447      * @since 1.4
448      */
449     public DisplayMode getDisplayMode() {
450         GraphicsConfiguration gc = getDefaultConfiguration();
451         Rectangle r = gc.getBounds();
452         ColorModel cm = gc.getColorModel();
453         return new DisplayMode(r.width, r.height, cm.getPixelSize(), 0);
454     }
455 
456     /**
457      * Returns all display modes available for this
458      * <code>GraphicsDevice</code>.
459      * The returned display modes are allowed to have a refresh rate
460      * {@link DisplayMode#REFRESH_RATE_UNKNOWN} if it is indeterminate.
461      * Likewise, the returned display modes are allowed to have a bit depth
462      * {@link DisplayMode#BIT_DEPTH_MULTI} if it is indeterminate or if multiple
463      * bit depths are supported.
464      * @return all of the display modes available for this graphics device.
465      * @since 1.4
466      */
467     public DisplayMode[] getDisplayModes() {
468         return new DisplayMode[] { getDisplayMode() };
469     }
470 
471     /**
472      * This method returns the number of bytes available in
473      * accelerated memory on this device.
474      * Some images are created or cached
475      * in accelerated memory on a first-come,
476      * first-served basis.  On some operating systems,
477      * this memory is a finite resource.  Calling this method
478      * and scheduling the creation and flushing of images carefully may
479      * enable applications to make the most efficient use of
480      * that finite resource.
481      * <br>
482      * Note that the number returned is a snapshot of how much
483      * memory is available; some images may still have problems
484      * being allocated into that memory.  For example, depending
485      * on operating system, driver, memory configuration, and
486      * thread situations, the full extent of the size reported
487      * may not be available for a given image.  There are further
488      * inquiry methods on the {@link ImageCapabilities} object
489      * associated with a VolatileImage that can be used to determine
490      * whether a particular VolatileImage has been created in accelerated
491      * memory.
492      * @return number of bytes available in accelerated memory.
493      * A negative return value indicates that the amount of accelerated memory
494      * on this GraphicsDevice is indeterminate.
495      * @see java.awt.image.VolatileImage#flush
496      * @see ImageCapabilities#isAccelerated
497      * @since 1.4
498      */
499     public int getAvailableAcceleratedMemory() {
500         return -1;
501     }
502 
503     /**
504      * Returns whether the given level of translucency is supported by
505      * this graphics device.
506      *
507      * @param translucencyKind a kind of translucency support
508      * @return whether the given translucency kind is supported
509      *
510      * @since 1.7
511      */
512     public boolean isWindowTranslucencySupported(WindowTranslucency translucencyKind) {
513         switch (translucencyKind) {
514             case PERPIXEL_TRANSPARENT:
515                 return isWindowShapingSupported();
516             case TRANSLUCENT:
517                 return isWindowOpacitySupported();
518             case PERPIXEL_TRANSLUCENT:
519                 return isWindowPerpixelTranslucencySupported();
520         }
521         return false;
522     }
523 
524     /**
525      * Returns whether the windowing system supports changing the shape
526      * of top-level windows.
527      * Note that this method may sometimes return true, but the native
528      * windowing system may still not support the concept of
529      * shaping (due to the bugs in the windowing system).
530      */
531     static boolean isWindowShapingSupported() {
532         Toolkit curToolkit = Toolkit.getDefaultToolkit();
533         if (!(curToolkit instanceof SunToolkit)) {
534             return false;
535         }
536         return ((SunToolkit)curToolkit).isWindowShapingSupported();
537     }
538 
539     /**
540      * Returns whether the windowing system supports changing the opacity
541      * value of top-level windows.
542      * Note that this method may sometimes return true, but the native
543      * windowing system may still not support the concept of
544      * translucency (due to the bugs in the windowing system).
545      */
546     static boolean isWindowOpacitySupported() {
547         Toolkit curToolkit = Toolkit.getDefaultToolkit();
548         if (!(curToolkit instanceof SunToolkit)) {
549             return false;
550         }
551         return ((SunToolkit)curToolkit).isWindowOpacitySupported();
552     }
553 
554     boolean isWindowPerpixelTranslucencySupported() {
555         /*
556          * Per-pixel alpha is supported if all the conditions are TRUE:
557          *    1. The toolkit is a sort of SunToolkit
558          *    2. The toolkit supports translucency in general
559          *        (isWindowTranslucencySupported())
560          *    3. There's at least one translucency-capable
561          *        GraphicsConfiguration
562          */
563         Toolkit curToolkit = Toolkit.getDefaultToolkit();
564         if (!(curToolkit instanceof SunToolkit)) {
565             return false;
566         }
567         if (!((SunToolkit)curToolkit).isWindowTranslucencySupported()) {
568             return false;
569         }
570 
571         // TODO: cache translucency capable GC
572         return getTranslucencyCapableGC() != null;
573     }
574 
575     GraphicsConfiguration getTranslucencyCapableGC() {
576         // If the default GC supports translucency return true.
577         // It is important to optimize the verification this way,
578         // see CR 6661196 for more details.
579         GraphicsConfiguration defaultGC = getDefaultConfiguration();
580         if (defaultGC.isTranslucencyCapable()) {
581             return defaultGC;
582         }
583 
584         // ... otherwise iterate through all the GCs.
585         GraphicsConfiguration[] configs = getConfigurations();
586         for (int j = 0; j < configs.length; j++) {
587             if (configs[j].isTranslucencyCapable()) {
588                 return configs[j];
589             }
590         }
591 
592         return null;
593     }
594 }