jdk/src/share/classes/java/awt/Window.java
changeset 2648 aa45a227fce3
parent 2647 ea80a312972e
child 2808 a139a919f645
child 3454 0d34cbec5989
--- a/jdk/src/share/classes/java/awt/Window.java	Mon Apr 20 19:18:41 2009 +0400
+++ b/jdk/src/share/classes/java/awt/Window.java	Tue Apr 21 11:35:52 2009 +0400
@@ -25,6 +25,7 @@
 package java.awt;
 
 import java.awt.event.*;
+import java.awt.geom.Path2D;
 import java.awt.geom.Point2D;
 import java.awt.im.InputContext;
 import java.awt.image.BufferStrategy;
@@ -297,6 +298,7 @@
     /*
      * Opacity level of the window
      *
+     * @serial
      * @see #setOpacity(float)
      * @see #getOpacity()
      * @since 1.7
@@ -307,6 +309,7 @@
      * The shape assigned to this window. This field is set to null if
      * no shape is set (rectangular window).
      *
+     * @serial
      * @see #getShape()
      * @see #setShape(Shape)
      * @since 1.7
@@ -3340,32 +3343,78 @@
     // ******************** SHAPES & TRANSPARENCY CODE ********************
 
     /**
-     * JavaDoc
+     * Returns the opacity of the window.
+     *
+     * @return the opacity of the window
+     *
+     * @see Window#setOpacity
+     * @see GraphicsDevice.WindowTranslucency
+     *
+     * @since 1.7
      */
-    /*public */float getOpacity() {
+    public float getOpacity() {
         synchronized (getTreeLock()) {
             return opacity;
         }
     }
 
     /**
-     * JavaDoc
+     * Sets the opacity of the window.
+     * <p>
+     * The opacity value is in 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.
+     * <p>
+     * In order for this method to enable the translucency effect, the {@link
+     * GraphicsDevice#isWindowTranslucencySupported()} method must indicate that
+     * the {@link GraphicsDevice.WindowTranslucency#TRANSLUCENT TRANSLUCENT}
+     * translucency is supported.
+     * <p>
+     * Also note that the window must not be in the full-screen mode when
+     * setting the opacity value &lt; 1.0f. Otherwise the {@code
+     * IllegalComponentStateException} is thrown.
+     * <p>
+     * The translucency levels of individual pixels may also be effected by the
+     * alpha component of their color (see {@link setBackground()}) and the
+     * current shape of this window (see {@link setShape()}).
+     *
+     * @param opacity the opacity level to set to the window
+     *
+     * @throws IllegalArgumentException if the opacity is out of the range
+     *     [0..1]
+     * @throws IllegalComponentStateException if the window is in full screen
+     *     mode, and the opacity is less than 1.0f
+     * @throws UnsupportedOperationException if the {@code
+     *     GraphicsDevice.WindowTranslucency#TRANSLUCENT TRANSLUCENT}
+     *     translucency kind is not supported and the opacity is less than 1.0f
+     *
+     * @see Window#getOpacity
+     * @see Window#setBackground()
+     * @see Window#setShape()
+     * @see GraphicsDevice.WindowTranslucency
+     * @see GraphicsDevice#isWindowTranslucencySupported()
+     *
+     * @since 1.7
      */
-    /*public */void setOpacity(float opacity) {
+    public void setOpacity(float opacity) {
         synchronized (getTreeLock()) {
             if (opacity < 0.0f || opacity > 1.0f) {
                 throw new IllegalArgumentException(
                     "The value of opacity should be in the range [0.0f .. 1.0f].");
             }
-            GraphicsConfiguration gc = getGraphicsConfiguration();
-            GraphicsDevice gd = gc.getDevice();
-            if (!gd.isWindowTranslucencySupported(GraphicsDevice.WindowTranslucency.TRANSLUCENT)) {
-                throw new UnsupportedOperationException(
+            if (opacity < 1.0f) {
+                GraphicsConfiguration gc = getGraphicsConfiguration();
+                GraphicsDevice gd = gc.getDevice();
+                if (gc.getDevice().getFullScreenWindow() == this) {
+                    throw new IllegalComponentStateException(
+                        "Setting opacity for full-screen window is not supported.");
+                }
+                if (!gd.isWindowTranslucencySupported(
+                    GraphicsDevice.WindowTranslucency.TRANSLUCENT))
+                {
+                    throw new UnsupportedOperationException(
                         "TRANSLUCENT translucency is not supported.");
-            }
-            if ((gc.getDevice().getFullScreenWindow() == this) && (opacity < 1.0f)) {
-                throw new IllegalArgumentException(
-                    "Setting opacity for full-screen window is not supported.");
+                }
             }
             this.opacity = opacity;
             WindowPeer peer = (WindowPeer)getPeer();
@@ -3376,37 +3425,86 @@
     }
 
     /**
-     * JavaDoc
+     * Returns the shape of the window.
+     *
+     * The value returned by this method may not be the same as
+     * previously set with {@code setShape(shape)}, but it is guaranteed
+     * to represent the same shape.
+     *
+     * @return the shape of the window or {@code null} if no
+     *     shape is specified for the window
+     *
+     * @see Window#setShape
+     * @see GraphicsDevice.WindowTranslucency
+     *
+     * @since 1.7
      */
-    /*public */Shape getShape() {
+    public Shape getShape() {
         synchronized (getTreeLock()) {
-            return shape;
+            return shape == null ? null : new Path2D.Float(shape);
         }
     }
 
     /**
-     * JavaDoc
+     * Sets the shape of the window.
+     * <p>
+     * Setting a shape enables cutting off some parts of the window, leaving
+     * visible and clickable only those parts belonging to the given shape
+     * (see {@link Shape}). If the shape argument is null, this methods
+     * restores the default shape (making the window rectangular on most
+     * platforms.)
+     * <p>
+     * The following conditions must be met in order to set a non-null shape:
+     * <ul>
+     * <li>The {@link GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSPARENT
+     * PERPIXEL_TRANSPARENT} translucency kind must be supported by the
+     * underlying system (see {@link })
+     * <i>and</i>
+     * <li>The window must not be in the full-screen mode (see
+     * {@link GraphicsDevice#setFullScreenWindow()})
+     * </ul>
+     * If a certain condition is not met, either the {@code
+     * UnsupportedOperationException} or {@code IllegalComponentStateException}
+     * is thrown.
+     * <p>
+     * The tranlucency levels of individual pixels may also be effected by the
+     * alpha component of their color (see {@link setBackground()}) and the
+     * opacity value (see {@link setOpacity()}). See {@link
+     * GraphicsDevice#WindowTranslucency} for more details.
      *
-     * @param window the window to set the shape to
      * @param shape the shape to set to the window
-     * @throws IllegalArgumentException if the window is in full screen mode,
-     *                                  and the shape is not null
+     *
+     * @throws IllegalComponentStateException if the shape is not {@code
+     *     null} and the window is in full-screen mode
+     * @throws UnsupportedOperationException if the shape is not {@code
+     *     null} and {@link GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSPARENT
+     *     PERPIXEL_TRANSPARENT} translucency is not supported
+     *
+     * @see Window#getShape()
+     * @see Window#setBackgound()
+     * @see Window#setOpacity()
+     * @see GraphicsDevice.WindowTranslucency
+     * @see GraphicsDevice#isWindowTranslucencySupported()
+     *
+     * @since 1.7
      */
-    /*public */void setShape(Shape shape) {
+    public void setShape(Shape shape) {
         synchronized (getTreeLock()) {
-            GraphicsConfiguration gc = getGraphicsConfiguration();
-            GraphicsDevice gd = gc.getDevice();
-            if (!gd.isWindowTranslucencySupported(
-                    GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSPARENT))
-            {
-                throw new UnsupportedOperationException(
+            if (shape != null) {
+                GraphicsConfiguration gc = getGraphicsConfiguration();
+                GraphicsDevice gd = gc.getDevice();
+                if (gc.getDevice().getFullScreenWindow() == this) {
+                    throw new IllegalComponentStateException(
+                        "Setting shape for full-screen window is not supported.");
+                }
+                if (!gd.isWindowTranslucencySupported(
+                        GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSPARENT))
+                {
+                    throw new UnsupportedOperationException(
                         "PERPIXEL_TRANSPARENT translucency is not supported.");
+                }
             }
-            if ((gc.getDevice().getFullScreenWindow() == this) && (shape != null)) {
-                throw new IllegalArgumentException(
-                    "Setting shape for full-screen window is not supported.");
-            }
-            this.shape = shape;
+            this.shape = (shape == null) ? null : new Path2D.Float(shape);
             WindowPeer peer = (WindowPeer)getPeer();
             if (peer != null) {
                 peer.applyShape(shape == null ? null : Region.getInstance(shape, null));
@@ -3415,66 +3513,115 @@
     }
 
     /**
-     * JavaDoc
+     * Gets the background color of this window.
+     * <p>
+     * Note that the alpha component of the returned color indicates whether
+     * the window is in the non-opaque (per-pixel translucent) mode.
+     *
+     * @return this component's background color
+     *
+     * @see Window#setBackground
+     * @see GraphicsDevice.WindowTranslucency
      */
-/*
+    @Override
+    public Color getBackground() {
+        return super.getBackground();
+    }
+
+    /**
+     * Sets the background color of this window.
+     * <p>
+     * If the windowing system supports the {@link
+     * GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSLUCENT PERPIXEL_TRANSLUCENT}
+     * tranclucency, the alpha component of the given background color
+     * may effect the mode of operation for this window: it indicates whether
+     * this window must be opaque (alpha == 1.0f) or per-pixel translucent
+     * (alpha &lt; 1.0f).  All the following conditions must be met in order
+     * to be able to enable the per-pixel transparency mode for this window:
+     * <ul>
+     * <li>The {@link GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSLUCENT
+     * PERPIXEL_TRANSLUCENT} translucency must be supported
+     * by the graphics device where this window is located <i>and</i>
+     * <li>The window must not be in the full-screen mode (see {@link
+     * GraphicsDevice#setFullScreenWindow()})
+     * </ul>
+     * If a certain condition is not met at the time of calling this method,
+     * the alpha component of the given background color will not effect the
+     * mode of operation for this window.
+     * <p>
+     * When the window is per-pixel translucent, the drawing sub-system
+     * respects the alpha value of each individual pixel. If a pixel gets
+     * painted with the alpha color component equal to zero, it becomes
+     * visually transparent, if the alpha of the pixel is equal to 1.0f, the
+     * pixel is fully opaque. Interim values of the alpha color component make
+     * the pixel semi-transparent. In this mode the background of the window
+     * gets painted with the alpha value of the given background color (meaning
+     * that it is not painted at all if the alpha value of the argument of this
+     * method is equal to zero.)
+     * <p>
+     * The actual level of translucency of a given pixel also depends on window
+     * opacity (see {@link setOpacity()}), as well as the current shape of
+     * this window (see {@link setShape()}).
+     * <p>
+     * Note that painting a pixel with the alpha value of 0 may or may not
+     * disable the mouse event handling on this pixel. This is a
+     * platform-dependent behavior. To make sure the mouse clicks do not get
+     * dispatched to a particular pixel, the pixel must be excluded from the
+     * shape of the window.
+     * <p>
+     * Enabling the per-pixel translucency mode may change the graphics
+     * configuration of this window due to the native platform requirements.
+     *
+     * @param bgColor the color to become this window's background color.
+     *
+     * @throws IllegalComponentStateException if the alpha value of the given
+     *     background color is less than 1.0f and the window is in
+     *     full-screen mode
+     * @throws UnsupportedOperationException if the alpha value of the given
+     *     background color is less than 1.0f and
+     *     {@link GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSLUCENT
+     *     PERPIXEL_TRANSLUCENT} translucency is not supported
+     *
+     * @see Window#getBackground
+     * @see Window#setOpacity()
+     * @see Window#setShape()
+     * @see GraphicsDevice.WindowTranslucency
+     * @see GraphicsDevice#isWindowTranslucencySupported()
+     * @see GraphicsConfiguration#isTranslucencyCapable()
+     */
     @Override
     public void setBackground(Color bgColor) {
+        Color oldBg = getBackground();
+        if (oldBg != null && oldBg.equals(bgColor)) {
+            return;
+        }
+        super.setBackground(bgColor);
+        int oldAlpha = oldBg != null ? oldBg.getAlpha() : 255;
         int alpha = bgColor.getAlpha();
-        if (alpha < 255) { // non-opaque window
+        if ((oldAlpha == 255) && (alpha < 255)) { // non-opaque window
             GraphicsConfiguration gc = getGraphicsConfiguration();
             GraphicsDevice gd = gc.getDevice();
             if (gc.getDevice().getFullScreenWindow() == this) {
-                throw new IllegalArgumentException(
+                throw new IllegalComponentStateException(
                     "Making full-screen window non opaque is not supported.");
             }
             if (!gc.isTranslucencyCapable()) {
                 GraphicsConfiguration capableGC = gd.getTranslucencyCapableGC();
                 if (capableGC == null) {
-                    throw new IllegalArgumentException(
+                    throw new UnsupportedOperationException(
                         "PERPIXEL_TRANSLUCENT translucency is not supported");
                 }
-                // TODO: change GC
+                setGraphicsConfiguration(capableGC);
             }
             setLayersOpaque(this, false);
+        } else if ((oldAlpha < 255) && (alpha == 255)) {
+            setLayersOpaque(this, true);
         }
-
-        super.setBackground(bgColor);
-
         WindowPeer peer = (WindowPeer)getPeer();
         if (peer != null) {
             peer.setOpaque(alpha == 255);
         }
     }
-*/
-
-    private transient boolean opaque = true;
-
-    void setOpaque(boolean opaque) {
-        synchronized (getTreeLock()) {
-            GraphicsConfiguration gc = getGraphicsConfiguration();
-            if (!opaque && !com.sun.awt.AWTUtilities.isTranslucencyCapable(gc)) {
-            throw new IllegalArgumentException(
-                    "The window must use a translucency-compatible graphics configuration");
-            }
-            if (!com.sun.awt.AWTUtilities.isTranslucencySupported(
-                    com.sun.awt.AWTUtilities.Translucency.PERPIXEL_TRANSLUCENT))
-            {
-                throw new UnsupportedOperationException(
-                        "PERPIXEL_TRANSLUCENT translucency is not supported.");
-            }
-            if ((gc.getDevice().getFullScreenWindow() == this) && !opaque) {
-                throw new IllegalArgumentException(
-                    "Making full-screen window non opaque is not supported.");
-            }
-            setLayersOpaque(this, opaque);
-            this.opaque = opaque;
-            WindowPeer peer = (WindowPeer)getPeer();
-            if (peer != null) {
-                peer.setOpaque(opaque);
-            }
-        }
-    }
 
     private void updateWindow(BufferedImage backBuffer) {
         synchronized (getTreeLock()) {
@@ -3505,10 +3652,10 @@
             }
             lp.setOpaque(isOpaque);
             root.setOpaque(isOpaque);
-            root.setDoubleBuffered(isOpaque); //XXX: the "white rect" workaround
+            root.setDoubleBuffered(isOpaque);
             if (content != null) {
                 content.setOpaque(isOpaque);
-                content.setDoubleBuffered(isOpaque); //XXX: the "white rect" workaround
+                content.setDoubleBuffered(isOpaque);
 
                 // Iterate down one level to see whether we have a JApplet
                 // (which is also a RootPaneContainer) which requires processing
@@ -3523,36 +3670,6 @@
                 }
             }
         }
-
-        Color bg = component.getBackground();
-        boolean hasTransparentBg = TRANSPARENT_BACKGROUND_COLOR.equals(bg);
-
-        Container container = null;
-        if (component instanceof Container) {
-            container = (Container) component;
-        }
-
-        if (isOpaque) {
-            if (hasTransparentBg) {
-                // Note: we use the SystemColor.window color as the default.
-                // This color is used in the WindowPeer implementations to
-                // initialize the background color of the window if it is null.
-                // (This might not be the right thing to do for other
-                // RootPaneContainers we might be invoked with)
-                Color newColor = null;
-                if (container != null && container.preserveBackgroundColor != null) {
-                    newColor = container.preserveBackgroundColor;
-                } else {
-                    newColor = SystemColor.window;
-                }
-                component.setBackground(newColor);
-            }
-        } else {
-            if (!hasTransparentBg && container != null) {
-                container.preserveBackgroundColor = bg;
-            }
-            component.setBackground(TRANSPARENT_BACKGROUND_COLOR);
-        }
     }
 
 
@@ -3620,20 +3737,16 @@
                 window.setShape(shape);
             }
             public boolean isOpaque(Window window) {
-                /*
-                return window.getBackground().getAlpha() < 255;
-                */
-                synchronized (window.getTreeLock()) {
-                    return window.opaque;
-                }
+                Color bg = window.getBackground();
+                return (bg != null) ? bg.getAlpha() == 255 : true;
             }
             public void setOpaque(Window window, boolean opaque) {
-                /*
                 Color bg = window.getBackground();
+                if (bg == null) {
+                    bg = new Color(0, 0, 0, 0);
+                }
                 window.setBackground(new Color(bg.getRed(), bg.getGreen(), bg.getBlue(),
                                                opaque ? 255 : 0));
-                */
-                window.setOpaque(opaque);
             }
             public void updateWindow(Window window, BufferedImage backBuffer) {
                 window.updateWindow(backBuffer);