JDK-8039793 : Focused component is in a different frame than the selected frame
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 7u45,8,9
  • Priority: P3
  • Status: Open
  • Resolution: Unresolved
  • OS: windows_7
  • CPU: x86_64
  • Submitted: 2014-03-17
  • Updated: 2018-09-12
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.
Other
tbdUnresolved
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) Client VM (build 24.45-b08, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]

A DESCRIPTION OF THE PROBLEM :
When programmatically selecting frames, it is possible to end up with the focused component in a different frame than the frame that is selected. This is because focus is done asynchronously, so the permanent focus owner is not yet accurate when JInternalFrame.restoreSubcomponentFocus is called. 

Even though we don't leave selection on interim frame, we need all the events to be fired in order to react on them and stay event driven. Both frames are visible to the user, and images, words, etc. change because of those events. We cannot simply reject the first selection move because 1) we need all the events fired and 2) the frames are in non-coupled, independent code.

The fix in JInternalFrame for bug number 6505027 introduced this bug. The internal comments in JInternalFrame setSelected and restoreSubcomponentFocus also somewhat address this need.

REGRESSION.  Last worked in version 6u43

ADDITIONAL REGRESSION INFORMATION: 
java version "1.6.0_21"
Java(TM) SE Runtime Environment (build 1.6.0_21-b06)
Java HotSpot(TM) Client VM (build 17.0-b16, mixed mode)

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Create and show a JDesktopPane in a JFrame.
Create and add two JInternalFrames, each containing at least one focusable component, to the desktop pane.
After add, the second frame should be selected and have focus.
Programmatically select the first frame and then the second frame.



EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The second frame is selected and its child component is the focused component.
ACTUAL -
The second frame is selected but the focused component is in the non-selected (first) frame.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.Container;
import java.awt.FlowLayout;
import java.beans.PropertyVetoException;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class JInternalFrameSelectionTest extends JFrame
{
   public static void main(String args[])
   {
      JFrame mainFrame = new JInternalFrameSelectionTest();
      mainFrame.setSize(700, 400);
      mainFrame.setVisible(true);

      JDesktopPane desktopPane = new JDesktopPane();
      mainFrame.getContentPane().add(desktopPane);

      final JInternalFrame frame1 = new JInternalFrame("Frame 1", true, true, true, true);
      frame1.setBounds(10, 10, 300, 300);
      Container contentPane = frame1.getContentPane();
      contentPane.setLayout(new FlowLayout());
      contentPane.add(new JTextField("frame 1 field"));
      desktopPane.add(frame1);
      frame1.setVisible(true);

      final JInternalFrame frame2 = new JInternalFrame("Frame 2", true, true, true, true);
      frame2.setBounds(350, 10, 300, 300);
      contentPane = frame2.getContentPane();
      contentPane.setLayout(new FlowLayout());
      contentPane.add(new JTextField("frame 2 field"));
      desktopPane.add(frame2);
      frame2.setVisible(true);

      SwingUtilities.invokeLater(new Runnable()
      {
         @Override
         public void run()
         {
            try
            {
               frame1.setSelected(true);
            }
            catch (PropertyVetoException e)
            {
            }
            try
            {
               frame2.setSelected(true);
            }
            catch (PropertyVetoException e)
            {
            }
         }
      });
   }
}

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

CUSTOMER SUBMITTED WORKAROUND :
Extend JInternalFrame and override restoreSubcomponentFocus to remove the check that the permanent focus owner is descending from the frame being selected. However, since lastFocusOwner and setLastFocusOwner are private, they had to be "hacked" via reflection.


Comments
Regression of JDK-6505027. KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner() in restoreSubComponentFocus() returns JTextField whose parent is JInternalFrame("frame2") so SwingUtilities.isDescendingFrom(component, this) returns true as "this" points to 2nd internal frame so lastFocusOwner is not transferred to 2nd internal frame from 1st. It seems permanent foucs owner should have been pointed to 1st internal frame when 1st internal frame is "selected". Now, what happens is when updateLastFocusOwner() is called, the component is JTextField but it parent is 1st internal frame so it shifts the focus to 1st internal frame's textfield.
12-09-2018

not a regression in 8 or 9
16-05-2014

as P3 affected 9 should be fixed or deferred
11-04-2014

is it affected 8 and 9?
09-04-2014