6981400: Tabbing between textfield do not work properly when ALT+TAB
authorant
Fri, 31 Aug 2012 16:31:29 +0400
changeset 13652 42544e68dc39
parent 13651 cf84d3383a29
child 13653 012c6f8f0279
6981400: Tabbing between textfield do not work properly when ALT+TAB 7157015: [macosx] Situation when KeyEventDispatcher doesn't work on AWT but does on Swing. 7121442: Regression : Reopen CR 6458497 still reproducible using JDK 7. Reviewed-by: art, leonidr
jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java
jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java
jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsRootPaneUI.java
jdk/src/share/classes/java/awt/Component.java
jdk/src/share/classes/java/awt/Container.java
jdk/src/share/classes/java/awt/DefaultKeyboardFocusManager.java
jdk/src/share/classes/java/awt/Dialog.java
jdk/src/share/classes/java/awt/EventQueue.java
jdk/src/share/classes/java/awt/SequencedEvent.java
jdk/src/share/classes/sun/awt/AWTAccessor.java
jdk/src/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java
jdk/src/share/classes/sun/awt/SunToolkit.java
jdk/src/share/classes/sun/awt/TimedWindowEvent.java
jdk/src/solaris/classes/sun/awt/X11/XBaseWindow.java
jdk/src/solaris/classes/sun/awt/X11/XComponentPeer.java
jdk/src/windows/native/sun/windows/awt_Window.cpp
jdk/test/java/awt/Focus/6981400/Test1.java
jdk/test/java/awt/Focus/6981400/Test2.java
jdk/test/java/awt/Focus/6981400/Test3.java
--- a/jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java	Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java	Fri Aug 31 16:31:29 2012 +0400
@@ -1251,9 +1251,6 @@
 
         if (!target.isFocusOwner() && LWKeyboardFocusManagerPeer.shouldFocusOnClick(target)) {
             LWKeyboardFocusManagerPeer.requestFocusFor(target, CausedFocusEvent.Cause.MOUSE_EVENT);
-        } else {
-            // Anyway request focus to the toplevel.
-            getWindowPeerOrSelf().requestWindowFocus(CausedFocusEvent.Cause.MOUSE_EVENT);
         }
     }
 
--- a/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java	Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java	Fri Aug 31 16:31:29 2012 +0400
@@ -798,6 +798,14 @@
                     mouseClickButtons |= eventButtonMask;
                 }
 
+                // The window should be focused on mouse click. If it gets activated by the native platform,
+                // this request will be no op. It will take effect when:
+                // 1. A simple not focused window is clicked.
+                // 2. An active but not focused owner frame/dialog is clicked.
+                // The mouse event then will trigger a focus request "in window" to the component, so the window
+                // should gain focus before.
+                requestWindowFocus(CausedFocusEvent.Cause.MOUSE_EVENT);
+
                 mouseDownTarget[targetIdx] = targetPeer;
             } else if (id == MouseEvent.MOUSE_DRAGGED) {
                 // Cocoa dragged event has the information about which mouse
@@ -914,20 +922,16 @@
     public void dispatchKeyEvent(int id, long when, int modifiers,
                                  int keyCode, char keyChar, int keyLocation)
     {
-        KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();
+        LWKeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();
         Component focusOwner = kfmPeer.getCurrentFocusOwner();
 
-        // Null focus owner may receive key event when
-        // application hides the focused window upon ESC press
-        // (AWT transfers/clears the focus owner) and pending ESC release
-        // may come to already hidden window. This check eliminates NPE.
-        if (focusOwner != null) {
-            KeyEvent event =
-                new KeyEvent(focusOwner, id, when, modifiers,
-                             keyCode, keyChar, keyLocation);
-            LWComponentPeer peer = (LWComponentPeer)focusOwner.getPeer();
-            peer.postEvent(event);
+        if (focusOwner == null) {
+            focusOwner = kfmPeer.getCurrentFocusedWindow();
+            if (focusOwner == null) {
+                focusOwner = this.getTarget();
+            }
         }
+        postEvent(new KeyEvent(focusOwner, id, when, modifiers, keyCode, keyChar, keyLocation));
     }
 
 
@@ -1260,7 +1264,7 @@
         kfmPeer.setCurrentFocusedWindow(becomesFocused ? getTarget() : null);
 
         int eventID = becomesFocused ? WindowEvent.WINDOW_GAINED_FOCUS : WindowEvent.WINDOW_LOST_FOCUS;
-        WindowEvent windowEvent = new WindowEvent(getTarget(), eventID, oppositeWindow);
+        WindowEvent windowEvent = new TimedWindowEvent(getTarget(), eventID, oppositeWindow, System.currentTimeMillis());
 
         // TODO: wrap in SequencedEvent
         postEvent(windowEvent);
--- a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsRootPaneUI.java	Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsRootPaneUI.java	Fri Aug 31 16:31:29 2012 +0400
@@ -30,6 +30,8 @@
 import java.awt.Event;
 import java.awt.KeyEventPostProcessor;
 import java.awt.Window;
+import java.awt.Toolkit;
+import sun.awt.SunToolkit;
 
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
@@ -125,7 +127,19 @@
                 }
                 JMenu menu = mbar != null ? mbar.getMenu(0) : null;
 
-                if (menu != null) {
+                // It might happen that the altRelease event is processed
+                // with a reasonable delay since it has been generated.
+                // Here we check the last deactivation time of the containing
+                // window. If this time appears to be greater than the altRelease
+                // event time the event is skipped to avoid unexpected menu
+                // activation. See 7121442.
+                boolean skip = false;
+                Toolkit tk = Toolkit.getDefaultToolkit();
+                if (tk instanceof SunToolkit) {
+                    skip = ev.getWhen() <= ((SunToolkit)tk).getWindowDeactivationTime(winAncestor);
+                }
+
+                if (menu != null && !skip) {
                     MenuElement[] path = new MenuElement[2];
                     path[0] = mbar;
                     path[1] = menu;
--- a/jdk/src/share/classes/java/awt/Component.java	Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/share/classes/java/awt/Component.java	Fri Aug 31 16:31:29 2012 +0400
@@ -4710,7 +4710,10 @@
         /*
          * 0. Set timestamp and modifiers of current event.
          */
-        EventQueue.setCurrentEventAndMostRecentTime(e);
+        if (!(e instanceof KeyEvent)) {
+            // Timestamp of a key event is set later in DKFM.preDispatchKeyEvent(KeyEvent).
+            EventQueue.setCurrentEventAndMostRecentTime(e);
+        }
 
         /*
          * 1. Pre-dispatchers. Do any necessary retargeting/reordering here
@@ -7606,13 +7609,33 @@
                                      boolean focusedWindowChangeAllowed,
                                      CausedFocusEvent.Cause cause)
     {
+        // 1) Check if the event being dispatched is a system-generated mouse event.
+        AWTEvent currentEvent = EventQueue.getCurrentEvent();
+        if (currentEvent instanceof MouseEvent &&
+            SunToolkit.isSystemGenerated(currentEvent))
+        {
+            // 2) Sanity check: if the mouse event component source belongs to the same containing window.
+            Component source = ((MouseEvent)currentEvent).getComponent();
+            if (source == null || source.getContainingWindow() == getContainingWindow()) {
+                focusLog.finest("requesting focus by mouse event \"in window\"");
+
+                // If both the conditions are fulfilled the focus request should be strictly
+                // bounded by the toplevel window. It's assumed that the mouse event activates
+                // the window (if it wasn't active) and this makes it possible for a focus
+                // request with a strong in-window requirement to change focus in the bounds
+                // of the toplevel. If, by any means, due to asynchronous nature of the event
+                // dispatching mechanism, the window happens to be natively inactive by the time
+                // this focus request is eventually handled, it should not re-activate the
+                // toplevel. Otherwise the result may not meet user expectations. See 6981400.
+                focusedWindowChangeAllowed = false;
+            }
+        }
         if (!isRequestFocusAccepted(temporary, focusedWindowChangeAllowed, cause)) {
             if (focusLog.isLoggable(PlatformLogger.FINEST)) {
                 focusLog.finest("requestFocus is not accepted");
             }
             return false;
         }
-
         // Update most-recent map
         KeyboardFocusManager.setMostRecentFocusOwner(this);
 
@@ -7645,7 +7668,15 @@
         }
 
         // Focus this Component
-        long time = EventQueue.getMostRecentEventTime();
+        long time = 0;
+        if (EventQueue.isDispatchThread()) {
+            time = Toolkit.getEventQueue().getMostRecentKeyEventTime();
+        } else {
+            // A focus request made from outside EDT should not be associated with any event
+            // and so its time stamp is simply set to the current time.
+            time = System.currentTimeMillis();
+        }
+
         boolean success = peer.requestFocus
             (this, temporary, focusedWindowChangeAllowed, time, cause);
         if (!success) {
--- a/jdk/src/share/classes/java/awt/Container.java	Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/share/classes/java/awt/Container.java	Fri Aug 31 16:31:29 2012 +0400
@@ -2863,7 +2863,7 @@
 
         // keep the KeyEvents from being dispatched
         // until the focus has been transfered
-        long time = Toolkit.getEventQueue().getMostRecentEventTime();
+        long time = Toolkit.getEventQueue().getMostRecentKeyEventTime();
         Component predictedFocusOwner = (Component.isInstanceOf(this, "javax.swing.JInternalFrame")) ? ((javax.swing.JInternalFrame)(this)).getMostRecentFocusOwner() : null;
         if (predictedFocusOwner != null) {
             KeyboardFocusManager.getCurrentKeyboardFocusManager().
--- a/jdk/src/share/classes/java/awt/DefaultKeyboardFocusManager.java	Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/share/classes/java/awt/DefaultKeyboardFocusManager.java	Fri Aug 31 16:31:29 2012 +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<Window> realOppositeWindowWR = NULL_WINDOW_WR;
     private WeakReference<Component> realOppositeComponentWR = NULL_COMPONENT_WR;
     private int inSendMessage;
-    private LinkedList enqueuedKeyEvents = new LinkedList(),
-        typeAheadMarkers = new LinkedList();
+    private LinkedList<KeyEvent> enqueuedKeyEvents = new LinkedList<KeyEvent>();
+    private LinkedList<TypeAheadMarker> typeAheadMarkers = new LinkedList<TypeAheadMarker>();
     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<TypeAheadMarker> 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<TypeAheadMarker> 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<TypeAheadMarker> 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<TypeAheadMarker> 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<TypeAheadMarker> 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<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)) {
@@ -1277,8 +1306,8 @@
             return;
         }
 
-        for (Iterator iter = enqueuedKeyEvents.iterator(); iter.hasNext(); ) {
-            KeyEvent ke = (KeyEvent)iter.next();
+        for (Iterator<KeyEvent> iter = enqueuedKeyEvents.iterator(); iter.hasNext(); ) {
+            KeyEvent ke = iter.next();
             long time = ke.getWhen();
 
             if (start < time && (end < 0 || time <= end)) {
--- a/jdk/src/share/classes/java/awt/Dialog.java	Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/share/classes/java/awt/Dialog.java	Fri Aug 31 16:31:29 2012 +0400
@@ -924,7 +924,7 @@
                     isEnabled() && !isModalBlocked()) {
                     // keep the KeyEvents from being dispatched
                     // until the focus has been transfered
-                    time.set(Toolkit.getEventQueue().getMostRecentEventTimeEx());
+                    time.set(Toolkit.getEventQueue().getMostRecentKeyEventTime());
                     KeyboardFocusManager.getCurrentKeyboardFocusManager().
                         enqueueKeyEvents(time.get(), toFocus);
                 }
--- a/jdk/src/share/classes/java/awt/EventQueue.java	Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/share/classes/java/awt/EventQueue.java	Fri Aug 31 16:31:29 2012 +0400
@@ -163,6 +163,11 @@
      */
     private long mostRecentEventTime = System.currentTimeMillis();
 
+    /*
+     * The time stamp of the last KeyEvent .
+     */
+    private long mostRecentKeyEventTime = System.currentTimeMillis();
+
     /**
      * The modifiers field of the current event, if the current event is an
      * InputEvent or ActionEvent.
@@ -1132,6 +1137,15 @@
         }
     }
 
+    synchronized long getMostRecentKeyEventTime() {
+        pushPopLock.lock();
+        try {
+            return mostRecentKeyEventTime;
+        } finally {
+            pushPopLock.unlock();
+        }
+    }
+
     static void setCurrentEventAndMostRecentTime(AWTEvent e) {
         Toolkit.getEventQueue().setCurrentEventAndMostRecentTimeImpl(e);
     }
@@ -1156,6 +1170,9 @@
             if (e instanceof InputEvent) {
                 InputEvent ie = (InputEvent)e;
                 mostRecentEventTime2 = ie.getWhen();
+                if (e instanceof KeyEvent) {
+                    mostRecentKeyEventTime = ie.getWhen();
+                }
             } else if (e instanceof InputMethodEvent) {
                 InputMethodEvent ime = (InputMethodEvent)e;
                 mostRecentEventTime2 = ime.getWhen();
--- a/jdk/src/share/classes/java/awt/SequencedEvent.java	Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/share/classes/java/awt/SequencedEvent.java	Fri Aug 31 16:31:29 2012 +0400
@@ -26,6 +26,7 @@
 package java.awt;
 
 import java.util.LinkedList;
+import sun.awt.AWTAccessor;
 import sun.awt.AppContext;
 import sun.awt.SunToolkit;
 
@@ -54,6 +55,17 @@
     private AppContext appContext;
     private boolean disposed;
 
+    static {
+        AWTAccessor.setSequencedEventAccessor(new AWTAccessor.SequencedEventAccessor() {
+            public AWTEvent getNested(AWTEvent sequencedEvent) {
+                return ((SequencedEvent)sequencedEvent).nested;
+            }
+            public boolean isSequencedEvent(AWTEvent event) {
+                return event instanceof SequencedEvent;
+            }
+        });
+    }
+
     /**
      * Constructs a new SequencedEvent which will dispatch the specified
      * nested event.
--- a/jdk/src/share/classes/sun/awt/AWTAccessor.java	Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/share/classes/sun/awt/AWTAccessor.java	Fri Aug 31 16:31:29 2012 +0400
@@ -487,6 +487,21 @@
     }
 
     /*
+     * An accessor for the SequencedEventAccessor class
+     */
+    public interface SequencedEventAccessor {
+        /*
+         * Returns the nested event.
+         */
+        AWTEvent getNested(AWTEvent sequencedEvent);
+
+        /*
+         * Returns true if the event is an instances of SequencedEvent.
+         */
+        boolean isSequencedEvent(AWTEvent event);
+    }
+
+    /*
      * Accessor instances are initialized in the static initializers of
      * corresponding AWT classes by using setters defined below.
      */
@@ -502,6 +517,7 @@
     private static PopupMenuAccessor popupMenuAccessor;
     private static FileDialogAccessor fileDialogAccessor;
     private static ScrollPaneAdjustableAccessor scrollPaneAdjustableAccessor;
+    private static SequencedEventAccessor sequencedEventAccessor;
 
     /*
      * Set an accessor object for the java.awt.Component class.
@@ -709,4 +725,21 @@
         }
         return scrollPaneAdjustableAccessor;
     }
+
+    /*
+     * Set an accessor object for the java.awt.SequencedEvent class.
+     */
+    public static void setSequencedEventAccessor(SequencedEventAccessor sea) {
+        sequencedEventAccessor = sea;
+    }
+
+    /*
+     * Get the accessor object for the java.awt.SequencedEvent class.
+     */
+    public static SequencedEventAccessor getSequencedEventAccessor() {
+        // The class is not public. So we can't ensure it's initialized.
+        // Null returned value means it's not initialized
+        // (so not a single instance of the event has been created).
+        return sequencedEventAccessor;
+    }
 }
--- a/jdk/src/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java	Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java	Fri Aug 31 16:31:29 2012 +0400
@@ -128,7 +128,7 @@
 
             if (focusLog.isLoggable(PlatformLogger.FINER))
                 focusLog.finer("Posting focus event: " + fl);
-            SunToolkit.postPriorityEvent(fl);
+            SunToolkit.postEvent(SunToolkit.targetToAppContext(currentOwner), fl);
         }
 
         FocusEvent fg = new CausedFocusEvent(lightweightChild, FocusEvent.FOCUS_GAINED,
@@ -136,7 +136,7 @@
 
         if (focusLog.isLoggable(PlatformLogger.FINER))
             focusLog.finer("Posting focus event: " + fg);
-        SunToolkit.postPriorityEvent(fg);
+        SunToolkit.postEvent(SunToolkit.targetToAppContext(lightweightChild), fg);
         return true;
     }
 
--- a/jdk/src/share/classes/sun/awt/SunToolkit.java	Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/share/classes/sun/awt/SunToolkit.java	Fri Aug 31 16:31:29 2012 +0400
@@ -513,6 +513,19 @@
         if (event == null) {
             throw new NullPointerException();
         }
+
+        AWTAccessor.SequencedEventAccessor sea = AWTAccessor.getSequencedEventAccessor();
+        if (sea != null && sea.isSequencedEvent(event)) {
+            AWTEvent nested = sea.getNested(event);
+            if (nested.getID() == WindowEvent.WINDOW_LOST_FOCUS &&
+                nested instanceof TimedWindowEvent)
+            {
+                TimedWindowEvent twe = (TimedWindowEvent)nested;
+                ((SunToolkit)Toolkit.getDefaultToolkit()).
+                    setWindowDeactivationTime((Window)twe.getSource(), twe.getWhen());
+            }
+        }
+
         // All events posted via this method are system-generated.
         // Placing the following call here reduces considerably the
         // number of places throughout the toolkit that would
@@ -1964,6 +1977,28 @@
         return false;
     }
 
+    private static final Object DEACTIVATION_TIMES_MAP_KEY = new Object();
+
+    public synchronized void setWindowDeactivationTime(Window w, long time) {
+        AppContext ctx = getAppContext(w);
+        WeakHashMap<Window, Long> map = (WeakHashMap<Window, Long>)ctx.get(DEACTIVATION_TIMES_MAP_KEY);
+        if (map == null) {
+            map = new WeakHashMap<Window, Long>();
+            ctx.put(DEACTIVATION_TIMES_MAP_KEY, map);
+        }
+        map.put(w, time);
+    }
+
+    public synchronized long getWindowDeactivationTime(Window w) {
+        AppContext ctx = getAppContext(w);
+        WeakHashMap<Window, Long> map = (WeakHashMap<Window, Long>)ctx.get(DEACTIVATION_TIMES_MAP_KEY);
+        if (map == null) {
+            return -1;
+        }
+        Long time = map.get(w);
+        return time == null ? -1 : time;
+    }
+
     // Cosntant alpha
     public boolean isWindowOpacitySupported() {
         return false;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/awt/TimedWindowEvent.java	Fri Aug 31 16:31:29 2012 +0400
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.awt;
+
+import java.awt.event.WindowEvent;
+import java.awt.Window;
+
+public class TimedWindowEvent extends WindowEvent {
+
+    private long time;
+
+    public long getWhen() {
+        return time;
+    }
+
+    public TimedWindowEvent(Window source, int id, Window opposite, long time) {
+        super(source, id, opposite);
+        this.time = time;
+    }
+
+    public TimedWindowEvent(Window source, int id, Window opposite,
+                            int oldState, int newState, long time)
+    {
+        super(source, id, opposite, oldState, newState);
+        this.time = time;
+    }
+}
+
--- a/jdk/src/solaris/classes/sun/awt/X11/XBaseWindow.java	Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/solaris/classes/sun/awt/X11/XBaseWindow.java	Fri Aug 31 16:31:29 2012 +0400
@@ -1001,6 +1001,13 @@
         switch (xev.get_type()) {
         case XConstants.ButtonPress:
             if (buttonState == 0) {
+                XWindowPeer parent = getToplevelXWindow();
+                // See 6385277, 6981400.
+                if (parent != null && parent.isFocusableWindow()) {
+                    // A click in a client area drops the actual focused window retaining.
+                    parent.setActualFocusedWindow(null);
+                    parent.requestWindowFocus(xbe.get_time(), true);
+                }
                 XAwtState.setAutoGrabWindow(this);
             }
             break;
--- a/jdk/src/solaris/classes/sun/awt/X11/XComponentPeer.java	Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/solaris/classes/sun/awt/X11/XComponentPeer.java	Fri Aug 31 16:31:29 2012 +0400
@@ -588,33 +588,6 @@
 
     }
 
-    public void handleButtonPressRelease(XEvent xev) {
-        /*
-         * Fix for 6385277.
-         * We request focus on simple Window by click in order
-         * to make it behave like Frame/Dialog in this case and also to unify
-         * the behaviour with what we have on MS Windows.
-         * handleJavaMouseEvent() would be more suitable place to do this
-         * but we want Swing to have this functionality also.
-         */
-        if (xev.get_type() == XConstants.ButtonPress) {
-            final XWindowPeer parentXWindow = getParentTopLevel();
-            Window parentWindow = (Window)parentXWindow.getTarget();
-            if (parentXWindow.isFocusableWindow() && parentXWindow.isSimpleWindow() &&
-                XKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow() != parentWindow)
-            {
-                postEvent(new InvocationEvent(parentWindow, new  Runnable() {
-                        public void run() {
-                            // Request focus on the EDT of 'parentWindow' because
-                            // XDecoratedPeer.requestWindowFocus() calls client code.
-                            parentXWindow.requestXFocus();
-                        }
-                    }));
-            }
-        }
-        super.handleButtonPressRelease(xev);
-    }
-
     public Dimension getMinimumSize() {
         return target.getSize();
     }
--- a/jdk/src/windows/native/sun/windows/awt_Window.cpp	Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/windows/native/sun/windows/awt_Window.cpp	Fri Aug 31 16:31:29 2012 +0400
@@ -1477,7 +1477,7 @@
     if (wClassEvent == NULL) {
         if (env->PushLocalFrame(1) < 0)
             return;
-        wClassEvent = env->FindClass("java/awt/event/WindowEvent");
+        wClassEvent = env->FindClass("sun/awt/TimedWindowEvent");
         if (wClassEvent != NULL) {
             wClassEvent = (jclass)env->NewGlobalRef(wClassEvent);
         }
@@ -1491,7 +1491,7 @@
     if (wEventInitMID == NULL) {
         wEventInitMID =
             env->GetMethodID(wClassEvent, "<init>",
-                             "(Ljava/awt/Window;ILjava/awt/Window;II)V");
+                             "(Ljava/awt/Window;ILjava/awt/Window;IIJ)V");
         DASSERT(wEventInitMID);
         if (wEventInitMID == NULL) {
             return;
@@ -1532,7 +1532,7 @@
         }
     }
     jobject event = env->NewObject(wClassEvent, wEventInitMID, target, id,
-                                   jOpposite, oldState, newState);
+                                   jOpposite, oldState, newState, TimeHelper::getMessageTimeUTC());
     DASSERT(!safe_ExceptionOccurred(env));
     DASSERT(event != NULL);
     if (jOpposite != NULL) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Focus/6981400/Test1.java	Fri Aug 31 16:31:29 2012 +0400
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug     6981400
+ * @summary Tabbing between textfiled do not work properly when ALT+TAB
+ * @author  anton.tarasov
+ * @library ../../regtesthelpers
+ * @build   Util
+ * @run     main Test1
+ */
+
+// This test shows a frame with four focusable components: b0, b1, b2, b3.
+// Then it presses Tab three times. EDT is freezed for a while on the first FOCUS_LOST event.
+// Meantime, the test clicks in a component of another frame and then clicks in the title
+// of the original frame. When EDT awakes and all the queued events get processed,
+// the other frame should ones gain focus and then pass it to the original frame.
+// The b3 component of the orinial frame should finally become a focus owner.
+// The FOCUS_LOST/FOCUS_GAINED events order in the original frame is tracked and should be:
+// b0 -> b1 -> b2 -> b3.
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import javax.swing.*;
+import test.java.awt.regtesthelpers.Util;
+
+public class Test1 {
+    static JFrame f0 = new JFrame("base_frame") { public String getName() {return "base_frame";} };
+    static JButton f0b0 = new JB("b0");
+    static JButton f0b1 = new JB("b1");
+    static JButton f0b2 = new JB("b2");
+    static JButton f0b3 = new JB("b3");
+
+    static JFrame f1 = new JFrame("swing_frame") { public String getName() {return "swing_frame";} };
+    static JButton f1b0 = new JButton("button");
+
+    static Frame f2 = new Frame("awt_frame") { public String getName() {return "awt_frame";} };
+    static Button f2b0 = new Button("button");
+
+    static Robot robot;
+
+    static List<Component> gainedList = new ArrayList<Component>();
+    static List<Component> lostList = new ArrayList<Component>();
+
+    static Component[] refGainedList = new Component[] {f0b1, f0b2, f0b3, f0b3};
+    static Component[] refLostList = new Component[] {f0b0, f0b1, f0b2, f0b3};
+
+    static boolean tracking;
+
+    public static void main(String[] args) {
+        Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
+            public void eventDispatched(AWTEvent e) {
+                System.out.println(e);
+            }
+        }, FocusEvent.FOCUS_EVENT_MASK | WindowEvent.WINDOW_EVENT_MASK);
+
+        try {
+            robot = new Robot();
+        } catch (AWTException ex) {
+            throw new RuntimeException("Error: can't create Robot");
+        }
+
+        f0.add(f0b0);
+        f0.add(f0b1);
+        f0.add(f0b2);
+        f0.add(f0b3);
+        f0.setLayout(new FlowLayout());
+        f0.setBounds(0, 100, 400, 200);
+
+        f1.add(f1b0);
+        f1.setBounds(0, 400, 400, 200);
+
+        f2.add(f2b0);
+        f2.setBounds(0, 400, 400, 200);
+
+        f0b0.addFocusListener(new FocusAdapter() {
+            @Override
+            public void focusLost(FocusEvent e) {
+                try {
+                    Thread.sleep(1000);
+                } catch (Exception ex) {}
+            }
+        });
+
+        //
+        // Case 1. Test against swing JFrame.
+        //
+
+        f1.setVisible(true);
+        f0.setVisible(true);
+
+        Util.waitForIdle(robot);
+
+        if (!f0b0.isFocusOwner()) {
+            Util.clickOnComp(f0b0, robot);
+            Util.waitForIdle(robot);
+            if (!f0b0.isFocusOwner()) {
+                throw new RuntimeException("Error: can't focus the component " + f0b0);
+            }
+        }
+
+        System.out.println("\nTest case 1: swing frame\n");
+        test(f1b0);
+
+        //
+        // Case 2. Test against awt Frame.
+        //
+
+        tracking = false;
+        gainedList.clear();
+        lostList.clear();
+
+        f1.dispose();
+        f2.setAutoRequestFocus(false);
+        f2.setVisible(true);
+        Util.waitForIdle(robot);
+
+        Util.clickOnComp(f0b0, robot);
+        Util.waitForIdle(robot);
+        if (!f0b0.isFocusOwner()) {
+            throw new RuntimeException("Error: can't focus the component " + f0b0);
+        }
+
+        System.out.println("\nTest case 2: awt frame\n");
+        test(f2b0);
+
+        System.out.println("\nTest passed.");
+    }
+
+    public static void test(Component compToClick) {
+        tracking = true;
+
+        robot.keyPress(KeyEvent.VK_TAB);
+        robot.delay(50);
+        robot.keyRelease(KeyEvent.VK_TAB);
+        robot.delay(50);
+
+        robot.keyPress(KeyEvent.VK_TAB);
+        robot.delay(50);
+        robot.keyRelease(KeyEvent.VK_TAB);
+        robot.delay(50);
+
+        robot.keyPress(KeyEvent.VK_TAB);
+        robot.delay(50);
+        robot.keyRelease(KeyEvent.VK_TAB);
+
+        robot.delay(50);
+        Util.clickOnComp(compToClick, robot);
+
+        robot.delay(50);
+        Util.clickOnTitle(f0, robot);
+
+        Util.waitForIdle(robot);
+
+        if (!f0b3.isFocusOwner()) {
+            throw new RuntimeException("Test failed: f0b3 is not a focus owner");
+        }
+
+        if (!"sun.awt.X11.XToolkit".equals(Toolkit.getDefaultToolkit().getClass().getName())) {
+
+            if (!Arrays.asList(refGainedList).equals(gainedList)) {
+                System.out.println("gained list: " + gainedList);
+                throw new RuntimeException("Test failed: wrong FOCUS_GAINED events order");
+            }
+            if (!Arrays.asList(refLostList).equals(lostList)) {
+                System.out.println("lost list: " + lostList);
+                throw new RuntimeException("Test failed: wrong FOCUS_LOST events order");
+            }
+        }
+    }
+}
+
+class JB extends JButton {
+    String name;
+
+    public JB(String name) {
+        super(name);
+        this.name = name;
+
+        addFocusListener(new FocusListener() {
+            public void focusGained(FocusEvent e) {
+                if (Test1.tracking)
+                    Test1.gainedList.add(e.getComponent());
+            }
+
+            public void focusLost(FocusEvent e) {
+                if (Test1.tracking)
+                    Test1.lostList.add(e.getComponent());
+            }
+        });
+    }
+
+    public String toString() {
+        return "[" + name + "]";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Focus/6981400/Test2.java	Fri Aug 31 16:31:29 2012 +0400
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug     6981400
+ * @summary Tabbing between textfiled do not work properly when ALT+TAB
+ * @author  anton.tarasov
+ * @library ../../regtesthelpers
+ * @build   Util
+ * @run     main Test2
+ */
+
+// A focus request made after a char is typed ahead shouldn't affect the char's target component.
+
+import java.awt.*;
+import java.awt.event.*;
+import test.java.awt.regtesthelpers.Util;
+
+public class Test2 {
+    static Frame f = new Frame("frame");
+    static TextArea t0 = new TextArea(1, 10) { public String toString() { return "[TA-0]";} };
+    static TextArea t1 = new TextArea(1, 10) { public String toString() { return "[TA-1]";} };
+    static TextArea t2 = new TextArea(1, 10) { public String toString() { return "[TA-2]";} };
+
+    static volatile boolean passed = true;
+
+    static Robot robot;
+
+    public static void main(String[] args) {
+        Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
+            public void eventDispatched(AWTEvent e) {
+                System.out.println(e);
+                if (e.getID() == KeyEvent.KEY_TYPED) {
+                    if (e.getSource() != t1) {
+                        passed = false;
+                        throw new RuntimeException("Test failed: the key event has wrong source: " + e);
+                    }
+                }
+            }
+        }, FocusEvent.FOCUS_EVENT_MASK | KeyEvent.KEY_EVENT_MASK);
+
+        try {
+            robot = new Robot();
+        } catch (AWTException ex) {
+            throw new RuntimeException("Error: can't create Robot");
+        }
+
+        f.add(t0);
+        f.add(t1);
+        f.add(t2);
+
+        f.setLayout(new FlowLayout());
+        f.pack();
+
+        t0.addFocusListener(new FocusAdapter() {
+            public void focusLost(FocusEvent e) {
+                try {
+                    Thread.sleep(3000);
+                } catch (Exception ex) {}
+            }
+        });
+
+        // The request shouldn't affect the key event delivery.
+        new Thread(new Runnable() {
+            public void run() {
+                try {
+                    Thread.sleep(2000);
+                } catch (Exception ex) {}
+                System.out.println("requesting focus to " + t2);
+                t2.requestFocus();
+            }
+        }).start();
+
+
+        f.setVisible(true);
+        Util.waitForIdle(robot);
+
+        test();
+
+        if (passed) System.out.println("\nTest passed.");
+    }
+
+    static void test() {
+        Util.clickOnComp(t1, robot);
+
+        // The key event should be eventually delivered to t1.
+        robot.delay(50);
+        robot.keyPress(KeyEvent.VK_A);
+        robot.delay(50);
+        robot.keyRelease(KeyEvent.VK_A);
+
+        Util.waitForIdle(robot);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Focus/6981400/Test3.java	Fri Aug 31 16:31:29 2012 +0400
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug     6981400
+ * @summary Tabbing between textfiled do not work properly when ALT+TAB
+ * @author  anton.tarasov
+ * @library ../../regtesthelpers
+ * @build   Util
+ * @run     main Test3
+ */
+
+// A menu item in a frame should not be auto-selected when switching by Alt+TAB back and forth.
+
+import java.awt.*;
+import javax.swing.*;
+import java.awt.event.*;
+import test.java.awt.regtesthelpers.Util;
+
+public class Test3 {
+    static JFrame f = new JFrame("Frame");
+    static JMenuBar bar = new JMenuBar();
+    static JMenu menu = new JMenu("File");
+    static JMenuItem item = new JMenuItem("Save");
+
+    static JButton b0 = new JButton("b0");
+    static JButton b1 = new JButton("b1");
+
+    static Robot robot;
+
+    public static void main(String[] args) {
+        Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
+            public void eventDispatched(AWTEvent e) {
+                System.err.println(e);
+            }
+        }, KeyEvent.KEY_EVENT_MASK);
+
+        try {
+            robot = new Robot();
+        } catch (AWTException ex) {
+            throw new RuntimeException("Error: can't create Robot");
+        }
+
+        try {
+            UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
+        } catch (Exception e) {}
+
+        b0.addFocusListener(new FocusAdapter() {
+            public void focusLost(FocusEvent f) {
+                try {
+                    Thread.sleep(2000);
+                } catch (Exception e) {}
+            }
+        });
+
+        menu.add(item);
+        bar.add(menu);
+        f.setJMenuBar(bar);
+
+        f.add(b0);
+        f.add(b1);
+
+        f.setLayout(new FlowLayout());
+        f.setSize(400, 100);
+        f.setVisible(true);
+        Util.waitForIdle(robot);
+
+        if (!b0.hasFocus()) {
+            Util.clickOnComp(b0, robot);
+            Util.waitForIdle(robot);
+            if (!b0.hasFocus()) {
+                throw new RuntimeException("Error: can't focus " + b0);
+            }
+        }
+
+        test();
+
+        System.out.println("Test passed.");
+    }
+
+    public static void test() {
+        robot.keyPress(KeyEvent.VK_TAB);
+        robot.delay(50);
+        robot.keyRelease(KeyEvent.VK_TAB);
+        robot.delay(50);
+
+        robot.keyPress(KeyEvent.VK_ALT);
+        robot.delay(50);
+        robot.keyPress(KeyEvent.VK_TAB);
+        robot.delay(50);
+        robot.keyRelease(KeyEvent.VK_ALT);
+        robot.delay(50);
+        robot.keyRelease(KeyEvent.VK_TAB);
+
+        robot.delay(500);
+
+        robot.keyPress(KeyEvent.VK_ALT);
+        robot.delay(50);
+        robot.keyPress(KeyEvent.VK_TAB);
+        robot.delay(50);
+        robot.keyRelease(KeyEvent.VK_ALT);
+        robot.delay(50);
+        robot.keyRelease(KeyEvent.VK_TAB);
+
+        // Control shot.
+        Util.clickOnTitle(f, robot);
+        Util.waitForIdle(robot);
+
+        if (menu.isSelected()) {
+            throw new RuntimeException("Test failed: the menu gets selected");
+        }
+        if (!b1.hasFocus()) {
+            throw new RuntimeException("Test failed: the button is not a focus owner " + b1);
+        }
+    }
+}
+
+