JDK-6829858 : JInternalFrame is not redrawing heavyweight children properly
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 6u10,6u12
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2009-04-14
  • Updated: 2013-08-02
  • Resolved: 2011-03-07
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other JDK 6 JDK 7
5.0-poolResolved 6u60Fixed 7 b57Fixed
Related Reports
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.6.0_12"
Java(TM) SE Runtime Environment (build 1.6.0_12-b04)
Java HotSpot(TM) Client VM (build 11.2-b01, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
When a JInternalFrame contains a heavyweight component and the internal frame is positioned such that the heavyweight component is not completely displayed the component is not redrawn properly when it becomes visible again.  It only refreshes when the internal frame is moved or resized.

This was working up through 1.6.0_11
It is not working in 1.6.0_12, 1.6.0_13, 1.6.0_14-ea-b04

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Put a heavyweight component inside a JInternalFrame
Put the internal frame inside a JDesktopPane
Put the desktop pane inside a heavyweight panel (keeps hw component from showing outside the desktop)

Move the internal frame so that the heavyweight component is half way off the desktop
Resize the desktop so the entire internal frame is visible.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The heavyweight component is redrawn properly as it becomes visible.
ACTUAL -
The part of the heavyweight component that was not displayed is not redrawn until the frame is moved or resized.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
        Panel hwPanel = new Panel(new GridBagLayout());
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        panel.add(hwPanel, gbc);
       
        JDesktopPane desktop = new JDesktopPane();
        gbc = new GridBagConstraints();
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.fill = GridBagConstraints.BOTH;
        hwPanel.add(desktop, gbc);

        iFrame = new JInternalFrame("one", true, true, true, true);
        iFrame.setLayout(new GridBagLayout());
        iFrame.setPreferredSize(new Dimension(150, 55));
        desktop.add(iFrame);
        
        Button button = new Button("HW Button");
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 1;
        iFrame.add(button, gbc);

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
In the test case above setting the frame to not visible and back to visible fixes the problem.

However, I have not found a workaround for the real application.
It has:
 -heavy weight canvas in the place of a button
- multiple internal frames
- Desktop Pane is inside a JScrollPane

Comments
SUGGESTED FIX --- old/src/share/classes/java/awt/Container.java 2009-04-17 14:46:11.000000000 +0400 +++ new/src/share/classes/java/awt/Container.java 2009-04-17 14:46:10.000000000 +0400 @@ -3977,10 +3977,8 @@ Component comp = getComponent(index); if (!comp.isLightweight()) { comp.applyCurrentShape(); - if (comp instanceof Container && ((Container)comp).getLayout() == null) { - ((Container)comp).recursiveApplyCurrentShape(); - } - } else if (comp instanceof Container && + } + if (comp instanceof Container && ((Container)comp).hasHeavyweightDescendants()) { ((Container)comp).recursiveApplyCurrentShape(); }
17-04-2009

EVALUATION When the frame is resized by the user, at first it becomes invalid. After that validate() is being invoked in order to make it valid. Note that invalidating the frame makes all of its component invalid, which means that the Component.areBoundsValid() returns false for every component, hence effectively disabling the mixing code that recalculates shapes of heavyweight components. Validation is being done starting from the leafs up to the root, and only when the top-level component (i.e. the frame) becomes valid, the areBoundsValid() begins to return true for the direct children of the frame, hence allowing the Container.mixOnValidating() do its job. The mixOnValidating() basically invokes the Container.recursiveApplyCurrentShape() that recursively traverses the component hierarchy, calculates the current shape for each heavyweight component, and applies it to the components. Note that traversing stops whenever the method encounters a heavyweight container with a non-null layout. In the test for this CR there's a heavyweight panel that has a non-null layout (BorderLayout) and actually contains all the rest of the components. This leads to the observed result: the recursiveApplyCurrentShape() method stops on this panel w/o updating the shapes of children of the panel - thus the bug is reproduced. The reason to check for non-null layout seems currently unknown. It was added as a part of the fix for 6768230 (HW/LW mixing code slows down resize performance). Eliminating the check to invoke the method on any container resolves the problem.
16-04-2009

EVALUATION Complete test that can be used to reproduce the problem is attached.
14-04-2009