JDK-6430802 : modal dialog problems on multi head non-xinerama
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 6
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: linux
  • CPU: x86
  • Submitted: 2006-05-26
  • Updated: 2011-01-19
  • Resolved: 2006-07-21
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.
JDK 6
6 b93Fixed
Related Reports
Relates :  
Relates :  
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
Solaris 8


EXTRA RELEVANT SYSTEM CONFIGURATION :
non-xinerama multiple head X-windows system

A DESCRIPTION OF THE PROBLEM :
When using multiple screens within one application, awt gets confused about which window should receive focus when using modal dialogs.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile & run the attached program.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Pressing "Open Dialog" should open a dialog with one button ("Close") on any screen. Pressing "Close" should close the dialog, and allow one to press "Open Dialog" again.
ACTUAL -
Only on the primary screen does the "Close" button close the dialog. On the secondary (I only have 2 screens) screen pressing the "Close" button brings the original JFrame on top of the dialog rather than closing the dialog. As long as "Close" is pressed somewhere within the boundaries of the original JFrame, that JFrame is brought forward (even though it doesn't get focus). If the dialog is moved away from the JFrame and "Close" is pressed, it works properly.

Note that on some window managers it isn't possible to get to the JDialog hiding behind the JFrame when this happens. As a result, the user has an unresposive desktop until the Java process is killed. On Solaris 8 using dtwm, things can get really nasty (even killing the Java app doesn't necessarily put things right).


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("Frame "+i,gs[i].getDefaultConfiguration());
                        JButton button=new JButton("Open Dialog");
                        button.setMinimumSize(new Dimension(200,100));
                        button.setPreferredSize(new Dimension(200,100));
                        button.setSize(new Dimension(200,100));
                        button.addActionListener(new ButtonActionListener(frame,new TestDialog(frame,"Dialog #"+i,true,gs[i].getDefaultConfiguration())));
                        frame.getContentPane().add(button);
                        frame.pack();
                        frame.show();
                }
        }
        private static class ButtonActionListener implements ActionListener {
                JFrame frame;
                JDialog dialog;
                public ButtonActionListener(JFrame frame,JDialog dialog) {
                        super();
                        this.frame=frame;
                        this.dialog=dialog;
                }
                public void actionPerformed(ActionEvent e) {
                        dialog.setLocationRelativeTo(frame);
                        dialog.show();
                }
        }
        public static class TestDialog extends JDialog {
                public TestDialog(Frame owner,String title, boolean modal, GraphicsConfiguration gc) {
                        super(owner,title,modal,gc);
                        JButton button=new JButton("Close");
                        button.addActionListener(new ActionListener() {
                                public void actionPerformed(ActionEvent e) {
                                        dispose();
                                }
                        });
                        getContentPane().add(button);
                        pack();
                }
        }
        public static void main(String args[]) {
                new TestCase();
        }
}

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

CUSTOMER SUBMITTED WORKAROUND :
Use an older version of the JVM (<1.6)

Comments
EVALUATION When setting the WM_TRANSIENT_FOR hint we should check if both windows (we set the hint *for* and *to*) are located on the same screen (via the getScreenNumber() method), because some window managers fail to behave coorectly otherwise. One of such window managers is dtwm. In the middle of the process of setting WM_TRANSIENT_FOR hints to set up a modal dialog there was a situation when two windows placed on different screens became transient one for another. And in spite of the terminate state was right this could break the internal logic of the dtwm and cause it to hang. The situation happened because we checked the getScreenNumber() result in the updateTransientFor() method, but didn't so in the setToplevelTransientFor() method that gets called from methods other than updateTransientFor(). The fix is to check the equality of screen numbers in the setToplevelTransientFor() before telling the window manager to make the windows transient.
03-07-2006

SUGGESTED FIX $ sccs diffs -C XWindowPeer.java ------- XWindowPeer.java ------- *** /tmp/sccs.CtIoCV 2006-07-03 14:35:33.000000000 +0400 --- XWindowPeer.java 2006-07-03 14:35:32.000000000 +0400 *************** *** 1135,1149 **** if (!allStates && (window.getWMState() != transientForWindow.getWMState())) { return; } ! long bpw = window.getWindow(); ! while (!XToolkit.isToplevelWindow(bpw) && !XToolkit.isXAWTToplevelWindow(bpw)) { ! bpw = XToolkit.getParentWindow(bpw); ! } ! long tpw = transientForWindow.getWindow(); ! while (!XToolkit.isToplevelWindow(tpw) && !XToolkit.isXAWTToplevelWindow(tpw)) { ! tpw = XToolkit.getParentWindow(tpw); } - XlibWrapper.XSetTransientFor(XToolkit.getDisplay(), bpw, tpw); } /* --- 1135,1151 ---- if (!allStates && (window.getWMState() != transientForWindow.getWMState())) { return; } ! if (window.getScreenNumber() == transientForWindow.getScreenNumber()) { ! long bpw = window.getWindow(); ! while (!XToolkit.isToplevelWindow(bpw) && !XToolkit.isXAWTToplevelWindow(bpw)) { ! bpw = XToolkit.getParentWindow(bpw); ! } ! long tpw = transientForWindow.getWindow(); ! while (!XToolkit.isToplevelWindow(tpw) && !XToolkit.isXAWTToplevelWindow(tpw)) { ! tpw = XToolkit.getParentWindow(tpw); ! } ! XlibWrapper.XSetTransientFor(XToolkit.getDisplay(), bpw, tpw); } } /*
03-07-2006

EVALUATION I'm not able to reproduce this bug other than with dtwm window manager on solaris. I tried KDE/linux, GNOME/linux and GNOME/solaris, mwm/linux, dtwm/solaris - every time sequence of statements in Java is the same, but sometimes dtwm hangs while other window managers don't.
02-06-2006