4

Problem

Our standalone Swing application shows modal JDialog at some specific events (button click etc.) The dialog contains some other Swing components (JLabels, JButtons, ...). Rather then setting its dimension explicitly through JDialog.setBounds(...) method we call JDialog.pack() (or JOptionPane's showDialog(...) methods calls it implicitly). The dimension calculated by pack() method is always constant (e.g. 300x100 px.) Unfortunately, sometimes real dimension of visible dialog is 1x1 px (JDialog.getSize().equals(new Dimension(1, 1))).

JDialog initialization

There are 2 ways we initialize JDialogs in our application. We checked that both initialization methods are always called from EventDispatchThread.

First method

We just create an instance of ADialog which is subclass of JDialog. Here is a snippet of our initialization procedure:

ADialog dialog = new ADialog();
dialog.setContentPane(content);
dialog.setVisible(true);

Here is our ADialog implementation:

public class ADialog extends JDialog implements ComponentListener {

    public JfosDialog(Frame owner) {
        super(owner);
        init();
    }

    private void init() {
        super.addComponentListener(this);
    }

    @Override
    public void componentShown(ComponentEvent e) {
        // Calling pack() at this place is really weird, but we
        // have to do it since some subclasses put their
        // content to dialog in overriden componentShown().
        pack();
    }

    @Override
    public void componentMoved(ComponentEvent e) { /** not interested */ }

    @Override
    public void componentResized(ComponentEvent e) { /** not interested */ }
}

Second method

public JOptionPane showDialog(...) {
    JOptionPane jop = new JOptionPane(message, msgType, option, null, textMessages);
    JDialog dialog = jop.createDialog(owner, titleMsg);
    setDialogTraversal(dialog);
    dialog.setVisible(true);
    dialog.dispose();
    return jop;
}

Reproducibility

Environment

  • Ubuntu 12.04., JRE 1.6 / JRE 1.7 / OpenJDK 1.6
  • Windows XP, JRE 1.6.u16

Reproducing the problem with first initialization method

We just show and then hide the dialog N times (0 < N < 1000) and once upon the time dialog's dimension is 1x1 (sign of threading issue, race condition). Since the nature of this problem is very stochastic we've written simple java.awt.Robot script which shows and hides the dialog in loop. It's just more comfortable than doing it manually.

Reproducing the problem with second initialization method

The steps are same as in first method: just show and then hide the dialog N times. Unfortunatelly we are unable to reproduce it in our development environment, but it can be quite easily reproduced in production PC (there is different CPU than in our development environment, some antivirus installed which permanently creates system load, etc.)

So far we are not able to reproduce the problem in some sort of test/sample project. This might suggest, that there is something wrong in our application. However, it seems that the problem may be somewhere in native code of Swing (see Tracing section).

Tracing

We traced the cause of our problem in 64bit OpenJDK 1.6.0_24. We found out that the dimension of JDialog is modified by XConfigureEvent fired by XToolkit. The event is constructed in event loop of XToolkit.run(boolean) method after returnig from native method invocation.

To simplify things I post here only a code snippet illustrating XToolkit's event loop mechanism with results of our tracing. You may also see the full source code here.

public class XToolkit ... {
    ...
    public void run(boolean loop) {
        XEvent ev = new XEvent();
        while(true) {
            awtLock();
            try {
                if (loop == SECONDARY_LOOP) {
                    ...
                } else {
                    ...

                    // ===========================================
                    // The following invocation of native method sometimes
                    // updates ev object in a way that ev.get_type() method returns value 22
                    // indicating that the event's type is XConfigureEvent.
                    // In such case, as I mentioned in text above, the value of
                    // ev.get_xconfigure().get_width() / .get_height()
                    // is sometimes 1.

                    XlibWrapper.XNextEvent(getDisplay(),ev.pData); // <-----

                    // ===========================================
                }
                ...
                // The XConfigureEvent with get_width() == 1 and
                // get_heigth() == 1 is dispatcher here:
                dispatchEvent(ev); // <-----
                ...
            } catch (...) {
                ...
            }
        }
    }
    ...
}

Do you have any ideas how to fix this bug / trace it deeper / reproduce it more robustly... ?

I appreciate any ideas since this bug is a real pain.

Michal Vician
  • 2,486
  • 2
  • 28
  • 47
  • See also [Initial Threads](http://download.oracle.com/javase/tutorial/uiswing/concurrency/initial.html). – trashgod May 31 '12 at 23:04
  • right as (@trashgod) mentioned, you can do anything, prepare your GUI any of ways, but setVisible must me inside invokeLater, rest of methods isn't important for EDT and visibility in the screen, especially if JDialog and JOptionPane called out of EDT, the you can see only toolbar on the screen, RootPane isn't visible – mKorbel Jun 01 '12 at 05:45
  • @mKorbel's [Q&A](http://stackoverflow.com/q/7787998/230513) cites two ways to detect EDT violations. – trashgod Jun 01 '12 at 05:50
  • We have checked all initialization methods and `setVisible(true)` are called in EDT. I also modified my post and added our initialization code. – Michal Vician Jun 01 '12 at 06:40
  • Do you have an example of a subclass that adds its content to the dialog in the `componentShown` method? – Jeffrey Jun 01 '12 at 21:10

1 Answers1

6

pack() should honor the preferred (or minimum size depending on the layou tmanager) of your components.

Try to explicitely set a minimum and preferred size for the components on your dialog and see if that fixes the problem.

As far as race conditions are concerned it could well be an incorrect initialization in your code as well. Most components will honer their content (e.g. the text of a JLabel) when the layout manager queries their preferred (or minimum size). So maybe the code that populates your components does not always run in the same order. Did you make sure to create the dialog and all contained components on the AWT thread?

  • I added to my post some info concerning our initialization procedures. We checked that JDialogs are created and otherwise manipulated in EventDispatchThread. – Michal Vician Jun 01 '12 at 06:37