/* | 
|
 * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. | 
|
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
|
 * | 
|
 * This code is free software; you can redistribute it and/or modify it | 
|
 * under the terms of the GNU General Public License version 2 only, as | 
|
 * published by the Free Software Foundation.  Oracle designates this | 
|
 * particular file as subject to the "Classpath" exception as provided | 
|
 * by Oracle in the LICENSE file that accompanied this code. | 
|
 * | 
|
 * This code is distributed in the hope that it will be useful, but WITHOUT | 
|
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
|
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
|
 * version 2 for more details (a copy is included in the LICENSE file that | 
|
 * accompanied this code). | 
|
 * | 
|
 * You should have received a copy of the GNU General Public License version | 
|
 * 2 along with this work; if not, write to the Free Software Foundation, | 
|
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
|
 * | 
|
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | 
|
 * or visit www.oracle.com if you need additional information or have any | 
|
 * questions. | 
|
*/  | 
|
package com.sun.awt;  | 
|
import java.awt.*;  | 
|
import sun.awt.AWTAccessor;  | 
|
import sun.awt.SunToolkit;  | 
|
/** | 
|
 * A collection of utility methods for AWT. | 
|
 * | 
|
 * The functionality provided by the static methods of the class includes: | 
|
 * <ul> | 
|
 * <li>Setting shapes on top-level windows | 
|
 * <li>Setting a constant alpha value for each pixel of a top-level window | 
|
 * <li>Making a window non-opaque, after that it paints only explicitly | 
|
 * painted pixels on the screen, with arbitrary alpha values for every pixel. | 
|
 * <li>Setting a 'mixing-cutout' shape for a component. | 
|
 * </ul> | 
|
 * <p> | 
|
 * A "top-level window" is an instance of the {@code Window} class (or its | 
|
 * descendant, such as {@code JFrame}). | 
|
 * <p> | 
|
 * Some of the mentioned features may not be supported by the native platform. | 
|
 * To determine whether a particular feature is supported, the user must use | 
|
 * the {@code isTranslucencySupported()} method of the class passing a desired | 
|
 * translucency kind (a member of the {@code Translucency} enum) as an | 
|
 * argument. | 
|
 * <p> | 
|
 * The per-pixel alpha feature also requires the user to create her/his | 
|
 * windows using a translucency-capable graphics configuration. | 
|
 * The {@code isTranslucencyCapable()} method must | 
|
 * be used to verify whether any given GraphicsConfiguration supports | 
|
 * the trasnlcency effects. | 
|
 * <p> | 
|
 * <b>WARNING</b>: This class is an implementation detail and only meant | 
|
 * for limited use outside of the core platform. This API may change | 
|
 * drastically between update release, and it may even be | 
|
 * removed or be moved in some other package(s)/class(es). | 
|
*/  | 
|
public final class AWTUtilities { | 
|
    /** | 
|
     * The AWTUtilities class should not be instantiated | 
|
*/  | 
|
    private AWTUtilities() { | 
|
}  | 
|
    /** Kinds of translucency supported by the underlying system. | 
|
     *  @see #isTranslucencySupported | 
|
*/  | 
|
    public static enum Translucency { | 
|
        /** | 
|
         * Represents support in the underlying system for windows each pixel | 
|
         * of which is guaranteed to be either completely opaque, with | 
|
         * an alpha value of 1.0, or completely transparent, with an alpha | 
|
         * value of 0.0. | 
|
*/  | 
|
PERPIXEL_TRANSPARENT,  | 
|
        /** | 
|
         * Represents support in the underlying system for windows all of | 
|
         * the pixels of which have the same alpha value between or including | 
|
         * 0.0 and 1.0. | 
|
*/  | 
|
TRANSLUCENT,  | 
|
        /** | 
|
         * Represents support in the underlying system for windows that | 
|
         * contain or might contain pixels with arbitrary alpha values | 
|
         * between and including 0.0 and 1.0. | 
|
*/  | 
|
PERPIXEL_TRANSLUCENT;  | 
|
}  | 
|
    /** | 
|
     * Returns whether the given level of translucency is supported by | 
|
     * the underlying system. | 
|
     * | 
|
     * Note that this method may sometimes return the value | 
|
     * indicating that the particular level is supported, but | 
|
     * the native windowing system may still not support the | 
|
     * given level of translucency (due to the bugs in | 
|
     * the windowing system). | 
|
     * | 
|
     * @param translucencyKind a kind of translucency support | 
|
     *                         (either PERPIXEL_TRANSPARENT, | 
|
     *                         TRANSLUCENT, or PERPIXEL_TRANSLUCENT) | 
|
     * @return whether the given translucency kind is supported | 
|
*/  | 
|
    public static boolean isTranslucencySupported(Translucency translucencyKind) { | 
|
switch (translucencyKind) {  | 
|
case PERPIXEL_TRANSPARENT:  | 
|
return isWindowShapingSupported();  | 
|
case TRANSLUCENT:  | 
|
return isWindowOpacitySupported();  | 
|
case PERPIXEL_TRANSLUCENT:  | 
|
return isWindowTranslucencySupported();  | 
|
}  | 
|
return false;  | 
|
}  | 
|
    /** | 
|
     * Returns whether the windowing system supports changing the opacity | 
|
     * value of top-level windows. | 
|
     * Note that this method may sometimes return true, but the native | 
|
     * windowing system may still not support the concept of | 
|
     * translucency (due to the bugs in the windowing system). | 
|
*/  | 
|
    private static boolean isWindowOpacitySupported() { | 
|
Toolkit curToolkit = Toolkit.getDefaultToolkit();  | 
|
if (!(curToolkit instanceof SunToolkit)) {  | 
|
return false;  | 
|
}  | 
|
return ((SunToolkit)curToolkit).isWindowOpacitySupported();  | 
|
}  | 
|
    /** | 
|
     * Set the opacity of the window. The opacity is at the range [0..1]. | 
|
     * Note that setting the opacity level of 0 may or may not disable | 
|
     * the mouse event handling on this window. This is | 
|
     * a platform-dependent behavior. | 
|
     * | 
|
     * In order for this method to enable the translucency effect, | 
|
     * the isTranslucencySupported() method should indicate that the | 
|
     * TRANSLUCENT level of translucency is supported. | 
|
     * | 
|
     * <p>Also note that the window must not be in the full-screen mode | 
|
     * when setting the opacity value < 1.0f. Otherwise | 
|
     * the IllegalArgumentException is thrown. | 
|
     * | 
|
     * @param window the window to set the opacity level to | 
|
     * @param opacity the opacity level to set to the window | 
|
     * @throws NullPointerException if the window argument is null | 
|
     * @throws IllegalArgumentException if the opacity is out of | 
|
     *                                  the range [0..1] | 
|
     * @throws IllegalArgumentException if the window is in full screen mode, | 
|
     *                                  and the opacity is less than 1.0f | 
|
     * @throws UnsupportedOperationException if the TRANSLUCENT translucency | 
|
     *                                       kind is not supported | 
|
*/  | 
|
public static void setWindowOpacity(Window window, float opacity) {  | 
|
if (window == null) {  | 
|
throw new NullPointerException(  | 
|
                    "The window argument should not be null."); | 
|
}  | 
|
AWTAccessor.getWindowAccessor().setOpacity(window, opacity);  | 
|
}  | 
|
    /** | 
|
     * Get the opacity of the window. If the opacity has not | 
|
     * yet being set, this method returns 1.0. | 
|
     * | 
|
     * @param window the window to get the opacity level from | 
|
     * @throws NullPointerException if the window argument is null | 
|
*/  | 
|
public static float getWindowOpacity(Window window) {  | 
|
if (window == null) {  | 
|
throw new NullPointerException(  | 
|
                    "The window argument should not be null."); | 
|
}  | 
|
return AWTAccessor.getWindowAccessor().getOpacity(window);  | 
|
}  | 
|
    /** | 
|
     * Returns whether the windowing system supports changing the shape | 
|
     * of top-level windows. | 
|
     * Note that this method may sometimes return true, but the native | 
|
     * windowing system may still not support the concept of | 
|
     * shaping (due to the bugs in the windowing system). | 
|
*/  | 
|
    public static boolean isWindowShapingSupported() { | 
|
Toolkit curToolkit = Toolkit.getDefaultToolkit();  | 
|
if (!(curToolkit instanceof SunToolkit)) {  | 
|
return false;  | 
|
}  | 
|
return ((SunToolkit)curToolkit).isWindowShapingSupported();  | 
|
}  | 
|
    /** | 
|
     * Returns an object that implements the Shape interface and represents | 
|
     * the shape previously set with the call to the setWindowShape() method. | 
|
     * If no shape has been set yet, or the shape has been reset to null, | 
|
     * this method returns null. | 
|
     * | 
|
     * @param window the window to get the shape from | 
|
     * @return the current shape of the window | 
|
     * @throws NullPointerException if the window argument is null | 
|
*/  | 
|
public static Shape getWindowShape(Window window) {  | 
|
if (window == null) {  | 
|
throw new NullPointerException(  | 
|
                    "The window argument should not be null."); | 
|
}  | 
|
return AWTAccessor.getWindowAccessor().getShape(window);  | 
|
}  | 
|
    /** | 
|
     * Sets a shape for the given window. | 
|
     * If the shape argument is null, this methods restores | 
|
     * the default shape making the window rectangular. | 
|
     * <p>Note that in order to set a shape, the window must be undecorated. | 
|
     * If the window is decorated, this method ignores the {@code shape} | 
|
     * argument and resets the shape to null. | 
|
     * <p>Also note that the window must not be in the full-screen mode | 
|
     * when setting a non-null shape. Otherwise the IllegalArgumentException | 
|
     * is thrown. | 
|
     * <p>Depending on the platform, the method may return without | 
|
     * effecting the shape of the window if the window has a non-null warning | 
|
     * string ({@link Window#getWarningString()}). In this case the passed | 
|
     * shape object is ignored. | 
|
     * | 
|
     * @param window the window to set the shape to | 
|
     * @param shape the shape to set to the window | 
|
     * @throws NullPointerException if the window argument is null | 
|
     * @throws IllegalArgumentException if the window is in full screen mode, | 
|
     *                                  and the shape is not null | 
|
     * @throws UnsupportedOperationException if the PERPIXEL_TRANSPARENT | 
|
     *                                       translucency kind is not supported | 
|
*/  | 
|
public static void setWindowShape(Window window, Shape shape) {  | 
|
if (window == null) {  | 
|
throw new NullPointerException(  | 
|
                    "The window argument should not be null."); | 
|
}  | 
|
AWTAccessor.getWindowAccessor().setShape(window, shape);  | 
|
}  | 
|
    private static boolean isWindowTranslucencySupported() { | 
|
/*  | 
|
* Per-pixel alpha is supported if all the conditions are TRUE:  | 
|
* 1. The toolkit is a sort of SunToolkit  | 
|
* 2. The toolkit supports translucency in general  | 
|
* (isWindowTranslucencySupported())  | 
|
* 3. There's at least one translucency-capable  | 
|
* GraphicsConfiguration  | 
|
*/  | 
|
Toolkit curToolkit = Toolkit.getDefaultToolkit();  | 
|
if (!(curToolkit instanceof SunToolkit)) {  | 
|
return false;  | 
|
}  | 
|
if (!((SunToolkit)curToolkit).isWindowTranslucencySupported()) {  | 
|
return false;  | 
|
}  | 
|
GraphicsEnvironment env =  | 
|
GraphicsEnvironment.getLocalGraphicsEnvironment();  | 
|
// If the default GC supports translucency return true.  | 
|
// It is important to optimize the verification this way,  | 
|
        // see CR 6661196 for more details. | 
|
if (isTranslucencyCapable(env.getDefaultScreenDevice()  | 
|
.getDefaultConfiguration()))  | 
|
        { | 
|
return true;  | 
|
}  | 
|
        // ... otherwise iterate through all the GCs. | 
|
GraphicsDevice[] devices = env.getScreenDevices();  | 
|
for (int i = 0; i < devices.length; i++) {  | 
|
GraphicsConfiguration[] configs = devices[i].getConfigurations();  | 
|
for (int j = 0; j < configs.length; j++) {  | 
|
if (isTranslucencyCapable(configs[j])) {  | 
|
return true;  | 
|
}  | 
|
}  | 
|
}  | 
|
return false;  | 
|
}  | 
|
    /** | 
|
     * Enables the per-pixel alpha support for the given window. | 
|
     * Once the window becomes non-opaque (the isOpaque is set to false), | 
|
     * the drawing sub-system is starting to respect the alpha value of each | 
|
     * separate pixel. If a pixel gets painted with alpha color component | 
|
     * equal to zero, it becomes visually transparent, if the alpha of the | 
|
     * pixel is equal to 255, the pixel is fully opaque. Interim values | 
|
     * of the alpha color component make the pixel semi-transparent (i.e. | 
|
     * translucent). | 
|
     * <p>Note that in order for the window to support the per-pixel alpha | 
|
     * mode, the window must be created using the GraphicsConfiguration | 
|
     * for which the {@link #isTranslucencyCapable} | 
|
     * method returns true. | 
|
     * <p>Also note that some native systems enable the per-pixel translucency | 
|
     * mode for any window created using the translucency-compatible | 
|
     * graphics configuration. However, it is highly recommended to always | 
|
     * invoke the setWindowOpaque() method for these windows, at least for | 
|
     * the sake of cross-platform compatibility reasons. | 
|
     * <p>Also note that the window must not be in the full-screen mode | 
|
     * when making it non-opaque. Otherwise the IllegalArgumentException | 
|
     * is thrown. | 
|
     * <p>If the window is a {@code Frame} or a {@code Dialog}, the window must | 
|
     * be undecorated prior to enabling the per-pixel translucency effect (see | 
|
     * {@link Frame#setUndecorated()} and/or {@link Dialog#setUndecorated()}). | 
|
     * If the window becomes decorated through a subsequent call to the | 
|
     * corresponding {@code setUndecorated()} method, the per-pixel | 
|
     * translucency effect will be disabled and the opaque property reset to | 
|
     * {@code true}. | 
|
     * <p>Depending on the platform, the method may return without | 
|
     * effecting the opaque property of the window if the window has a non-null | 
|
     * warning string ({@link Window#getWarningString()}). In this case | 
|
     * the passed 'isOpaque' value is ignored. | 
|
     * | 
|
     * @param window the window to set the shape to | 
|
     * @param isOpaque whether the window must be opaque (true), | 
|
     *                 or translucent (false) | 
|
     * @throws NullPointerException if the window argument is null | 
|
     * @throws IllegalArgumentException if the window uses | 
|
     *                                  a GraphicsConfiguration for which the | 
|
     *                                  {@code isTranslucencyCapable()} | 
|
     *                                  method returns false | 
|
     * @throws IllegalArgumentException if the window is in full screen mode, | 
|
     *                                  and the isOpaque is false | 
|
     * @throws IllegalArgumentException if the window is decorated and the | 
|
     * isOpaque argument is {@code false}. | 
|
     * @throws UnsupportedOperationException if the PERPIXEL_TRANSLUCENT | 
|
     *                                       translucency kind is not supported | 
|
*/  | 
|
public static void setWindowOpaque(Window window, boolean isOpaque) {  | 
|
if (window == null) {  | 
|
throw new NullPointerException(  | 
|
                    "The window argument should not be null."); | 
|
}  | 
|
if (!isOpaque && !isTranslucencySupported(Translucency.PERPIXEL_TRANSLUCENT)) {  | 
|
throw new UnsupportedOperationException(  | 
|
                    "The PERPIXEL_TRANSLUCENT translucency kind is not supported"); | 
|
}  | 
|
AWTAccessor.getWindowAccessor().setOpaque(window, isOpaque);  | 
|
}  | 
|
    /** | 
|
     * Returns whether the window is opaque or translucent. | 
|
     * | 
|
     * @param window the window to set the shape to | 
|
     * @return whether the window is currently opaque (true) | 
|
     *         or translucent (false) | 
|
     * @throws NullPointerException if the window argument is null | 
|
*/  | 
|
public static boolean isWindowOpaque(Window window) {  | 
|
if (window == null) {  | 
|
throw new NullPointerException(  | 
|
                    "The window argument should not be null."); | 
|
}  | 
|
return window.isOpaque();  | 
|
}  | 
|
    /** | 
|
     * Verifies whether a given GraphicsConfiguration supports | 
|
     * the PERPIXEL_TRANSLUCENT kind of translucency. | 
|
     * All windows that are intended to be used with the {@link #setWindowOpaque} | 
|
     * method must be created using a GraphicsConfiguration for which this method | 
|
     * returns true. | 
|
     * <p>Note that some native systems enable the per-pixel translucency | 
|
     * mode for any window created using a translucency-capable | 
|
     * graphics configuration. However, it is highly recommended to always | 
|
     * invoke the setWindowOpaque() method for these windows, at least | 
|
     * for the sake of cross-platform compatibility reasons. | 
|
     * | 
|
     * @param gc GraphicsConfiguration | 
|
     * @throws NullPointerException if the gc argument is null | 
|
     * @return whether the given GraphicsConfiguration supports | 
|
     *         the translucency effects. | 
|
*/  | 
|
public static boolean isTranslucencyCapable(GraphicsConfiguration gc) {  | 
|
if (gc == null) {  | 
|
throw new NullPointerException("The gc argument should not be null");  | 
|
}  | 
|
        /* | 
|
        return gc.isTranslucencyCapable(); | 
|
*/  | 
|
Toolkit curToolkit = Toolkit.getDefaultToolkit();  | 
|
if (!(curToolkit instanceof SunToolkit)) {  | 
|
return false;  | 
|
}  | 
|
return ((SunToolkit)curToolkit).isTranslucencyCapable(gc);  | 
|
}  | 
|
    /** | 
|
     * Sets a 'mixing-cutout' shape for the given component. | 
|
     * | 
|
     * By default a lightweight component is treated as an opaque rectangle for | 
|
     * the purposes of the Heavyweight/Lightweight Components Mixing feature. | 
|
     * This method enables developers to set an arbitrary shape to be cut out | 
|
     * from heavyweight components positioned underneath the lightweight | 
|
     * component in the z-order. | 
|
     * <p> | 
|
     * The {@code shape} argument may have the following values: | 
|
     * <ul> | 
|
     * <li>{@code null} - reverts the default cutout shape (the rectangle equal | 
|
     * to the component's {@code getBounds()}) | 
|
     * <li><i>empty-shape</i> - does not cut out anything from heavyweight | 
|
     * components. This makes the given lightweight component effectively | 
|
     * transparent. Note that descendants of the lightweight component still | 
|
     * affect the shapes of heavyweight components.  An example of an | 
|
     * <i>empty-shape</i> is {@code new Rectangle()}. | 
|
     * <li><i>non-empty-shape</i> - the given shape will be cut out from | 
|
     * heavyweight components. | 
|
     * </ul> | 
|
     * <p> | 
|
     * The most common example when the 'mixing-cutout' shape is needed is a | 
|
     * glass pane component. The {@link JRootPane#setGlassPane()} method | 
|
     * automatically sets the <i>empty-shape</i> as the 'mixing-cutout' shape | 
|
     * for the given glass pane component.  If a developer needs some other | 
|
     * 'mixing-cutout' shape for the glass pane (which is rare), this must be | 
|
     * changed manually after installing the glass pane to the root pane. | 
|
     * <p> | 
|
     * Note that the 'mixing-cutout' shape neither affects painting, nor the | 
|
     * mouse events handling for the given component. It is used exclusively | 
|
     * for the purposes of the Heavyweight/Lightweight Components Mixing | 
|
     * feature. | 
|
     * | 
|
     * @param component the component that needs non-default | 
|
     * 'mixing-cutout' shape | 
|
     * @param shape the new 'mixing-cutout' shape | 
|
     * @throws NullPointerException if the component argument is {@code null} | 
|
*/  | 
|
public static void setComponentMixingCutoutShape(Component component,  | 
|
Shape shape)  | 
|
    { | 
|
if (component == null) {  | 
|
throw new NullPointerException(  | 
|
                    "The component argument should not be null."); | 
|
}  | 
|
AWTAccessor.getComponentAccessor().setMixingCutoutShape(component,  | 
|
shape);  | 
|
}  | 
|
}  | 
|