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