JDK-6563771 : Erroneous window closing and complete workstation freeze up
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 6
  • Priority: P3
  • Status: Closed
  • Resolution: Won't Fix
  • OS: solaris_8
  • CPU: sparc
  • Submitted: 2007-05-31
  • Updated: 2010-04-04
  • Resolved: 2007-06-05
Related Reports
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
1.6.0_01 SERuntime: build 1.6.0_01-b06

ADDITIONAL OS VERSION INFORMATION :
SunOS <hostname> 5.8 Generic_117350-33 sun4u sparc SUNW, Sun-Blade-150. Also occurrs on Sun-Blade-2000

EXTRA RELEVANT SYSTEM CONFIGURATION :
These Solaris systems are running JEDI 1.3. Problem occurred on both a daul core Solaris and a single core Solaris.

A DESCRIPTION OF THE PROBLEM :
App. opens a JFrame that has 2 buttons. Each button opens a dialog box, call them A and B. Dialog box B has a button that brings up a modal dialog box, call it C. Open both A & B, then press B's button and bring up C. Close C, and then close B. Window A closes also, but no window closing event is posted back to the main frame for A's closing. B's closing event is posted to the main frame.
Alternatively, open A, close A, open B, open C, close C and then close B. Repeat this sequence some (small) number of times. The entire workstation freezes up. Have to do a rlogin & kill the entire login session. The login screen then appears & can log in normally. However, you find that dtwm is running at 50% CPU utilization. Kill that process, and a fresh well behaved dtwm starts up.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Build my test program & follow the above steps.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Only those windows commanded to close would close; workstation to not freeze up.
ACTUAL -
As described above

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.util.HashMap;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.Color;

import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class Freeze extends JFrame implements ActionListener
{
    private JTextArea logTextArea;
    private FreezeDialog freezeDialog1;
    private FreezeDialog freezeDialog2;
    private HashMap dialogIds = new HashMap();

    public static void main(String[] args)
    {
	Freeze freeze = new Freeze();
    }

    public Freeze()
    {
	setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	setResizable(true);
	setTitle("Freezer");
	createLayout();
	pack();
	setSize(300, 350);
	setVisible(true);
    }

    private void createLayout()
    {
	JPanel framePanel = new JPanel();
	framePanel.setLayout(new BorderLayout());

	logTextArea = new JTextArea();
	logTextArea.setBackground(Color.gray);
	logTextArea.setForeground(Color.white);
	logTextArea.setEditable(false);
	logTextArea.setSelectedTextColor(Color.black);
	logTextArea.setSelectionColor(Color.white);

	JPanel contentPanel = new JPanel();
	contentPanel.setLayout(new BorderLayout());
	JButton dialogButton = new JButton("Push Me");
	dialogButton.addActionListener(this);
	dialogButton.setActionCommand("child1");
	contentPanel.add(dialogButton);

	JPanel otherPanel = new JPanel();
	otherPanel.setLayout(new BorderLayout());
	JButton otherButton = new JButton("No, push Me");
	otherButton.addActionListener(this);
	otherButton.setActionCommand("child2");
	otherPanel.add(otherButton);

	framePanel.add(contentPanel, BorderLayout.NORTH);
	framePanel.add(otherPanel, BorderLayout.SOUTH);
	JScrollPane logger = new JScrollPane(logTextArea);
	framePanel.add(logger, BorderLayout.CENTER);

	this.add(framePanel);
    }

    public void actionPerformed(ActionEvent e)
    {
	String action = e.getActionCommand();

	if (action.equals("child1")) {
	    showDialog1();
	    logTextArea.append("Direct Child1 is opening\n");
	} else if (action.equals("child2")) {
	    showDialog2();
	    logTextArea.append("Direct Child2 is opening\n");
	}
    }

    private void showDialog1()
    {
	if (freezeDialog1 == null) {
	    FreezeDialog dialog = new FreezeDialog(1);
	    dialog.addWindowListener(new DialogWindowListener());
	    dialog.setVisible(true);
	    freezeDialog1 = dialog;
	    String name = dialog.getName();
	    dialogIds.put(name, "1");
	} else {
	    freezeDialog1.toFront();
	}
    }

    private void showDialog2()
    {
	if (freezeDialog2 == null) {
	    FreezeDialog dialog = new FreezeDialog(2);
	    dialog.addWindowListener(new DialogWindowListener());
	    dialog.setVisible(true);
	    freezeDialog2 = dialog;
	    String name = dialog.getName();
	    dialogIds.put(name, "2");
	} else {
	    freezeDialog2.toFront();
	}
    }


    class DialogWindowListener extends WindowAdapter
    {
	public DialogWindowListener()
	{
	}
	
	public void windowClosing(WindowEvent e)
	{
	    String winName = ((Component)e.getSource()).getName();
	    String msg = "Direct Child"+dialogIds.get(winName)+" is closing\n";
	    logTextArea.append(msg);
	    if (dialogIds.get(winName).equals("1")) {
		freezeDialog1 = null;
	    } else {
		freezeDialog2 = null;
	    }
	}
    }
}


---------------------------------------------------------------------------------------------------

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;

public class FreezeDialog extends JDialog implements ActionListener
{
    public FreezeDialog(int num)
    {
	createLayout(num);
	setSize(580,350);
	setLocation(200+num*30, 100+num*30);
	setTitle("Direct Child"+num);
    }

    public void actionPerformed(ActionEvent e)
    {
	String action = e.getActionCommand();
	if (action.equals("dirButton")) {
	    makeGrandchild();
	}
    }

    private void makeGrandchild()
    {
	FreezeSubDialog gchild = new FreezeSubDialog(this);
	gchild.showDialog();
    }

    private void createLayout(int num)
    {
	JPanel panel = new JPanel();
	panel.setLayout(new BorderLayout());
	panel.setBorder(BorderFactory.createEtchedBorder());
	setLayout(new FlowLayout(FlowLayout.CENTER, 2, 5));

	if (num == 2) {
	    JButton button = new JButton("Make a grandchild");
	    button.addActionListener(this);
	    button.setActionCommand("dirButton");
	    panel.add(button);
	}

	this.add(panel);
    }
}

--------------------------------------------------------------------------------------------------


import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JPanel;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;

public class FreezeSubDialog extends JDialog
    implements ActionListener, MouseListener
{
    public FreezeSubDialog(FreezeDialog owner)
    {
	super (owner);

	createLayout();
	setModal(true);
	setSize(350, 320);
	setLocationRelativeTo(owner);
	setTitle("Honored Grandchild");
    }

    public void actionPerformed(ActionEvent e)
    {
	String action = e.getActionCommand();
	if (action.equals("cancelButton")) {
	    dispose();
	}
    }

    public void mouseClicked(MouseEvent e)
    {
    }

    public void mouseEntered(MouseEvent e)
    {
    }

    public void mouseExited(MouseEvent e)
    {
    }

    public void mousePressed(MouseEvent e)
    {
    }

    public void mouseReleased(MouseEvent e)
    {
    }

    public String showDialog()
    {
	setVisible(true);
	String retval = null;
	return retval;
    }

    private void createLayout()
    {
	JPanel contentPanel = new JPanel();
	contentPanel.setLayout(new BorderLayout());

	JButton cancelButton = new JButton("Cancel");
	cancelButton.addActionListener(this);
	cancelButton.setActionCommand("cancelButton");
	contentPanel.add(cancelButton);

	setContentPane(contentPanel);
    }
}






	

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

CUSTOMER SUBMITTED WORKAROUND :
no workaround found

Comments
EVALUATION Well, this is a known problem in dtwm window manager: it doesn't handle on-fly changes of WM_TRANSIENT_FOR hint correctly. This can be easily checked: after A and B are shown, C is shown and hidden, sometimes dtwm treats A as transient for B (or B as transient for A), but the value of WM_TRANSIENT_FOR hint for both of them point to another window (Swing shared owner frame). That's why closing one of A/B also closed another window and no notification is sent to Java. Sometimes these bugs in dtwm lead to the window manager hangs (I feel this is some kind of infinite loop in its code).
05-06-2007