jdk/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java
changeset 25859 3317bb8137f4
parent 23276 add6f5c93bc6
child 26749 b6598aa90114
equal deleted inserted replaced
25858:836adbf7a2cd 25859:3317bb8137f4
       
     1 /*
       
     2  * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 package java.awt;
       
    26 
       
    27 import java.awt.event.FocusEvent;
       
    28 import java.awt.event.KeyEvent;
       
    29 import java.awt.event.WindowEvent;
       
    30 import java.awt.peer.ComponentPeer;
       
    31 import java.awt.peer.LightweightPeer;
       
    32 import java.lang.ref.WeakReference;
       
    33 import java.util.LinkedList;
       
    34 import java.util.Iterator;
       
    35 import java.util.ListIterator;
       
    36 import java.util.Set;
       
    37 
       
    38 import sun.util.logging.PlatformLogger;
       
    39 
       
    40 import sun.awt.AppContext;
       
    41 import sun.awt.SunToolkit;
       
    42 import sun.awt.AWTAccessor;
       
    43 import sun.awt.CausedFocusEvent;
       
    44 import sun.awt.TimedWindowEvent;
       
    45 
       
    46 /**
       
    47  * The default KeyboardFocusManager for AWT applications. Focus traversal is
       
    48  * done in response to a Component's focus traversal keys, and using a
       
    49  * Container's FocusTraversalPolicy.
       
    50  * <p>
       
    51  * Please see
       
    52  * <a href="http://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html">
       
    53  * How to Use the Focus Subsystem</a>,
       
    54  * a section in <em>The Java Tutorial</em>, and the
       
    55  * <a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a>
       
    56  * for more information.
       
    57  *
       
    58  * @author David Mendenhall
       
    59  *
       
    60  * @see FocusTraversalPolicy
       
    61  * @see Component#setFocusTraversalKeys
       
    62  * @see Component#getFocusTraversalKeys
       
    63  * @since 1.4
       
    64  */
       
    65 public class DefaultKeyboardFocusManager extends KeyboardFocusManager {
       
    66     private static final PlatformLogger focusLog = PlatformLogger.getLogger("java.awt.focus.DefaultKeyboardFocusManager");
       
    67 
       
    68     // null weak references to not create too many objects
       
    69     private static final WeakReference<Window> NULL_WINDOW_WR =
       
    70         new WeakReference<Window>(null);
       
    71     private static final WeakReference<Component> NULL_COMPONENT_WR =
       
    72         new WeakReference<Component>(null);
       
    73     private WeakReference<Window> realOppositeWindowWR = NULL_WINDOW_WR;
       
    74     private WeakReference<Component> realOppositeComponentWR = NULL_COMPONENT_WR;
       
    75     private int inSendMessage;
       
    76     private LinkedList<KeyEvent> enqueuedKeyEvents = new LinkedList<KeyEvent>();
       
    77     private LinkedList<TypeAheadMarker> typeAheadMarkers = new LinkedList<TypeAheadMarker>();
       
    78     private boolean consumeNextKeyTyped;
       
    79 
       
    80     static {
       
    81         AWTAccessor.setDefaultKeyboardFocusManagerAccessor(
       
    82             new AWTAccessor.DefaultKeyboardFocusManagerAccessor() {
       
    83                 public void consumeNextKeyTyped(DefaultKeyboardFocusManager dkfm, KeyEvent e) {
       
    84                     dkfm.consumeNextKeyTyped(e);
       
    85                 }
       
    86             });
       
    87     }
       
    88 
       
    89     private static class TypeAheadMarker {
       
    90         long after;
       
    91         Component untilFocused;
       
    92 
       
    93         TypeAheadMarker(long after, Component untilFocused) {
       
    94             this.after = after;
       
    95             this.untilFocused = untilFocused;
       
    96         }
       
    97         /**
       
    98          * Returns string representation of the marker
       
    99          */
       
   100         public String toString() {
       
   101             return ">>> Marker after " + after + " on " + untilFocused;
       
   102         }
       
   103     }
       
   104 
       
   105     private Window getOwningFrameDialog(Window window) {
       
   106         while (window != null && !(window instanceof Frame ||
       
   107                                    window instanceof Dialog)) {
       
   108             window = (Window)window.getParent();
       
   109         }
       
   110         return window;
       
   111     }
       
   112 
       
   113     /*
       
   114      * This series of restoreFocus methods is used for recovering from a
       
   115      * rejected focus or activation change. Rejections typically occur when
       
   116      * the user attempts to focus a non-focusable Component or Window.
       
   117      */
       
   118     private void restoreFocus(FocusEvent fe, Window newFocusedWindow) {
       
   119         Component realOppositeComponent = this.realOppositeComponentWR.get();
       
   120         Component vetoedComponent = fe.getComponent();
       
   121 
       
   122         if (newFocusedWindow != null && restoreFocus(newFocusedWindow,
       
   123                                                      vetoedComponent, false))
       
   124         {
       
   125         } else if (realOppositeComponent != null &&
       
   126                    doRestoreFocus(realOppositeComponent, vetoedComponent, false)) {
       
   127         } else if (fe.getOppositeComponent() != null &&
       
   128                    doRestoreFocus(fe.getOppositeComponent(), vetoedComponent, false)) {
       
   129         } else {
       
   130             clearGlobalFocusOwnerPriv();
       
   131         }
       
   132     }
       
   133     private void restoreFocus(WindowEvent we) {
       
   134         Window realOppositeWindow = this.realOppositeWindowWR.get();
       
   135         if (realOppositeWindow != null
       
   136             && restoreFocus(realOppositeWindow, null, false))
       
   137         {
       
   138             // do nothing, everything is done in restoreFocus()
       
   139         } else if (we.getOppositeWindow() != null &&
       
   140                    restoreFocus(we.getOppositeWindow(), null, false))
       
   141         {
       
   142             // do nothing, everything is done in restoreFocus()
       
   143         } else {
       
   144             clearGlobalFocusOwnerPriv();
       
   145         }
       
   146     }
       
   147     private boolean restoreFocus(Window aWindow, Component vetoedComponent,
       
   148                                  boolean clearOnFailure) {
       
   149         Component toFocus =
       
   150             KeyboardFocusManager.getMostRecentFocusOwner(aWindow);
       
   151 
       
   152         if (toFocus != null && toFocus != vetoedComponent && doRestoreFocus(toFocus, vetoedComponent, false)) {
       
   153             return true;
       
   154         } else if (clearOnFailure) {
       
   155             clearGlobalFocusOwnerPriv();
       
   156             return true;
       
   157         } else {
       
   158             return false;
       
   159         }
       
   160     }
       
   161     private boolean restoreFocus(Component toFocus, boolean clearOnFailure) {
       
   162         return doRestoreFocus(toFocus, null, clearOnFailure);
       
   163     }
       
   164     private boolean doRestoreFocus(Component toFocus, Component vetoedComponent,
       
   165                                    boolean clearOnFailure)
       
   166     {
       
   167         if (toFocus != vetoedComponent && toFocus.isShowing() && toFocus.canBeFocusOwner() &&
       
   168             toFocus.requestFocus(false, CausedFocusEvent.Cause.ROLLBACK))
       
   169         {
       
   170             return true;
       
   171         } else {
       
   172             Component nextFocus = toFocus.getNextFocusCandidate();
       
   173             if (nextFocus != null && nextFocus != vetoedComponent &&
       
   174                 nextFocus.requestFocusInWindow(CausedFocusEvent.Cause.ROLLBACK))
       
   175             {
       
   176                 return true;
       
   177             } else if (clearOnFailure) {
       
   178                 clearGlobalFocusOwnerPriv();
       
   179                 return true;
       
   180             } else {
       
   181                 return false;
       
   182             }
       
   183         }
       
   184     }
       
   185 
       
   186     /**
       
   187      * A special type of SentEvent which updates a counter in the target
       
   188      * KeyboardFocusManager if it is an instance of
       
   189      * DefaultKeyboardFocusManager.
       
   190      */
       
   191     private static class DefaultKeyboardFocusManagerSentEvent
       
   192         extends SentEvent
       
   193     {
       
   194         /*
       
   195          * serialVersionUID
       
   196          */
       
   197         private static final long serialVersionUID = -2924743257508701758L;
       
   198 
       
   199         public DefaultKeyboardFocusManagerSentEvent(AWTEvent nested,
       
   200                                                     AppContext toNotify) {
       
   201             super(nested, toNotify);
       
   202         }
       
   203         public final void dispatch() {
       
   204             KeyboardFocusManager manager =
       
   205                 KeyboardFocusManager.getCurrentKeyboardFocusManager();
       
   206             DefaultKeyboardFocusManager defaultManager =
       
   207                 (manager instanceof DefaultKeyboardFocusManager)
       
   208                 ? (DefaultKeyboardFocusManager)manager
       
   209                 : null;
       
   210 
       
   211             if (defaultManager != null) {
       
   212                 synchronized (defaultManager) {
       
   213                     defaultManager.inSendMessage++;
       
   214                 }
       
   215             }
       
   216 
       
   217             super.dispatch();
       
   218 
       
   219             if (defaultManager != null) {
       
   220                 synchronized (defaultManager) {
       
   221                     defaultManager.inSendMessage--;
       
   222                 }
       
   223             }
       
   224         }
       
   225     }
       
   226 
       
   227     /**
       
   228      * Sends a synthetic AWTEvent to a Component. If the Component is in
       
   229      * the current AppContext, then the event is immediately dispatched.
       
   230      * If the Component is in a different AppContext, then the event is
       
   231      * posted to the other AppContext's EventQueue, and this method blocks
       
   232      * until the event is handled or target AppContext is disposed.
       
   233      * Returns true if successfuly dispatched event, false if failed
       
   234      * to dispatch.
       
   235      */
       
   236     static boolean sendMessage(Component target, AWTEvent e) {
       
   237         e.isPosted = true;
       
   238         AppContext myAppContext = AppContext.getAppContext();
       
   239         final AppContext targetAppContext = target.appContext;
       
   240         final SentEvent se =
       
   241             new DefaultKeyboardFocusManagerSentEvent(e, myAppContext);
       
   242 
       
   243         if (myAppContext == targetAppContext) {
       
   244             se.dispatch();
       
   245         } else {
       
   246             if (targetAppContext.isDisposed()) {
       
   247                 return false;
       
   248             }
       
   249             SunToolkit.postEvent(targetAppContext, se);
       
   250             if (EventQueue.isDispatchThread()) {
       
   251                 EventDispatchThread edt = (EventDispatchThread)
       
   252                     Thread.currentThread();
       
   253                 edt.pumpEvents(SentEvent.ID, new Conditional() {
       
   254                         public boolean evaluate() {
       
   255                             return !se.dispatched && !targetAppContext.isDisposed();
       
   256                         }
       
   257                     });
       
   258             } else {
       
   259                 synchronized (se) {
       
   260                     while (!se.dispatched && !targetAppContext.isDisposed()) {
       
   261                         try {
       
   262                             se.wait(1000);
       
   263                         } catch (InterruptedException ie) {
       
   264                             break;
       
   265                         }
       
   266                     }
       
   267                 }
       
   268             }
       
   269         }
       
   270         return se.dispatched;
       
   271     }
       
   272 
       
   273     /*
       
   274      * Checks if the focus window event follows key events waiting in the type-ahead
       
   275      * queue (if any). This may happen when a user types ahead in the window, the client
       
   276      * listeners hang EDT for a while, and the user switches b/w toplevels. In that
       
   277      * case the focus window events may be dispatched before the type-ahead events
       
   278      * get handled. This may lead to wrong focus behavior and in order to avoid it,
       
   279      * the focus window events are reposted to the end of the event queue. See 6981400.
       
   280      */
       
   281     private boolean repostIfFollowsKeyEvents(WindowEvent e) {
       
   282         if (!(e instanceof TimedWindowEvent)) {
       
   283             return false;
       
   284         }
       
   285         TimedWindowEvent we = (TimedWindowEvent)e;
       
   286         long time = we.getWhen();
       
   287         synchronized (this) {
       
   288             KeyEvent ke = enqueuedKeyEvents.isEmpty() ? null : enqueuedKeyEvents.getFirst();
       
   289             if (ke != null && time >= ke.getWhen()) {
       
   290                 TypeAheadMarker marker = typeAheadMarkers.isEmpty() ? null : typeAheadMarkers.getFirst();
       
   291                 if (marker != null) {
       
   292                     Window toplevel = marker.untilFocused.getContainingWindow();
       
   293                     // Check that the component awaiting focus belongs to
       
   294                     // the current focused window. See 8015454.
       
   295                     if (toplevel != null && toplevel.isFocused()) {
       
   296                         SunToolkit.postEvent(AppContext.getAppContext(), new SequencedEvent(e));
       
   297                         return true;
       
   298                     }
       
   299                 }
       
   300             }
       
   301         }
       
   302         return false;
       
   303     }
       
   304 
       
   305     /**
       
   306      * This method is called by the AWT event dispatcher requesting that the
       
   307      * current KeyboardFocusManager dispatch the specified event on its behalf.
       
   308      * DefaultKeyboardFocusManagers dispatch all FocusEvents, all WindowEvents
       
   309      * related to focus, and all KeyEvents. These events are dispatched based
       
   310      * on the KeyboardFocusManager's notion of the focus owner and the focused
       
   311      * and active Windows, sometimes overriding the source of the specified
       
   312      * AWTEvent. If this method returns <code>false</code>, then the AWT event
       
   313      * dispatcher will attempt to dispatch the event itself.
       
   314      *
       
   315      * @param e the AWTEvent to be dispatched
       
   316      * @return <code>true</code> if this method dispatched the event;
       
   317      *         <code>false</code> otherwise
       
   318      */
       
   319     public boolean dispatchEvent(AWTEvent e) {
       
   320         if (focusLog.isLoggable(PlatformLogger.Level.FINE) && (e instanceof WindowEvent || e instanceof FocusEvent)) {
       
   321             focusLog.fine("" + e);
       
   322         }
       
   323         switch (e.getID()) {
       
   324             case WindowEvent.WINDOW_GAINED_FOCUS: {
       
   325                 if (repostIfFollowsKeyEvents((WindowEvent)e)) {
       
   326                     break;
       
   327                 }
       
   328 
       
   329                 WindowEvent we = (WindowEvent)e;
       
   330                 Window oldFocusedWindow = getGlobalFocusedWindow();
       
   331                 Window newFocusedWindow = we.getWindow();
       
   332                 if (newFocusedWindow == oldFocusedWindow) {
       
   333                     break;
       
   334                 }
       
   335 
       
   336                 if (!(newFocusedWindow.isFocusableWindow()
       
   337                       && newFocusedWindow.isVisible()
       
   338                       && newFocusedWindow.isDisplayable()))
       
   339                 {
       
   340                     // we can not accept focus on such window, so reject it.
       
   341                     restoreFocus(we);
       
   342                     break;
       
   343                 }
       
   344                 // If there exists a current focused window, then notify it
       
   345                 // that it has lost focus.
       
   346                 if (oldFocusedWindow != null) {
       
   347                     boolean isEventDispatched =
       
   348                         sendMessage(oldFocusedWindow,
       
   349                                 new WindowEvent(oldFocusedWindow,
       
   350                                                 WindowEvent.WINDOW_LOST_FOCUS,
       
   351                                                 newFocusedWindow));
       
   352                     // Failed to dispatch, clear by ourselfves
       
   353                     if (!isEventDispatched) {
       
   354                         setGlobalFocusOwner(null);
       
   355                         setGlobalFocusedWindow(null);
       
   356                     }
       
   357                 }
       
   358 
       
   359                 // Because the native libraries do not post WINDOW_ACTIVATED
       
   360                 // events, we need to synthesize one if the active Window
       
   361                 // changed.
       
   362                 Window newActiveWindow =
       
   363                     getOwningFrameDialog(newFocusedWindow);
       
   364                 Window currentActiveWindow = getGlobalActiveWindow();
       
   365                 if (newActiveWindow != currentActiveWindow) {
       
   366                     sendMessage(newActiveWindow,
       
   367                                 new WindowEvent(newActiveWindow,
       
   368                                                 WindowEvent.WINDOW_ACTIVATED,
       
   369                                                 currentActiveWindow));
       
   370                     if (newActiveWindow != getGlobalActiveWindow()) {
       
   371                         // Activation change was rejected. Unlikely, but
       
   372                         // possible.
       
   373                         restoreFocus(we);
       
   374                         break;
       
   375                     }
       
   376                 }
       
   377 
       
   378                 setGlobalFocusedWindow(newFocusedWindow);
       
   379 
       
   380                 if (newFocusedWindow != getGlobalFocusedWindow()) {
       
   381                     // Focus change was rejected. Will happen if
       
   382                     // newFocusedWindow is not a focusable Window.
       
   383                     restoreFocus(we);
       
   384                     break;
       
   385                 }
       
   386 
       
   387                 // Restore focus to the Component which last held it. We do
       
   388                 // this here so that client code can override our choice in
       
   389                 // a WINDOW_GAINED_FOCUS handler.
       
   390                 //
       
   391                 // Make sure that the focus change request doesn't change the
       
   392                 // focused Window in case we are no longer the focused Window
       
   393                 // when the request is handled.
       
   394                 if (inSendMessage == 0) {
       
   395                     // Identify which Component should initially gain focus
       
   396                     // in the Window.
       
   397                     //
       
   398                     // * If we're in SendMessage, then this is a synthetic
       
   399                     //   WINDOW_GAINED_FOCUS message which was generated by a
       
   400                     //   the FOCUS_GAINED handler. Allow the Component to
       
   401                     //   which the FOCUS_GAINED message was targeted to
       
   402                     //   receive the focus.
       
   403                     // * Otherwise, look up the correct Component here.
       
   404                     //   We don't use Window.getMostRecentFocusOwner because
       
   405                     //   window is focused now and 'null' will be returned
       
   406 
       
   407 
       
   408                     // Calculating of most recent focus owner and focus
       
   409                     // request should be synchronized on KeyboardFocusManager.class
       
   410                     // to prevent from thread race when user will request
       
   411                     // focus between calculation and our request.
       
   412                     // But if focus transfer is synchronous, this synchronization
       
   413                     // may cause deadlock, thus we don't synchronize this block.
       
   414                     Component toFocus = KeyboardFocusManager.
       
   415                         getMostRecentFocusOwner(newFocusedWindow);
       
   416                     if ((toFocus == null) &&
       
   417                         newFocusedWindow.isFocusableWindow())
       
   418                     {
       
   419                         toFocus = newFocusedWindow.getFocusTraversalPolicy().
       
   420                             getInitialComponent(newFocusedWindow);
       
   421                     }
       
   422                     Component tempLost = null;
       
   423                     synchronized(KeyboardFocusManager.class) {
       
   424                         tempLost = newFocusedWindow.setTemporaryLostComponent(null);
       
   425                     }
       
   426 
       
   427                     // The component which last has the focus when this window was focused
       
   428                     // should receive focus first
       
   429                     if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
       
   430                         focusLog.finer("tempLost {0}, toFocus {1}",
       
   431                                        tempLost, toFocus);
       
   432                     }
       
   433                     if (tempLost != null) {
       
   434                         tempLost.requestFocusInWindow(CausedFocusEvent.Cause.ACTIVATION);
       
   435                     }
       
   436 
       
   437                     if (toFocus != null && toFocus != tempLost) {
       
   438                         // If there is a component which requested focus when this window
       
   439                         // was inactive it expects to receive focus after activation.
       
   440                         toFocus.requestFocusInWindow(CausedFocusEvent.Cause.ACTIVATION);
       
   441                     }
       
   442                 }
       
   443 
       
   444                 Window realOppositeWindow = this.realOppositeWindowWR.get();
       
   445                 if (realOppositeWindow != we.getOppositeWindow()) {
       
   446                     we = new WindowEvent(newFocusedWindow,
       
   447                                          WindowEvent.WINDOW_GAINED_FOCUS,
       
   448                                          realOppositeWindow);
       
   449                 }
       
   450                 return typeAheadAssertions(newFocusedWindow, we);
       
   451             }
       
   452 
       
   453             case WindowEvent.WINDOW_ACTIVATED: {
       
   454                 WindowEvent we = (WindowEvent)e;
       
   455                 Window oldActiveWindow = getGlobalActiveWindow();
       
   456                 Window newActiveWindow = we.getWindow();
       
   457                 if (oldActiveWindow == newActiveWindow) {
       
   458                     break;
       
   459                 }
       
   460 
       
   461                 // If there exists a current active window, then notify it that
       
   462                 // it has lost activation.
       
   463                 if (oldActiveWindow != null) {
       
   464                     boolean isEventDispatched =
       
   465                         sendMessage(oldActiveWindow,
       
   466                                 new WindowEvent(oldActiveWindow,
       
   467                                                 WindowEvent.WINDOW_DEACTIVATED,
       
   468                                                 newActiveWindow));
       
   469                     // Failed to dispatch, clear by ourselfves
       
   470                     if (!isEventDispatched) {
       
   471                         setGlobalActiveWindow(null);
       
   472                     }
       
   473                     if (getGlobalActiveWindow() != null) {
       
   474                         // Activation change was rejected. Unlikely, but
       
   475                         // possible.
       
   476                         break;
       
   477                     }
       
   478                 }
       
   479 
       
   480                 setGlobalActiveWindow(newActiveWindow);
       
   481 
       
   482                 if (newActiveWindow != getGlobalActiveWindow()) {
       
   483                     // Activation change was rejected. Unlikely, but
       
   484                     // possible.
       
   485                     break;
       
   486                 }
       
   487 
       
   488                 return typeAheadAssertions(newActiveWindow, we);
       
   489             }
       
   490 
       
   491             case FocusEvent.FOCUS_GAINED: {
       
   492                 FocusEvent fe = (FocusEvent)e;
       
   493                 CausedFocusEvent.Cause cause = (fe instanceof CausedFocusEvent) ?
       
   494                     ((CausedFocusEvent)fe).getCause() : CausedFocusEvent.Cause.UNKNOWN;
       
   495                 Component oldFocusOwner = getGlobalFocusOwner();
       
   496                 Component newFocusOwner = fe.getComponent();
       
   497                 if (oldFocusOwner == newFocusOwner) {
       
   498                     if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
       
   499                         focusLog.fine("Skipping {0} because focus owner is the same", e);
       
   500                     }
       
   501                     // We can't just drop the event - there could be
       
   502                     // type-ahead markers associated with it.
       
   503                     dequeueKeyEvents(-1, newFocusOwner);
       
   504                     break;
       
   505                 }
       
   506 
       
   507                 // If there exists a current focus owner, then notify it that
       
   508                 // it has lost focus.
       
   509                 if (oldFocusOwner != null) {
       
   510                     boolean isEventDispatched =
       
   511                         sendMessage(oldFocusOwner,
       
   512                                     new CausedFocusEvent(oldFocusOwner,
       
   513                                                    FocusEvent.FOCUS_LOST,
       
   514                                                    fe.isTemporary(),
       
   515                                                    newFocusOwner, cause));
       
   516                     // Failed to dispatch, clear by ourselfves
       
   517                     if (!isEventDispatched) {
       
   518                         setGlobalFocusOwner(null);
       
   519                         if (!fe.isTemporary()) {
       
   520                             setGlobalPermanentFocusOwner(null);
       
   521                         }
       
   522                     }
       
   523                 }
       
   524 
       
   525                 // Because the native windowing system has a different notion
       
   526                 // of the current focus and activation states, it is possible
       
   527                 // that a Component outside of the focused Window receives a
       
   528                 // FOCUS_GAINED event. We synthesize a WINDOW_GAINED_FOCUS
       
   529                 // event in that case.
       
   530                 final Window newFocusedWindow = SunToolkit.getContainingWindow(newFocusOwner);
       
   531                 final Window currentFocusedWindow = getGlobalFocusedWindow();
       
   532                 if (newFocusedWindow != null &&
       
   533                     newFocusedWindow != currentFocusedWindow)
       
   534                 {
       
   535                     sendMessage(newFocusedWindow,
       
   536                                 new WindowEvent(newFocusedWindow,
       
   537                                         WindowEvent.WINDOW_GAINED_FOCUS,
       
   538                                                 currentFocusedWindow));
       
   539                     if (newFocusedWindow != getGlobalFocusedWindow()) {
       
   540                         // Focus change was rejected. Will happen if
       
   541                         // newFocusedWindow is not a focusable Window.
       
   542 
       
   543                         // Need to recover type-ahead, but don't bother
       
   544                         // restoring focus. That was done by the
       
   545                         // WINDOW_GAINED_FOCUS handler
       
   546                         dequeueKeyEvents(-1, newFocusOwner);
       
   547                         break;
       
   548                     }
       
   549                 }
       
   550 
       
   551                 if (!(newFocusOwner.isFocusable() && newFocusOwner.isShowing() &&
       
   552                     // Refuse focus on a disabled component if the focus event
       
   553                     // isn't of UNKNOWN reason (i.e. not a result of a direct request
       
   554                     // but traversal, activation or system generated).
       
   555                     (newFocusOwner.isEnabled() || cause.equals(CausedFocusEvent.Cause.UNKNOWN))))
       
   556                 {
       
   557                     // we should not accept focus on such component, so reject it.
       
   558                     dequeueKeyEvents(-1, newFocusOwner);
       
   559                     if (KeyboardFocusManager.isAutoFocusTransferEnabled()) {
       
   560                         // If FOCUS_GAINED is for a disposed component (however
       
   561                         // it shouldn't happen) its toplevel parent is null. In this
       
   562                         // case we have to try to restore focus in the current focused
       
   563                         // window (for the details: 6607170).
       
   564                         if (newFocusedWindow == null) {
       
   565                             restoreFocus(fe, currentFocusedWindow);
       
   566                         } else {
       
   567                             restoreFocus(fe, newFocusedWindow);
       
   568                         }
       
   569                         setMostRecentFocusOwner(newFocusedWindow, null); // see: 8013773
       
   570                     }
       
   571                     break;
       
   572                 }
       
   573 
       
   574                 setGlobalFocusOwner(newFocusOwner);
       
   575 
       
   576                 if (newFocusOwner != getGlobalFocusOwner()) {
       
   577                     // Focus change was rejected. Will happen if
       
   578                     // newFocusOwner is not focus traversable.
       
   579                     dequeueKeyEvents(-1, newFocusOwner);
       
   580                     if (KeyboardFocusManager.isAutoFocusTransferEnabled()) {
       
   581                         restoreFocus(fe, newFocusedWindow);
       
   582                     }
       
   583                     break;
       
   584                 }
       
   585 
       
   586                 if (!fe.isTemporary()) {
       
   587                     setGlobalPermanentFocusOwner(newFocusOwner);
       
   588 
       
   589                     if (newFocusOwner != getGlobalPermanentFocusOwner()) {
       
   590                         // Focus change was rejected. Unlikely, but possible.
       
   591                         dequeueKeyEvents(-1, newFocusOwner);
       
   592                         if (KeyboardFocusManager.isAutoFocusTransferEnabled()) {
       
   593                             restoreFocus(fe, newFocusedWindow);
       
   594                         }
       
   595                         break;
       
   596                     }
       
   597                 }
       
   598 
       
   599                 setNativeFocusOwner(getHeavyweight(newFocusOwner));
       
   600 
       
   601                 Component realOppositeComponent = this.realOppositeComponentWR.get();
       
   602                 if (realOppositeComponent != null &&
       
   603                     realOppositeComponent != fe.getOppositeComponent()) {
       
   604                     fe = new CausedFocusEvent(newFocusOwner,
       
   605                                         FocusEvent.FOCUS_GAINED,
       
   606                                         fe.isTemporary(),
       
   607                                         realOppositeComponent, cause);
       
   608                     ((AWTEvent) fe).isPosted = true;
       
   609                 }
       
   610                 return typeAheadAssertions(newFocusOwner, fe);
       
   611             }
       
   612 
       
   613             case FocusEvent.FOCUS_LOST: {
       
   614                 FocusEvent fe = (FocusEvent)e;
       
   615                 Component currentFocusOwner = getGlobalFocusOwner();
       
   616                 if (currentFocusOwner == null) {
       
   617                     if (focusLog.isLoggable(PlatformLogger.Level.FINE))
       
   618                         focusLog.fine("Skipping {0} because focus owner is null", e);
       
   619                     break;
       
   620                 }
       
   621                 // Ignore cases where a Component loses focus to itself.
       
   622                 // If we make a mistake because of retargeting, then the
       
   623                 // FOCUS_GAINED handler will correct it.
       
   624                 if (currentFocusOwner == fe.getOppositeComponent()) {
       
   625                     if (focusLog.isLoggable(PlatformLogger.Level.FINE))
       
   626                         focusLog.fine("Skipping {0} because current focus owner is equal to opposite", e);
       
   627                     break;
       
   628                 }
       
   629 
       
   630                 setGlobalFocusOwner(null);
       
   631 
       
   632                 if (getGlobalFocusOwner() != null) {
       
   633                     // Focus change was rejected. Unlikely, but possible.
       
   634                     restoreFocus(currentFocusOwner, true);
       
   635                     break;
       
   636                 }
       
   637 
       
   638                 if (!fe.isTemporary()) {
       
   639                     setGlobalPermanentFocusOwner(null);
       
   640 
       
   641                     if (getGlobalPermanentFocusOwner() != null) {
       
   642                         // Focus change was rejected. Unlikely, but possible.
       
   643                         restoreFocus(currentFocusOwner, true);
       
   644                         break;
       
   645                     }
       
   646                 } else {
       
   647                     Window owningWindow = currentFocusOwner.getContainingWindow();
       
   648                     if (owningWindow != null) {
       
   649                         owningWindow.setTemporaryLostComponent(currentFocusOwner);
       
   650                     }
       
   651                 }
       
   652 
       
   653                 setNativeFocusOwner(null);
       
   654 
       
   655                 fe.setSource(currentFocusOwner);
       
   656 
       
   657                 realOppositeComponentWR = (fe.getOppositeComponent() != null)
       
   658                     ? new WeakReference<Component>(currentFocusOwner)
       
   659                     : NULL_COMPONENT_WR;
       
   660 
       
   661                 return typeAheadAssertions(currentFocusOwner, fe);
       
   662             }
       
   663 
       
   664             case WindowEvent.WINDOW_DEACTIVATED: {
       
   665                 WindowEvent we = (WindowEvent)e;
       
   666                 Window currentActiveWindow = getGlobalActiveWindow();
       
   667                 if (currentActiveWindow == null) {
       
   668                     break;
       
   669                 }
       
   670 
       
   671                 if (currentActiveWindow != e.getSource()) {
       
   672                     // The event is lost in time.
       
   673                     // Allow listeners to precess the event but do not
       
   674                     // change any global states
       
   675                     break;
       
   676                 }
       
   677 
       
   678                 setGlobalActiveWindow(null);
       
   679                 if (getGlobalActiveWindow() != null) {
       
   680                     // Activation change was rejected. Unlikely, but possible.
       
   681                     break;
       
   682                 }
       
   683 
       
   684                 we.setSource(currentActiveWindow);
       
   685                 return typeAheadAssertions(currentActiveWindow, we);
       
   686             }
       
   687 
       
   688             case WindowEvent.WINDOW_LOST_FOCUS: {
       
   689                 if (repostIfFollowsKeyEvents((WindowEvent)e)) {
       
   690                     break;
       
   691                 }
       
   692 
       
   693                 WindowEvent we = (WindowEvent)e;
       
   694                 Window currentFocusedWindow = getGlobalFocusedWindow();
       
   695                 Window losingFocusWindow = we.getWindow();
       
   696                 Window activeWindow = getGlobalActiveWindow();
       
   697                 Window oppositeWindow = we.getOppositeWindow();
       
   698                 if (focusLog.isLoggable(PlatformLogger.Level.FINE))
       
   699                     focusLog.fine("Active {0}, Current focused {1}, losing focus {2} opposite {3}",
       
   700                                   activeWindow, currentFocusedWindow,
       
   701                                   losingFocusWindow, oppositeWindow);
       
   702                 if (currentFocusedWindow == null) {
       
   703                     break;
       
   704                 }
       
   705 
       
   706                 // Special case -- if the native windowing system posts an
       
   707                 // event claiming that the active Window has lost focus to the
       
   708                 // focused Window, then discard the event. This is an artifact
       
   709                 // of the native windowing system not knowing which Window is
       
   710                 // really focused.
       
   711                 if (inSendMessage == 0 && losingFocusWindow == activeWindow &&
       
   712                     oppositeWindow == currentFocusedWindow)
       
   713                 {
       
   714                     break;
       
   715                 }
       
   716 
       
   717                 Component currentFocusOwner = getGlobalFocusOwner();
       
   718                 if (currentFocusOwner != null) {
       
   719                     // The focus owner should always receive a FOCUS_LOST event
       
   720                     // before the Window is defocused.
       
   721                     Component oppositeComp = null;
       
   722                     if (oppositeWindow != null) {
       
   723                         oppositeComp = oppositeWindow.getTemporaryLostComponent();
       
   724                         if (oppositeComp == null) {
       
   725                             oppositeComp = oppositeWindow.getMostRecentFocusOwner();
       
   726                         }
       
   727                     }
       
   728                     if (oppositeComp == null) {
       
   729                         oppositeComp = oppositeWindow;
       
   730                     }
       
   731                     sendMessage(currentFocusOwner,
       
   732                                 new CausedFocusEvent(currentFocusOwner,
       
   733                                                FocusEvent.FOCUS_LOST,
       
   734                                                true,
       
   735                                                oppositeComp, CausedFocusEvent.Cause.ACTIVATION));
       
   736                 }
       
   737 
       
   738                 setGlobalFocusedWindow(null);
       
   739                 if (getGlobalFocusedWindow() != null) {
       
   740                     // Focus change was rejected. Unlikely, but possible.
       
   741                     restoreFocus(currentFocusedWindow, null, true);
       
   742                     break;
       
   743                 }
       
   744 
       
   745                 we.setSource(currentFocusedWindow);
       
   746                 realOppositeWindowWR = (oppositeWindow != null)
       
   747                     ? new WeakReference<Window>(currentFocusedWindow)
       
   748                     : NULL_WINDOW_WR;
       
   749                 typeAheadAssertions(currentFocusedWindow, we);
       
   750 
       
   751                 if (oppositeWindow == null) {
       
   752                     // Then we need to deactive the active Window as well.
       
   753                     // No need to synthesize in other cases, because
       
   754                     // WINDOW_ACTIVATED will handle it if necessary.
       
   755                     sendMessage(activeWindow,
       
   756                                 new WindowEvent(activeWindow,
       
   757                                                 WindowEvent.WINDOW_DEACTIVATED,
       
   758                                                 null));
       
   759                     if (getGlobalActiveWindow() != null) {
       
   760                         // Activation change was rejected. Unlikely,
       
   761                         // but possible.
       
   762                         restoreFocus(currentFocusedWindow, null, true);
       
   763                     }
       
   764                 }
       
   765                 break;
       
   766             }
       
   767 
       
   768             case KeyEvent.KEY_TYPED:
       
   769             case KeyEvent.KEY_PRESSED:
       
   770             case KeyEvent.KEY_RELEASED:
       
   771                 return typeAheadAssertions(null, e);
       
   772 
       
   773             default:
       
   774                 return false;
       
   775         }
       
   776 
       
   777         return true;
       
   778     }
       
   779 
       
   780     /**
       
   781      * Called by <code>dispatchEvent</code> if no other
       
   782      * KeyEventDispatcher in the dispatcher chain dispatched the KeyEvent, or
       
   783      * if no other KeyEventDispatchers are registered. If the event has not
       
   784      * been consumed, its target is enabled, and the focus owner is not null,
       
   785      * this method dispatches the event to its target. This method will also
       
   786      * subsequently dispatch the event to all registered
       
   787      * KeyEventPostProcessors. After all this operations are finished,
       
   788      * the event is passed to peers for processing.
       
   789      * <p>
       
   790      * In all cases, this method returns <code>true</code>, since
       
   791      * DefaultKeyboardFocusManager is designed so that neither
       
   792      * <code>dispatchEvent</code>, nor the AWT event dispatcher, should take
       
   793      * further action on the event in any situation.
       
   794      *
       
   795      * @param e the KeyEvent to be dispatched
       
   796      * @return <code>true</code>
       
   797      * @see Component#dispatchEvent
       
   798      */
       
   799     public boolean dispatchKeyEvent(KeyEvent e) {
       
   800         Component focusOwner = (((AWTEvent)e).isPosted) ? getFocusOwner() : e.getComponent();
       
   801 
       
   802         if (focusOwner != null && focusOwner.isShowing() && focusOwner.canBeFocusOwner()) {
       
   803             if (!e.isConsumed()) {
       
   804                 Component comp = e.getComponent();
       
   805                 if (comp != null && comp.isEnabled()) {
       
   806                     redispatchEvent(comp, e);
       
   807                 }
       
   808             }
       
   809         }
       
   810         boolean stopPostProcessing = false;
       
   811         java.util.List<KeyEventPostProcessor> processors = getKeyEventPostProcessors();
       
   812         if (processors != null) {
       
   813             for (java.util.Iterator<KeyEventPostProcessor> iter = processors.iterator();
       
   814                  !stopPostProcessing && iter.hasNext(); )
       
   815             {
       
   816                 stopPostProcessing = iter.next().
       
   817                             postProcessKeyEvent(e);
       
   818             }
       
   819         }
       
   820         if (!stopPostProcessing) {
       
   821             postProcessKeyEvent(e);
       
   822         }
       
   823 
       
   824         // Allow the peer to process KeyEvent
       
   825         Component source = e.getComponent();
       
   826         ComponentPeer peer = source.getPeer();
       
   827 
       
   828         if (peer == null || peer instanceof LightweightPeer) {
       
   829             // if focus owner is lightweight then its native container
       
   830             // processes event
       
   831             Container target = source.getNativeContainer();
       
   832             if (target != null) {
       
   833                 peer = target.getPeer();
       
   834             }
       
   835         }
       
   836         if (peer != null) {
       
   837             peer.handleEvent(e);
       
   838         }
       
   839 
       
   840         return true;
       
   841     }
       
   842 
       
   843     /**
       
   844      * This method will be called by <code>dispatchKeyEvent</code>. It will
       
   845      * handle any unconsumed KeyEvents that map to an AWT
       
   846      * <code>MenuShortcut</code> by consuming the event and activating the
       
   847      * shortcut.
       
   848      *
       
   849      * @param e the KeyEvent to post-process
       
   850      * @return <code>true</code>
       
   851      * @see #dispatchKeyEvent
       
   852      * @see MenuShortcut
       
   853      */
       
   854     public boolean postProcessKeyEvent(KeyEvent e) {
       
   855         if (!e.isConsumed()) {
       
   856             Component target = e.getComponent();
       
   857             Container p = (Container)
       
   858                 (target instanceof Container ? target : target.getParent());
       
   859             if (p != null) {
       
   860                 p.postProcessKeyEvent(e);
       
   861             }
       
   862         }
       
   863         return true;
       
   864     }
       
   865 
       
   866     private void pumpApprovedKeyEvents() {
       
   867         KeyEvent ke;
       
   868         do {
       
   869             ke = null;
       
   870             synchronized (this) {
       
   871                 if (enqueuedKeyEvents.size() != 0) {
       
   872                     ke = enqueuedKeyEvents.getFirst();
       
   873                     if (typeAheadMarkers.size() != 0) {
       
   874                         TypeAheadMarker marker = typeAheadMarkers.getFirst();
       
   875                         // Fixed 5064013: may appears that the events have the same time
       
   876                         // if (ke.getWhen() >= marker.after) {
       
   877                         // The fix is rolled out.
       
   878 
       
   879                         if (ke.getWhen() > marker.after) {
       
   880                             ke = null;
       
   881                         }
       
   882                     }
       
   883                     if (ke != null) {
       
   884                         if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
       
   885                             focusLog.finer("Pumping approved event {0}", ke);
       
   886                         }
       
   887                         enqueuedKeyEvents.removeFirst();
       
   888                     }
       
   889                 }
       
   890             }
       
   891             if (ke != null) {
       
   892                 preDispatchKeyEvent(ke);
       
   893             }
       
   894         } while (ke != null);
       
   895     }
       
   896 
       
   897     /**
       
   898      * Dumps the list of type-ahead queue markers to stderr
       
   899      */
       
   900     void dumpMarkers() {
       
   901         if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) {
       
   902             focusLog.finest(">>> Markers dump, time: {0}", System.currentTimeMillis());
       
   903             synchronized (this) {
       
   904                 if (typeAheadMarkers.size() != 0) {
       
   905                     Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator();
       
   906                     while (iter.hasNext()) {
       
   907                         TypeAheadMarker marker = iter.next();
       
   908                         focusLog.finest("    {0}", marker);
       
   909                     }
       
   910                 }
       
   911             }
       
   912         }
       
   913     }
       
   914 
       
   915     private boolean typeAheadAssertions(Component target, AWTEvent e) {
       
   916 
       
   917         // Clear any pending events here as well as in the FOCUS_GAINED
       
   918         // handler. We need this call here in case a marker was removed in
       
   919         // response to a call to dequeueKeyEvents.
       
   920         pumpApprovedKeyEvents();
       
   921 
       
   922         switch (e.getID()) {
       
   923             case KeyEvent.KEY_TYPED:
       
   924             case KeyEvent.KEY_PRESSED:
       
   925             case KeyEvent.KEY_RELEASED: {
       
   926                 KeyEvent ke = (KeyEvent)e;
       
   927                 synchronized (this) {
       
   928                     if (e.isPosted && typeAheadMarkers.size() != 0) {
       
   929                         TypeAheadMarker marker = typeAheadMarkers.getFirst();
       
   930                         // Fixed 5064013: may appears that the events have the same time
       
   931                         // if (ke.getWhen() >= marker.after) {
       
   932                         // The fix is rolled out.
       
   933 
       
   934                         if (ke.getWhen() > marker.after) {
       
   935                             if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
       
   936                                 focusLog.finer("Storing event {0} because of marker {1}", ke, marker);
       
   937                             }
       
   938                             enqueuedKeyEvents.addLast(ke);
       
   939                             return true;
       
   940                         }
       
   941                     }
       
   942                 }
       
   943 
       
   944                 // KeyEvent was posted before focus change request
       
   945                 return preDispatchKeyEvent(ke);
       
   946             }
       
   947 
       
   948             case FocusEvent.FOCUS_GAINED:
       
   949                 if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) {
       
   950                     focusLog.finest("Markers before FOCUS_GAINED on {0}", target);
       
   951                 }
       
   952                 dumpMarkers();
       
   953                 // Search the marker list for the first marker tied to
       
   954                 // the Component which just gained focus. Then remove
       
   955                 // that marker, any markers which immediately follow
       
   956                 // and are tied to the same component, and all markers
       
   957                 // that preceed it. This handles the case where
       
   958                 // multiple focus requests were made for the same
       
   959                 // Component in a row and when we lost some of the
       
   960                 // earlier requests. Since FOCUS_GAINED events will
       
   961                 // not be generated for these additional requests, we
       
   962                 // need to clear those markers too.
       
   963                 synchronized (this) {
       
   964                     boolean found = false;
       
   965                     if (hasMarker(target)) {
       
   966                         for (Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator();
       
   967                              iter.hasNext(); )
       
   968                         {
       
   969                             if (iter.next().untilFocused == target) {
       
   970                                 found = true;
       
   971                             } else if (found) {
       
   972                                 break;
       
   973                             }
       
   974                             iter.remove();
       
   975                         }
       
   976                     } else {
       
   977                         // Exception condition - event without marker
       
   978                         if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
       
   979                             focusLog.finer("Event without marker {0}", e);
       
   980                         }
       
   981                     }
       
   982                 }
       
   983                 focusLog.finest("Markers after FOCUS_GAINED");
       
   984                 dumpMarkers();
       
   985 
       
   986                 redispatchEvent(target, e);
       
   987 
       
   988                 // Now, dispatch any pending KeyEvents which have been
       
   989                 // released because of the FOCUS_GAINED event so that we don't
       
   990                 // have to wait for another event to be posted to the queue.
       
   991                 pumpApprovedKeyEvents();
       
   992                 return true;
       
   993 
       
   994             default:
       
   995                 redispatchEvent(target, e);
       
   996                 return true;
       
   997         }
       
   998     }
       
   999 
       
  1000     /**
       
  1001      * Returns true if there are some marker associated with component <code>comp</code>
       
  1002      * in a markers' queue
       
  1003      * @since 1.5
       
  1004      */
       
  1005     private boolean hasMarker(Component comp) {
       
  1006         for (Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator(); iter.hasNext(); ) {
       
  1007             if (iter.next().untilFocused == comp) {
       
  1008                 return true;
       
  1009             }
       
  1010         }
       
  1011         return false;
       
  1012     }
       
  1013 
       
  1014     /**
       
  1015      * Clears markers queue
       
  1016      * @since 1.5
       
  1017      */
       
  1018     void clearMarkers() {
       
  1019         synchronized(this) {
       
  1020             typeAheadMarkers.clear();
       
  1021         }
       
  1022     }
       
  1023 
       
  1024     private boolean preDispatchKeyEvent(KeyEvent ke) {
       
  1025         if (((AWTEvent) ke).isPosted) {
       
  1026             Component focusOwner = getFocusOwner();
       
  1027             ke.setSource(((focusOwner != null) ? focusOwner : getFocusedWindow()));
       
  1028         }
       
  1029         if (ke.getSource() == null) {
       
  1030             return true;
       
  1031         }
       
  1032 
       
  1033         // Explicitly set the key event timestamp here (not in Component.dispatchEventImpl):
       
  1034         // - A key event is anyway passed to this method which starts its actual dispatching.
       
  1035         // - If a key event is put to the type ahead queue, its time stamp should not be registered
       
  1036         //   until its dispatching actually starts (by this method).
       
  1037         EventQueue.setCurrentEventAndMostRecentTime(ke);
       
  1038 
       
  1039         /**
       
  1040          * Fix for 4495473.
       
  1041          * This fix allows to correctly dispatch events when native
       
  1042          * event proxying mechanism is active.
       
  1043          * If it is active we should redispatch key events after
       
  1044          * we detected its correct target.
       
  1045          */
       
  1046         if (KeyboardFocusManager.isProxyActive(ke)) {
       
  1047             Component source = (Component)ke.getSource();
       
  1048             Container target = source.getNativeContainer();
       
  1049             if (target != null) {
       
  1050                 ComponentPeer peer = target.getPeer();
       
  1051                 if (peer != null) {
       
  1052                     peer.handleEvent(ke);
       
  1053                     /**
       
  1054                      * Fix for 4478780 - consume event after it was dispatched by peer.
       
  1055                      */
       
  1056                     ke.consume();
       
  1057                 }
       
  1058             }
       
  1059             return true;
       
  1060         }
       
  1061 
       
  1062         java.util.List<KeyEventDispatcher> dispatchers = getKeyEventDispatchers();
       
  1063         if (dispatchers != null) {
       
  1064             for (java.util.Iterator<KeyEventDispatcher> iter = dispatchers.iterator();
       
  1065                  iter.hasNext(); )
       
  1066              {
       
  1067                  if (iter.next().
       
  1068                      dispatchKeyEvent(ke))
       
  1069                  {
       
  1070                      return true;
       
  1071                  }
       
  1072              }
       
  1073         }
       
  1074         return dispatchKeyEvent(ke);
       
  1075     }
       
  1076 
       
  1077     /*
       
  1078      * @param e is a KEY_PRESSED event that can be used
       
  1079      *          to track the next KEY_TYPED related.
       
  1080      */
       
  1081     private void consumeNextKeyTyped(KeyEvent e) {
       
  1082         consumeNextKeyTyped = true;
       
  1083     }
       
  1084 
       
  1085     private void consumeTraversalKey(KeyEvent e) {
       
  1086         e.consume();
       
  1087         consumeNextKeyTyped = (e.getID() == KeyEvent.KEY_PRESSED) &&
       
  1088                               !e.isActionKey();
       
  1089     }
       
  1090 
       
  1091     /*
       
  1092      * return true if event was consumed
       
  1093      */
       
  1094     private boolean consumeProcessedKeyEvent(KeyEvent e) {
       
  1095         if ((e.getID() == KeyEvent.KEY_TYPED) && consumeNextKeyTyped) {
       
  1096             e.consume();
       
  1097             consumeNextKeyTyped = false;
       
  1098             return true;
       
  1099         }
       
  1100         return false;
       
  1101     }
       
  1102 
       
  1103     /**
       
  1104      * This method initiates a focus traversal operation if and only if the
       
  1105      * KeyEvent represents a focus traversal key for the specified
       
  1106      * focusedComponent. It is expected that focusedComponent is the current
       
  1107      * focus owner, although this need not be the case. If it is not,
       
  1108      * focus traversal will nevertheless proceed as if focusedComponent
       
  1109      * were the focus owner.
       
  1110      *
       
  1111      * @param focusedComponent the Component that is the basis for a focus
       
  1112      *        traversal operation if the specified event represents a focus
       
  1113      *        traversal key for the Component
       
  1114      * @param e the event that may represent a focus traversal key
       
  1115      */
       
  1116     public void processKeyEvent(Component focusedComponent, KeyEvent e) {
       
  1117         // consume processed event if needed
       
  1118         if (consumeProcessedKeyEvent(e)) {
       
  1119             return;
       
  1120         }
       
  1121 
       
  1122         // KEY_TYPED events cannot be focus traversal keys
       
  1123         if (e.getID() == KeyEvent.KEY_TYPED) {
       
  1124             return;
       
  1125         }
       
  1126 
       
  1127         if (focusedComponent.getFocusTraversalKeysEnabled() &&
       
  1128             !e.isConsumed())
       
  1129         {
       
  1130             AWTKeyStroke stroke = AWTKeyStroke.getAWTKeyStrokeForEvent(e),
       
  1131                 oppStroke = AWTKeyStroke.getAWTKeyStroke(stroke.getKeyCode(),
       
  1132                                                  stroke.getModifiers(),
       
  1133                                                  !stroke.isOnKeyRelease());
       
  1134             Set<AWTKeyStroke> toTest;
       
  1135             boolean contains, containsOpp;
       
  1136 
       
  1137             toTest = focusedComponent.getFocusTraversalKeys(
       
  1138                 KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
       
  1139             contains = toTest.contains(stroke);
       
  1140             containsOpp = toTest.contains(oppStroke);
       
  1141 
       
  1142             if (contains || containsOpp) {
       
  1143                 consumeTraversalKey(e);
       
  1144                 if (contains) {
       
  1145                     focusNextComponent(focusedComponent);
       
  1146                 }
       
  1147                 return;
       
  1148             } else if (e.getID() == KeyEvent.KEY_PRESSED) {
       
  1149                 // Fix for 6637607: consumeNextKeyTyped should be reset.
       
  1150                 consumeNextKeyTyped = false;
       
  1151             }
       
  1152 
       
  1153             toTest = focusedComponent.getFocusTraversalKeys(
       
  1154                 KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
       
  1155             contains = toTest.contains(stroke);
       
  1156             containsOpp = toTest.contains(oppStroke);
       
  1157 
       
  1158             if (contains || containsOpp) {
       
  1159                 consumeTraversalKey(e);
       
  1160                 if (contains) {
       
  1161                     focusPreviousComponent(focusedComponent);
       
  1162                 }
       
  1163                 return;
       
  1164             }
       
  1165 
       
  1166             toTest = focusedComponent.getFocusTraversalKeys(
       
  1167                 KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);
       
  1168             contains = toTest.contains(stroke);
       
  1169             containsOpp = toTest.contains(oppStroke);
       
  1170 
       
  1171             if (contains || containsOpp) {
       
  1172                 consumeTraversalKey(e);
       
  1173                 if (contains) {
       
  1174                     upFocusCycle(focusedComponent);
       
  1175                 }
       
  1176                 return;
       
  1177             }
       
  1178 
       
  1179             if (!((focusedComponent instanceof Container) &&
       
  1180                   ((Container)focusedComponent).isFocusCycleRoot())) {
       
  1181                 return;
       
  1182             }
       
  1183 
       
  1184             toTest = focusedComponent.getFocusTraversalKeys(
       
  1185                 KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS);
       
  1186             contains = toTest.contains(stroke);
       
  1187             containsOpp = toTest.contains(oppStroke);
       
  1188 
       
  1189             if (contains || containsOpp) {
       
  1190                 consumeTraversalKey(e);
       
  1191                 if (contains) {
       
  1192                     downFocusCycle((Container)focusedComponent);
       
  1193                 }
       
  1194             }
       
  1195         }
       
  1196     }
       
  1197 
       
  1198     /**
       
  1199      * Delays dispatching of KeyEvents until the specified Component becomes
       
  1200      * the focus owner. KeyEvents with timestamps later than the specified
       
  1201      * timestamp will be enqueued until the specified Component receives a
       
  1202      * FOCUS_GAINED event, or the AWT cancels the delay request by invoking
       
  1203      * <code>dequeueKeyEvents</code> or <code>discardKeyEvents</code>.
       
  1204      *
       
  1205      * @param after timestamp of current event, or the current, system time if
       
  1206      *        the current event has no timestamp, or the AWT cannot determine
       
  1207      *        which event is currently being handled
       
  1208      * @param untilFocused Component which will receive a FOCUS_GAINED event
       
  1209      *        before any pending KeyEvents
       
  1210      * @see #dequeueKeyEvents
       
  1211      * @see #discardKeyEvents
       
  1212      */
       
  1213     protected synchronized void enqueueKeyEvents(long after,
       
  1214                                                  Component untilFocused) {
       
  1215         if (untilFocused == null) {
       
  1216             return;
       
  1217         }
       
  1218 
       
  1219         if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
       
  1220             focusLog.finer("Enqueue at {0} for {1}",
       
  1221                        after, untilFocused);
       
  1222         }
       
  1223 
       
  1224         int insertionIndex = 0,
       
  1225             i = typeAheadMarkers.size();
       
  1226         ListIterator<TypeAheadMarker> iter = typeAheadMarkers.listIterator(i);
       
  1227 
       
  1228         for (; i > 0; i--) {
       
  1229             TypeAheadMarker marker = iter.previous();
       
  1230             if (marker.after <= after) {
       
  1231                 insertionIndex = i;
       
  1232                 break;
       
  1233             }
       
  1234         }
       
  1235 
       
  1236         typeAheadMarkers.add(insertionIndex,
       
  1237                              new TypeAheadMarker(after, untilFocused));
       
  1238     }
       
  1239 
       
  1240     /**
       
  1241      * Releases for normal dispatching to the current focus owner all
       
  1242      * KeyEvents which were enqueued because of a call to
       
  1243      * <code>enqueueKeyEvents</code> with the same timestamp and Component.
       
  1244      * If the given timestamp is less than zero, the outstanding enqueue
       
  1245      * request for the given Component with the <b>oldest</b> timestamp (if
       
  1246      * any) should be cancelled.
       
  1247      *
       
  1248      * @param after the timestamp specified in the call to
       
  1249      *        <code>enqueueKeyEvents</code>, or any value &lt; 0
       
  1250      * @param untilFocused the Component specified in the call to
       
  1251      *        <code>enqueueKeyEvents</code>
       
  1252      * @see #enqueueKeyEvents
       
  1253      * @see #discardKeyEvents
       
  1254      */
       
  1255     protected synchronized void dequeueKeyEvents(long after,
       
  1256                                                  Component untilFocused) {
       
  1257         if (untilFocused == null) {
       
  1258             return;
       
  1259         }
       
  1260 
       
  1261         if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
       
  1262             focusLog.finer("Dequeue at {0} for {1}",
       
  1263                        after, untilFocused);
       
  1264         }
       
  1265 
       
  1266         TypeAheadMarker marker;
       
  1267         ListIterator<TypeAheadMarker> iter = typeAheadMarkers.listIterator
       
  1268             ((after >= 0) ? typeAheadMarkers.size() : 0);
       
  1269 
       
  1270         if (after < 0) {
       
  1271             while (iter.hasNext()) {
       
  1272                 marker = iter.next();
       
  1273                 if (marker.untilFocused == untilFocused)
       
  1274                 {
       
  1275                     iter.remove();
       
  1276                     return;
       
  1277                 }
       
  1278             }
       
  1279         } else {
       
  1280             while (iter.hasPrevious()) {
       
  1281                 marker = iter.previous();
       
  1282                 if (marker.untilFocused == untilFocused &&
       
  1283                     marker.after == after)
       
  1284                 {
       
  1285                     iter.remove();
       
  1286                     return;
       
  1287                 }
       
  1288             }
       
  1289         }
       
  1290     }
       
  1291 
       
  1292     /**
       
  1293      * Discards all KeyEvents which were enqueued because of one or more calls
       
  1294      * to <code>enqueueKeyEvents</code> with the specified Component, or one of
       
  1295      * its descendants.
       
  1296      *
       
  1297      * @param comp the Component specified in one or more calls to
       
  1298      *        <code>enqueueKeyEvents</code>, or a parent of such a Component
       
  1299      * @see #enqueueKeyEvents
       
  1300      * @see #dequeueKeyEvents
       
  1301      */
       
  1302     protected synchronized void discardKeyEvents(Component comp) {
       
  1303         if (comp == null) {
       
  1304             return;
       
  1305         }
       
  1306 
       
  1307         long start = -1;
       
  1308 
       
  1309         for (Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator(); iter.hasNext(); ) {
       
  1310             TypeAheadMarker marker = iter.next();
       
  1311             Component toTest = marker.untilFocused;
       
  1312             boolean match = (toTest == comp);
       
  1313             while (!match && toTest != null && !(toTest instanceof Window)) {
       
  1314                 toTest = toTest.getParent();
       
  1315                 match = (toTest == comp);
       
  1316             }
       
  1317             if (match) {
       
  1318                 if (start < 0) {
       
  1319                     start = marker.after;
       
  1320                 }
       
  1321                 iter.remove();
       
  1322             } else if (start >= 0) {
       
  1323                 purgeStampedEvents(start, marker.after);
       
  1324                 start = -1;
       
  1325             }
       
  1326         }
       
  1327 
       
  1328         purgeStampedEvents(start, -1);
       
  1329     }
       
  1330 
       
  1331     // Notes:
       
  1332     //   * must be called inside a synchronized block
       
  1333     //   * if 'start' is < 0, then this function does nothing
       
  1334     //   * if 'end' is < 0, then all KeyEvents from 'start' to the end of the
       
  1335     //     queue will be removed
       
  1336     private void purgeStampedEvents(long start, long end) {
       
  1337         if (start < 0) {
       
  1338             return;
       
  1339         }
       
  1340 
       
  1341         for (Iterator<KeyEvent> iter = enqueuedKeyEvents.iterator(); iter.hasNext(); ) {
       
  1342             KeyEvent ke = iter.next();
       
  1343             long time = ke.getWhen();
       
  1344 
       
  1345             if (start < time && (end < 0 || time <= end)) {
       
  1346                 iter.remove();
       
  1347             }
       
  1348 
       
  1349             if (end >= 0 && time > end) {
       
  1350                 break;
       
  1351             }
       
  1352         }
       
  1353     }
       
  1354 
       
  1355     /**
       
  1356      * Focuses the Component before aComponent, typically based on a
       
  1357      * FocusTraversalPolicy.
       
  1358      *
       
  1359      * @param aComponent the Component that is the basis for the focus
       
  1360      *        traversal operation
       
  1361      * @see FocusTraversalPolicy
       
  1362      * @see Component#transferFocusBackward
       
  1363      */
       
  1364     public void focusPreviousComponent(Component aComponent) {
       
  1365         if (aComponent != null) {
       
  1366             aComponent.transferFocusBackward();
       
  1367         }
       
  1368     }
       
  1369 
       
  1370     /**
       
  1371      * Focuses the Component after aComponent, typically based on a
       
  1372      * FocusTraversalPolicy.
       
  1373      *
       
  1374      * @param aComponent the Component that is the basis for the focus
       
  1375      *        traversal operation
       
  1376      * @see FocusTraversalPolicy
       
  1377      * @see Component#transferFocus
       
  1378      */
       
  1379     public void focusNextComponent(Component aComponent) {
       
  1380         if (aComponent != null) {
       
  1381             aComponent.transferFocus();
       
  1382         }
       
  1383     }
       
  1384 
       
  1385     /**
       
  1386      * Moves the focus up one focus traversal cycle. Typically, the focus owner
       
  1387      * is set to aComponent's focus cycle root, and the current focus cycle
       
  1388      * root is set to the new focus owner's focus cycle root. If, however,
       
  1389      * aComponent's focus cycle root is a Window, then the focus owner is set
       
  1390      * to the focus cycle root's default Component to focus, and the current
       
  1391      * focus cycle root is unchanged.
       
  1392      *
       
  1393      * @param aComponent the Component that is the basis for the focus
       
  1394      *        traversal operation
       
  1395      * @see Component#transferFocusUpCycle
       
  1396      */
       
  1397     public void upFocusCycle(Component aComponent) {
       
  1398         if (aComponent != null) {
       
  1399             aComponent.transferFocusUpCycle();
       
  1400         }
       
  1401     }
       
  1402 
       
  1403     /**
       
  1404      * Moves the focus down one focus traversal cycle. If aContainer is a focus
       
  1405      * cycle root, then the focus owner is set to aContainer's default
       
  1406      * Component to focus, and the current focus cycle root is set to
       
  1407      * aContainer. If aContainer is not a focus cycle root, then no focus
       
  1408      * traversal operation occurs.
       
  1409      *
       
  1410      * @param aContainer the Container that is the basis for the focus
       
  1411      *        traversal operation
       
  1412      * @see Container#transferFocusDownCycle
       
  1413      */
       
  1414     public void downFocusCycle(Container aContainer) {
       
  1415         if (aContainer != null && aContainer.isFocusCycleRoot()) {
       
  1416             aContainer.transferFocusDownCycle();
       
  1417         }
       
  1418     }
       
  1419 }