SUGGESTED FIX
Name: osR10079 Date: 08/12/2002
The fix for problem with requesting focus just after
showing frame.
------- KeyboardFocusManager.java -------
*** /tmp/sccs.HEaGeu Tue Jul 2 12:01:33 2002
--- KeyboardFocusManager.java Tue Jun 25 17:49:51 2002
***************
*** 1609,1623 ****
}
}
static synchronized void setMostRecentFocusOwner(Window window,
! Component component) {
! // ATTN: component has a strong reference to window via chain
! // of Component.parent fields. Since WeakHasMap refers to its
! // values strongly, we need to break the strong link from the
! // value (component) back to its key (window).
! WeakReference weakValue = null;
! if (component != null) {
! weakValue = new WeakReference(component);
! }
mostRecentFocusOwners.put(window, weakValue);
}
static void clearMostRecentFocusOwner(Component comp) {
--- 1609,1623 ----
}
}
static synchronized void setMostRecentFocusOwner(Window window,
! Component component) {
! // ATTN: component has a strong reference to window via chain
! // of Component.parent fields. Since WeakHasMap refers to its
! // values strongly, we need to break the strong link from the
! // value (component) back to its key (window).
! WeakReference weakValue = null;
! if (component != null) {
! weakValue = new WeakReference(component);
! }
mostRecentFocusOwners.put(window, weakValue);
}
static void clearMostRecentFocusOwner(Component comp) {
***************
*** 1634,1649 ****
}
}
! if ((window != null)
! && (getMostRecentFocusOwner((Window)window) == comp))
! {
! setMostRecentFocusOwner((Window)window, null);
}
}
static synchronized Component getMostRecentFocusOwner(Window window) {
! WeakReference weakValue =
! (WeakReference)mostRecentFocusOwners.get(window);
! return weakValue == null ? null : (Component)weakValue.get();
}
/**
--- 1634,1651 ----
}
}
! synchronized (KeyboardFocusManager.class) {
! if ((window != null)
! && (getMostRecentFocusOwner((Window)window) == comp))
! {
! setMostRecentFocusOwner((Window)window, null);
! }
}
}
static synchronized Component getMostRecentFocusOwner(Window window) {
! WeakReference weakValue =
! (WeakReference)mostRecentFocusOwners.get(window);
! return weakValue == null ? null : (Component)weakValue.get();
}
/**
------- DefaultKeyboardFocusManager.java -------
*** /tmp/sccs.IEaGeu Tue Jul 2 12:01:33 2002
--- DefaultKeyboardFocusManager.java Tue Jul 2 11:54:04 2002
***************
*** 254,274 ****
}
}
- // Identify which Component should initially gain focus in
- // the Window.
- //
- // * If we're in SendMessage, then this is a synthetic
- // WINDOW_GAINED_FOCUS message which was generated by a
- // the FOCUS_GAINED handler. Allow the Component to which the
- // FOCUS_GAINED message was targeted to receive the focus.
- // * Otherwise, look up the correct Component here. If we
- // perform the lookup after the call to setGlobalFocusOwner,
- // 'null' will be returned.
- Component requestingComp = getCurrentWaitingRequest(newFocusedWindow);
- Component toFocus = (inSendMessage == 0)
- ? newFocusedWindow.getMostRecentFocusOwner()
- : null;
-
setGlobalFocusedWindow(newFocusedWindow);
if (newFocusedWindow != getGlobalFocusedWindow()) {
--- 254,259 ----
***************
*** 285,298 ****
// Make sure that the focus change request doesn't change the
// focused Window in case we are no longer the focused Window
// when the request is handled.
if (requestingComp != null) {
FocusEvent defGain = new FocusEvent(requestingComp, FocusEvent.FOCUS_GAINED,
false);
sendMessage(requestingComp, defGain);
! } else if (toFocus != null) {
! toFocus.requestFocusInWindow();
! }
Window realOppositeWindow = this.realOppositeWindow;
if (realOppositeWindow != we.getOppositeWindow()) {
we = new WindowEvent(newFocusedWindow,
--- 270,313 ----
// Make sure that the focus change request doesn't change the
// focused Window in case we are no longer the focused Window
// when the request is handled.
+ Component requestingComp = getCurrentWaitingRequest(newFocusedWindow);
if (requestingComp != null) {
FocusEvent defGain = new FocusEvent(requestingComp, FocusEvent.FOCUS_GAINED,
false);
sendMessage(requestingComp, defGain);
! } else if (inSendMessage == 0) {
! // Identify which Component should initially gain focus
! // in the Window.
! //
! // * If we're in SendMessage, then this is a synthetic
! // WINDOW_GAINED_FOCUS message which was generated by a
! // the FOCUS_GAINED handler. Allow the Component to
! // which the FOCUS_GAINED message was targeted to
! // receive the focus.
! // * Otherwise, look up the correct Component here.
! // We don't use Window.getMostRecentFocusOwner because
! // window is focused now and 'null' will be returned
+
+ // Calculating of most recent focus owner and focus
+ // request should be synchronized on KeyboardFocusManager.class
+ // to prevent from thread race when user will request
+ // focus between calculation and our request.
+ // But if focus transfer is synchronous, this synchronization
+ // may cause deadlock, thus we don't synchronize this block.
+ Component toFocus = KeyboardFocusManager.
+ getMostRecentFocusOwner(newFocusedWindow);
+ if ((toFocus == null) &&
+ newFocusedWindow.isFocusableWindow())
+ {
+ toFocus = newFocusedWindow.getFocusTraversalPolicy().
+ getInitialComponent(newFocusedWindow);
+ }
+ if (toFocus != null) {
+ toFocus.requestFocusInWindow();
+ }
+ }
+
Window realOppositeWindow = this.realOppositeWindow;
if (realOppositeWindow != we.getOppositeWindow()) {
we = new WindowEvent(newFocusedWindow,
======================================================================
|
WORK AROUND
Name: jtC48319 Date: 06/17/98
It appears that when the buttons are added to the
frame that the buttons maintain the focus. Meaning
if there are buttons on the frame, the frame will
not accept keyboard events.
If the buttons are not installed everything works
just fine. The only way I could get the key events
to work was to add a key listner to each of the
buttons. That way, no matter which button had focus
they each would process a key event. The code I
had to add to make this work is as follows and belongs
in the constructor.
yellow.addKeyListener(new KeyAdapter()
{
public void keyTyped(KeyEvent e)
{ButtonTest.this.keyTyped(e);}
}
blue.addKeyListener(new KeyAdapter()
{
public void keyTyped(KeyEvent e)
{ButtonTest.this.keyTyped(e);}
}
Now this works, but I do not think this is the way
it should work. I would think that the button
component should not have to handle all key events.
The frame component should be able to process key
events whether or not it has buttons.
Thank you.
jukka@canada 1998-06-17
The test program will work if keyPressed is used instead of keyTyped.
41,42c41,42
< public void keyTyped(KeyEvent e)
< { ButtonTest.this.keyTyped(e); }
---
> public void keyPressed(KeyEvent e)
> { ButtonTest.this.keyPressed(e); }
50c50
< public void keyTyped(KeyEvent evt)
---
> public void keyPressed(KeyEvent evt)
======================================================================
Name: osR10079 Date: 12/21/2001
We can provide two workarounds for this problem:
1. invoke frame.requestFocus() on EDT by invokeAndWait()/invokeLater().
2. make the frame the initial component by changing FocusTraversalPolicy
or by calling setFocusable(true) on the frame.
###@###.### 21 Dec 2001
======================================================================
|
EVALUATION
eric.hawkes@eng 1998-06-18
This bug sounds as though it has the same root cause as 4033894
and/or 4027897. The problem in each case seems to be that the
frame cannot regain focus after it has lost it.
Name: rpR10076 Date: 11/16/2001
commit to hopper and tiger
======================================================================
Name: osR10079 Date: 12/21/2001
In the test user tries to listen KeyEvents on Frame. For
this reason KeyListener is registered on the frame, and
requestFocus() is called on the frame.
But requestFocus() is called before frame showing, and AWT rejects
this call because the frame is not visible. Thus after application
start focus is placed on button (initial component), not on the frame
itself.
To fix this problem we need to call requestFocus() after
setVisible(true). But here we have other problem:
requestFocus() is called on main thread, and at the same time on EDT
DefaultKeyboardFocusManager dispatches WINDOW_GAINED_FOCUS (which
comes as a result of setVisible(true)) and in this
handler it determines component which should be a focus owner and
requests focus on this component. To find out this component, DKFM
call getMostRecentFocusOwner() method on focused window.
Thus we have the following situation:
1. On EDT we call Window.getMostRecentFocusOwner(), which returns
the button as new focus owner, since it is initial component for this
frame.
2. On main thread we call requestFocus() on the frame.
3. On EDT we call requstFocus() on the button.
And after that the button becomes a focus owner.
So, user expects the frame to be a focus owner and we try to do so
(for this reason we have most recent focus owner, which we update in
requestFocus()). But because of the thread race and the fact that our
code is not thread safe, focus is placed on the button.
###@###.### 21 Dec 2001
======================================================================
Name: osR10079 Date: 08/12/2002
======================================================================
|