/* * * Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */ package java.awt; import java.awt.event.FocusEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.WindowEvent; import java.beans.*; import java.util.Set; import java.util.HashSet; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.ListIterator; import java.util.StringTokenizer; import java.util.WeakHashMap; import java.lang.ref.WeakReference; import sun.awt.peer.LightweightPeer; import sun.awt.SunToolkit; import sun.awt.AppContext; public abstract class KeyboardFocusManager implements KeyEventDispatcher, KeyEventPostProcessor { public static final int FORWARD_TRAVERSAL_KEYS = 0; public static final int BACKWARD_TRAVERSAL_KEYS = 1; public static final int UP_CYCLE_TRAVERSAL_KEYS = 2; public static final int DOWN_CYCLE_TRAVERSAL_KEYS = 3; static final int TRAVERSAL_KEY_LENGTH = DOWN_CYCLE_TRAVERSAL_KEYS + 1; private static Component focusOwner; private static Component permanentFocusOwner; private static Window focusedWindow; private static Window activeWindow=null; private FocusTraversalPolicy defaultPolicy = new DefaultFocusTraversalPolicy(); private static final String[] defaultFocusTraversalKeyPropertyNames = { "forwardDefaultFocusTraversalKeys", "backwardDefaultFocusTraversalKeys", "upCycleDefaultFocusTraversalKeys", "downCycleDefaultFocusTraversalKeys" }; private static final String[] defaultFocusTraversalKeyStrings = { "TAB,ctrl TAB", "shift TAB,ctrl shift TAB", "", "" }; private Set[] defaultFocusTraversalKeys = new Set[4]; private static Container currentFocusCycleRoot; private VetoableChangeSupport vetoableSupport; private PropertyChangeSupport changeSupport; private java.util.LinkedList keyEventDispatchers; private java.util.LinkedList keyEventPostProcessors; private static java.util.Map mostRecentFocusOwners = new WeakHashMap(); private static final String notPrivileged = "this KeyboardFocusManager is not installed in the current thread's context"; private static AWTPermission replaceKeyboardFocusManagerPermission; static KeyboardFocusManager manager; private native void _clearGlobalFocusOwner(); static native Component getNativeFocusOwner(); static native Window getNativeFocusedWindow(); /** * Initialize JNI field and method IDs */ private static native void initIDs(); private boolean initialized=false; /* * SequencedEvent which is currently dispatched in AppContext. */ transient SequencedEvent currentSequencedEvent = null; final void setCurrentSequencedEvent(SequencedEvent current) { synchronized (SequencedEvent.class) { //assert(current == null || currentSequencedEvent == null); currentSequencedEvent = current; } } final SequencedEvent getCurrentSequencedEvent() { synchronized (SequencedEvent.class) { return currentSequencedEvent; } } private static final class LightweightFocusRequest { final Component component; final boolean temporary; LightweightFocusRequest(Component component, boolean temporary) { this.component = component; this.temporary = temporary; } public String toString() { return "LightweightFocusRequest[component=" + component + ",temporary=" + temporary + "]"; } } private static final class HeavyweightFocusRequest { final Component heavyweight; final LinkedList lightweightRequests; static final HeavyweightFocusRequest CLEAR_GLOBAL_FOCUS_OWNER = new HeavyweightFocusRequest(); private HeavyweightFocusRequest() { heavyweight = null; lightweightRequests = null; } HeavyweightFocusRequest(Component heavyweight, Component descendant, boolean temporary) { /* if (dbg.on) { dbg.assertion(heavyweight != null); } */ this.heavyweight = heavyweight; this.lightweightRequests = new LinkedList(); addLightweightRequest(descendant, temporary); } boolean addLightweightRequest(Component descendant, boolean temporary) { /* if (dbg.on) { dbg.assertion(this != HeavyweightFocusRequest. CLEAR_GLOBAL_FOCUS_OWNER); dbg.assertion(descendant != null); } */ Component lastDescendant = ((lightweightRequests.size() > 0) ? ((LightweightFocusRequest)lightweightRequests.getLast()). component : null); if (descendant != lastDescendant) { // Not a duplicate request lightweightRequests.add (new LightweightFocusRequest(descendant, temporary)); return true; } else { return false; } } LightweightFocusRequest getFirstLightweightRequest() { if (this == CLEAR_GLOBAL_FOCUS_OWNER) { return null; } return (LightweightFocusRequest)lightweightRequests.getFirst(); } public String toString() { boolean first = true; String str = "HeavyweightFocusRequest[heavweight=" + heavyweight + ",lightweightRequests="; if (lightweightRequests == null) { str += null; } else { str += "["; for (Iterator iter = lightweightRequests.iterator(); iter.hasNext(); ) { if (first) { first = false; } else { str += ","; } str += iter.next(); } str += "]"; } str += "]"; return str; } } private static boolean focusedWindowChanged(Component a, Component b) { Window wa = getContainingWindow(a); Window wb = getContainingWindow(b); if (wa == null || wb == null) { return false; } return (wa != wb); } static Window getContainingWindow(Component comp) { while (comp != null && !(comp instanceof Window)) { comp = comp.getParent(); } return (Window)comp; } private static Component getHeavyweight(Component comp) { if (comp == null || comp.peer == null) { return null; } else if (comp.peer instanceof LightweightPeer) { return comp.getNativeContainer(); } else { return comp; } } /* * heavyweightRequests is used as a monitor for synchronized changes of * currentLightweightRequests, clearingCurrentLightweightRequests and * newFocusOwner. */ private static LinkedList heavyweightRequests = new LinkedList(); private static LinkedList currentLightweightRequests; private static boolean clearingCurrentLightweightRequests; private static Component newFocusOwner = null; int requestCount() { return heavyweightRequests.size(); } static final int SNFH_FAILURE = 0; static final int SNFH_SUCCESS_HANDLED = 1; static final int SNFH_SUCCESS_PROCEED = 2; /** * Indicates whether the native implementation should proceed with a * pending, native focus request. Before changing the focus at the native * level, the AWT implementation should always call this function for * permission. This function will reject the request if a duplicate request * preceded it, or if the specified heavyweight Component already owns the * focus and no native focus changes are pending. Otherwise, the request * will be approved and the focus request list will be updated so that, * if necessary, the proper descendant will be focused when the * corresponding FOCUS_GAINED event on the heavyweight is received. * * An implementation must ensure that calls to this method and native * focus changes are atomic. If this is not guaranteed, then the ordering * of the focus request list may be incorrect, leading to errors in the * type-ahead mechanism. Typically this is accomplished by only calling * this function from the native event pumping thread, or by holding a * global, native lock during invocation. */ static int shouldNativelyFocusHeavyweight (Component heavyweight, Component descendant, boolean temporary, boolean focusedWindowChangeAllowed, long time) { /* if (dbg.on) { dbg.assertion(heavyweight != null); dbg.assertion(time != 0); } */ if (descendant == null) { // Focus transfers from a lightweight child back to the // heavyweight Container should be treated like lightweight // focus transfers. descendant = heavyweight; } synchronized (heavyweightRequests) { HeavyweightFocusRequest hwFocusRequest = (HeavyweightFocusRequest) ((heavyweightRequests.size() > 0) ? heavyweightRequests.getLast() : null); if (hwFocusRequest == null && heavyweight == getNativeFocusOwner()) { Component currentFocusOwner = getCurrentKeyboardFocusManager(). getGlobalFocusOwner(); if (descendant == currentFocusOwner) { // Redundant request. return SNFH_FAILURE; } // 'heavyweight' owns the native focus and there are no pending // requests. 'heavyweight' must be a Container and // 'descendant' must not be the focus owner. Otherwise, // we would never have gotten this far. getCurrentKeyboardFocusManager (SunToolkit.targetToAppContext(descendant)). enqueueKeyEvents(time, descendant); hwFocusRequest = new HeavyweightFocusRequest(heavyweight, descendant, temporary); heavyweightRequests.add(hwFocusRequest); if (currentFocusOwner != null) { FocusEvent currentFocusOwnerEvent = new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST, temporary, descendant); SunToolkit.postEvent(currentFocusOwner.appContext, currentFocusOwnerEvent); } FocusEvent newFocusOwnerEvent = new FocusEvent(descendant, FocusEvent.FOCUS_GAINED, temporary, currentFocusOwner); SunToolkit.postEvent(descendant.appContext, newFocusOwnerEvent); return SNFH_SUCCESS_HANDLED; } else if (hwFocusRequest != null && hwFocusRequest.heavyweight == heavyweight) { // 'heavyweight' doesn't have the native focus right now, but // if all pending requests were completed, it would. Add // descendant to the heavyweight's list of pending // lightweight focus transfers. if (hwFocusRequest.addLightweightRequest(descendant, temporary)) { getCurrentKeyboardFocusManager (SunToolkit.targetToAppContext(descendant)). enqueueKeyEvents(time, descendant); } return SNFH_SUCCESS_HANDLED; } else { if (!focusedWindowChangeAllowed) { // For purposes of computing oldFocusedWindow, we should // look at the second to last HeavyweightFocusRequest on // the queue iff the last HeavyweightFocusRequest is // CLEAR_GLOBAL_FOCUS_OWNER. If there is no second to last // HeavyweightFocusRequest, null is an acceptable value. if (hwFocusRequest == HeavyweightFocusRequest.CLEAR_GLOBAL_FOCUS_OWNER) { int size = heavyweightRequests.size(); hwFocusRequest = (HeavyweightFocusRequest)((size >= 2) ? heavyweightRequests.get(size - 2) : null); } if (focusedWindowChanged(heavyweight, (hwFocusRequest != null) ? hwFocusRequest.heavyweight : getNativeFocusedWindow())) { return SNFH_FAILURE; } } getCurrentKeyboardFocusManager (SunToolkit.targetToAppContext(descendant)). enqueueKeyEvents(time, descendant); heavyweightRequests.add (new HeavyweightFocusRequest(heavyweight, descendant, temporary)); return SNFH_SUCCESS_PROCEED; } } } static void processCurrentLightweightRequests() { KeyboardFocusManager manager = getCurrentKeyboardFocusManager(); LinkedList localLightweightRequests = null; synchronized(heavyweightRequests) { if (currentLightweightRequests != null) { clearingCurrentLightweightRequests = true; localLightweightRequests = currentLightweightRequests; currentLightweightRequests = null; } else { // do nothing return; } } try { if (localLightweightRequests != null) { for (Iterator iter = localLightweightRequests.iterator(); iter.hasNext(); ) { Component currentFocusOwner = manager. getGlobalFocusOwner(); if (currentFocusOwner == null) { // If this ever happens, a focus change has been // rejected. Stop generating more focus changes. break; } LightweightFocusRequest lwFocusRequest = (LightweightFocusRequest)iter.next(); FocusEvent currentFocusOwnerEvent = new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST, lwFocusRequest.temporary, lwFocusRequest.component); FocusEvent newFocusOwnerEvent = new FocusEvent(lwFocusRequest.component, FocusEvent.FOCUS_GAINED, lwFocusRequest.temporary, currentFocusOwner); currentFocusOwner.dispatchEvent(currentFocusOwnerEvent); lwFocusRequest.component. dispatchEvent(newFocusOwnerEvent); } } } finally { clearingCurrentLightweightRequests = false; localLightweightRequests = null; } } static FocusEvent retargetUnexpectedFocusEvent(FocusEvent fe) { synchronized (heavyweightRequests) { // Any other case represents a failure condition which we did // not expect. We need to clearFocusRequestList() and patch up // the event as best as possible. if (removeFirstRequest()) { return (FocusEvent)retargetFocusEvent(fe); } Component source = fe.getComponent(); Component opposite = fe.getOppositeComponent(); boolean temporary = false; if (fe.getID() == FocusEvent.FOCUS_LOST && (opposite == null || focusedWindowChanged(source, opposite))) { temporary = true; } return new FocusEvent(source, fe.getID(), temporary, opposite); } } static FocusEvent retargetFocusGained(FocusEvent fe) { // assert (fe.getID() == FocusEvent.FOCUS_GAINED); Component currentFocusOwner = getCurrentKeyboardFocusManager(). getGlobalFocusOwner(); Component source = fe.getComponent(); Component opposite = fe.getOppositeComponent(); Component nativeSource = getHeavyweight(source); synchronized (heavyweightRequests) { HeavyweightFocusRequest hwFocusRequest = (HeavyweightFocusRequest) ((heavyweightRequests.size() > 0) ? heavyweightRequests.getFirst() : null); if (hwFocusRequest == HeavyweightFocusRequest.CLEAR_GLOBAL_FOCUS_OWNER) { return retargetUnexpectedFocusEvent(fe); } if (source != null && nativeSource == null && hwFocusRequest != null) { // if source w/o peer and // if source is equal to first lightweight // then we should correct source and nativeSource if (source == hwFocusRequest.getFirstLightweightRequest().component) { source = hwFocusRequest.heavyweight; nativeSource = source; // source is heavuweight itself } } if (hwFocusRequest != null && nativeSource == hwFocusRequest.heavyweight) { // Focus change as a result of a known call to requestFocus(), // or known click on a peer focusable heavyweight Component. heavyweightRequests.removeFirst(); LightweightFocusRequest lwFocusRequest = (LightweightFocusRequest)hwFocusRequest. lightweightRequests.removeFirst(); Component newSource = lwFocusRequest.component; if (currentFocusOwner != null) { /* * Since we receive FOCUS_GAINED when current focus * owner is not null, correcponding FOCUS_LOST is supposed * to be lost. And so, we keep new focus owner * to determine synthetic FOCUS_LOST event which will be * generated by KeyboardFocusManager for this FOCUS_GAINED. * * This code based on knowledge of * DefaultKeyboardFocusManager's implementation and might * be not applicable for another KeyboardFocusManager. */ newFocusOwner = newSource; } // LMK - comment out the check for opposite == null - it // always is for us boolean temporary = (//opposite == null || focusedWindowChanged(newSource, opposite)) ? false : lwFocusRequest.temporary; if (hwFocusRequest.lightweightRequests.size() > 0) { currentLightweightRequests = hwFocusRequest.lightweightRequests; EventQueue.invokeLater(new Runnable() { public void run() { processCurrentLightweightRequests(); } }); } // 'opposite' will be fixed by // DefaultKeyboardFocusManager.realOppositeComponent return new FocusEvent(newSource, FocusEvent.FOCUS_GAINED, temporary, opposite); } if (currentFocusOwner != null && getContainingWindow(currentFocusOwner) == source && (hwFocusRequest == null || source != hwFocusRequest.heavyweight)) { // Special case for FOCUS_GAINED in top-levels // If it arrives as the result of activation we should skip it // This event will not have appropriate request record and // on arrival there will be already some focus owner set. return new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_GAINED, false, null); } return retargetUnexpectedFocusEvent(fe); } // end synchronized(heavyweightRequests) } static FocusEvent retargetFocusLost(FocusEvent fe) { // assert (fe.getID() == FocusEvent.FOCUS_LOST); Component currentFocusOwner = getCurrentKeyboardFocusManager(). getGlobalFocusOwner(); Component opposite = fe.getOppositeComponent(); Component nativeOpposite = getHeavyweight(opposite); synchronized (heavyweightRequests) { HeavyweightFocusRequest hwFocusRequest = (HeavyweightFocusRequest) ((heavyweightRequests.size() > 0) ? heavyweightRequests.getFirst() : null); if (hwFocusRequest == HeavyweightFocusRequest.CLEAR_GLOBAL_FOCUS_OWNER) { if (currentFocusOwner != null) { // Call to KeyboardFocusManager.clearGlobalFocusOwner() heavyweightRequests.removeFirst(); return new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST, false, null); } // Otherwise, fall through to failure case below } else if (opposite == null) { // Focus leaving application if (currentFocusOwner != null) { return new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST, true, null); } else { return fe; } } else if (hwFocusRequest != null && (nativeOpposite == hwFocusRequest.heavyweight || nativeOpposite == null && opposite == hwFocusRequest.getFirstLightweightRequest().component)) { if (currentFocusOwner == null) { return fe; } // Focus change as a result of a known call to requestFocus(), // or click on a peer focusable heavyweight Component. // If a focus transfer is made across top-levels, then the // FOCUS_LOST event is always temporary, and the FOCUS_GAINED // event is always permanent. Otherwise, the stored temporary // value is honored. LightweightFocusRequest lwFocusRequest = (LightweightFocusRequest)hwFocusRequest. lightweightRequests.getFirst(); boolean temporary = focusedWindowChanged(opposite, currentFocusOwner) ? true : lwFocusRequest.temporary; return new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST, temporary, lwFocusRequest.component); } return retargetUnexpectedFocusEvent(fe); } // end synchronized(heavyweightRequests) } static AWTEvent retargetFocusEvent(AWTEvent event) { if (clearingCurrentLightweightRequests) { return event; } KeyboardFocusManager manager = getCurrentKeyboardFocusManager(); synchronized(heavyweightRequests) { /* * This code handles FOCUS_LOST event which is generated by * DefaultKeyboardFocusManager for FOCUS_GAINED. * * This code based on knowledge of DefaultKeyboardFocusManager's * implementation and might be not applicable for another * KeyboardFocusManager. * * Fix for 4472032 */ if (newFocusOwner != null && event.getID() == FocusEvent.FOCUS_LOST) { FocusEvent fe = (FocusEvent)event; if (manager.getGlobalFocusOwner() == fe.getComponent() && fe.getOppositeComponent() == newFocusOwner) { newFocusOwner = null; return event; } } } processCurrentLightweightRequests(); switch (event.getID()) { case FocusEvent.FOCUS_GAINED: { event = retargetFocusGained((FocusEvent)event); break; } case FocusEvent.FOCUS_LOST: { event = retargetFocusLost((FocusEvent)event); break; } default: /* do nothing */ } return event; } static boolean removeFirstRequest() { KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); synchronized(heavyweightRequests) { HeavyweightFocusRequest hwFocusRequest = (HeavyweightFocusRequest) ((heavyweightRequests.size() > 0) ? heavyweightRequests.getFirst() : null); if (hwFocusRequest != null) { heavyweightRequests.removeFirst(); if (hwFocusRequest.lightweightRequests != null) { for (Iterator lwIter = hwFocusRequest.lightweightRequests. iterator(); lwIter.hasNext(); ) { manager.dequeueKeyEvents (-1, ((LightweightFocusRequest)lwIter.next()). component); } } } return (heavyweightRequests.size() > 0); } } static void removeLastFocusRequest(Component heavyweight) { /* if (dbg.on) { dbg.assertion(heavyweight != null); } */ synchronized(heavyweightRequests) { HeavyweightFocusRequest hwFocusRequest = (HeavyweightFocusRequest) ((heavyweightRequests.size() > 0) ? heavyweightRequests.getLast() : null); if (hwFocusRequest != null && hwFocusRequest.heavyweight == heavyweight) { heavyweightRequests.removeLast(); } } } static void removeFocusRequest(Component component) { /* if (dbg.on) { dbg.assertion(component != null); } */ Component heavyweight = (component.peer instanceof LightweightPeer) ? component.getNativeContainer() : component; if (heavyweight == null) { return; } synchronized (heavyweightRequests) { if ((currentLightweightRequests != null) && (currentLightweightRequests.size() > 0)) { LightweightFocusRequest lwFocusRequest = (LightweightFocusRequest)currentLightweightRequests.getFirst(); Component comp = lwFocusRequest.component; Component currentHeavyweight = (comp.peer instanceof LightweightPeer) ? comp.getNativeContainer() : comp; if (currentHeavyweight == component) { currentLightweightRequests = null; } else { for (Iterator iter = currentLightweightRequests.iterator(); iter.hasNext(); ) { if (((LightweightFocusRequest)iter.next()). component == component) { iter.remove(); } } if (currentLightweightRequests.size() == 0) { currentLightweightRequests = null; } } } for (Iterator iter = heavyweightRequests.iterator(); iter.hasNext(); ) { HeavyweightFocusRequest hwFocusRequest = (HeavyweightFocusRequest)iter.next(); if (hwFocusRequest.heavyweight == heavyweight) { if (heavyweight == component) { iter.remove(); continue; } for (Iterator lwIter = hwFocusRequest.lightweightRequests. iterator(); lwIter.hasNext(); ) { if (((LightweightFocusRequest)lwIter.next()). component == component) { lwIter.remove(); } } if (hwFocusRequest.lightweightRequests.size() == 0) { iter.remove(); } } } } } private static void clearFocusRequestList() { KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); synchronized (heavyweightRequests) { for (Iterator iter = heavyweightRequests.iterator(); iter.hasNext(); ) { HeavyweightFocusRequest hwFocusRequest = (HeavyweightFocusRequest)iter.next(); if (hwFocusRequest.lightweightRequests == null) { continue; } for (Iterator lwIter = hwFocusRequest.lightweightRequests. iterator(); lwIter.hasNext(); ) { manager.dequeueKeyEvents (-1, ((LightweightFocusRequest)lwIter.next()). component); } } heavyweightRequests.clear(); } } public static KeyboardFocusManager getCurrentKeyboardFocusManager() { return getCurrentKeyboardFocusManager(AppContext.getAppContext()); } synchronized static KeyboardFocusManager getCurrentKeyboardFocusManager(AppContext appcontext) { KeyboardFocusManager manager = (KeyboardFocusManager) appcontext.get(KeyboardFocusManager.class); if (manager == null) { manager = new DefaultKeyboardFocusManager(); appcontext.put(KeyboardFocusManager.class, manager); } return manager; } // Bug #6223096: TCK: PP-TCK_11 Signature Test fails with CDC-PP-Sec /* synchronized static void setCurrentKeyboardFocusManager( KeyboardFocusManager newManager) throws SecurityException { AppContext appcontext = AppContext.getAppContext(); if (newManager != null) { SecurityManager security = System.getSecurityManager(); if (security != null) { if (replaceKeyboardFocusManagerPermission == null) { replaceKeyboardFocusManagerPermission = new AWTPermission("replaceKeyboardFocusManager"); } security. checkPermission(replaceKeyboardFocusManagerPermission); } appcontext.put(KeyboardFocusManager.class, newManager); } else { appcontext.remove(KeyboardFocusManager.class); } } */ static Set initFocusTraversalKeysSet(String value, Set targetSet) { StringTokenizer tokens = new StringTokenizer(value, ","); while (tokens.hasMoreTokens()) { targetSet.add(AWTKeyStroke.getAWTKeyStroke(tokens.nextToken())); } return (targetSet.isEmpty()) ? Collections.EMPTY_SET : Collections.unmodifiableSet(targetSet); } KeyboardFocusManager() { for (int i = 0; i < TRAVERSAL_KEY_LENGTH; i++) { defaultFocusTraversalKeys[i] = initFocusTraversalKeysSet(defaultFocusTraversalKeyStrings[i], new HashSet()); } } public Component getFocusOwner() { synchronized (KeyboardFocusManager.class) { if (focusOwner == null) { return null; } return (focusOwner.appContext == AppContext.getAppContext()) ? focusOwner : null; } } Component getGlobalFocusOwner() throws SecurityException { synchronized (KeyboardFocusManager.class) { if (this == getCurrentKeyboardFocusManager()) { return focusOwner; } else { throw new SecurityException(notPrivileged); } } } void setGlobalFocusOwner(Component focusOwner) { Component oldFocusOwner = null; boolean shouldFire = false; if (focusOwner == null || focusOwner.isFocusable()) { synchronized (KeyboardFocusManager.class) { oldFocusOwner = getFocusOwner(); try { fireVetoableChange("focusOwner", oldFocusOwner, focusOwner); } catch (PropertyVetoException e) { return; } KeyboardFocusManager.focusOwner = focusOwner; if (focusOwner != null && (getCurrentFocusCycleRoot() == null || !focusOwner.isFocusCycleRoot(getCurrentFocusCycleRoot()))) { Container rootAncestor = focusOwner.getFocusCycleRootAncestor(); if (rootAncestor == null && (focusOwner instanceof Window)) { rootAncestor = (Container) focusOwner; } if (rootAncestor != null) { setGlobalCurrentFocusCycleRoot(rootAncestor); } } shouldFire = true; } } if (shouldFire) { firePropertyChange("focusOwner", oldFocusOwner, focusOwner); } } public void clearGlobalFocusOwner() { if (!GraphicsEnvironment.isHeadless()) { // Toolkit must be fully initialized, otherwise // _clearGlobalFocusOwner will crash or throw an exception Toolkit.getDefaultToolkit(); if (!initialized) { // 6253293 - don't want to initialize the toolkit in the // constructor as this starts a bunch of threads up and doesn't // allow the VM to exit. Don't do it till we need it initIDs(); initialized=true; } _clearGlobalFocusOwner(); } } /** * Returns the Window which will be active after processing this request, * or null if this is a duplicate request. The active Window is useful * because some native platforms do not support setting the native focus * owner to null. On these platforms, the obvious choice is to set the * focus owner to the focus proxy of the active Window. */ static Window markClearGlobalFocusOwner() { synchronized (heavyweightRequests) { HeavyweightFocusRequest hwFocusRequest = (HeavyweightFocusRequest) ((heavyweightRequests.size() > 0) ? heavyweightRequests.getLast() : null); if (hwFocusRequest == HeavyweightFocusRequest.CLEAR_GLOBAL_FOCUS_OWNER) { // duplicate request return null; } heavyweightRequests.add (HeavyweightFocusRequest.CLEAR_GLOBAL_FOCUS_OWNER); Component activeWindow = ((hwFocusRequest != null) ? getContainingWindow(hwFocusRequest.heavyweight) : getNativeFocusedWindow()); while (activeWindow != null && !((activeWindow instanceof Frame) || (activeWindow instanceof Dialog))) { activeWindow = activeWindow.getParent(); } return (Window)activeWindow; } } public Component getPermanentFocusOwner() { synchronized (KeyboardFocusManager.class) { if (permanentFocusOwner == null) { return null; } return (permanentFocusOwner.appContext == AppContext.getAppContext()) ? permanentFocusOwner : null; } } Component getGlobalPermanentFocusOwner() throws SecurityException { synchronized (KeyboardFocusManager.class) { if (this == getCurrentKeyboardFocusManager()) { return permanentFocusOwner; } else { throw new SecurityException(notPrivileged); } } } void setGlobalPermanentFocusOwner(Component permanentFocusOwner) { Component oldPermanentFocusOwner = null; boolean shouldFire = false; if (permanentFocusOwner == null || permanentFocusOwner.isFocusable()) { synchronized (KeyboardFocusManager.class) { oldPermanentFocusOwner = getPermanentFocusOwner(); try { fireVetoableChange("permanentFocusOwner", oldPermanentFocusOwner, permanentFocusOwner); } catch (PropertyVetoException e) { return; } KeyboardFocusManager.permanentFocusOwner = permanentFocusOwner; KeyboardFocusManager.setMostRecentFocusOwner(permanentFocusOwner); shouldFire = true; } } if (shouldFire) { firePropertyChange("permanentFocusOwner", oldPermanentFocusOwner, permanentFocusOwner); } } public Window getFocusedWindow() { synchronized (KeyboardFocusManager.class) { if (focusedWindow == null) { return null; } return (focusedWindow.appContext == AppContext.getAppContext()) ? focusedWindow : null; } } Window getGlobalFocusedWindow() throws SecurityException { synchronized (KeyboardFocusManager.class) { if (this == getCurrentKeyboardFocusManager()) { return focusedWindow; } else { throw new SecurityException(notPrivileged); } } } void setGlobalFocusedWindow(Window focusedWindow) { Window oldFocusedWindow = null; boolean shouldFire = false; if (focusedWindow == null || focusedWindow.isFocusableWindow()) { synchronized (KeyboardFocusManager.class) { oldFocusedWindow = getFocusedWindow(); try { fireVetoableChange("focusedWindow", oldFocusedWindow, focusedWindow); } catch (PropertyVetoException e) { return; } KeyboardFocusManager.focusedWindow = focusedWindow; shouldFire = true; } } if (shouldFire) { firePropertyChange("focusedWindow", oldFocusedWindow, focusedWindow); } } public Window getActiveWindow() { synchronized (KeyboardFocusManager.class) { if (activeWindow == null) { return null; } return (activeWindow.appContext == AppContext.getAppContext()) ? activeWindow : null; } } Window getGlobalActiveWindow() throws SecurityException { synchronized (KeyboardFocusManager.class) { if (this == getCurrentKeyboardFocusManager()) { return activeWindow; } else { throw new SecurityException(notPrivileged); } } } void setGlobalActiveWindow(Window activeWindow) { // 6205919: // PP-TCK: api/java_awt/Event/WinEventTests.html#WinEventTest0008 hangs. // // The following code was once performed within the synchronized block // of KeyboardFocusManager.class and caused a deadlock because the call // activeWindow.isFocusableWindow() can potentially try to grab the AWT // tree lock, while another thread might be doing a dispose call, // acquiring the AWT tree lock before trying to acquire the // KeyboardFocusManager.class lock. if ((activeWindow != null) && (!activeWindow.isFocusableWindow())) { return; } Window oldActiveWindow; synchronized (KeyboardFocusManager.class) { oldActiveWindow = getActiveWindow(); try { fireVetoableChange("activeWindow", oldActiveWindow, activeWindow); } catch (PropertyVetoException e) { return; } KeyboardFocusManager.activeWindow = activeWindow; } firePropertyChange("activeWindow", oldActiveWindow, activeWindow); } public synchronized FocusTraversalPolicy getDefaultFocusTraversalPolicy() { return defaultPolicy; } public void setDefaultFocusTraversalPolicy(FocusTraversalPolicy defaultPolicy) { if (defaultPolicy == null) { throw new IllegalArgumentException("default focus traversal policy cannot be null"); } FocusTraversalPolicy oldPolicy; synchronized (this) { oldPolicy = this.defaultPolicy; this.defaultPolicy = defaultPolicy; } firePropertyChange("defaultFocusTraversalPolicy", oldPolicy, defaultPolicy); } public void setDefaultFocusTraversalKeys(int id, Set keystrokes) { if (id < 0 || id >= TRAVERSAL_KEY_LENGTH) { throw new IllegalArgumentException("invalid focus traversal key identifier"); } if (keystrokes == null) { throw new IllegalArgumentException("cannot set null Set of default focus traversal keys"); } Set oldKeys; synchronized (this) { for (Iterator iter = keystrokes.iterator(); iter.hasNext();) { Object obj = iter.next(); if (obj == null) { throw new IllegalArgumentException("cannot set null focus traversal key"); } AWTKeyStroke keystroke = (AWTKeyStroke) obj; if (keystroke.getKeyChar() != KeyEvent.CHAR_UNDEFINED) { throw new IllegalArgumentException("focus traversal keys cannot map to KEY_TYPED events"); } for (int i = 0; i < TRAVERSAL_KEY_LENGTH; i++) { if (i == id) { continue; } if (defaultFocusTraversalKeys[i].contains(keystroke)) { throw new IllegalArgumentException("focus traversal keys must be unique for a Component"); } } } oldKeys = defaultFocusTraversalKeys[id]; defaultFocusTraversalKeys[id] = Collections.unmodifiableSet(new HashSet(keystrokes)); } firePropertyChange(defaultFocusTraversalKeyPropertyNames[id], oldKeys, keystrokes); } public Set getDefaultFocusTraversalKeys(int id) { if (id < 0 || id >= TRAVERSAL_KEY_LENGTH) { throw new IllegalArgumentException("invalid focus traversal key identifier"); } return defaultFocusTraversalKeys[id]; } public Container getCurrentFocusCycleRoot() { synchronized (KeyboardFocusManager.class) { if (currentFocusCycleRoot == null) { return null; } return (currentFocusCycleRoot.appContext == AppContext.getAppContext()) ? currentFocusCycleRoot:null; } } Container getGlobalCurrentFocusCycleRoot() throws SecurityException { synchronized (KeyboardFocusManager.class) { if (this == getCurrentKeyboardFocusManager()) { return currentFocusCycleRoot; } else { throw new SecurityException(notPrivileged); } } } void setGlobalCurrentFocusCycleRoot(Container newFocusCycleRoot) { Container oldFocusCycleRoot; synchronized (KeyboardFocusManager.class) { oldFocusCycleRoot = getCurrentFocusCycleRoot(); currentFocusCycleRoot = newFocusCycleRoot; } firePropertyChange("currentFocusCycleRoot", oldFocusCycleRoot, newFocusCycleRoot); } public void addPropertyChangeListener(PropertyChangeListener listener) { if (listener != null) { synchronized (this) { if (changeSupport == null) { changeSupport = new PropertyChangeSupport(this); } changeSupport.addPropertyChangeListener(listener); } } } public void removePropertyChangeListener(PropertyChangeListener listener) { if (listener != null) { synchronized (this) { if (changeSupport != null) { changeSupport.removePropertyChangeListener(listener); } } } } public synchronized PropertyChangeListener[] getPropertyChangeListeners() { if (changeSupport == null) { changeSupport = new PropertyChangeSupport(this); } return changeSupport.getPropertyChangeListeners(); } /* public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { if (listener != null) { synchronized (this) { if (changeSupport == null) { changeSupport = new PropertyChangeSupport(this); } changeSupport.addPropertyChangeListener(propertyName, listener); } } } public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { if (listener != null) { synchronized (this) { if (changeSupport != null) { changeSupport.removePropertyChangeListener(propertyName, listener); } } } } public synchronized PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { if (changeSupport == null) { changeSupport = new PropertyChangeSupport(this); } return changeSupport.getPropertyChangeListeners(propertyName); } */ void firePropertyChange(String propertyName, Object oldValue, Object newValue) { PropertyChangeSupport changeSupport = this.changeSupport; if (changeSupport != null) { changeSupport.firePropertyChange(propertyName, oldValue, newValue); } } public void addVetoableChangeListener(VetoableChangeListener listener) { if (listener != null) { synchronized (this) { if (vetoableSupport == null) { vetoableSupport = new VetoableChangeSupport(this); } vetoableSupport.addVetoableChangeListener(listener); } } } public void removeVetoableChangeListener(VetoableChangeListener listener) { if (listener != null) { synchronized (this) { if (vetoableSupport != null) { vetoableSupport.removeVetoableChangeListener(listener); } } } } public synchronized VetoableChangeListener[] getVetoableChangeListeners() { if (vetoableSupport == null) { vetoableSupport = new VetoableChangeSupport(this); } return vetoableSupport.getVetoableChangeListeners(); } /* public void addVetoableChangeListener(String propertyName, VetoableChangeListener listener) { if (listener != null) { synchronized (this) { if (vetoableSupport == null) { vetoableSupport = new VetoableChangeSupport(this); } vetoableSupport.addVetoableChangeListener(propertyName, listener); } } } public void removeVetoableChangeListener(String propertyName, VetoableChangeListener listener) { if (listener != null) { synchronized (this) { if (vetoableSupport != null) { vetoableSupport.removeVetoableChangeListener(propertyName, listener); } } } } public synchronized VetoableChangeListener[] getVetoableChangeListeners(String propertyName) { if (vetoableSupport == null) { vetoableSupport = new VetoableChangeSupport(this); } return vetoableSupport.getVetoableChangeListeners(propertyName); } */ void fireVetoableChange(String propertyName, Object oldValue, Object newValue) throws PropertyVetoException { VetoableChangeSupport vetoableSupport = this.vetoableSupport; if (vetoableSupport != null) { vetoableSupport.fireVetoableChange(propertyName, oldValue, newValue); } } public void addKeyEventDispatcher(KeyEventDispatcher dispatcher) { if (dispatcher != null) { synchronized (this) { if (keyEventDispatchers == null) { keyEventDispatchers = new java.util.LinkedList(); } keyEventDispatchers.add(dispatcher); } } } public void removeKeyEventDispatcher(KeyEventDispatcher dispatcher) { if (dispatcher != null) { synchronized (this) { if (keyEventDispatchers != null) { keyEventDispatchers.remove(dispatcher); } } } } synchronized java.util.List getKeyEventDispatchers() { return (keyEventDispatchers != null) ? (java.util.List) keyEventDispatchers.clone() : null; } public void addKeyEventPostProcessor(KeyEventPostProcessor processor) { if (processor != null) { synchronized (this) { if (keyEventPostProcessors == null) { keyEventPostProcessors = new java.util.LinkedList(); } keyEventPostProcessors.add(processor); } } } public void removeKeyEventPostProcessor(KeyEventPostProcessor processor) { if (processor != null) { synchronized (this) { if (keyEventPostProcessors != null) { keyEventPostProcessors.remove(processor); } } } } java.util.List getKeyEventPostProcessors() { return (keyEventPostProcessors != null) ? (java.util.List) keyEventPostProcessors.clone() : null; } static void setMostRecentFocusOwner(Component component) { Component window = component; while (window != null && !(window instanceof Window)) { window = window.parent; } if (window != null) { setMostRecentFocusOwner((Window) window, component); } } static synchronized void setMostRecentFocusOwner(Window window, Component component) { WeakReference weakValue = null; if (component != null) { weakValue = new WeakReference(component); } mostRecentFocusOwners.put(window, weakValue); } static void clearMostRecentFocusOwner(Component comp) { Container window; if (comp == null) { return; } synchronized (comp.getTreeLock()) { window = comp.getParent(); while (window != null && !(window instanceof Window)) { window = window.getParent(); } } synchronized (KeyboardFocusManager.class) { if ((window != null) && (getMostRecentFocusOwner((Window) window) == comp)) { setMostRecentFocusOwner((Window) window, null); } if (window != null) { Window realWindow = (Window) window; if (realWindow.getTemporaryLostComponent() == comp) { realWindow.setTemporaryLostComponent(null); } } } } static synchronized Component getMostRecentFocusOwner(Window window) { WeakReference weakValue = (WeakReference) mostRecentFocusOwners.get(window); return weakValue == null ? null : (Component) weakValue.get(); } public abstract boolean dispatchEvent(AWTEvent e); public final void redispatchEvent(Component target, AWTEvent e) { e.focusManagerIsDispatching = true; target.dispatchEvent(e); e.focusManagerIsDispatching = false; } public abstract boolean dispatchKeyEvent(KeyEvent e); public abstract boolean postProcessKeyEvent(KeyEvent e); public abstract void processKeyEvent(Component focusedComponent, KeyEvent e); public abstract void focusNextComponent(Component aComponent); public abstract void focusPreviousComponent(Component aComponent); public abstract void upFocusCycle(Component aComponent); public abstract void downFocusCycle(Container aContainer); abstract void enqueueKeyEvents(long after, Component untilFocused); abstract void dequeueKeyEvents(long after, Component untilFocused); abstract void discardKeyEvents(Component comp); public final void focusNextComponent() { Component focusOwner = getFocusOwner(); if (focusOwner != null) { focusNextComponent(focusOwner); } } public final void focusPreviousComponent() { Component focusOwner = getFocusOwner(); if (focusOwner != null) { focusPreviousComponent(focusOwner); } } public final void upFocusCycle() { Component focusOwner = getFocusOwner(); if (focusOwner != null) { upFocusCycle(focusOwner); } } public final void downFocusCycle() { Component focusOwner = getFocusOwner(); if (focusOwner instanceof Container) { downFocusCycle((Container) focusOwner); } } }