United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-6431340 : NullPointerException on Dialog hide on dual head system (non-xinerama)

Details
Type:
Bug
Submit Date:
2006-05-29
Status:
Resolved
Updated Date:
2011-02-16
Project Name:
JDK
Resolved Date:
2006-06-30
Component:
client-libs
OS:
linux
Sub-Component:
java.awt
CPU:
x86
Priority:
P4
Resolution:
Fixed
Affected Versions:
6
Fixed Versions:

Related Reports
Relates:

Sub Tasks

Description
FULL PRODUCT VERSION :
java version "1.6.0-beta2"
Java(TM) SE Runtime Environment (build 1.6.0-beta2-b84)
Java HotSpot(TM) 64-Bit Server VM (build 1.6.0-beta2-b84, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Red Hat Linux Fedora Core 4
custom 2.6.16 kernel x86_64 GNU/Linux

EXTRA RELEVANT SYSTEM CONFIGURATION :
Dual head X-Windows system (non-Xinerama)

A DESCRIPTION OF THE PROBLEM :
Hiding a modal dialog (e.g. JDialog.dispose()) that is the child of a non-modal dialog, which in turn is the child of a JFrame causes a NullPointerException if the windows are on a secondary screen of a multi-head x-windows configuration (non-Xinerama).

Tested with JOptionPane.showMessageDialog and JFileChooser. Based on trace info, this probably happens on any Dialog.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached test program. Press the "Open Dialog" button. Press OK on the message dialog.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Dialog closes.
ACTUAL -
Primary screen- dialog closes.
Secondary screen: NullPointerException thrown, dialog stays up.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception occurred during event dispatching:
java.lang.NullPointerException
        at sun.awt.X11.XWindowPeer.restoreTransientFor(XWindowPeer.java:1199)
        at sun.awt.X11.XWindowPeer.removeFromTransientFors(XWindowPeer.java:1265)
        at sun.awt.X11.XWindowPeer.setModalBlocked(XWindowPeer.java:1020)
        at java.awt.Window.setModalBlocked(Window.java:1159)
        at java.awt.Dialog.unblockWindow(Dialog.java:1538)
        at java.awt.Dialog.modalHide(Dialog.java:1442)
        at java.awt.Dialog.hideAndDisposePreHandler(Dialog.java:1171)
        at java.awt.Dialog.hide(Dialog.java:1213)
        at java.awt.Component.show(Component.java:1418)
        at java.awt.Component.setVisible(Component.java:1369)
        at java.awt.Window.setVisible(Window.java:694)
        at java.awt.Dialog.setVisible(Dialog.java:979)
        at javax.swing.JOptionPane$3.propertyChange(JOptionPane.java:997)
        at java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:339)
        at java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:276)
        at java.awt.Component.firePropertyChange(Component.java:7802)
        at javax.swing.JOptionPane.setValue(JOptionPane.java:1940)
        at javax.swing.plaf.basic.BasicOptionPaneUI$ButtonActionListener.actionPerformed(BasicOptionPaneUI.java:1184)
        at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
        at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
        at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:377)
        at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:232)
        at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
        at java.awt.Component.processMouseEvent(Component.java:5999)
        at javax.swing.JComponent.processMouseEvent(JComponent.java:3203)
        at java.awt.Component.processEvent(Component.java:5764)
        at java.awt.Container.processEvent(Container.java:1984)
        at java.awt.Component.dispatchEventImpl(Component.java:4407)
        at java.awt.Container.dispatchEventImpl(Container.java:2042)
        at java.awt.Component.dispatchEvent(Component.java:4237)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4248)
        at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3912)
        at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3842)
        at java.awt.Container.dispatchEventImpl(Container.java:2028)
        at java.awt.Window.dispatchEventImpl(Window.java:2300)
        at java.awt.Component.dispatchEvent(Component.java:4237)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:600)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:177)
        at java.awt.Dialog$1.run(Dialog.java:1039)
        at java.awt.Dialog$2.run(Dialog.java:1085)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.awt.Dialog.show(Dialog.java:1083)
        at javax.swing.JOptionPane.showOptionDialog(JOptionPane.java:848)
        at javax.swing.JOptionPane.showMessageDialog(JOptionPane.java:645)
        at javax.swing.JOptionPane.showMessageDialog(JOptionPane.java:616)
        at TestCase$ButtonActionListener.actionPerformed(TestCase.java:35)
        at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
        at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
        at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:377)
        at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:232)
        at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
        at java.awt.Component.processMouseEvent(Component.java:5999)
        at javax.swing.JComponent.processMouseEvent(JComponent.java:3203)
        at java.awt.Component.processEvent(Component.java:5764)
        at java.awt.Container.processEvent(Container.java:1984)
        at java.awt.Component.dispatchEventImpl(Component.java:4407)
        at java.awt.Container.dispatchEventImpl(Container.java:2042)
        at java.awt.Component.dispatchEvent(Component.java:4237)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4248)
        at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3912)
        at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3842)
        at java.awt.Container.dispatchEventImpl(Container.java:2028)
        at java.awt.Window.dispatchEventImpl(Window.java:2300)
        at java.awt.Component.dispatchEvent(Component.java:4237)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:600)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class TestCase {
        public TestCase() {
                GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
                GraphicsDevice[] gs = ge.getScreenDevices();

                if (gs.length<2) {
                        System.out.println("Not multi-head environment, test not valid!");
                        System.exit(1);
                }

                for (int i=0; i<gs.length; i++) {
                        JFrame frame=new JFrame("Main App",gs[i].getDefaultConfiguration());
                        frame.show();
                        JDialog dialog=new JDialog(frame,"Dialog "+i,false,gs[i].getDefaultConfiguration());
                        JButton button=new JButton("Open Dialog");
                        button.addActionListener(new ButtonActionListener(dialog));
                        dialog.getContentPane().add(button);
                        dialog.pack();
                        dialog.show();
                }
        }
        private static class ButtonActionListener implements ActionListener {
                JDialog dialog;
                public ButtonActionListener(JDialog dialog) {
                        super();
                        this.dialog=dialog;
                }
                public void actionPerformed(ActionEvent e) {
                        JOptionPane.showMessageDialog(dialog,"Null Pointer Exception Ahead!","Press OK for NPE",JOptionPane.INFORMATION_MESSAGE);
                }
        }
        public static void main(String args[]) {
                new TestCase();
        }
}

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

CUSTOMER SUBMITTED WORKAROUND :
Use Java version <1.6

                                    

Comments
EVALUATION

This may be related to another recent bug 6430802.
                                     
2006-05-29
SUGGESTED FIX

*** /tmp/geta7531.yv7534	2006-05-29 12:21:01.913252426 +0400
--- XWindowPeer.java	2006-05-29 12:02:32.000000000 +0400
***************
*** 1013,1019 ****
      private static Vector<XWindowPeer> collectJavaToplevels() {
          Vector<XWindowPeer> javaToplevels = new Vector<XWindowPeer>();
          Vector<Long> v = new Vector<Long>();
!         v.add(XToolkit.getDefaultRootWindow());
          while (v.size() > 0) {
              long win = v.remove(0);
              XQueryTree qt = new XQueryTree(win);
--- 1013,1030 ----
      private static Vector<XWindowPeer> collectJavaToplevels() {
          Vector<XWindowPeer> javaToplevels = new Vector<XWindowPeer>();
          Vector<Long> v = new Vector<Long>();
!         X11GraphicsEnvironment ge =
!             (X11GraphicsEnvironment)GraphicsEnvironment.getLocalGraphicsEnvironment();
!         GraphicsDevice[] gds = ge.getScreenDevices();
!         if (!ge.runningXinerama() && (gds.length > 1)) {
!             for (GraphicsDevice gd : gds) {
!                 int screen = ((X11GraphicsDevice)gd).getScreen();
!                 long rootWindow = XlibWrapper.RootWindow(XToolkit.getDisplay(), screen);
!                 v.add(rootWindow);
!             }
!         } else {
!             v.add(XToolkit.getDefaultRootWindow());
!         }
          while (v.size() > 0) {
              long win = v.remove(0);
              XQueryTree qt = new XQueryTree(win);
***************
*** 1146,1159 ****
      void updateTransientFor() {
          int state = getWMState();
          XWindowPeer p = prevTransientFor;
!         while ((p != null) && (p.getWMState() != state)) {
              p = p.prevTransientFor;
          }
          if (p != null) {
              setToplevelTransientFor(this, p, false, false);
          }
          XWindowPeer n = nextTransientFor;
!         while ((n != null) && (n.getWMState() != state)) {
              n = n.nextTransientFor;
          }
          if (n != null) {
--- 1157,1170 ----
      void updateTransientFor() {
          int state = getWMState();
          XWindowPeer p = prevTransientFor;
!         while ((p != null) && ((p.getWMState() != state) || (p.getScreenNumber() != getScreenNumber()))) {
              p = p.prevTransientFor;
          }
          if (p != null) {
              setToplevelTransientFor(this, p, false, false);
          }
          XWindowPeer n = nextTransientFor;
!         while ((n != null) && ((n.getWMState() != state) || (n.getScreenNumber() != getScreenNumber()))) {
              n = n.nextTransientFor;
          }
          if (n != null) {
                                     
2006-05-29
EVALUATION

On linux/solaris with XToolkit new AWT modality uses WM_TRANSIENT_FOR hint. When a modal dialog is shown all its blocked windows are set up into a single transient_for chain, each window is transient for previous one. In the case of multiscreen configurations, both Xinerama-enabled or Xinerama-disabled, there may be a situation when this chain is partly on one screen and partly on another. This may confuse a window manager and lead to exceptions.

Here is an example (very close to the test from the bug description). Say we have two frames, A and B, A on screen #0 and B on screen #1. Then we show two modeless dialogs D1 with parent A and D2 with parent B. D1 is located on screen #0 and D2 is located on screen #1. Then we show modal dialog M with parent D1 on screen #0, and all these 5 windows (including M) must be arranged into a chain. This chain depends on the current z-order of these windows, for example it can be like this: A-D1-B-D2-M. If all the windows are on the same screen, everything would be fine, however in this case it would lead to M not to be a child of D1 (D1 can be above M which is wrong).

The fix of this problem may be the same as for 6401700/6412803: we should keep a single logical transient_for chain and several real chains for different X screens. When running with Xinerama on all the screens are the same so no changes are required.
                                     
2006-05-29



Hardware and Software, Engineered to Work Together