/* |
|
* 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); |
|
} |
|
} |
|