--- old/src/share/classes/java/awt/DefaultKeyboardFocusManager.java 2012-08-29 13:45:18.000000000 +0400 +++ new/src/share/classes/java/awt/DefaultKeyboardFocusManager.java 2012-08-29 13:45:18.000000000 +0400 @@ -40,6 +40,7 @@ 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 @@ -71,8 +72,8 @@ private WeakReference realOppositeWindowWR = NULL_WINDOW_WR; private WeakReference realOppositeComponentWR = NULL_COMPONENT_WR; private int inSendMessage; - private LinkedList enqueuedKeyEvents = new LinkedList(), - typeAheadMarkers = new LinkedList(); + private LinkedList enqueuedKeyEvents = new LinkedList(); + private LinkedList typeAheadMarkers = new LinkedList(); private boolean consumeNextKeyTyped; private static class TypeAheadMarker { @@ -259,6 +260,31 @@ 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. @@ -277,6 +303,10 @@ 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(); @@ -636,6 +666,10 @@ } case WindowEvent.WINDOW_LOST_FOCUS: { + if (repostIfFollowsKeyEvents((WindowEvent)e)) { + break; + } + WindowEvent we = (WindowEvent)e; Window currentFocusedWindow = getGlobalFocusedWindow(); Window losingFocusWindow = we.getWindow(); @@ -815,10 +849,9 @@ ke = null; synchronized (this) { if (enqueuedKeyEvents.size() != 0) { - ke = (KeyEvent)enqueuedKeyEvents.getFirst(); + ke = enqueuedKeyEvents.getFirst(); if (typeAheadMarkers.size() != 0) { - TypeAheadMarker marker = (TypeAheadMarker) - typeAheadMarkers.getFirst(); + 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. @@ -847,9 +880,9 @@ focusLog.finest(">>> Markers dump, time: {0}", System.currentTimeMillis()); synchronized (this) { if (typeAheadMarkers.size() != 0) { - Iterator iter = typeAheadMarkers.iterator(); + Iterator iter = typeAheadMarkers.iterator(); while (iter.hasNext()) { - TypeAheadMarker marker = (TypeAheadMarker)iter.next(); + TypeAheadMarker marker = iter.next(); focusLog.finest(" {0}", marker); } } @@ -871,8 +904,7 @@ KeyEvent ke = (KeyEvent)e; synchronized (this) { if (e.isPosted && typeAheadMarkers.size() != 0) { - TypeAheadMarker marker = (TypeAheadMarker) - typeAheadMarkers.getFirst(); + 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. @@ -905,12 +937,10 @@ synchronized (this) { boolean found = false; if (hasMarker(target)) { - for (Iterator iter = typeAheadMarkers.iterator(); + for (Iterator iter = typeAheadMarkers.iterator(); iter.hasNext(); ) { - if (((TypeAheadMarker)iter.next()).untilFocused == - target) - { + if (iter.next().untilFocused == target) { found = true; } else if (found) { break; @@ -945,8 +975,8 @@ * @since 1.5 */ private boolean hasMarker(Component comp) { - for (Iterator iter = typeAheadMarkers.iterator(); iter.hasNext(); ) { - if (((TypeAheadMarker)iter.next()).untilFocused == comp) { + for (Iterator iter = typeAheadMarkers.iterator(); iter.hasNext(); ) { + if (iter.next().untilFocused == comp) { return true; } } @@ -972,11 +1002,10 @@ 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. + // 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); /** @@ -1164,10 +1193,10 @@ int insertionIndex = 0, i = typeAheadMarkers.size(); - ListIterator iter = typeAheadMarkers.listIterator(i); + ListIterator iter = typeAheadMarkers.listIterator(i); for (; i > 0; i--) { - TypeAheadMarker marker = (TypeAheadMarker)iter.previous(); + TypeAheadMarker marker = iter.previous(); if (marker.after <= after) { insertionIndex = i; break; @@ -1203,12 +1232,12 @@ after, untilFocused); TypeAheadMarker marker; - ListIterator iter = typeAheadMarkers.listIterator + ListIterator iter = typeAheadMarkers.listIterator ((after >= 0) ? typeAheadMarkers.size() : 0); if (after < 0) { while (iter.hasNext()) { - marker = (TypeAheadMarker)iter.next(); + marker = iter.next(); if (marker.untilFocused == untilFocused) { iter.remove(); @@ -1217,7 +1246,7 @@ } } else { while (iter.hasPrevious()) { - marker = (TypeAheadMarker)iter.previous(); + marker = iter.previous(); if (marker.untilFocused == untilFocused && marker.after == after) { @@ -1245,8 +1274,8 @@ long start = -1; - for (Iterator iter = typeAheadMarkers.iterator(); iter.hasNext(); ) { - TypeAheadMarker marker = (TypeAheadMarker)iter.next(); + for (Iterator iter = typeAheadMarkers.iterator(); iter.hasNext(); ) { + TypeAheadMarker marker = iter.next(); Component toTest = marker.untilFocused; boolean match = (toTest == comp); while (!match && toTest != null && !(toTest instanceof Window)) { @@ -1277,8 +1306,8 @@ return; } - for (Iterator iter = enqueuedKeyEvents.iterator(); iter.hasNext(); ) { - KeyEvent ke = (KeyEvent)iter.next(); + for (Iterator iter = enqueuedKeyEvents.iterator(); iter.hasNext(); ) { + KeyEvent ke = iter.next(); long time = ke.getWhen(); if (start < time && (end < 0 || time <= end)) {