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™ 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 }