JDK-8139218 : Dialog that opens and closes quickly changes focus in original focusowner
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 8u60
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_7
  • CPU: x86_64
  • Submitted: 2015-09-07
  • Updated: 2018-02-15
  • Resolved: 2016-05-31
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 8 JDK 9
8u162Fixed 9 b124Fixed
Description
FULL PRODUCT VERSION :
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]

A DESCRIPTION OF THE PROBLEM :
Focus switches from the focussed component to two components further in the focus chain when a dialog is opened and closed before it received focus itself.

It seems to go wrong because
java.awt.Component#7663: A component registers itself as mostRecentFocusOwner
java.awt.Component#7703: The component requests focus (this fails in the reproduction)

Is done in combination with:
java.awt.DefaultKeyboardFocusManager:doRestoreFocus(Window, Component, Boolean): trying to focus the MostRecentFocusOwner and then the next one

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1) Run the attached source
2) Press Enter in any of the textfields
A dialog opens and closes immediately.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The focused component should still be the textfield that was focused when pressing Enter.
ACTUAL -
The focus switches from the original field to the field that is 2 components further in the focus chain.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.WindowConstants;

public class FocusBug extends JFrame implements ActionListener
{
  private final SimpleDialog mDialog = new SimpleDialog();

  public static void main(String[] args)
  {
    FocusBug tfs = new FocusBug();
    tfs.setVisible(true);
  }

  public FocusBug()
  {
    setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

    Container c = getContentPane();
    c.setLayout(new FlowLayout());
    for (int i = 0; i < 10; i++)
    {
      JTextField tf = new JTextField(10);
      c.add(tf);
      tf.addActionListener(this);
    }
    pack();
  }

  @Override
  public void actionPerformed(ActionEvent e)
  {
    mDialog.showQuickly();
  }

  private static class SimpleDialog extends JDialog
  {
    public void showQuickly()
    {
      setVisible(true);
      setVisible(false);
    }
  }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
It is possible to add a WindowFocusListener to the dialog that waits until the setVisible(false) is called _and_ it has received focus. If one of the two is called it should wait before actually calling super.setVisible(false).


Comments
The root cause is restoreFocus() does not wait until asynchronous native focus is set and traverse focus to the next component.
21-10-2015

Moving to JDK project. Has a potential test case. Setting Fix/Version to JDK 9 for Dev evaluation. Will consider N-bp as needed.
08-10-2015