Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/awt/DefaultKeyboardFocusManager.java
38829 views
/*1* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package java.awt;2526import java.awt.event.FocusEvent;27import java.awt.event.KeyEvent;28import java.awt.event.WindowEvent;29import java.awt.peer.ComponentPeer;30import java.awt.peer.LightweightPeer;31import java.lang.ref.WeakReference;32import java.util.Iterator;33import java.util.LinkedList;34import java.util.ListIterator;35import java.util.Set;3637import sun.awt.AWTAccessor;38import sun.awt.AppContext;39import sun.awt.CausedFocusEvent;40import sun.awt.SunToolkit;41import sun.awt.TimedWindowEvent;42import sun.util.logging.PlatformLogger;4344/**45* The default KeyboardFocusManager for AWT applications. Focus traversal is46* done in response to a Component's focus traversal keys, and using a47* Container's FocusTraversalPolicy.48* <p>49* Please see50* <a href="https://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html">51* How to Use the Focus Subsystem</a>,52* a section in <em>The Java Tutorial</em>, and the53* <a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a>54* for more information.55*56* @author David Mendenhall57*58* @see FocusTraversalPolicy59* @see Component#setFocusTraversalKeys60* @see Component#getFocusTraversalKeys61* @since 1.462*/63public class DefaultKeyboardFocusManager extends KeyboardFocusManager {64private static final PlatformLogger focusLog = PlatformLogger.getLogger("java.awt.focus.DefaultKeyboardFocusManager");6566// null weak references to not create too many objects67private static final WeakReference<Window> NULL_WINDOW_WR =68new WeakReference<Window>(null);69private static final WeakReference<Component> NULL_COMPONENT_WR =70new WeakReference<Component>(null);71private WeakReference<Window> realOppositeWindowWR = NULL_WINDOW_WR;72private WeakReference<Component> realOppositeComponentWR = NULL_COMPONENT_WR;73private int inSendMessage;74private LinkedList<KeyEvent> enqueuedKeyEvents = new LinkedList<KeyEvent>();75private LinkedList<TypeAheadMarker> typeAheadMarkers = new LinkedList<TypeAheadMarker>();76private boolean consumeNextKeyTyped;77private Component restoreFocusTo;7879static {80AWTAccessor.setDefaultKeyboardFocusManagerAccessor(81new AWTAccessor.DefaultKeyboardFocusManagerAccessor() {82public void consumeNextKeyTyped(DefaultKeyboardFocusManager dkfm, KeyEvent e) {83dkfm.consumeNextKeyTyped(e);84}85});86}8788private static class TypeAheadMarker {89long after;90Component untilFocused;9192TypeAheadMarker(long after, Component untilFocused) {93this.after = after;94this.untilFocused = untilFocused;95}96/**97* Returns string representation of the marker98*/99public String toString() {100return ">>> Marker after " + after + " on " + untilFocused;101}102}103104private Window getOwningFrameDialog(Window window) {105while (window != null && !(window instanceof Frame ||106window instanceof Dialog)) {107window = (Window)window.getParent();108}109return window;110}111112/*113* This series of restoreFocus methods is used for recovering from a114* rejected focus or activation change. Rejections typically occur when115* the user attempts to focus a non-focusable Component or Window.116*/117private void restoreFocus(FocusEvent fe, Window newFocusedWindow) {118Component realOppositeComponent = this.realOppositeComponentWR.get();119Component vetoedComponent = fe.getComponent();120121if (newFocusedWindow != null && restoreFocus(newFocusedWindow,122vetoedComponent, false))123{124} else if (realOppositeComponent != null &&125doRestoreFocus(realOppositeComponent, vetoedComponent, false)) {126} else if (fe.getOppositeComponent() != null &&127doRestoreFocus(fe.getOppositeComponent(), vetoedComponent, false)) {128} else {129clearGlobalFocusOwnerPriv();130}131}132private void restoreFocus(WindowEvent we) {133Window realOppositeWindow = this.realOppositeWindowWR.get();134if (realOppositeWindow != null135&& restoreFocus(realOppositeWindow, null, false))136{137// do nothing, everything is done in restoreFocus()138} else if (we.getOppositeWindow() != null &&139restoreFocus(we.getOppositeWindow(), null, false))140{141// do nothing, everything is done in restoreFocus()142} else {143clearGlobalFocusOwnerPriv();144}145}146private boolean restoreFocus(Window aWindow, Component vetoedComponent,147boolean clearOnFailure) {148restoreFocusTo = null;149Component toFocus =150KeyboardFocusManager.getMostRecentFocusOwner(aWindow);151152if (toFocus != null && toFocus != vetoedComponent) {153if (getHeavyweight(aWindow) != getNativeFocusOwner()) {154// cannot restore focus synchronously155if (!toFocus.isShowing() || !toFocus.canBeFocusOwner()) {156toFocus = toFocus.getNextFocusCandidate();157}158if (toFocus != null && toFocus != vetoedComponent) {159if (!toFocus.requestFocus(false,160CausedFocusEvent.Cause.ROLLBACK)) {161restoreFocusTo = toFocus;162}163return true;164}165} else if (doRestoreFocus(toFocus, vetoedComponent, false)) {166return true;167}168}169if (clearOnFailure) {170clearGlobalFocusOwnerPriv();171return true;172} else {173return false;174}175}176private boolean restoreFocus(Component toFocus, boolean clearOnFailure) {177return doRestoreFocus(toFocus, null, clearOnFailure);178}179private boolean doRestoreFocus(Component toFocus, Component vetoedComponent,180boolean clearOnFailure)181{182boolean success = true;183if (toFocus != vetoedComponent && toFocus.isShowing() && toFocus.canBeFocusOwner() &&184(success = toFocus.requestFocus(false, CausedFocusEvent.Cause.ROLLBACK)))185{186return true;187} else {188if (!success && getGlobalFocusedWindow() != SunToolkit.getContainingWindow(toFocus)) {189restoreFocusTo = toFocus;190return true;191}192Component nextFocus = toFocus.getNextFocusCandidate();193if (nextFocus != null && nextFocus != vetoedComponent &&194nextFocus.requestFocusInWindow(CausedFocusEvent.Cause.ROLLBACK))195{196return true;197} else if (clearOnFailure) {198clearGlobalFocusOwnerPriv();199return true;200} else {201return false;202}203}204}205206/**207* A special type of SentEvent which updates a counter in the target208* KeyboardFocusManager if it is an instance of209* DefaultKeyboardFocusManager.210*/211private static class DefaultKeyboardFocusManagerSentEvent212extends SentEvent213{214/*215* serialVersionUID216*/217private static final long serialVersionUID = -2924743257508701758L;218219public DefaultKeyboardFocusManagerSentEvent(AWTEvent nested,220AppContext toNotify) {221super(nested, toNotify);222}223public final void dispatch() {224KeyboardFocusManager manager =225KeyboardFocusManager.getCurrentKeyboardFocusManager();226DefaultKeyboardFocusManager defaultManager =227(manager instanceof DefaultKeyboardFocusManager)228? (DefaultKeyboardFocusManager)manager229: null;230231if (defaultManager != null) {232synchronized (defaultManager) {233defaultManager.inSendMessage++;234}235}236237super.dispatch();238239if (defaultManager != null) {240synchronized (defaultManager) {241defaultManager.inSendMessage--;242}243}244}245}246247/**248* Sends a synthetic AWTEvent to a Component. If the Component is in249* the current AppContext, then the event is immediately dispatched.250* If the Component is in a different AppContext, then the event is251* posted to the other AppContext's EventQueue, and this method blocks252* until the event is handled or target AppContext is disposed.253* Returns true if successfuly dispatched event, false if failed254* to dispatch.255*/256static boolean sendMessage(Component target, AWTEvent e) {257e.isPosted = true;258AppContext myAppContext = AppContext.getAppContext();259final AppContext targetAppContext = target.appContext;260final SentEvent se =261new DefaultKeyboardFocusManagerSentEvent(e, myAppContext);262263if (myAppContext == targetAppContext) {264se.dispatch();265} else {266if (targetAppContext.isDisposed()) {267return false;268}269SunToolkit.postEvent(targetAppContext, se);270if (EventQueue.isDispatchThread()) {271EventDispatchThread edt = (EventDispatchThread)272Thread.currentThread();273edt.pumpEvents(SentEvent.ID, new Conditional() {274public boolean evaluate() {275return !se.dispatched && !targetAppContext.isDisposed();276}277});278} else {279synchronized (se) {280while (!se.dispatched && !targetAppContext.isDisposed()) {281try {282se.wait(1000);283} catch (InterruptedException ie) {284break;285}286}287}288}289}290return se.dispatched;291}292293/*294* Checks if the focus window event follows key events waiting in the type-ahead295* queue (if any). This may happen when a user types ahead in the window, the client296* listeners hang EDT for a while, and the user switches b/w toplevels. In that297* case the focus window events may be dispatched before the type-ahead events298* get handled. This may lead to wrong focus behavior and in order to avoid it,299* the focus window events are reposted to the end of the event queue. See 6981400.300*/301private boolean repostIfFollowsKeyEvents(WindowEvent e) {302if (!(e instanceof TimedWindowEvent)) {303return false;304}305TimedWindowEvent we = (TimedWindowEvent)e;306long time = we.getWhen();307synchronized (this) {308KeyEvent ke = enqueuedKeyEvents.isEmpty() ? null : enqueuedKeyEvents.getFirst();309if (ke != null && time >= ke.getWhen()) {310TypeAheadMarker marker = typeAheadMarkers.isEmpty() ? null : typeAheadMarkers.getFirst();311if (marker != null) {312Window toplevel = marker.untilFocused.getContainingWindow();313// Check that the component awaiting focus belongs to314// the current focused window. See 8015454.315if (toplevel != null && toplevel.isFocused()) {316SunToolkit.postEvent(AppContext.getAppContext(), new SequencedEvent(e));317return true;318}319}320}321}322return false;323}324325/**326* This method is called by the AWT event dispatcher requesting that the327* current KeyboardFocusManager dispatch the specified event on its behalf.328* DefaultKeyboardFocusManagers dispatch all FocusEvents, all WindowEvents329* related to focus, and all KeyEvents. These events are dispatched based330* on the KeyboardFocusManager's notion of the focus owner and the focused331* and active Windows, sometimes overriding the source of the specified332* AWTEvent. If this method returns <code>false</code>, then the AWT event333* dispatcher will attempt to dispatch the event itself.334*335* @param e the AWTEvent to be dispatched336* @return <code>true</code> if this method dispatched the event;337* <code>false</code> otherwise338*/339public boolean dispatchEvent(AWTEvent e) {340if (focusLog.isLoggable(PlatformLogger.Level.FINE) && (e instanceof WindowEvent || e instanceof FocusEvent)) {341focusLog.fine("" + e);342}343switch (e.getID()) {344case WindowEvent.WINDOW_GAINED_FOCUS: {345if (repostIfFollowsKeyEvents((WindowEvent)e)) {346break;347}348349WindowEvent we = (WindowEvent)e;350Window oldFocusedWindow = getGlobalFocusedWindow();351Window newFocusedWindow = we.getWindow();352if (newFocusedWindow == oldFocusedWindow) {353break;354}355356if (!(newFocusedWindow.isFocusableWindow()357&& newFocusedWindow.isVisible()358&& newFocusedWindow.isDisplayable()))359{360// we can not accept focus on such window, so reject it.361restoreFocus(we);362break;363}364// If there exists a current focused window, then notify it365// that it has lost focus.366if (oldFocusedWindow != null) {367boolean isEventDispatched =368sendMessage(oldFocusedWindow,369new WindowEvent(oldFocusedWindow,370WindowEvent.WINDOW_LOST_FOCUS,371newFocusedWindow));372// Failed to dispatch, clear by ourselfves373if (!isEventDispatched) {374setGlobalFocusOwner(null);375setGlobalFocusedWindow(null);376}377}378379// Because the native libraries do not post WINDOW_ACTIVATED380// events, we need to synthesize one if the active Window381// changed.382Window newActiveWindow =383getOwningFrameDialog(newFocusedWindow);384Window currentActiveWindow = getGlobalActiveWindow();385if (newActiveWindow != currentActiveWindow) {386sendMessage(newActiveWindow,387new WindowEvent(newActiveWindow,388WindowEvent.WINDOW_ACTIVATED,389currentActiveWindow));390if (newActiveWindow != getGlobalActiveWindow()) {391// Activation change was rejected. Unlikely, but392// possible.393restoreFocus(we);394break;395}396}397398setGlobalFocusedWindow(newFocusedWindow);399400if (newFocusedWindow != getGlobalFocusedWindow()) {401// Focus change was rejected. Will happen if402// newFocusedWindow is not a focusable Window.403restoreFocus(we);404break;405}406407// Restore focus to the Component which last held it. We do408// this here so that client code can override our choice in409// a WINDOW_GAINED_FOCUS handler.410//411// Make sure that the focus change request doesn't change the412// focused Window in case we are no longer the focused Window413// when the request is handled.414if (inSendMessage == 0) {415// Identify which Component should initially gain focus416// in the Window.417//418// * If we're in SendMessage, then this is a synthetic419// WINDOW_GAINED_FOCUS message which was generated by a420// the FOCUS_GAINED handler. Allow the Component to421// which the FOCUS_GAINED message was targeted to422// receive the focus.423// * Otherwise, look up the correct Component here.424// We don't use Window.getMostRecentFocusOwner because425// window is focused now and 'null' will be returned426427428// Calculating of most recent focus owner and focus429// request should be synchronized on KeyboardFocusManager.class430// to prevent from thread race when user will request431// focus between calculation and our request.432// But if focus transfer is synchronous, this synchronization433// may cause deadlock, thus we don't synchronize this block.434Component toFocus = KeyboardFocusManager.435getMostRecentFocusOwner(newFocusedWindow);436boolean isFocusRestore = restoreFocusTo != null &&437toFocus == restoreFocusTo;438if ((toFocus == null) &&439newFocusedWindow.isFocusableWindow())440{441toFocus = newFocusedWindow.getFocusTraversalPolicy().442getInitialComponent(newFocusedWindow);443}444Component tempLost = null;445synchronized(KeyboardFocusManager.class) {446tempLost = newFocusedWindow.setTemporaryLostComponent(null);447}448449// The component which last has the focus when this window was focused450// should receive focus first451if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {452focusLog.finer("tempLost {0}, toFocus {1}",453tempLost, toFocus);454}455if (tempLost != null) {456tempLost.requestFocusInWindow(457isFocusRestore && tempLost == toFocus ?458CausedFocusEvent.Cause.ROLLBACK :459CausedFocusEvent.Cause.ACTIVATION);460}461462if (toFocus != null && toFocus != tempLost) {463// If there is a component which requested focus when this window464// was inactive it expects to receive focus after activation.465toFocus.requestFocusInWindow(CausedFocusEvent.Cause.ACTIVATION);466}467}468restoreFocusTo = null;469470Window realOppositeWindow = this.realOppositeWindowWR.get();471if (realOppositeWindow != we.getOppositeWindow()) {472we = new WindowEvent(newFocusedWindow,473WindowEvent.WINDOW_GAINED_FOCUS,474realOppositeWindow);475}476return typeAheadAssertions(newFocusedWindow, we);477}478479case WindowEvent.WINDOW_ACTIVATED: {480WindowEvent we = (WindowEvent)e;481Window oldActiveWindow = getGlobalActiveWindow();482Window newActiveWindow = we.getWindow();483if (oldActiveWindow == newActiveWindow) {484break;485}486487// If there exists a current active window, then notify it that488// it has lost activation.489if (oldActiveWindow != null) {490boolean isEventDispatched =491sendMessage(oldActiveWindow,492new WindowEvent(oldActiveWindow,493WindowEvent.WINDOW_DEACTIVATED,494newActiveWindow));495// Failed to dispatch, clear by ourselfves496if (!isEventDispatched) {497setGlobalActiveWindow(null);498}499if (getGlobalActiveWindow() != null) {500// Activation change was rejected. Unlikely, but501// possible.502break;503}504}505506setGlobalActiveWindow(newActiveWindow);507508if (newActiveWindow != getGlobalActiveWindow()) {509// Activation change was rejected. Unlikely, but510// possible.511break;512}513514return typeAheadAssertions(newActiveWindow, we);515}516517case FocusEvent.FOCUS_GAINED: {518restoreFocusTo = null;519FocusEvent fe = (FocusEvent)e;520CausedFocusEvent.Cause cause = (fe instanceof CausedFocusEvent) ?521((CausedFocusEvent)fe).getCause() : CausedFocusEvent.Cause.UNKNOWN;522Component oldFocusOwner = getGlobalFocusOwner();523Component newFocusOwner = fe.getComponent();524if (oldFocusOwner == newFocusOwner) {525if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {526focusLog.fine("Skipping {0} because focus owner is the same", e);527}528// We can't just drop the event - there could be529// type-ahead markers associated with it.530dequeueKeyEvents(-1, newFocusOwner);531break;532}533534// If there exists a current focus owner, then notify it that535// it has lost focus.536if (oldFocusOwner != null) {537boolean isEventDispatched =538sendMessage(oldFocusOwner,539new CausedFocusEvent(oldFocusOwner,540FocusEvent.FOCUS_LOST,541fe.isTemporary(),542newFocusOwner, cause));543// Failed to dispatch, clear by ourselfves544if (!isEventDispatched) {545setGlobalFocusOwner(null);546if (!fe.isTemporary()) {547setGlobalPermanentFocusOwner(null);548}549}550}551552// Because the native windowing system has a different notion553// of the current focus and activation states, it is possible554// that a Component outside of the focused Window receives a555// FOCUS_GAINED event. We synthesize a WINDOW_GAINED_FOCUS556// event in that case.557final Window newFocusedWindow = SunToolkit.getContainingWindow(newFocusOwner);558final Window currentFocusedWindow = getGlobalFocusedWindow();559if (newFocusedWindow != null &&560newFocusedWindow != currentFocusedWindow)561{562sendMessage(newFocusedWindow,563new WindowEvent(newFocusedWindow,564WindowEvent.WINDOW_GAINED_FOCUS,565currentFocusedWindow));566if (newFocusedWindow != getGlobalFocusedWindow()) {567// Focus change was rejected. Will happen if568// newFocusedWindow is not a focusable Window.569570// Need to recover type-ahead, but don't bother571// restoring focus. That was done by the572// WINDOW_GAINED_FOCUS handler573dequeueKeyEvents(-1, newFocusOwner);574break;575}576}577578if (!(newFocusOwner.isFocusable() && newFocusOwner.isShowing() &&579// Refuse focus on a disabled component if the focus event580// isn't of UNKNOWN reason (i.e. not a result of a direct request581// but traversal, activation or system generated).582(newFocusOwner.isEnabled() || cause.equals(CausedFocusEvent.Cause.UNKNOWN))))583{584// we should not accept focus on such component, so reject it.585dequeueKeyEvents(-1, newFocusOwner);586if (KeyboardFocusManager.isAutoFocusTransferEnabled()) {587// If FOCUS_GAINED is for a disposed component (however588// it shouldn't happen) its toplevel parent is null. In this589// case we have to try to restore focus in the current focused590// window (for the details: 6607170).591if (newFocusedWindow == null) {592restoreFocus(fe, currentFocusedWindow);593} else {594restoreFocus(fe, newFocusedWindow);595}596setMostRecentFocusOwner(newFocusedWindow, null); // see: 8013773597}598break;599}600601setGlobalFocusOwner(newFocusOwner);602603if (newFocusOwner != getGlobalFocusOwner()) {604// Focus change was rejected. Will happen if605// newFocusOwner is not focus traversable.606dequeueKeyEvents(-1, newFocusOwner);607if (KeyboardFocusManager.isAutoFocusTransferEnabled()) {608restoreFocus(fe, (Window)newFocusedWindow);609}610break;611}612613if (!fe.isTemporary()) {614setGlobalPermanentFocusOwner(newFocusOwner);615616if (newFocusOwner != getGlobalPermanentFocusOwner()) {617// Focus change was rejected. Unlikely, but possible.618dequeueKeyEvents(-1, newFocusOwner);619if (KeyboardFocusManager.isAutoFocusTransferEnabled()) {620restoreFocus(fe, (Window)newFocusedWindow);621}622break;623}624}625626setNativeFocusOwner(getHeavyweight(newFocusOwner));627628Component realOppositeComponent = this.realOppositeComponentWR.get();629if (realOppositeComponent != null &&630realOppositeComponent != fe.getOppositeComponent()) {631fe = new CausedFocusEvent(newFocusOwner,632FocusEvent.FOCUS_GAINED,633fe.isTemporary(),634realOppositeComponent, cause);635((AWTEvent) fe).isPosted = true;636}637return typeAheadAssertions(newFocusOwner, fe);638}639640case FocusEvent.FOCUS_LOST: {641FocusEvent fe = (FocusEvent)e;642Component currentFocusOwner = getGlobalFocusOwner();643if (currentFocusOwner == null) {644if (focusLog.isLoggable(PlatformLogger.Level.FINE))645focusLog.fine("Skipping {0} because focus owner is null", e);646break;647}648// Ignore cases where a Component loses focus to itself.649// If we make a mistake because of retargeting, then the650// FOCUS_GAINED handler will correct it.651if (currentFocusOwner == fe.getOppositeComponent()) {652if (focusLog.isLoggable(PlatformLogger.Level.FINE))653focusLog.fine("Skipping {0} because current focus owner is equal to opposite", e);654break;655}656657setGlobalFocusOwner(null);658659if (getGlobalFocusOwner() != null) {660// Focus change was rejected. Unlikely, but possible.661restoreFocus(currentFocusOwner, true);662break;663}664665if (!fe.isTemporary()) {666setGlobalPermanentFocusOwner(null);667668if (getGlobalPermanentFocusOwner() != null) {669// Focus change was rejected. Unlikely, but possible.670restoreFocus(currentFocusOwner, true);671break;672}673} else {674Window owningWindow = currentFocusOwner.getContainingWindow();675if (owningWindow != null) {676owningWindow.setTemporaryLostComponent(currentFocusOwner);677}678}679680setNativeFocusOwner(null);681682fe.setSource(currentFocusOwner);683684realOppositeComponentWR = (fe.getOppositeComponent() != null)685? new WeakReference<Component>(currentFocusOwner)686: NULL_COMPONENT_WR;687688return typeAheadAssertions(currentFocusOwner, fe);689}690691case WindowEvent.WINDOW_DEACTIVATED: {692WindowEvent we = (WindowEvent)e;693Window currentActiveWindow = getGlobalActiveWindow();694if (currentActiveWindow == null) {695break;696}697698if (currentActiveWindow != e.getSource()) {699// The event is lost in time.700// Allow listeners to precess the event but do not701// change any global states702break;703}704705setGlobalActiveWindow(null);706if (getGlobalActiveWindow() != null) {707// Activation change was rejected. Unlikely, but possible.708break;709}710711we.setSource(currentActiveWindow);712return typeAheadAssertions(currentActiveWindow, we);713}714715case WindowEvent.WINDOW_LOST_FOCUS: {716if (repostIfFollowsKeyEvents((WindowEvent)e)) {717break;718}719720WindowEvent we = (WindowEvent)e;721Window currentFocusedWindow = getGlobalFocusedWindow();722Window losingFocusWindow = we.getWindow();723Window activeWindow = getGlobalActiveWindow();724Window oppositeWindow = we.getOppositeWindow();725if (focusLog.isLoggable(PlatformLogger.Level.FINE))726focusLog.fine("Active {0}, Current focused {1}, losing focus {2} opposite {3}",727activeWindow, currentFocusedWindow,728losingFocusWindow, oppositeWindow);729if (currentFocusedWindow == null) {730break;731}732733// Special case -- if the native windowing system posts an734// event claiming that the active Window has lost focus to the735// focused Window, then discard the event. This is an artifact736// of the native windowing system not knowing which Window is737// really focused.738if (inSendMessage == 0 && losingFocusWindow == activeWindow &&739oppositeWindow == currentFocusedWindow)740{741break;742}743744Component currentFocusOwner = getGlobalFocusOwner();745if (currentFocusOwner != null) {746// The focus owner should always receive a FOCUS_LOST event747// before the Window is defocused.748Component oppositeComp = null;749if (oppositeWindow != null) {750oppositeComp = oppositeWindow.getTemporaryLostComponent();751if (oppositeComp == null) {752oppositeComp = oppositeWindow.getMostRecentFocusOwner();753}754}755if (oppositeComp == null) {756oppositeComp = oppositeWindow;757}758sendMessage(currentFocusOwner,759new CausedFocusEvent(currentFocusOwner,760FocusEvent.FOCUS_LOST,761true,762oppositeComp, CausedFocusEvent.Cause.ACTIVATION));763}764765setGlobalFocusedWindow(null);766if (getGlobalFocusedWindow() != null) {767// Focus change was rejected. Unlikely, but possible.768restoreFocus(currentFocusedWindow, null, true);769break;770}771772we.setSource(currentFocusedWindow);773realOppositeWindowWR = (oppositeWindow != null)774? new WeakReference<Window>(currentFocusedWindow)775: NULL_WINDOW_WR;776typeAheadAssertions(currentFocusedWindow, we);777778if (oppositeWindow == null && activeWindow != null) {779// Then we need to deactive the active Window as well.780// No need to synthesize in other cases, because781// WINDOW_ACTIVATED will handle it if necessary.782sendMessage(activeWindow,783new WindowEvent(activeWindow,784WindowEvent.WINDOW_DEACTIVATED,785null));786if (getGlobalActiveWindow() != null) {787// Activation change was rejected. Unlikely,788// but possible.789restoreFocus(currentFocusedWindow, null, true);790}791}792break;793}794795case KeyEvent.KEY_TYPED:796case KeyEvent.KEY_PRESSED:797case KeyEvent.KEY_RELEASED:798return typeAheadAssertions(null, e);799800default:801return false;802}803804return true;805}806807/**808* Called by <code>dispatchEvent</code> if no other809* KeyEventDispatcher in the dispatcher chain dispatched the KeyEvent, or810* if no other KeyEventDispatchers are registered. If the event has not811* been consumed, its target is enabled, and the focus owner is not null,812* this method dispatches the event to its target. This method will also813* subsequently dispatch the event to all registered814* KeyEventPostProcessors. After all this operations are finished,815* the event is passed to peers for processing.816* <p>817* In all cases, this method returns <code>true</code>, since818* DefaultKeyboardFocusManager is designed so that neither819* <code>dispatchEvent</code>, nor the AWT event dispatcher, should take820* further action on the event in any situation.821*822* @param e the KeyEvent to be dispatched823* @return <code>true</code>824* @see Component#dispatchEvent825*/826public boolean dispatchKeyEvent(KeyEvent e) {827Component focusOwner = (((AWTEvent)e).isPosted) ? getFocusOwner() : e.getComponent();828829if (focusOwner != null && focusOwner.isShowing() && focusOwner.canBeFocusOwner()) {830if (!e.isConsumed()) {831Component comp = e.getComponent();832if (comp != null && comp.isEnabled()) {833redispatchEvent(comp, e);834}835}836}837boolean stopPostProcessing = false;838java.util.List<KeyEventPostProcessor> processors = getKeyEventPostProcessors();839if (processors != null) {840for (java.util.Iterator<KeyEventPostProcessor> iter = processors.iterator();841!stopPostProcessing && iter.hasNext(); )842{843stopPostProcessing = iter.next().844postProcessKeyEvent(e);845}846}847if (!stopPostProcessing) {848postProcessKeyEvent(e);849}850851// Allow the peer to process KeyEvent852Component source = e.getComponent();853ComponentPeer peer = source.getPeer();854855if (peer == null || peer instanceof LightweightPeer) {856// if focus owner is lightweight then its native container857// processes event858Container target = source.getNativeContainer();859if (target != null) {860peer = target.getPeer();861}862}863if (peer != null) {864peer.handleEvent(e);865}866867return true;868}869870/**871* This method will be called by <code>dispatchKeyEvent</code>. It will872* handle any unconsumed KeyEvents that map to an AWT873* <code>MenuShortcut</code> by consuming the event and activating the874* shortcut.875*876* @param e the KeyEvent to post-process877* @return <code>true</code>878* @see #dispatchKeyEvent879* @see MenuShortcut880*/881public boolean postProcessKeyEvent(KeyEvent e) {882if (!e.isConsumed()) {883Component target = e.getComponent();884Container p = (Container)885(target instanceof Container ? target : target.getParent());886if (p != null) {887p.postProcessKeyEvent(e);888}889}890return true;891}892893private void pumpApprovedKeyEvents() {894KeyEvent ke;895do {896ke = null;897synchronized (this) {898if (enqueuedKeyEvents.size() != 0) {899ke = enqueuedKeyEvents.getFirst();900if (typeAheadMarkers.size() != 0) {901TypeAheadMarker marker = typeAheadMarkers.getFirst();902// Fixed 5064013: may appears that the events have the same time903// if (ke.getWhen() >= marker.after) {904// The fix is rolled out.905906if (ke.getWhen() > marker.after) {907ke = null;908}909}910if (ke != null) {911if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {912focusLog.finer("Pumping approved event {0}", ke);913}914enqueuedKeyEvents.removeFirst();915}916}917}918if (ke != null) {919preDispatchKeyEvent(ke);920}921} while (ke != null);922}923924/**925* Dumps the list of type-ahead queue markers to stderr926*/927void dumpMarkers() {928if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) {929focusLog.finest(">>> Markers dump, time: {0}", System.currentTimeMillis());930synchronized (this) {931if (typeAheadMarkers.size() != 0) {932Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator();933while (iter.hasNext()) {934TypeAheadMarker marker = iter.next();935focusLog.finest(" {0}", marker);936}937}938}939}940}941942private boolean typeAheadAssertions(Component target, AWTEvent e) {943944// Clear any pending events here as well as in the FOCUS_GAINED945// handler. We need this call here in case a marker was removed in946// response to a call to dequeueKeyEvents.947pumpApprovedKeyEvents();948949switch (e.getID()) {950case KeyEvent.KEY_TYPED:951case KeyEvent.KEY_PRESSED:952case KeyEvent.KEY_RELEASED: {953KeyEvent ke = (KeyEvent)e;954synchronized (this) {955if (e.isPosted && typeAheadMarkers.size() != 0) {956TypeAheadMarker marker = typeAheadMarkers.getFirst();957// Fixed 5064013: may appears that the events have the same time958// if (ke.getWhen() >= marker.after) {959// The fix is rolled out.960961if (ke.getWhen() > marker.after) {962if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {963focusLog.finer("Storing event {0} because of marker {1}", ke, marker);964}965enqueuedKeyEvents.addLast(ke);966return true;967}968}969}970971// KeyEvent was posted before focus change request972return preDispatchKeyEvent(ke);973}974975case FocusEvent.FOCUS_GAINED:976if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) {977focusLog.finest("Markers before FOCUS_GAINED on {0}", target);978}979dumpMarkers();980// Search the marker list for the first marker tied to981// the Component which just gained focus. Then remove982// that marker, any markers which immediately follow983// and are tied to the same component, and all markers984// that preceed it. This handles the case where985// multiple focus requests were made for the same986// Component in a row and when we lost some of the987// earlier requests. Since FOCUS_GAINED events will988// not be generated for these additional requests, we989// need to clear those markers too.990synchronized (this) {991boolean found = false;992if (hasMarker(target)) {993for (Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator();994iter.hasNext(); )995{996if (iter.next().untilFocused == target) {997found = true;998} else if (found) {999break;1000}1001iter.remove();1002}1003} else {1004// Exception condition - event without marker1005if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {1006focusLog.finer("Event without marker {0}", e);1007}1008}1009}1010focusLog.finest("Markers after FOCUS_GAINED");1011dumpMarkers();10121013redispatchEvent(target, e);10141015// Now, dispatch any pending KeyEvents which have been1016// released because of the FOCUS_GAINED event so that we don't1017// have to wait for another event to be posted to the queue.1018pumpApprovedKeyEvents();1019return true;10201021default:1022redispatchEvent(target, e);1023return true;1024}1025}10261027/**1028* Returns true if there are some marker associated with component <code>comp</code>1029* in a markers' queue1030* @since 1.51031*/1032private boolean hasMarker(Component comp) {1033for (Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator(); iter.hasNext(); ) {1034if (iter.next().untilFocused == comp) {1035return true;1036}1037}1038return false;1039}10401041/**1042* Clears markers queue1043* @since 1.51044*/1045void clearMarkers() {1046synchronized(this) {1047typeAheadMarkers.clear();1048}1049}10501051private boolean preDispatchKeyEvent(KeyEvent ke) {1052if (((AWTEvent) ke).isPosted) {1053Component focusOwner = getFocusOwner();1054ke.setSource(((focusOwner != null) ? focusOwner : getFocusedWindow()));1055}1056if (ke.getSource() == null) {1057return true;1058}10591060// 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 registered1063// until its dispatching actually starts (by this method).1064EventQueue.setCurrentEventAndMostRecentTime(ke);10651066/**1067* Fix for 4495473.1068* This fix allows to correctly dispatch events when native1069* event proxying mechanism is active.1070* If it is active we should redispatch key events after1071* we detected its correct target.1072*/1073if (KeyboardFocusManager.isProxyActive(ke)) {1074Component source = (Component)ke.getSource();1075Container target = source.getNativeContainer();1076if (target != null) {1077ComponentPeer peer = target.getPeer();1078if (peer != null) {1079peer.handleEvent(ke);1080/**1081* Fix for 4478780 - consume event after it was dispatched by peer.1082*/1083ke.consume();1084}1085}1086return true;1087}10881089java.util.List<KeyEventDispatcher> dispatchers = getKeyEventDispatchers();1090if (dispatchers != null) {1091for (java.util.Iterator<KeyEventDispatcher> iter = dispatchers.iterator();1092iter.hasNext(); )1093{1094if (iter.next().1095dispatchKeyEvent(ke))1096{1097return true;1098}1099}1100}1101return dispatchKeyEvent(ke);1102}11031104/*1105* @param e is a KEY_PRESSED event that can be used1106* to track the next KEY_TYPED related.1107*/1108private void consumeNextKeyTyped(KeyEvent e) {1109consumeNextKeyTyped = true;1110}11111112private void consumeTraversalKey(KeyEvent e) {1113e.consume();1114consumeNextKeyTyped = (e.getID() == KeyEvent.KEY_PRESSED) &&1115!e.isActionKey();1116}11171118/*1119* return true if event was consumed1120*/1121private boolean consumeProcessedKeyEvent(KeyEvent e) {1122if ((e.getID() == KeyEvent.KEY_TYPED) && consumeNextKeyTyped) {1123e.consume();1124consumeNextKeyTyped = false;1125return true;1126}1127return false;1128}11291130/**1131* This method initiates a focus traversal operation if and only if the1132* KeyEvent represents a focus traversal key for the specified1133* focusedComponent. It is expected that focusedComponent is the current1134* focus owner, although this need not be the case. If it is not,1135* focus traversal will nevertheless proceed as if focusedComponent1136* were the focus owner.1137*1138* @param focusedComponent the Component that is the basis for a focus1139* traversal operation if the specified event represents a focus1140* traversal key for the Component1141* @param e the event that may represent a focus traversal key1142*/1143public void processKeyEvent(Component focusedComponent, KeyEvent e) {1144// consume processed event if needed1145if (consumeProcessedKeyEvent(e)) {1146return;1147}11481149// KEY_TYPED events cannot be focus traversal keys1150if (e.getID() == KeyEvent.KEY_TYPED) {1151return;1152}11531154if (focusedComponent.getFocusTraversalKeysEnabled() &&1155!e.isConsumed())1156{1157AWTKeyStroke stroke = AWTKeyStroke.getAWTKeyStrokeForEvent(e),1158oppStroke = AWTKeyStroke.getAWTKeyStroke(stroke.getKeyCode(),1159stroke.getModifiers(),1160!stroke.isOnKeyRelease());1161Set<AWTKeyStroke> toTest;1162boolean contains, containsOpp;11631164toTest = focusedComponent.getFocusTraversalKeys(1165KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);1166contains = toTest.contains(stroke);1167containsOpp = toTest.contains(oppStroke);11681169if (contains || containsOpp) {1170consumeTraversalKey(e);1171if (contains) {1172focusNextComponent(focusedComponent);1173}1174return;1175} else if (e.getID() == KeyEvent.KEY_PRESSED) {1176// Fix for 6637607: consumeNextKeyTyped should be reset.1177consumeNextKeyTyped = false;1178}11791180toTest = focusedComponent.getFocusTraversalKeys(1181KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);1182contains = toTest.contains(stroke);1183containsOpp = toTest.contains(oppStroke);11841185if (contains || containsOpp) {1186consumeTraversalKey(e);1187if (contains) {1188focusPreviousComponent(focusedComponent);1189}1190return;1191}11921193toTest = focusedComponent.getFocusTraversalKeys(1194KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);1195contains = toTest.contains(stroke);1196containsOpp = toTest.contains(oppStroke);11971198if (contains || containsOpp) {1199consumeTraversalKey(e);1200if (contains) {1201upFocusCycle(focusedComponent);1202}1203return;1204}12051206if (!((focusedComponent instanceof Container) &&1207((Container)focusedComponent).isFocusCycleRoot())) {1208return;1209}12101211toTest = focusedComponent.getFocusTraversalKeys(1212KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS);1213contains = toTest.contains(stroke);1214containsOpp = toTest.contains(oppStroke);12151216if (contains || containsOpp) {1217consumeTraversalKey(e);1218if (contains) {1219downFocusCycle((Container)focusedComponent);1220}1221}1222}1223}12241225/**1226* Delays dispatching of KeyEvents until the specified Component becomes1227* the focus owner. KeyEvents with timestamps later than the specified1228* timestamp will be enqueued until the specified Component receives a1229* FOCUS_GAINED event, or the AWT cancels the delay request by invoking1230* <code>dequeueKeyEvents</code> or <code>discardKeyEvents</code>.1231*1232* @param after timestamp of current event, or the current, system time if1233* the current event has no timestamp, or the AWT cannot determine1234* which event is currently being handled1235* @param untilFocused Component which will receive a FOCUS_GAINED event1236* before any pending KeyEvents1237* @see #dequeueKeyEvents1238* @see #discardKeyEvents1239*/1240protected synchronized void enqueueKeyEvents(long after,1241Component untilFocused) {1242if (untilFocused == null) {1243return;1244}12451246if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {1247focusLog.finer("Enqueue at {0} for {1}",1248after, untilFocused);1249}12501251int insertionIndex = 0,1252i = typeAheadMarkers.size();1253ListIterator<TypeAheadMarker> iter = typeAheadMarkers.listIterator(i);12541255for (; i > 0; i--) {1256TypeAheadMarker marker = iter.previous();1257if (marker.after <= after) {1258insertionIndex = i;1259break;1260}1261}12621263typeAheadMarkers.add(insertionIndex,1264new TypeAheadMarker(after, untilFocused));1265}12661267/**1268* Releases for normal dispatching to the current focus owner all1269* KeyEvents which were enqueued because of a call to1270* <code>enqueueKeyEvents</code> with the same timestamp and Component.1271* If the given timestamp is less than zero, the outstanding enqueue1272* request for the given Component with the <b>oldest</b> timestamp (if1273* any) should be cancelled.1274*1275* @param after the timestamp specified in the call to1276* <code>enqueueKeyEvents</code>, or any value < 01277* @param untilFocused the Component specified in the call to1278* <code>enqueueKeyEvents</code>1279* @see #enqueueKeyEvents1280* @see #discardKeyEvents1281*/1282protected synchronized void dequeueKeyEvents(long after,1283Component untilFocused) {1284if (untilFocused == null) {1285return;1286}12871288if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {1289focusLog.finer("Dequeue at {0} for {1}",1290after, untilFocused);1291}12921293TypeAheadMarker marker;1294ListIterator<TypeAheadMarker> iter = typeAheadMarkers.listIterator1295((after >= 0) ? typeAheadMarkers.size() : 0);12961297if (after < 0) {1298while (iter.hasNext()) {1299marker = iter.next();1300if (marker.untilFocused == untilFocused)1301{1302iter.remove();1303return;1304}1305}1306} else {1307while (iter.hasPrevious()) {1308marker = iter.previous();1309if (marker.untilFocused == untilFocused &&1310marker.after == after)1311{1312iter.remove();1313return;1314}1315}1316}1317}13181319/**1320* Discards all KeyEvents which were enqueued because of one or more calls1321* to <code>enqueueKeyEvents</code> with the specified Component, or one of1322* its descendants.1323*1324* @param comp the Component specified in one or more calls to1325* <code>enqueueKeyEvents</code>, or a parent of such a Component1326* @see #enqueueKeyEvents1327* @see #dequeueKeyEvents1328*/1329protected synchronized void discardKeyEvents(Component comp) {1330if (comp == null) {1331return;1332}13331334long start = -1;13351336for (Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator(); iter.hasNext(); ) {1337TypeAheadMarker marker = iter.next();1338Component toTest = marker.untilFocused;1339boolean match = (toTest == comp);1340while (!match && toTest != null && !(toTest instanceof Window)) {1341toTest = toTest.getParent();1342match = (toTest == comp);1343}1344if (match) {1345if (start < 0) {1346start = marker.after;1347}1348iter.remove();1349} else if (start >= 0) {1350purgeStampedEvents(start, marker.after);1351start = -1;1352}1353}13541355purgeStampedEvents(start, -1);1356}13571358// Notes:1359// * must be called inside a synchronized block1360// * if 'start' is < 0, then this function does nothing1361// * if 'end' is < 0, then all KeyEvents from 'start' to the end of the1362// queue will be removed1363private void purgeStampedEvents(long start, long end) {1364if (start < 0) {1365return;1366}13671368for (Iterator<KeyEvent> iter = enqueuedKeyEvents.iterator(); iter.hasNext(); ) {1369KeyEvent ke = iter.next();1370long time = ke.getWhen();13711372if (start < time && (end < 0 || time <= end)) {1373iter.remove();1374}13751376if (end >= 0 && time > end) {1377break;1378}1379}1380}13811382/**1383* Focuses the Component before aComponent, typically based on a1384* FocusTraversalPolicy.1385*1386* @param aComponent the Component that is the basis for the focus1387* traversal operation1388* @see FocusTraversalPolicy1389* @see Component#transferFocusBackward1390*/1391public void focusPreviousComponent(Component aComponent) {1392if (aComponent != null) {1393aComponent.transferFocusBackward();1394}1395}13961397/**1398* Focuses the Component after aComponent, typically based on a1399* FocusTraversalPolicy.1400*1401* @param aComponent the Component that is the basis for the focus1402* traversal operation1403* @see FocusTraversalPolicy1404* @see Component#transferFocus1405*/1406public void focusNextComponent(Component aComponent) {1407if (aComponent != null) {1408aComponent.transferFocus();1409}1410}14111412/**1413* Moves the focus up one focus traversal cycle. Typically, the focus owner1414* is set to aComponent's focus cycle root, and the current focus cycle1415* 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 set1417* to the focus cycle root's default Component to focus, and the current1418* focus cycle root is unchanged.1419*1420* @param aComponent the Component that is the basis for the focus1421* traversal operation1422* @see Component#transferFocusUpCycle1423*/1424public void upFocusCycle(Component aComponent) {1425if (aComponent != null) {1426aComponent.transferFocusUpCycle();1427}1428}14291430/**1431* Moves the focus down one focus traversal cycle. If aContainer is a focus1432* cycle root, then the focus owner is set to aContainer's default1433* Component to focus, and the current focus cycle root is set to1434* aContainer. If aContainer is not a focus cycle root, then no focus1435* traversal operation occurs.1436*1437* @param aContainer the Container that is the basis for the focus1438* traversal operation1439* @see Container#transferFocusDownCycle1440*/1441public void downFocusCycle(Container aContainer) {1442if (aContainer != null && aContainer.isFocusCycleRoot()) {1443aContainer.transferFocusDownCycle();1444}1445}1446}144714481449