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 JDialog
s 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.