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