1 /* 2 * Copyright (c) 2008, 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 com.sun.awt; 27 28 import java.awt.*; 29 30 import javax.swing.JRootPane; 31 32 import sun.awt.AWTAccessor; 33 import sun.awt.SunToolkit; 34 35 /** 36 * A collection of utility methods for AWT. 37 * 38 * The functionality provided by the static methods of the class includes: 39 * <ul> 40 * <li>Setting shapes on top-level windows 41 * <li>Setting a constant alpha value for each pixel of a top-level window 42 * <li>Making a window non-opaque, after that it paints only explicitly 43 * painted pixels on the screen, with arbitrary alpha values for every pixel. 44 * <li>Setting a 'mixing-cutout' shape for a component. 45 * </ul> 46 * <p> 47 * A "top-level window" is an instance of the {@code Window} class (or its 48 * descendant, such as {@code JFrame}). 49 * <p> 50 * Some of the mentioned features may not be supported by the native platform. 51 * To determine whether a particular feature is supported, the user must use 52 * the {@code isTranslucencySupported()} method of the class passing a desired 53 * translucency kind (a member of the {@code Translucency} enum) as an 54 * argument. 55 * <p> 56 * The per-pixel alpha feature also requires the user to create her/his 57 * windows using a translucency-capable graphics configuration. 58 * The {@code isTranslucencyCapable()} method must 59 * be used to verify whether any given GraphicsConfiguration supports 60 * the translucency effects. 61 * <p> 62 * <b>WARNING</b>: This class is an implementation detail and only meant 63 * for limited use outside of the core platform. This API may change 64 * drastically between update release, and it may even be 65 * removed or be moved in some other package(s)/class(es). 66 */ 67 public final class AWTUtilities { 68 69 /** 70 * The AWTUtilities class should not be instantiated 71 */ 72 private AWTUtilities() { 73 } 74 75 /** Kinds of translucency supported by the underlying system. 76 * @see #isTranslucencySupported 77 */ 78 public static enum Translucency { 79 /** 80 * Represents support in the underlying system for windows each pixel 81 * of which is guaranteed to be either completely opaque, with 82 * an alpha value of 1.0, or completely transparent, with an alpha 83 * value of 0.0. 84 */ 85 PERPIXEL_TRANSPARENT, 86 87 /** 88 * Represents support in the underlying system for windows all of 89 * the pixels of which have the same alpha value between or including 90 * 0.0 and 1.0. 91 */ 92 TRANSLUCENT, 93 94 /** 95 * Represents support in the underlying system for windows that 96 * contain or might contain pixels with arbitrary alpha values 97 * between and including 0.0 and 1.0. 98 */ 99 PERPIXEL_TRANSLUCENT; 100 } 101 102 103 /** 104 * Returns whether the given level of translucency is supported by 105 * the underlying system. 106 * 107 * Note that this method may sometimes return the value 108 * indicating that the particular level is supported, but 109 * the native windowing system may still not support the 110 * given level of translucency (due to the bugs in 111 * the windowing system). 112 * 113 * @param translucencyKind a kind of translucency support 114 * (either PERPIXEL_TRANSPARENT, 115 * TRANSLUCENT, or PERPIXEL_TRANSLUCENT) 116 * @return whether the given translucency kind is supported 117 */ 118 public static boolean isTranslucencySupported(Translucency translucencyKind) { 119 switch (translucencyKind) { 120 case PERPIXEL_TRANSPARENT: 121 return isWindowShapingSupported(); 122 case TRANSLUCENT: 123 return isWindowOpacitySupported(); 124 case PERPIXEL_TRANSLUCENT: 125 return isWindowTranslucencySupported(); 126 } 127 return false; 128 } 129 130 131 /** 132 * Returns whether the windowing system supports changing the opacity 133 * value of top-level windows. 134 * Note that this method may sometimes return true, but the native 135 * windowing system may still not support the concept of 136 * translucency (due to the bugs in the windowing system). 137 */ 138 private static boolean isWindowOpacitySupported() { 139 Toolkit curToolkit = Toolkit.getDefaultToolkit(); 140 if (!(curToolkit instanceof SunToolkit)) { 141 return false; 142 } 143 return ((SunToolkit)curToolkit).isWindowOpacitySupported(); 144 } 145 146 /** 147 * Set the opacity of the window. The opacity is at the range [0..1]. 148 * Note that setting the opacity level of 0 may or may not disable 149 * the mouse event handling on this window. This is 150 * a platform-dependent behavior. 151 * 152 * In order for this method to enable the translucency effect, 153 * the isTranslucencySupported() method should indicate that the 154 * TRANSLUCENT level of translucency is supported. 155 * 156 * <p>Also note that the window must not be in the full-screen mode 157 * when setting the opacity value < 1.0f. Otherwise 158 * the IllegalArgumentException is thrown. 159 * 160 * @param window the window to set the opacity level to 161 * @param opacity the opacity level to set to the window 162 * @throws NullPointerException if the window argument is null 163 * @throws IllegalArgumentException if the opacity is out of 164 * the range [0..1] 165 * @throws IllegalArgumentException if the window is in full screen mode, 166 * and the opacity is less than 1.0f 167 * @throws UnsupportedOperationException if the TRANSLUCENT translucency 168 * kind is not supported 169 */ 170 public static void setWindowOpacity(Window window, float opacity) { 171 if (window == null) { 172 throw new NullPointerException( 173 "The window argument should not be null."); 174 } 175 176 AWTAccessor.getWindowAccessor().setOpacity(window, opacity); 177 } 178 179 /** 180 * Get the opacity of the window. If the opacity has not 181 * yet being set, this method returns 1.0. 182 * 183 * @param window the window to get the opacity level from 184 * @throws NullPointerException if the window argument is null 185 */ 186 public static float getWindowOpacity(Window window) { 187 if (window == null) { 188 throw new NullPointerException( 189 "The window argument should not be null."); 190 } 191 192 return AWTAccessor.getWindowAccessor().getOpacity(window); 193 } 194 195 /** 196 * Returns whether the windowing system supports changing the shape 197 * of top-level windows. 198 * Note that this method may sometimes return true, but the native 199 * windowing system may still not support the concept of 200 * shaping (due to the bugs in the windowing system). 201 */ 202 public static boolean isWindowShapingSupported() { 203 Toolkit curToolkit = Toolkit.getDefaultToolkit(); 204 if (!(curToolkit instanceof SunToolkit)) { 205 return false; 206 } 207 return ((SunToolkit)curToolkit).isWindowShapingSupported(); 208 } 209 210 /** 211 * Returns an object that implements the Shape interface and represents 212 * the shape previously set with the call to the setWindowShape() method. 213 * If no shape has been set yet, or the shape has been reset to null, 214 * this method returns null. 215 * 216 * @param window the window to get the shape from 217 * @return the current shape of the window 218 * @throws NullPointerException if the window argument is null 219 */ 220 public static Shape getWindowShape(Window window) { 221 if (window == null) { 222 throw new NullPointerException( 223 "The window argument should not be null."); 224 } 225 return AWTAccessor.getWindowAccessor().getShape(window); 226 } 227 228 /** 229 * Sets a shape for the given window. 230 * If the shape argument is null, this methods restores 231 * the default shape making the window rectangular. 232 * <p>Note that in order to set a shape, the window must be undecorated. 233 * If the window is decorated, this method ignores the {@code shape} 234 * argument and resets the shape to null. 235 * <p>Also note that the window must not be in the full-screen mode 236 * when setting a non-null shape. Otherwise the IllegalArgumentException 237 * is thrown. 238 * <p>Depending on the platform, the method may return without 239 * effecting the shape of the window if the window has a non-null warning 240 * string ({@link Window#getWarningString()}). In this case the passed 241 * shape object is ignored. 242 * 243 * @param window the window to set the shape to 244 * @param shape the shape to set to the window 245 * @throws NullPointerException if the window argument is null 246 * @throws IllegalArgumentException if the window is in full screen mode, 247 * and the shape is not null 248 * @throws UnsupportedOperationException if the PERPIXEL_TRANSPARENT 249 * translucency kind is not supported 250 */ 251 public static void setWindowShape(Window window, Shape shape) { 252 if (window == null) { 253 throw new NullPointerException( 254 "The window argument should not be null."); 255 } 256 AWTAccessor.getWindowAccessor().setShape(window, shape); 257 } 258 259 private static boolean isWindowTranslucencySupported() { 260 /* 261 * Per-pixel alpha is supported if all the conditions are TRUE: 262 * 1. The toolkit is a sort of SunToolkit 263 * 2. The toolkit supports translucency in general 264 * (isWindowTranslucencySupported()) 265 * 3. There's at least one translucency-capable 266 * GraphicsConfiguration 267 */ 268 269 Toolkit curToolkit = Toolkit.getDefaultToolkit(); 270 if (!(curToolkit instanceof SunToolkit)) { 271 return false; 272 } 273 274 if (!((SunToolkit)curToolkit).isWindowTranslucencySupported()) { 275 return false; 276 } 277 278 GraphicsEnvironment env = 279 GraphicsEnvironment.getLocalGraphicsEnvironment(); 280 281 // If the default GC supports translucency return true. 282 // It is important to optimize the verification this way, 283 // see CR 6661196 for more details. 284 if (isTranslucencyCapable(env.getDefaultScreenDevice() 285 .getDefaultConfiguration())) 286 { 287 return true; 288 } 289 290 // ... otherwise iterate through all the GCs. 291 GraphicsDevice[] devices = env.getScreenDevices(); 292 293 for (int i = 0; i < devices.length; i++) { 294 GraphicsConfiguration[] configs = devices[i].getConfigurations(); 295 for (int j = 0; j < configs.length; j++) { 296 if (isTranslucencyCapable(configs[j])) { 297 return true; 298 } 299 } 300 } 301 302 return false; 303 } 304 305 /** 306 * Enables the per-pixel alpha support for the given window. 307 * Once the window becomes non-opaque (the isOpaque is set to false), 308 * the drawing sub-system is starting to respect the alpha value of each 309 * separate pixel. If a pixel gets painted with alpha color component 310 * equal to zero, it becomes visually transparent, if the alpha of the 311 * pixel is equal to 255, the pixel is fully opaque. Interim values 312 * of the alpha color component make the pixel semi-transparent (i.e. 313 * translucent). 314 * <p>Note that in order for the window to support the per-pixel alpha 315 * mode, the window must be created using the GraphicsConfiguration 316 * for which the {@link #isTranslucencyCapable} 317 * method returns true. 318 * <p>Also note that some native systems enable the per-pixel translucency 319 * mode for any window created using the translucency-compatible 320 * graphics configuration. However, it is highly recommended to always 321 * invoke the setWindowOpaque() method for these windows, at least for 322 * the sake of cross-platform compatibility reasons. 323 * <p>Also note that the window must not be in the full-screen mode 324 * when making it non-opaque. Otherwise the IllegalArgumentException 325 * is thrown. 326 * <p>If the window is a {@code Frame} or a {@code Dialog}, the window must 327 * be undecorated prior to enabling the per-pixel translucency effect (see 328 * {@link Frame#setUndecorated} and/or {@link Dialog#setUndecorated}). 329 * If the window becomes decorated through a subsequent call to the 330 * corresponding {@code setUndecorated()} method, the per-pixel 331 * translucency effect will be disabled and the opaque property reset to 332 * {@code true}. 333 * <p>Depending on the platform, the method may return without 334 * effecting the opaque property of the window if the window has a non-null 335 * warning string ({@link Window#getWarningString()}). In this case 336 * the passed 'isOpaque' value is ignored. 337 * 338 * @param window the window to set the shape to 339 * @param isOpaque whether the window must be opaque (true), 340 * or translucent (false) 341 * @throws NullPointerException if the window argument is null 342 * @throws IllegalArgumentException if the window uses 343 * a GraphicsConfiguration for which the 344 * {@code isTranslucencyCapable()} 345 * method returns false 346 * @throws IllegalArgumentException if the window is in full screen mode, 347 * and the isOpaque is false 348 * @throws IllegalArgumentException if the window is decorated and the 349 * isOpaque argument is {@code false}. 350 * @throws UnsupportedOperationException if the PERPIXEL_TRANSLUCENT 351 * translucency kind is not supported 352 */ 353 public static void setWindowOpaque(Window window, boolean isOpaque) { 354 if (window == null) { 355 throw new NullPointerException( 356 "The window argument should not be null."); 357 } 358 if (!isOpaque && !isTranslucencySupported(Translucency.PERPIXEL_TRANSLUCENT)) { 359 throw new UnsupportedOperationException( 360 "The PERPIXEL_TRANSLUCENT translucency kind is not supported"); 361 } 362 AWTAccessor.getWindowAccessor().setOpaque(window, isOpaque); 363 } 364 365 /** 366 * Returns whether the window is opaque or translucent. 367 * 368 * @param window the window to set the shape to 369 * @return whether the window is currently opaque (true) 370 * or translucent (false) 371 * @throws NullPointerException if the window argument is null 372 */ 373 public static boolean isWindowOpaque(Window window) { 374 if (window == null) { 375 throw new NullPointerException( 376 "The window argument should not be null."); 377 } 378 379 return window.isOpaque(); 380 } 381 382 /** 383 * Verifies whether a given GraphicsConfiguration supports 384 * the PERPIXEL_TRANSLUCENT kind of translucency. 385 * All windows that are intended to be used with the {@link #setWindowOpaque} 386 * method must be created using a GraphicsConfiguration for which this method 387 * returns true. 388 * <p>Note that some native systems enable the per-pixel translucency 389 * mode for any window created using a translucency-capable 390 * graphics configuration. However, it is highly recommended to always 391 * invoke the setWindowOpaque() method for these windows, at least 392 * for the sake of cross-platform compatibility reasons. 393 * 394 * @param gc GraphicsConfiguration 395 * @throws NullPointerException if the gc argument is null 396 * @return whether the given GraphicsConfiguration supports 397 * the translucency effects. 398 */ 399 public static boolean isTranslucencyCapable(GraphicsConfiguration gc) { 400 if (gc == null) { 401 throw new NullPointerException("The gc argument should not be null"); 402 } 403 /* 404 return gc.isTranslucencyCapable(); 405 */ 406 Toolkit curToolkit = Toolkit.getDefaultToolkit(); 407 if (!(curToolkit instanceof SunToolkit)) { 408 return false; 409 } 410 return ((SunToolkit)curToolkit).isTranslucencyCapable(gc); 411 } 412 413 /** 414 * Sets a 'mixing-cutout' shape for the given component. 415 * 416 * By default a lightweight component is treated as an opaque rectangle for 417 * the purposes of the Heavyweight/Lightweight Components Mixing feature. 418 * This method enables developers to set an arbitrary shape to be cut out 419 * from heavyweight components positioned underneath the lightweight 420 * component in the z-order. 421 * <p> 422 * The {@code shape} argument may have the following values: 423 * <ul> 424 * <li>{@code null} - reverts the default cutout shape (the rectangle equal 425 * to the component's {@code getBounds()}) 426 * <li><i>empty-shape</i> - does not cut out anything from heavyweight 427 * components. This makes the given lightweight component effectively 428 * transparent. Note that descendants of the lightweight component still 429 * affect the shapes of heavyweight components. An example of an 430 * <i>empty-shape</i> is {@code new Rectangle()}. 431 * <li><i>non-empty-shape</i> - the given shape will be cut out from 432 * heavyweight components. 433 * </ul> 434 * <p> 435 * The most common example when the 'mixing-cutout' shape is needed is a 436 * glass pane component. The {@link JRootPane#setGlassPane} method 437 * automatically sets the <i>empty-shape</i> as the 'mixing-cutout' shape 438 * for the given glass pane component. If a developer needs some other 439 * 'mixing-cutout' shape for the glass pane (which is rare), this must be 440 * changed manually after installing the glass pane to the root pane. 441 * <p> 442 * Note that the 'mixing-cutout' shape neither affects painting, nor the 443 * mouse events handling for the given component. It is used exclusively 444 * for the purposes of the Heavyweight/Lightweight Components Mixing 445 * feature. 446 * 447 * @param component the component that needs non-default 448 * 'mixing-cutout' shape 449 * @param shape the new 'mixing-cutout' shape 450 * @throws NullPointerException if the component argument is {@code null} 451 */ 452 @Deprecated(since = "9") 453 public static void setComponentMixingCutoutShape(Component component, 454 Shape shape) 455 { 456 if (component == null) { 457 throw new NullPointerException( 458 "The component argument should not be null."); 459 } 460 461 component.setMixingCutoutShape(shape); 462 } 463 } 464