United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6738762 Showing glassPane in non-opaque toplevel makes the topLevel blank
JDK-6738762 : Showing glassPane in non-opaque toplevel makes the topLevel blank

Details
Type:
Bug
Submit Date:
2008-08-19
Status:
Resolved
Updated Date:
2011-01-19
Project Name:
JDK
Resolved Date:
2008-09-02
Component:
client-libs
OS:
generic
Sub-Component:
java.awt
CPU:
generic
Priority:
P3
Resolution:
Fixed
Affected Versions:
7
Fixed Versions:
6u10 (b31)

Related Reports
Relates:

Sub Tasks

Description
If a window was made non opaque with help of the
frame.setUndecorated(true);
AWTUtilities.setWindowOpaque(frame, false);

it is turned into the blank rectangle when glassPane is shown
frame.getGlassPane().setVisible(true);

I tested it on the latest JDK 6u11 build

GlassPane tricks are quite popular among Swing programmers
moreover this bug prevents resizing of internalFrames,
because we temporarily show the glassPane when an internalFrame is being resized

import com.sun.awt.AWTUtilities;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class GlassPanelTest {

    private static void createGui() {
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JButton button = new JButton("Show GlassPane");
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                frame.getGlassPane().setVisible(true);
            }
        });
        
        frame.add(button);
        
        frame.setSize(200, 200);
        frame.setLocationRelativeTo(null);

        frame.setUndecorated(true);
        AWTUtilities.setWindowOpaque(frame, false);
        
        frame.setVisible(true);
    }

    public static void main(String[] args) throws Exception {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                GlassPanelTest.createGui();
            }
        });
    }
}

                                    

Comments
EVALUATION

When the window is non-opaque, and it needs to be repainted the sun.awt.windows.TranslucentWindowPainter (see src/windows/classes/sun/awt/windows/TranslucentWindowPainter.java) creates an ARGB_PRE buffered image and uses the Frame.paintAll(Graphics) method to paint the frame contents to the buffered image. The resulting image gets painted on the screen then.

I modified the given test case so that the button action handler include the following code before and after setting the glass pane visible:

   BufferedImage i1 = new BufferedImage(frame.getWidth(), frame.getHeight(),
      BufferedImage.TYPE_INT_ARGB_PRE);;
   frame.paintAll(i1.getGraphics());
   try {
      javax.imageio.ImageIO.write(i1, "png", new File("before.png"));
   } catch (IOException e1) {
      e1.printStackTrace();
   }

(the one located after showing the glass pane saves the image to the after.png file.) The resulting files and the modified test case are attached to the change request.

Obviously, the Swing paints the glass pane as an opaque panel, and therefore we observe this result on the screen. To fix the bug the Swing painting machinery must not paint the background of the glass pane (which is by default a non-opaque panel - it is unclear why Swing paints its background.).
                                     
2008-08-20
EVALUATION

The problem is that the glass pane is double buffered by default. All components in non-opaque frames must be double-buffer-disabled (setDoubleBuffered(false)).

To fix this issue we need to modify the Window.setLayersOpaque() method. The method must disable double-buffering on the glass pane (if any).
                                     
2008-08-21
SUGGESTED FIX

--- old/src/share/classes/java/awt/Window.java	2008-08-21 17:47:25.000000000 +0400
+++ new/src/share/classes/java/awt/Window.java	2008-08-21 17:47:25.000000000 +0400
@@ -3204,6 +3204,12 @@
             Container c = root.getContentPane();
             javax.swing.JComponent content = 
                 (c instanceof javax.swing.JComponent) ? (javax.swing.JComponent)c : null;
+            javax.swing.JComponent gp = 
+                (rpc.getGlassPane() instanceof javax.swing.JComponent) ?
+                (javax.swing.JComponent)rpc.getGlassPane() : null;
+            if (gp != null) {
+                gp.setDoubleBuffered(isOpaque);
+            }
             lp.setOpaque(isOpaque);
             //lp.setDoubleBuffered(isOpaque); //XXX: this might be needed maybe...
             root.setOpaque(isOpaque);
                                     
2008-08-21



Hardware and Software, Engineered to Work Together