2 * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
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).
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.
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
30 import sun.awt.AWTAccessor;
31 import sun.awt.SunToolkit;
34 * A collection of utility methods for AWT.
36 * The functionality provided by the static methods of the class includes:
38 * <li>Setting shapes on top-level windows
39 * <li>Setting a constant alpha value for each pixel of a top-level window
40 * <li>Making a window non-opaque, after that it paints only explicitly
41 * painted pixels on the screen, with arbitrary alpha values for every pixel.
42 * <li>Setting a 'mixing-cutout' shape for a component.
45 * A "top-level window" is an instance of the {@code Window} class (or its
46 * descendant, such as {@code JFrame}).
48 * Some of the mentioned features may not be supported by the native platform.
49 * To determine whether a particular feature is supported, the user must use
50 * the {@code isTranslucencySupported()} method of the class passing a desired
51 * translucency kind (a member of the {@code Translucency} enum) as an
54 * The per-pixel alpha feature also requires the user to create her/his
55 * windows using a translucency-capable graphics configuration.
56 * The {@code isTranslucencyCapable()} method must
57 * be used to verify whether any given GraphicsConfiguration supports
58 * the trasnlcency effects.
60 * <b>WARNING</b>: This class is an implementation detail and only meant
61 * for limited use outside of the core platform. This API may change
62 * drastically between update release, and it may even be
63 * removed or be moved in some other package(s)/class(es).
65 public final class AWTUtilities {
68 * The AWTUtilities class should not be instantiated
70 private AWTUtilities() {
73 /** Kinds of translucency supported by the underlying system.
74 * @see #isTranslucencySupported
76 public static enum Translucency {
78 * Represents support in the underlying system for windows each pixel
79 * of which is guaranteed to be either completely opaque, with
80 * an alpha value of 1.0, or completely transparent, with an alpha
86 * Represents support in the underlying system for windows all of
87 * the pixels of which have the same alpha value between or including
93 * Represents support in the underlying system for windows that
94 * contain or might contain pixels with arbitrary alpha values
95 * between and including 0.0 and 1.0.
102 * Returns whether the given level of translucency is supported by
103 * the underlying system.
105 * Note that this method may sometimes return the value
106 * indicating that the particular level is supported, but
107 * the native windowing system may still not support the
108 * given level of translucency (due to the bugs in
109 * the windowing system).
111 * @param translucencyKind a kind of translucency support
112 * (either PERPIXEL_TRANSPARENT,
113 * TRANSLUCENT, or PERPIXEL_TRANSLUCENT)
114 * @return whether the given translucency kind is supported
116 public static boolean isTranslucencySupported(Translucency translucencyKind) {
117 switch (translucencyKind) {
118 case PERPIXEL_TRANSPARENT:
119 return isWindowShapingSupported();
121 return isWindowOpacitySupported();
122 case PERPIXEL_TRANSLUCENT:
123 return isWindowTranslucencySupported();
130 * Returns whether the windowing system supports changing the opacity
131 * value of top-level windows.
132 * Note that this method may sometimes return true, but the native
133 * windowing system may still not support the concept of
134 * translucency (due to the bugs in the windowing system).
136 private static boolean isWindowOpacitySupported() {
137 Toolkit curToolkit = Toolkit.getDefaultToolkit();
138 if (!(curToolkit instanceof SunToolkit)) {
141 return ((SunToolkit)curToolkit).isWindowOpacitySupported();
145 * Set the opacity of the window. The opacity is at the range [0..1].
146 * Note that setting the opacity level of 0 may or may not disable
147 * the mouse event handling on this window. This is
148 * a platform-dependent behavior.
150 * In order for this method to enable the translucency effect,
151 * the isTranslucencySupported() method should indicate that the
152 * TRANSLUCENT level of translucency is supported.
154 * <p>Also note that the window must not be in the full-screen mode
155 * when setting the opacity value < 1.0f. Otherwise
156 * the IllegalArgumentException is thrown.
158 * @param window the window to set the opacity level to
159 * @param opacity the opacity level to set to the window
160 * @throws NullPointerException if the window argument is null
161 * @throws IllegalArgumentException if the opacity is out of
163 * @throws IllegalArgumentException if the window is in full screen mode,
164 * and the opacity is less than 1.0f
165 * @throws UnsupportedOperationException if the TRANSLUCENT translucency
166 * kind is not supported
168 public static void setWindowOpacity(Window window, float opacity) {
169 if (window == null) {
170 throw new NullPointerException(
171 "The window argument should not be null.");
174 AWTAccessor.getWindowAccessor().setOpacity(window, opacity);
178 * Get the opacity of the window. If the opacity has not
179 * yet being set, this method returns 1.0.
181 * @param window the window to get the opacity level from
182 * @throws NullPointerException if the window argument is null
184 public static float getWindowOpacity(Window window) {
185 if (window == null) {
186 throw new NullPointerException(
187 "The window argument should not be null.");
190 return AWTAccessor.getWindowAccessor().getOpacity(window);
194 * Returns whether the windowing system supports changing the shape
195 * of top-level windows.
196 * Note that this method may sometimes return true, but the native
197 * windowing system may still not support the concept of
198 * shaping (due to the bugs in the windowing system).
200 public static boolean isWindowShapingSupported() {
201 Toolkit curToolkit = Toolkit.getDefaultToolkit();
202 if (!(curToolkit instanceof SunToolkit)) {
205 return ((SunToolkit)curToolkit).isWindowShapingSupported();
209 * Returns an object that implements the Shape interface and represents
210 * the shape previously set with the call to the setWindowShape() method.
211 * If no shape has been set yet, or the shape has been reset to null,
212 * this method returns null.
214 * @param window the window to get the shape from
215 * @return the current shape of the window
216 * @throws NullPointerException if the window argument is null
218 public static Shape getWindowShape(Window window) {
219 if (window == null) {
220 throw new NullPointerException(
221 "The window argument should not be null.");
223 return AWTAccessor.getWindowAccessor().getShape(window);
227 * Sets a shape for the given window.
228 * If the shape argument is null, this methods restores
229 * the default shape making the window rectangular.
230 * <p>Note that in order to set a shape, the window must be undecorated.
231 * If the window is decorated, this method ignores the {@code shape}
232 * argument and resets the shape to null.
233 * <p>Also note that the window must not be in the full-screen mode
234 * when setting a non-null shape. Otherwise the IllegalArgumentException
236 * <p>Depending on the platform, the method may return without
237 * effecting the shape of the window if the window has a non-null warning
238 * string ({@link Window#getWarningString()}). In this case the passed
239 * shape object is ignored.
241 * @param window the window to set the shape to
242 * @param shape the shape to set to the window
243 * @throws NullPointerException if the window argument is null
244 * @throws IllegalArgumentException if the window is in full screen mode,
245 * and the shape is not null
246 * @throws UnsupportedOperationException if the PERPIXEL_TRANSPARENT
247 * translucency kind is not supported
249 public static void setWindowShape(Window window, Shape shape) {
250 if (window == null) {
251 throw new NullPointerException(
252 "The window argument should not be null.");
254 AWTAccessor.getWindowAccessor().setShape(window, shape);
257 private static boolean isWindowTranslucencySupported() {
259 * Per-pixel alpha is supported if all the conditions are TRUE:
260 * 1. The toolkit is a sort of SunToolkit
261 * 2. The toolkit supports translucency in general
262 * (isWindowTranslucencySupported())
263 * 3. There's at least one translucency-capable
264 * GraphicsConfiguration
267 Toolkit curToolkit = Toolkit.getDefaultToolkit();
268 if (!(curToolkit instanceof SunToolkit)) {
272 if (!((SunToolkit)curToolkit).isWindowTranslucencySupported()) {
276 GraphicsEnvironment env =
277 GraphicsEnvironment.getLocalGraphicsEnvironment();
279 // If the default GC supports translucency return true.
280 // It is important to optimize the verification this way,
281 // see CR 6661196 for more details.
282 if (isTranslucencyCapable(env.getDefaultScreenDevice()
283 .getDefaultConfiguration()))
288 // ... otherwise iterate through all the GCs.
289 GraphicsDevice[] devices = env.getScreenDevices();
291 for (int i = 0; i < devices.length; i++) {
292 GraphicsConfiguration[] configs = devices[i].getConfigurations();
293 for (int j = 0; j < configs.length; j++) {
294 if (isTranslucencyCapable(configs[j])) {
304 * Enables the per-pixel alpha support for the given window.
305 * Once the window becomes non-opaque (the isOpaque is set to false),
306 * the drawing sub-system is starting to respect the alpha value of each
307 * separate pixel. If a pixel gets painted with alpha color component
308 * equal to zero, it becomes visually transparent, if the alpha of the
309 * pixel is equal to 255, the pixel is fully opaque. Interim values
310 * of the alpha color component make the pixel semi-transparent (i.e.
312 * <p>Note that in order for the window to support the per-pixel alpha
313 * mode, the window must be created using the GraphicsConfiguration
314 * for which the {@link #isTranslucencyCapable}
315 * method returns true.
316 * <p>Also note that some native systems enable the per-pixel translucency
317 * mode for any window created using the translucency-compatible
318 * graphics configuration. However, it is highly recommended to always
319 * invoke the setWindowOpaque() method for these windows, at least for
320 * the sake of cross-platform compatibility reasons.
321 * <p>Also note that the window must not be in the full-screen mode
322 * when making it non-opaque. Otherwise the IllegalArgumentException
324 * <p>If the window is a {@code Frame} or a {@code Dialog}, the window must
325 * be undecorated prior to enabling the per-pixel translucency effect (see
326 * {@link Frame#setUndecorated()} and/or {@link Dialog#setUndecorated()}).
327 * If the window becomes decorated through a subsequent call to the
328 * corresponding {@code setUndecorated()} method, the per-pixel
329 * translucency effect will be disabled and the opaque property reset to
331 * <p>Depending on the platform, the method may return without
332 * effecting the opaque property of the window if the window has a non-null
333 * warning string ({@link Window#getWarningString()}). In this case
334 * the passed 'isOpaque' value is ignored.
336 * @param window the window to set the shape to
337 * @param isOpaque whether the window must be opaque (true),
338 * or translucent (false)
339 * @throws NullPointerException if the window argument is null
340 * @throws IllegalArgumentException if the window uses
341 * a GraphicsConfiguration for which the
342 * {@code isTranslucencyCapable()}
343 * method returns false
344 * @throws IllegalArgumentException if the window is in full screen mode,
345 * and the isOpaque is false
346 * @throws IllegalArgumentException if the window is decorated and the
347 * isOpaque argument is {@code false}.
348 * @throws UnsupportedOperationException if the PERPIXEL_TRANSLUCENT
349 * translucency kind is not supported
351 public static void setWindowOpaque(Window window, boolean isOpaque) {
352 if (window == null) {
353 throw new NullPointerException(
354 "The window argument should not be null.");
356 if (!isOpaque && !isTranslucencySupported(Translucency.PERPIXEL_TRANSLUCENT)) {
357 throw new UnsupportedOperationException(
358 "The PERPIXEL_TRANSLUCENT translucency kind is not supported");
360 AWTAccessor.getWindowAccessor().setOpaque(window, isOpaque);
364 * Returns whether the window is opaque or translucent.
366 * @param window the window to set the shape to
367 * @return whether the window is currently opaque (true)
368 * or translucent (false)
369 * @throws NullPointerException if the window argument is null
371 public static boolean isWindowOpaque(Window window) {
372 if (window == null) {
373 throw new NullPointerException(
374 "The window argument should not be null.");
377 return AWTAccessor.getWindowAccessor().isOpaque(window);
381 * Verifies whether a given GraphicsConfiguration supports
382 * the PERPIXEL_TRANSLUCENT kind of translucency.
383 * All windows that are intended to be used with the {@link #setWindowOpaque}
384 * method must be created using a GraphicsConfiguration for which this method
386 * <p>Note that some native systems enable the per-pixel translucency
387 * mode for any window created using a translucency-capable
388 * graphics configuration. However, it is highly recommended to always
389 * invoke the setWindowOpaque() method for these windows, at least
390 * for the sake of cross-platform compatibility reasons.
392 * @param gc GraphicsConfiguration
393 * @throws NullPointerException if the gc argument is null
394 * @return whether the given GraphicsConfiguration supports
395 * the translucency effects.
397 public static boolean isTranslucencyCapable(GraphicsConfiguration gc) {
399 throw new NullPointerException("The gc argument should not be null");
402 return gc.isTranslucencyCapable();
404 Toolkit curToolkit = Toolkit.getDefaultToolkit();
405 if (!(curToolkit instanceof SunToolkit)) {
408 return ((SunToolkit)curToolkit).isTranslucencyCapable(gc);
412 * Sets a 'mixing-cutout' shape for the given component.
414 * By default a lightweight component is treated as an opaque rectangle for
415 * the purposes of the Heavyweight/Lightweight Components Mixing feature.
416 * This method enables developers to set an arbitrary shape to be cut out
417 * from heavyweight components positioned underneath the lightweight
418 * component in the z-order.
420 * The {@code shape} argument may have the following values:
422 * <li>{@code null} - reverts the default cutout shape (the rectangle equal
423 * to the component's {@code getBounds()})
424 * <li><i>empty-shape</i> - does not cut out anything from heavyweight
425 * components. This makes the given lightweight component effectively
426 * transparent. Note that descendants of the lightweight component still
427 * affect the shapes of heavyweight components. An example of an
428 * <i>empty-shape</i> is {@code new Rectangle()}.
429 * <li><i>non-empty-shape</i> - the given shape will be cut out from
430 * heavyweight components.
433 * The most common example when the 'mixing-cutout' shape is needed is a
434 * glass pane component. The {@link JRootPane#setGlassPane()} method
435 * automatically sets the <i>empty-shape</i> as the 'mixing-cutout' shape
436 * for the given glass pane component. If a developer needs some other
437 * 'mixing-cutout' shape for the glass pane (which is rare), this must be
438 * changed manually after installing the glass pane to the root pane.
440 * Note that the 'mixing-cutout' shape neither affects painting, nor the
441 * mouse events handling for the given component. It is used exclusively
442 * for the purposes of the Heavyweight/Lightweight Components Mixing
445 * @param component the component that needs non-default
446 * 'mixing-cutout' shape
447 * @param shape the new 'mixing-cutout' shape
448 * @throws NullPointerException if the component argument is {@code null}
450 public static void setComponentMixingCutoutShape(Component component,
453 if (component == null) {
454 throw new NullPointerException(
455 "The component argument should not be null.");
458 AWTAccessor.getComponentAccessor().setMixingCutoutShape(component,