SUGGESTED FIX
+++ DefaultKeyboardFocusManager.java 2006-10-13 14:06:04.000000000 +0400
@@ -10,10 +10,11 @@
import java.awt.event.KeyEvent;
import java.awt.event.WindowEvent;
import java.awt.peer.ComponentPeer;
import java.awt.peer.LightweightPeer;
import java.beans.PropertyChangeListener;
+import java.lang.ref.WeakReference;
import java.util.LinkedList;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Set;
@@ -44,12 +45,17 @@
* @since 1.4
*/
public class DefaultKeyboardFocusManager extends KeyboardFocusManager {
private static final Logger focusLog = Logger.getLogger("java.awt.focus.DefaultKeyboardFocusManager");
- private Window realOppositeWindow;
- private Component realOppositeComponent;
+ // null weak references to not create too many objects
+ private static final WeakReference<Window> NULL_WINDOW_WR =
+ new WeakReference<Window>(null);
+ private static final WeakReference<Component> NULL_COMPONENT_WR =
+ new WeakReference<Component>(null);
+ private WeakReference<Window> realOppositeWindow = NULL_WINDOW_WR;
+ private WeakReference<Component> realOppositeComponent = NULL_COMPONENT_WR;
private int inSendMessage;
private LinkedList enqueuedKeyEvents = new LinkedList(),
typeAheadMarkers = new LinkedList();
private boolean consumeNextKeyTyped;
@@ -81,11 +87,11 @@
* This series of restoreFocus methods is used for recovering from a
* rejected focus or activation change. Rejections typically occur when
* the user attempts to focus a non-focusable Component or Window.
*/
private void restoreFocus(FocusEvent fe, Window newFocusedWindow) {
- Component realOppositeComponent = this.realOppositeComponent;
+ Component realOppositeComponent = this.realOppositeComponent.get();
Component vetoedComponent = fe.getComponent();
if (newFocusedWindow != null && restoreFocus(newFocusedWindow,
vetoedComponent, false))
{
@@ -96,11 +102,11 @@
} else {
clearGlobalFocusOwner();
}
}
private void restoreFocus(WindowEvent we) {
- Window realOppositeWindow = this.realOppositeWindow;
+ Window realOppositeWindow = this.realOppositeWindow.get();
if (realOppositeWindow != null && restoreFocus(realOppositeWindow,
null, false)) {
} else if (we.getOppositeWindow() != null &&
restoreFocus(we.getOppositeWindow(), null, false)) {
} else {
@@ -354,11 +360,11 @@
// was inactive it expects to receive focus after activation.
toFocus.requestFocusInWindow(CausedFocusEvent.Cause.ACTIVATION);
}
}
- Window realOppositeWindow = this.realOppositeWindow;
+ Window realOppositeWindow = this.realOppositeWindow.get();
if (realOppositeWindow != we.getOppositeWindow()) {
we = new WindowEvent(newFocusedWindow,
WindowEvent.WINDOW_GAINED_FOCUS,
realOppositeWindow);
}
@@ -487,11 +493,11 @@
}
}
setNativeFocusOwner(getHeavyweight(newFocusOwner));
- Component realOppositeComponent = this.realOppositeComponent;
+ Component realOppositeComponent = this.realOppositeComponent.get();
if (realOppositeComponent != null &&
realOppositeComponent != fe.getOppositeComponent()) {
fe = new CausedFocusEvent(newFocusOwner,
FocusEvent.FOCUS_GAINED,
fe.isTemporary(),
@@ -544,11 +550,12 @@
setNativeFocusOwner(null);
fe.setSource(currentFocusOwner);
realOppositeComponent = (fe.getOppositeComponent() != null)
- ? currentFocusOwner : null;
+ ? new WeakReference<Component>(currentFocusOwner)
+ : NULL_COMPONENT_WR;
return typeAheadAssertions(currentFocusOwner, fe);
}
case WindowEvent.WINDOW_DEACTIVATED: {
@@ -628,12 +635,12 @@
}
setNativeFocusedWindow(null);
we.setSource(currentFocusedWindow);
realOppositeWindow = (oppositeWindow != null)
- ? currentFocusedWindow
- : null;
+ ? new WeakReference<Window>(currentFocusedWindow)
+ : NULL_WINDOW_WR;
typeAheadAssertions(currentFocusedWindow, we);
if (oppositeWindow == null) {
// Then we need to deactive the active Window as well.
// No need to synthesize in other cases, because
|
EVALUATION
An interesting update: by giving focus to some other window (I used a native app), the leak will go away. Do the following with the test case:
*Create Focusable Frame
*Dispose Focusable Frame
At this point, you can keep GCing and GCing and the leak will persist. But as soon as you give focus to some other window, when you refocus the test window, GCing will clean up the heap.
|