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