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