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