JDK-6462093 : FocusEvent processed twice when requestFocus after JOptionPane.showMessage()
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.4.2,6
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_2000,windows_xp
  • CPU: x86
  • Submitted: 2006-08-21
  • Updated: 2011-01-19
  • Resolved: 2007-05-15
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.4.2_04"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_04-b05)
Java HotSpot(TM) Client VM (build 1.4.2_04-b05, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows 2000 ( build 5.00.2195 ) Service Pack 4

A DESCRIPTION OF THE PROBLEM :
When a component lost it focus and at focusLost() you show a JOptionPane.showMessage(), calling requestFocus of the same component that lost it causes a second call to focusLost().

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
When focus goes to text2, shows a message, then when finish to show the message, text1 request focus, and then focusEvent is callend again( no idea by what )


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Do not call two times the focusEvent when forcing the focus on the component that fires focusEvent.
ACTUAL -
Calls focusEvent once again after requestFocus() on the same component after displays a modal JDialog

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class FocusTest {
    public static void main(String[] args) {
        JFrame frame  = new JFrame("Focus test");
        final JTextField field1 = new JTextField("Test1");
        final JTextField field2 = new JTextField("Test2");
        field1.addFocusListener(new FocusAdapter(){
            public void focusGained(FocusEvent e){}
            public void focusLost(FocusEvent e){
                if( !e.isTemporary() ){
                    JOptionPane.showMessageDialog(null, "Focus lost in 1");
                    field1.requestFocus();  //- This makes the focus to be called again
                }
            }
        });
        frame.getContentPane().add(field1, BorderLayout.WEST);
        frame.getContentPane().add(field2, BorderLayout.CENTER);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setBounds(0,0,200,300);
        frame.show();
        
    }
} 
---------- END SOURCE ----------

Comments
EVALUATION here are some comments from 6555704 (which is a duplicate of this CR): I was able to reproduce the problem described in the first comment (additional focus gain/lost on text field just after closing dialog) on Windows. I think I knwo the cause of the problem: the test requests focus on tezt field just after closing dialog. This request is processsed by our focus subsystem and finally delivered to KFM.shouldNativelyFocusHeavyweight(). At this point native focus owner is null, native focused window is the frame, and there are no pending focus requests. In this case we thinks that we should natively set focus and so this produces problematic focus events. Imho in this case we should do nothing and wait when DKFM will process WINDOW_GAINED_FOCUS on the frame and request focus for text field as a most recent focus owner (note: most recent focus owner has been already updated in requestFocus()). The only question is if it is possible to have similar situation (naive focuse owner == null and native focused window != null) not during the activation process. (need to think about this) *** (#4 of 5): 2007-05-14 20:30:34 MSD ###@###.### Well, it looks like we can not filter out the request in shouldNativelyFocusHeavyweight() because the situation is the same as for request we do in DKFM on WINDOW_GAINED_FOCUS (or we need to add one more majic flag for this). Another approach would be to not request focus in DKFM is there are pending requests, but this way we will not restore focus to the compoment which temporary lost focus (so this will looks trange, though there is no such statements in the Focus spec). So, both approaches have some disadvantages and the problem is not a spec violation thus I'm postponing the fix for now (hope will find a better way to fix or more reasons to fix it :) *** (#5 of 5): 2007-05-15 12:41:38 MSD ###@###.###
15-05-2007

EVALUATION Ok, we call clearGlobalFocusOwner() from removeNotify() for button from JOptionPane, I think this should be addressed by the fix for 6411406 (Components automatically transfer focus on removal, even if developer requests focus elsewhere first). But the real problem is in DefaultKeyboardFocusManager. when we receive WINDOW_GAINED_FOCUS we perform two focus requests: 1. on the component which temporary lost focus (second text field in our case) 2. on most recent focus owner (the first text field in our case) But in the test we have the third request (which is performed before these two): it is request we do just after closing option pane. So, we finally have: a)focus gained on tf1 (because of the third request) b)focuse lost on tf1 and focus gained on tf2 (because of the first request) c)focus lost on tf2 and focus gained on tf1 (because of the second request) so on step b) we have focus lost which causes problem for the test (and user). Possible solution would be do not request focus on tf2 in DKFM, but this could cause focus spec violation. So, we need to find the right way to fix the problem.
28-08-2006

EVALUATION based on the event sequence it looks like we do clear focus for some reason :(
22-08-2006

EVALUATION JDK1.4.2 reports about two focus events, JDK5.0 - about three. Looks like a thread issue. Needs further investigation.
21-08-2006