JDK-4311608 : REGRESSION: (Kestrel RC1)JMenuItem action disabling own JMenu HANGS
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.3.0
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_nt
  • CPU: x86
  • Submitted: 2000-02-10
  • Updated: 2000-12-19
  • Resolved: 2000-12-19
Related Reports
Duplicate :  
Description

Name: skT88420			Date: 02/10/2000


java version "1.3.0rc1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0rc1-T)
Java HotSpot(TM) Client VM (build 1.3.0rc1-S, mixed mode)

If the action of a JMenuItem calls code that disbles the JMenu
on which the JMenuItem resides, the program hangs.  This did not
happen under jdk 1.2.2.

Here's a short example; both of the menu items will hang (on one item,
I tried using the Swing invokeLater() utility; that hangs too).

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

public class MenuBug {
	public static void main(String[] args) {
		JFrame f = new JFrame("Menu Bug");
		JMenuBar menubar = new JMenuBar();
		f.setJMenuBar(menubar);
		final JMenu bug = new JMenu("Kill the Program");
		menubar.add(bug);
		JMenuItem item = new JMenuItem("Now");
		item.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				bug.setEnabled(false);
			}
		});
		bug.add(item);

		item = new JMenuItem("Later");
		item.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				SwingUtilities.invokeLater(new Runnable() {
					public void run() {
						bug.setEnabled(false);
					}
				});
			}
		});
		bug.add(item);

		f.setSize(100, 100);
		f.setVisible(true);
	}
}
(Review ID: 101048) 
======================================================================

Name: skT45625			Date: 05/19/2000


java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)

Run this program and press the TAB key, and it will hang.  It appears as if the
FocusManager loops trying to find the next focusable component.

This may be the same problem that causes #4311608, but the test case is much
simpler.

=============================================================================
import java.awt.event.*;
import javax.swing.*;

/**
**  Run this program, and press Tab.  The program will hang (JDK 1.3)
*/

public class Hang {
    public static void main( String[] args ) {
        JFrame frame = new JFrame( "Press Tab to hang program" );

        JMenuBar menuBar = new JMenuBar();
        JMenu menu = new JMenu( "Empty" );
        menuBar.add( menu );
        frame.setJMenuBar( menuBar );

        frame.setSize( 300, 200 );
        frame.setLocation( 200, 200 );
        frame.validate();
        frame.show();
    }
}
=============================================================================
(Review ID: 105128)
======================================================================

Comments
EVALUATION This bug was introduced between 1.3 beta and RC1. The hang is an infinite loop in DefaultFocusManager.getPreviousComponent. The stackframe is not increasing so it's not the result of a recursive call. I looked at the code for JMenuItem and AbstractButton and backed out of the changes since August. The bug still occurred so I think I can safely rule out those changes. I also backed out of changes made to DefaultFocusManager and the bug still persists. There are a couple of suspicious places where this bug may hae been added to JComponent. There seems to have been a lot of code added to tweak or look at focus stuff and also some enable()/disable() methods added which could have produced side effects. Here's 3 stack traces of the current thread of the infinite loop: "AWT-EventQueue-0" prio=5 tid=0xd0738 nid=0xa runnable [0xfe900000..0xfe901a48] at javax.swing.DefaultFocusManager.inverseGetNextFocusable(DefaultFocusManager.java:334) at javax.swing.DefaultFocusManager.getComponentBefore(DefaultFocusManager.java:237) at javax.swing.DefaultFocusManager.getPreviousComponent(DefaultFocusManager.java:196) at javax.swing.DefaultFocusManager.getFocusableComponentAfter(DefaultFocusManager.java:156) at javax.swing.DefaultFocusManager.focusPreviousComponent(DefaultFocusManager.java:123) at javax.swing.JComponent.setEnabled(JComponent.java:1947) at javax.swing.AbstractButton.setEnabled(AbstractButton.java:1532) at javax.swing.JMenuItem.setEnabled(JMenuItem.java:272) at MenuBug$1.actionPerformed(MenuBug.java:30) at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1450) at javax.swing.AbstractButton$ForwardActionEvents.actionPerformed(AbstractButton.java:1504) at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:378) at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:250) at javax.swing.AbstractButton.doClick(AbstractButton.java:279) at javax.swing.plaf.basic.BasicMenuItemUI$MouseInputHandler.mouseReleased(BasicMenuItemUI.java:881) at java.awt.Component.processMouseEvent(Component.java:3717) at java.awt.Component.processEvent(Component.java:3546) at java.awt.Container.processEvent(Container.java:1163) at java.awt.Component.dispatchEventImpl(Component.java:2595) at java.awt.Container.dispatchEventImpl(Container.java:1212) at java.awt.Component.dispatchEvent(Component.java:2499) at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:2427) at java.awt.LightweightDispatcher.processMouseEvent(Container.java:2192) at java.awt.LightweightDispatcher.dispatchEvent(Container.java:2101) at java.awt.Container.dispatchEventImpl(Container.java:1199) at java.awt.Window.dispatchEventImpl(Window.java:912) at java.awt.Component.dispatchEvent(Component.java:2499) at java.awt.EventQueue.dispatchEvent(EventQueue.java:319) at java.awt.EventDispatchThread.pumpOneEvent(EventDispatchThread.java:103) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93) at java.awt.EventDispatchThread.run(EventDispatchThread.java:84) "AWT-EventQueue-0" prio=5 tid=0xd0738 nid=0xa runnable [0xfe900000..0xfe901a48] at java.lang.System.arraycopy(Native Method) at java.awt.Container.getComponents_NoClientCode(Container.java:189) at java.awt.Container.getComponents(Container.java:180) at javax.swing.DefaultFocusManager.inverseGetNextFocusable(DefaultFocusManager.java:330) at javax.swing.DefaultFocusManager.getComponentBefore(DefaultFocusManager.java:237) at javax.swing.DefaultFocusManager.getPreviousComponent(DefaultFocusManager.java:196) at javax.swing.DefaultFocusManager.getFocusableComponentAfter(DefaultFocusManager.java:156) at javax.swing.DefaultFocusManager.focusPreviousComponent(DefaultFocusManager.java:123) at javax.swing.JComponent.setEnabled(JComponent.java:1947) "AWT-EventQueue-0" prio=5 tid=0xd0738 nid=0xa runnable [0xfe900000..0xfe901a48] at javax.swing.DefaultFocusManager.compareTabOrder(DefaultFocusManager.java:263) at javax.swing.DefaultFocusManager.childrenTabOrder(DefaultFocusManager.java:352) at javax.swing.DefaultFocusManager.tabOrderPreviousComponent(DefaultFocusManager.java:311) at javax.swing.DefaultFocusManager.getComponentBefore(DefaultFocusManager.java:239) at javax.swing.DefaultFocusManager.getPreviousComponent(DefaultFocusManager.java:196) at javax.swing.DefaultFocusManager.getFocusableComponentAfter(DefaultFocusManager.java:156) at javax.swing.DefaultFocusManager.focusPreviousComponent(DefaultFocusManager.java:123) at javax.swing.JComponent.setEnabled(JComponent.java:1947) It should be noted that if the FocusManager call in JComponent.setEnabled() is commented out then the loop is gone. I don't think that's the solution but there is obviously some focusong side effects. mark.davidson@Eng 2000-02-16 --------------------------------------------------------------------------- This bug is reproducible with JDK1.2, 1.2.2, 1.3, 1.4 The cause of this bug are follows: When we call DefaultFocusManager.getFocusableComponentAfter() the initial component for the loop is menu (for our testcase). getPreviousComponent() calls cotinuously until we achieve root component. But the previous component for this root component is menubar (not menu) because the JMenu.isManagingFocus() are false. So, we never achieve the initial component again and never break our loop. Note! We have this infinit loop only when we have no any component which can receive a focus. ###@###.### 2000-05-18 I will not be putting back this fix because the focus rewrite now uner way will take care of it, we hope. I am leaving the bug open so that we can make sure of this. hania.gajewska@Eng 2000-07-13 Name: apR10133 Date: 12/19/2000 This bug is really not reproducible after focus management enhancements (bug 4290675). ###@###.### ======================================================================
11-06-2004

SUGGESTED FIX ------- DefaultFocusManager.java ------- *** /tmp/d0GdBLL Thu May 18 18:11:02 2000 --- DefaultFocusManager.java Thu May 18 18:07:57 2000 *************** *** 163,168 **** --- 163,169 ---- boolean moveForward) { Component nextComponent; Component initialComponent; + boolean rootPassed = false; nextComponent = initialComponent = focusedComponent; do { *************** *** 175,180 **** --- 176,189 ---- break; if(nextComponent == initialComponent) break; + if (nextComponent == rootContainer) { + if (!rootPassed) { + rootPassed = true; + } else { + nextComponent = null; + break; + } + } } while(!(nextComponent.isVisible() && nextComponent.isFocusTraversable() && nextComponent.isEnabled())); ###@###.### 2000-05-18
18-05-2000