src/share/classes/java/awt/DefaultKeyboardFocusManager.java
Print this page
*** 38,47 ****
--- 38,48 ----
import sun.util.logging.PlatformLogger;
import sun.awt.AppContext;
import sun.awt.SunToolkit;
import sun.awt.CausedFocusEvent;
+ import sun.awt.TimedWindowEvent;
/**
* The default KeyboardFocusManager for AWT applications. Focus traversal is
* done in response to a Component's focus traversal keys, and using a
* Container's FocusTraversalPolicy.
*** 69,80 ****
private static final WeakReference<Component> NULL_COMPONENT_WR =
new WeakReference<Component>(null);
private WeakReference<Window> realOppositeWindowWR = NULL_WINDOW_WR;
private WeakReference<Component> realOppositeComponentWR = NULL_COMPONENT_WR;
private int inSendMessage;
! private LinkedList enqueuedKeyEvents = new LinkedList(),
! typeAheadMarkers = new LinkedList();
private boolean consumeNextKeyTyped;
private static class TypeAheadMarker {
long after;
Component untilFocused;
--- 70,81 ----
private static final WeakReference<Component> NULL_COMPONENT_WR =
new WeakReference<Component>(null);
private WeakReference<Window> realOppositeWindowWR = NULL_WINDOW_WR;
private WeakReference<Component> realOppositeComponentWR = NULL_COMPONENT_WR;
private int inSendMessage;
! private LinkedList<KeyEvent> enqueuedKeyEvents = new LinkedList<KeyEvent>();
! private LinkedList<TypeAheadMarker> typeAheadMarkers = new LinkedList<TypeAheadMarker>();
private boolean consumeNextKeyTyped;
private static class TypeAheadMarker {
long after;
Component untilFocused;
*** 257,266 ****
--- 258,292 ----
}
}
return se.dispatched;
}
+ /*
+ * Checks if the focus window event follows key events waiting in the type-ahead
+ * queue (if any). This may happen when a user types ahead in the window, the client
+ * listeners hang EDT for a while, and the user switches b/w toplevels. In that
+ * case the focus window events may be dispatched before the type-ahead events
+ * get handled. This may lead to wrong focus behavior and in order to avoid it,
+ * the focus window events are reposted to the end of the event queue. See 6981400.
+ */
+ private boolean repostIfFollowsKeyEvents(WindowEvent e) {
+ if (!(e instanceof TimedWindowEvent)) {
+ return false;
+ }
+ TimedWindowEvent we = (TimedWindowEvent)e;
+ long time = we.getWhen();
+ synchronized (this) {
+ for (KeyEvent ke: enqueuedKeyEvents) {
+ if (time >= ke.getWhen()) {
+ SunToolkit.postEvent(AppContext.getAppContext(), new SequencedEvent(e));
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
/**
* This method is called by the AWT event dispatcher requesting that the
* current KeyboardFocusManager dispatch the specified event on its behalf.
* DefaultKeyboardFocusManagers dispatch all FocusEvents, all WindowEvents
* related to focus, and all KeyEvents. These events are dispatched based
*** 275,284 ****
--- 301,314 ----
*/
public boolean dispatchEvent(AWTEvent e) {
if (focusLog.isLoggable(PlatformLogger.FINE) && (e instanceof WindowEvent || e instanceof FocusEvent)) focusLog.fine("" + e);
switch (e.getID()) {
case WindowEvent.WINDOW_GAINED_FOCUS: {
+ if (repostIfFollowsKeyEvents((WindowEvent)e)) {
+ break;
+ }
+
WindowEvent we = (WindowEvent)e;
Window oldFocusedWindow = getGlobalFocusedWindow();
Window newFocusedWindow = we.getWindow();
if (newFocusedWindow == oldFocusedWindow) {
break;
*** 634,643 ****
--- 664,677 ----
we.setSource(currentActiveWindow);
return typeAheadAssertions(currentActiveWindow, we);
}
case WindowEvent.WINDOW_LOST_FOCUS: {
+ if (repostIfFollowsKeyEvents((WindowEvent)e)) {
+ break;
+ }
+
WindowEvent we = (WindowEvent)e;
Window currentFocusedWindow = getGlobalFocusedWindow();
Window losingFocusWindow = we.getWindow();
Window activeWindow = getGlobalActiveWindow();
Window oppositeWindow = we.getOppositeWindow();
*** 813,826 ****
KeyEvent ke;
do {
ke = null;
synchronized (this) {
if (enqueuedKeyEvents.size() != 0) {
! ke = (KeyEvent)enqueuedKeyEvents.getFirst();
if (typeAheadMarkers.size() != 0) {
! TypeAheadMarker marker = (TypeAheadMarker)
! typeAheadMarkers.getFirst();
// Fixed 5064013: may appears that the events have the same time
// if (ke.getWhen() >= marker.after) {
// The fix is rolled out.
if (ke.getWhen() > marker.after) {
--- 847,859 ----
KeyEvent ke;
do {
ke = null;
synchronized (this) {
if (enqueuedKeyEvents.size() != 0) {
! ke = enqueuedKeyEvents.getFirst();
if (typeAheadMarkers.size() != 0) {
! TypeAheadMarker marker = typeAheadMarkers.getFirst();
// Fixed 5064013: may appears that the events have the same time
// if (ke.getWhen() >= marker.after) {
// The fix is rolled out.
if (ke.getWhen() > marker.after) {
*** 845,857 ****
void dumpMarkers() {
if (focusLog.isLoggable(PlatformLogger.FINEST)) {
focusLog.finest(">>> Markers dump, time: {0}", System.currentTimeMillis());
synchronized (this) {
if (typeAheadMarkers.size() != 0) {
! Iterator iter = typeAheadMarkers.iterator();
while (iter.hasNext()) {
! TypeAheadMarker marker = (TypeAheadMarker)iter.next();
focusLog.finest(" {0}", marker);
}
}
}
}
--- 878,890 ----
void dumpMarkers() {
if (focusLog.isLoggable(PlatformLogger.FINEST)) {
focusLog.finest(">>> Markers dump, time: {0}", System.currentTimeMillis());
synchronized (this) {
if (typeAheadMarkers.size() != 0) {
! Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator();
while (iter.hasNext()) {
! TypeAheadMarker marker = iter.next();
focusLog.finest(" {0}", marker);
}
}
}
}
*** 869,880 ****
case KeyEvent.KEY_PRESSED:
case KeyEvent.KEY_RELEASED: {
KeyEvent ke = (KeyEvent)e;
synchronized (this) {
if (e.isPosted && typeAheadMarkers.size() != 0) {
! TypeAheadMarker marker = (TypeAheadMarker)
! typeAheadMarkers.getFirst();
// Fixed 5064013: may appears that the events have the same time
// if (ke.getWhen() >= marker.after) {
// The fix is rolled out.
if (ke.getWhen() > marker.after) {
--- 902,912 ----
case KeyEvent.KEY_PRESSED:
case KeyEvent.KEY_RELEASED: {
KeyEvent ke = (KeyEvent)e;
synchronized (this) {
if (e.isPosted && typeAheadMarkers.size() != 0) {
! TypeAheadMarker marker = typeAheadMarkers.getFirst();
// Fixed 5064013: may appears that the events have the same time
// if (ke.getWhen() >= marker.after) {
// The fix is rolled out.
if (ke.getWhen() > marker.after) {
*** 903,918 ****
// not be generated for these additional requests, we
// need to clear those markers too.
synchronized (this) {
boolean found = false;
if (hasMarker(target)) {
! for (Iterator iter = typeAheadMarkers.iterator();
iter.hasNext(); )
{
! if (((TypeAheadMarker)iter.next()).untilFocused ==
! target)
! {
found = true;
} else if (found) {
break;
}
iter.remove();
--- 935,948 ----
// not be generated for these additional requests, we
// need to clear those markers too.
synchronized (this) {
boolean found = false;
if (hasMarker(target)) {
! for (Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator();
iter.hasNext(); )
{
! if (iter.next().untilFocused == target) {
found = true;
} else if (found) {
break;
}
iter.remove();
*** 943,954 ****
* Returns true if there are some marker associated with component <code>comp</code>
* in a markers' queue
* @since 1.5
*/
private boolean hasMarker(Component comp) {
! for (Iterator iter = typeAheadMarkers.iterator(); iter.hasNext(); ) {
! if (((TypeAheadMarker)iter.next()).untilFocused == comp) {
return true;
}
}
return false;
}
--- 973,984 ----
* Returns true if there are some marker associated with component <code>comp</code>
* in a markers' queue
* @since 1.5
*/
private boolean hasMarker(Component comp) {
! for (Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator(); iter.hasNext(); ) {
! if (iter.next().untilFocused == comp) {
return true;
}
}
return false;
}
*** 970,984 ****
}
if (ke.getSource() == null) {
return true;
}
! // Explicitly set the current event and most recent timestamp here in
! // addition to the call in Component.dispatchEventImpl. Because
! // KeyEvents can be delivered in response to a FOCUS_GAINED event, the
! // current timestamp may be incorrect. We need to set it here so that
! // KeyEventDispatchers will use the correct time.
EventQueue.setCurrentEventAndMostRecentTime(ke);
/**
* Fix for 4495473.
* This fix allows to correctly dispatch events when native
--- 1000,1013 ----
}
if (ke.getSource() == null) {
return true;
}
! // Explicitly set the key event timestamp here (not in Component.dispatchEventImpl):
! // - A key event is anyway passed to this method which starts its actual dispatching.
! // - If a key event is put to the type ahead queue, its time stamp should not be registered
! // until its dispatching actually starts (by this method).
EventQueue.setCurrentEventAndMostRecentTime(ke);
/**
* Fix for 4495473.
* This fix allows to correctly dispatch events when native
*** 1162,1175 ****
focusLog.finer("Enqueue at {0} for {1}",
after, untilFocused);
int insertionIndex = 0,
i = typeAheadMarkers.size();
! ListIterator iter = typeAheadMarkers.listIterator(i);
for (; i > 0; i--) {
! TypeAheadMarker marker = (TypeAheadMarker)iter.previous();
if (marker.after <= after) {
insertionIndex = i;
break;
}
}
--- 1191,1204 ----
focusLog.finer("Enqueue at {0} for {1}",
after, untilFocused);
int insertionIndex = 0,
i = typeAheadMarkers.size();
! ListIterator<TypeAheadMarker> iter = typeAheadMarkers.listIterator(i);
for (; i > 0; i--) {
! TypeAheadMarker marker = iter.previous();
if (marker.after <= after) {
insertionIndex = i;
break;
}
}
*** 1201,1225 ****
focusLog.finer("Dequeue at {0} for {1}",
after, untilFocused);
TypeAheadMarker marker;
! ListIterator iter = typeAheadMarkers.listIterator
((after >= 0) ? typeAheadMarkers.size() : 0);
if (after < 0) {
while (iter.hasNext()) {
! marker = (TypeAheadMarker)iter.next();
if (marker.untilFocused == untilFocused)
{
iter.remove();
return;
}
}
} else {
while (iter.hasPrevious()) {
! marker = (TypeAheadMarker)iter.previous();
if (marker.untilFocused == untilFocused &&
marker.after == after)
{
iter.remove();
return;
--- 1230,1254 ----
focusLog.finer("Dequeue at {0} for {1}",
after, untilFocused);
TypeAheadMarker marker;
! ListIterator<TypeAheadMarker> iter = typeAheadMarkers.listIterator
((after >= 0) ? typeAheadMarkers.size() : 0);
if (after < 0) {
while (iter.hasNext()) {
! marker = iter.next();
if (marker.untilFocused == untilFocused)
{
iter.remove();
return;
}
}
} else {
while (iter.hasPrevious()) {
! marker = iter.previous();
if (marker.untilFocused == untilFocused &&
marker.after == after)
{
iter.remove();
return;
*** 1243,1254 ****
return;
}
long start = -1;
! for (Iterator iter = typeAheadMarkers.iterator(); iter.hasNext(); ) {
! TypeAheadMarker marker = (TypeAheadMarker)iter.next();
Component toTest = marker.untilFocused;
boolean match = (toTest == comp);
while (!match && toTest != null && !(toTest instanceof Window)) {
toTest = toTest.getParent();
match = (toTest == comp);
--- 1272,1283 ----
return;
}
long start = -1;
! for (Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator(); iter.hasNext(); ) {
! TypeAheadMarker marker = iter.next();
Component toTest = marker.untilFocused;
boolean match = (toTest == comp);
while (!match && toTest != null && !(toTest instanceof Window)) {
toTest = toTest.getParent();
match = (toTest == comp);
*** 1275,1286 ****
private void purgeStampedEvents(long start, long end) {
if (start < 0) {
return;
}
! for (Iterator iter = enqueuedKeyEvents.iterator(); iter.hasNext(); ) {
! KeyEvent ke = (KeyEvent)iter.next();
long time = ke.getWhen();
if (start < time && (end < 0 || time <= end)) {
iter.remove();
}
--- 1304,1315 ----
private void purgeStampedEvents(long start, long end) {
if (start < 0) {
return;
}
! for (Iterator<KeyEvent> iter = enqueuedKeyEvents.iterator(); iter.hasNext(); ) {
! KeyEvent ke = iter.next();
long time = ke.getWhen();
if (start < time && (end < 0 || time <= end)) {
iter.remove();
}