JDK-6522725 : Component in a minimized Frame has focus and receives key events
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 7
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2007-02-08
  • Updated: 2013-03-14
  • Resolved: 2011-03-07
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 7
7 b27Fixed
Related Reports
Relates :  
Description
This behavior is reproducable starting 5.0 on Linux and Solaris. It is not reproducable on Windows

I've a FocusListener added to a button in a frame. When FOCUS_LOST is triggered for the button, I'm calling requestFocus on the button to return the focus to the button. Even if I minimize the frame, focus stays on the button and pressing enter key triggers ActionEvent for the button

To reproduce:
1. Run the code below
2. When the Frames come up, notice that the focus is on the 'Click me' button.
3. Minimize the Frame, see that FocusOwner is still the button on minimized Frame (see the console output)
4. Press the space bar and it could be seen that action event is triggered for button (see the console output)

import java.awt.*;
import java.awt.event.*;

public class Test {
    
    private Button b1, b2;
    
    public static void main(String[] args) {
        new Test();
        new Thread(new Runnable() {
            public void run() {
                while (true) {
                    System.out.println("Focus Owner: " + 
                                       KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner());
                    try { Thread.sleep(5000); } catch (Exception e) {}
                }
            }
        }).start();
    }
    
    public Test() {
        Frame f = new Frame("F1");
        Frame f2 = new Frame("F2");
        f2.setLayout(new FlowLayout());
        f2.add(new Button("Sample"));
        f.setLayout(new FlowLayout());
        b1 = new Button("Click me");
        b1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                System.out.println("Action performed");
            }
        });
        b2 = new Button("Second Button");
        b1.addFocusListener(new FocusListener() {
            public void focusGained(FocusEvent event) {
                System.out.println("Button focus gained");
            }
            public void focusLost(FocusEvent event) {
                System.out.println("Button focus lost");
                b1.requestFocus();
            }
        });
        f.add(b1);
        f.add(b2);
        f2.setLocation(0, 200);
        f2.setSize(150, 150);
        f2.setVisible(true);
        f.setSize(150, 150);
        f.setVisible(true);
    }
}

Comments
SUGGESTED FIX http://sa.sfbay.sun.com/projects/awt_data/7/6522725.5
09-04-2008

EVALUATION I made a fix that disallows posting FOCUS_GAINED ahead of WINDOW_GAINED_FOCUS in case of requesting focus in an active owner when its owned window is currently focused. Looks like it works good (see attached webrev6522725-3.tgz). However I discovered some doc snipped in The Focus Spec: A KeyboardFocusManager must ensure proper event ordering, and a 1-to-1 correspondence between an event and its opposite event type. The peer layer does not make any of these guarantees. For example, it is possible for the peer layer to send a FOCUS_GAINED event before a WINDOW_GAINED_FOCUS event. The KeyboardFocusManager is responsible for ensuring that the WINDOW_GAINED_FOCUS event is dispatched before the FOCUS_GAINED event. It means that we can't remove synthesizing WINDOW_GAINED_FOCUS without modifying this text. And I guess that we should try to avoid doing the latter... =( The idea is to leave that code in the DKFM, but restrict it only to cases when focus is switched b/w windows of the same decorated owner (i.e. when native focus is set on a proxy that belongs to the owner). - - - Also. The reason of reg test failures with the 2nd fix (see above entries) is that I didn't detect focus switches b/w an owner and an owned windows. This should have been specially processed. Though, I consider this fix still not the safest.
09-08-2007

EVALUATION I faced with some problem investigating the 3rd suggestion above. On MS Windows when one switches focus b/w an owned window and the owner, the latter is not sent WM_ACTIVATE (as the native focus is on the proxy, that belongs to the owner). The only event posted to Java is FOCUS_GAINED. Thus it's assumed that DKFM will synthesize WINDOW_GAINED_FOCUS itself. It's excatly that code I thought to remove... On XAWT, a frame is always sent WINDOW_GAINED_FOCUS as it receives WM_TAKE_FOCUS on native level every time user clicks in it. Probably we can do something similar in MS Windows. Investigating it.
09-08-2007

EVALUATION The focus isn't switched and stays on the "Click Me" button in three cases: 1. Minimizing F1 (F2 gets hightlighted). 2. Clicking on F2 (F2 gets hightlighted). 3. Clicking on some native window. The reason is that there are three different states of the focused window: 1. native focused window 2. peer focused window 3. java focused window When the focus is requested on the ClickMe button in the FOCUS_LOST listener, after another toplevel has been clicked, then at that time the values of focused window are as follows: 1. native focused window = clicked toplevel 2. peer focused window = null 3. java focused window = F1 As the java focused window is not yet changed, the reaction on the focus request (see XComponentPeer.requestFocus) is just to post FOCUS_GAINED event. By the time when this event has reached DKFM, F1 window has already got WINDOW_LOST_FOCUS. DKFM detects that current java focused window differs from the parent of the ClickMe button (i.e. F1) and it simply synchronously sends WINDOW_GAINED_FOCUS on F1. I've considered 3 solutions: 1. On native level, when the focus is requested in window that is not native focused window but is still java focused window, I'm requesting focus in it instead of posting FOCUS_GAINED. With this fix, when I click in F2 a focus flicker happens b/w F1 & F2. (see webrev6522725_1.tgz attached) 2. The same as 1st, but I'm requesting focus via posting it to EDT (that is I'm postponing the request). This fix breaks many focus regression tests. (see webrev6522725_2.tgz attached) 3. Forbid synchronously sending WINDOW_GAINED_FOCUS when we receive FOCUS_GAINED on a window that is not java focused window. Actually I this this was originally wrong decision. Synthesizing WINDOW_GAINED_FOCUS does nothing without focusing the toplevel on native level. So I'm staying on this variant so far.
27-07-2007

EVALUATION Reproducibility: | 1.4.2 | 1.5 | 1.6 | 1.7 --------------------------------------------------------- WinXP | - | - | - | - ---------------------------------------------------------- Linux | - | + | + | + metacity 2.16 | b25 | | | ---------------------------------------------------------- Solaris | - | - | + | + metacity 2.16 | | | b24 |
16-02-2007