0001: /*
0002: *
0003: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
0004: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0005: *
0006: * This program is free software; you can redistribute it and/or
0007: * modify it under the terms of the GNU General Public License version
0008: * 2 only, as published by the Free Software Foundation.
0009: *
0010: * This program is distributed in the hope that it will be useful, but
0011: * WITHOUT ANY WARRANTY; without even the implied warranty of
0012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0013: * General Public License version 2 for more details (a copy is
0014: * included at /legal/license.txt).
0015: *
0016: * You should have received a copy of the GNU General Public License
0017: * version 2 along with this work; if not, write to the Free Software
0018: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0019: * 02110-1301 USA
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0022: * Clara, CA 95054 or visit www.sun.com if you need additional
0023: * information or have any questions.
0024: */
0025: package java.awt;
0026:
0027: import java.awt.event.FocusEvent;
0028: import java.awt.event.KeyEvent;
0029: import java.awt.event.WindowEvent;
0030: import java.beans.PropertyChangeListener;
0031: import java.util.LinkedList;
0032: import java.util.Iterator;
0033: import java.util.ListIterator;
0034: import java.util.Set;
0035: import sun.awt.AppContext;
0036: import sun.awt.SunToolkit;
0037: import sun.awt.peer.ComponentPeer;
0038: import sun.awt.peer.LightweightPeer;
0039:
0040: class DefaultKeyboardFocusManager extends KeyboardFocusManager {
0041: private boolean consumeNextKeyTyped;
0042: private boolean posting = false;
0043: private Window mostRecentFocusedWindow;
0044: private Window pendingWindow;
0045: private Window previousActiveWindow;
0046: private Component pendingComponent;
0047: private LinkedList enqueuedKeyEvents = new LinkedList();
0048: private LinkedList typeAheadMarkers = new LinkedList();
0049: private Window realOppositeWindow;
0050: private Component realOppositeComponent;
0051: private int inSendMessage;
0052:
0053: private static class TypeAheadMarker {
0054: long after;
0055: Component untilFocused;
0056:
0057: TypeAheadMarker(long after, Component untilFocused) {
0058: this .after = after;
0059: this .untilFocused = untilFocused;
0060: }
0061: }
0062:
0063: private Window getOwningFrameDialog(Window window) {
0064: while (window != null
0065: && !(window instanceof Frame || window instanceof Dialog)) {
0066: window = (Window) window.getParent();
0067: }
0068: return window;
0069: }
0070:
0071: /*
0072: * This series of restoreFocus methods is used for recovering from a
0073: * rejected focus or activation change. Rejections typically occur when
0074: * the user attempts to focus a non-focusable Component or Window.
0075:
0076: */
0077: private void restoreFocus(FocusEvent fe, Window newFocusedWindow) {
0078: Component realOppositeComponent = this .realOppositeComponent;
0079: Component vetoedComponent = fe.getComponent();
0080: if (newFocusedWindow != null
0081: && restoreFocus(newFocusedWindow, vetoedComponent,
0082: false)) {
0083: } else if (realOppositeComponent != null
0084: && restoreFocus(realOppositeComponent, false)) {
0085: } else if (fe.getOppositeComponent() != null
0086: && restoreFocus(fe.getOppositeComponent(), false)) {
0087: } else {
0088: clearGlobalFocusOwner();
0089: }
0090: }
0091:
0092: private void restoreFocus(WindowEvent we) {
0093: Window realOppositeWindow = this .realOppositeWindow;
0094: if (realOppositeWindow != null
0095: && restoreFocus(realOppositeWindow, null, false)) {
0096: } else if (we.getOppositeWindow() != null
0097: && restoreFocus(we.getOppositeWindow(), null, false)) {
0098: } else {
0099: clearGlobalFocusOwner();
0100: }
0101: }
0102:
0103: private boolean restoreFocus(Window aWindow,
0104: Component vetoedComponent, boolean clearOnFailure) {
0105: // bug 6203068 always call setActive - Qt may have a different notion
0106: // of the active window than we do. Also this takes care of generating
0107: // a WINDOW_GAINED_FOCUS event should we need one
0108: if (aWindow.isDisplayable()) {// && getGlobalActiveWindow() != aWindow) {
0109: sun.awt.peer.WindowPeer wpeer = (sun.awt.peer.WindowPeer) aWindow.peer;
0110: wpeer.setActive();
0111: }
0112: Component toFocus = KeyboardFocusManager
0113: .getMostRecentFocusOwner(aWindow);
0114: if (toFocus != null && toFocus != vetoedComponent
0115: && restoreFocus(toFocus, false)) {
0116: return true;
0117: } else if (clearOnFailure) {
0118: clearGlobalFocusOwner();
0119: return true;
0120: } else {
0121: return false;
0122: }
0123: }
0124:
0125: private boolean restoreFocus(Component toFocus,
0126: boolean clearOnFailure) {
0127:
0128: // LMK - as part of focus mgmt changes, requestFocusHelper no longer
0129: // returns false w/o consulting the peer. So we no longer need this
0130: // extra check here
0131: // 6198823: vetoableChangeListener not working as expected when trying
0132: // to veto a FOCUS_LOST event.
0133: //if (toFocus.hasFocus()) {
0134: // return true;
0135: //}
0136: // 6198823: vetoableChangeListener not working as expected when trying
0137: // to veto a FOCUS_LOST event.
0138: //
0139: // The new focus management system puts a check at the beginning of
0140: // the Component.requestFocusHelper() method to see whether the
0141: // component hasFocus(), if true, just returns false without going
0142: // through the steps of asking peer to request the focus. This has
0143: // the implication that if the clearGlobalFocusOwner() call was vetoed
0144: // by a vetoable change listener and the logic flow falls back to the
0145: // restoreFocus() call, after trying the first if branch and then the
0146: // second if branch without success, calling the third branch will lead
0147: // to an infinite recursion leading to stack overflow.
0148:
0149: if (toFocus.isShowing() && toFocus.isFocusable()
0150: && toFocus.requestFocus(false)) {
0151: return true;
0152: } else if (toFocus.nextFocusHelper()) {
0153: return true;
0154: } else if (clearOnFailure) {
0155: clearGlobalFocusOwner();
0156: return true;
0157: } else {
0158: return false;
0159: }
0160: }
0161:
0162: /**
0163: * A special type of SentEvent which updates a counter in the target
0164: * KeyboardFocusManager if it is an instance of
0165: * DefaultKeyboardFocusManager.
0166: */
0167: private static class DefaultKeyboardFocusManagerSentEvent extends
0168: SentEvent {
0169: public DefaultKeyboardFocusManagerSentEvent(AWTEvent nested,
0170: AppContext toNotify) {
0171: super (nested, toNotify);
0172: }
0173:
0174: public final void dispatch() {
0175: KeyboardFocusManager manager = KeyboardFocusManager
0176: .getCurrentKeyboardFocusManager();
0177: DefaultKeyboardFocusManager defaultManager = (manager instanceof DefaultKeyboardFocusManager) ? (DefaultKeyboardFocusManager) manager
0178: : null;
0179:
0180: if (defaultManager != null) {
0181: synchronized (defaultManager) {
0182: defaultManager.inSendMessage++;
0183: }
0184: }
0185:
0186: super .dispatch();
0187:
0188: if (defaultManager != null) {
0189: synchronized (defaultManager) {
0190: defaultManager.inSendMessage--;
0191: }
0192: }
0193: }
0194: }
0195:
0196: /**
0197: * Sends a synthetic AWTEvent to a Component. If the Component is in
0198: * the current AppContext, then the event is immediately dispatched.
0199: * If the Component is in a different AppContext, then the event is
0200: * posted to the other AppContext's EventQueue, and this method blocks
0201: * until the event is handled or target AppContext is disposed.
0202: * Returns true if successfuly dispatched event, false if failed
0203: * to dispatch.
0204: */
0205: private boolean sendMessage(Component target, AWTEvent e) {
0206: AppContext myAppContext = AppContext.getAppContext();
0207: final AppContext targetAppContext = target.appContext;
0208: final SentEvent se = new DefaultKeyboardFocusManagerSentEvent(
0209: e, myAppContext);
0210:
0211: if (myAppContext == targetAppContext) {
0212: se.dispatch();
0213: } else {
0214: if (targetAppContext.isDisposed()) {
0215: return false;
0216: }
0217: SunToolkit.postEvent(targetAppContext, se);
0218: if (EventQueue.isDispatchThread()) {
0219: EventDispatchThread edt = (EventDispatchThread) Thread
0220: .currentThread();
0221: edt.pumpEvents(SentEvent.ID, new Conditional() {
0222: public boolean evaluate() {
0223: return !se.dispatched
0224: && !targetAppContext.isDisposed();
0225: }
0226: });
0227: } else {
0228: synchronized (se) {
0229: while (!se.dispatched
0230: && !targetAppContext.isDisposed()) {
0231: try {
0232: se.wait(1000);
0233: } catch (InterruptedException ie) {
0234: break;
0235: }
0236: }
0237: }
0238: }
0239: }
0240: return se.dispatched;
0241: }
0242:
0243: public boolean dispatchEvent(AWTEvent e) {
0244: if (!(e instanceof WindowEvent) && !(e instanceof FocusEvent)
0245: && !(e instanceof KeyEvent)) {
0246: return false;
0247: }
0248: switch (e.getID()) {
0249: case WindowEvent.WINDOW_ACTIVATED: {
0250: WindowEvent we = (WindowEvent) e;
0251: Window newActiveWindow = we.getWindow();
0252: Window oldActiveWindow = getGlobalActiveWindow();
0253: Window oldFocusedWindow = getGlobalFocusedWindow();
0254: if (oldActiveWindow == newActiveWindow) {
0255: break;
0256: }
0257:
0258: // If there exists a current active window, then notify it that
0259: // it has lost activation.
0260: if (oldActiveWindow != null) {
0261: boolean isEventDispatched = sendMessage(
0262: oldActiveWindow, new WindowEvent(
0263: oldActiveWindow,
0264: WindowEvent.WINDOW_DEACTIVATED,
0265: newActiveWindow));
0266: // Failed to dispatch, clear by ourselfves
0267: if (!isEventDispatched) {
0268: setGlobalActiveWindow(null);
0269: }
0270: if (getGlobalActiveWindow() != null) {
0271: // Activation change was rejected. Unlikely, but
0272: // possible.
0273: break;
0274: }
0275: }
0276: setGlobalActiveWindow(newActiveWindow);
0277: if (newActiveWindow != getGlobalActiveWindow()) {
0278: // active change was rejected
0279: break;
0280: }
0281: return typeAheadAssertions(newActiveWindow, we);
0282: }
0283:
0284: case WindowEvent.WINDOW_GAINED_FOCUS: {
0285: WindowEvent we = (WindowEvent) e;
0286: Window newFocusedWindow = we.getWindow();
0287: Window oldFocusedWindow = getGlobalFocusedWindow();
0288: if (newFocusedWindow == oldFocusedWindow) {
0289: break;
0290: }
0291: /*
0292: // If there exists a current focused window, then notify it
0293: // that it has lost focus.
0294: if (oldFocusedWindow != null) {
0295: boolean isEventDispatched =
0296: sendMessage(oldFocusedWindow,
0297: new WindowEvent(oldFocusedWindow,
0298: WindowEvent.WINDOW_LOST_FOCUS,
0299: newFocusedWindow));
0300: // Failed to dispatch, clear by ourselfves
0301: if (!isEventDispatched) {
0302: setGlobalFocusOwner(null);
0303: setGlobalFocusedWindow(null);
0304: }
0305: }
0306: */
0307: // Fix for bug 6188289 - fire WINDOW_ACTIVATE event
0308: // Because the native libraries do not post WINDOW_ACTIVATED
0309: // events, we need to synthesize one if the active Window
0310: // changed.
0311: Window newActiveWindow = getOwningFrameDialog(newFocusedWindow);
0312: Window currentActiveWindow = getGlobalActiveWindow();
0313: if (newActiveWindow != currentActiveWindow) {
0314: sendMessage(newActiveWindow, new WindowEvent(
0315: newActiveWindow, WindowEvent.WINDOW_ACTIVATED,
0316: currentActiveWindow));
0317: if (newActiveWindow != getGlobalActiveWindow()) {
0318: // Activation change was rejected. Unlikely, but
0319: // possible.
0320: restoreFocus(we);
0321: break;
0322: }
0323: }
0324: setGlobalFocusedWindow(newFocusedWindow);
0325:
0326: if (newFocusedWindow != getGlobalFocusedWindow()) {
0327: // Focus change was rejected. Will happen if
0328: // newFocusedWindow is not a focusable Window.
0329: restoreFocus(we);
0330: break;
0331: }
0332: // Restore focus to the Component which last held it. We do
0333: // this here so that client code can override our choice in
0334: // a WINDOW_GAINED_FOCUS handler.
0335: //
0336: // Make sure that the focus change request doesn't change the
0337: // focused Window in case we are no longer the focused Window
0338: // when the request is handled.
0339: if (inSendMessage == 0) {
0340: // Identify which Component should initially gain focus
0341: // in the Window.
0342: //
0343: // * If we're in SendMessage, then this is a synthetic
0344: // WINDOW_GAINED_FOCUS message which was generated by a
0345: // the FOCUS_GAINED handler. Allow the Component to
0346: // which the FOCUS_GAINED message was targeted to
0347: // receive the focus.
0348: // * Otherwise, look up the correct Component here.
0349: // We don't use Window.getMostRecentFocusOwner because
0350: // window is focused now and 'null' will be returned
0351:
0352: // Calculating of most recent focus owner and focus
0353: // request should be synchronized on KeyboardFocusManager.class
0354: // to prevent from thread race when user will request
0355: // focus between calculation and our request.
0356: // But if focus transfer is synchronous, this synchronization
0357: // may cause deadlock, thus we don't synchronize this block.
0358: Component toFocus = KeyboardFocusManager
0359: .getMostRecentFocusOwner(newFocusedWindow);
0360: if ((toFocus == null)
0361: && newFocusedWindow.isFocusableWindow()) {
0362: toFocus = newFocusedWindow
0363: .getFocusTraversalPolicy()
0364: .getInitialComponent(newFocusedWindow);
0365: }
0366: Component tempLost = null;
0367: synchronized (KeyboardFocusManager.class) {
0368: tempLost = newFocusedWindow
0369: .setTemporaryLostComponent(null);
0370: }
0371:
0372: // The component which last has the focus when this window was focused
0373: // should receive focus first
0374: if (tempLost != null) {
0375: tempLost.requestFocusInWindow();
0376: }
0377:
0378: if (toFocus != null && toFocus != tempLost) {
0379: // If there is a component which requested focus when this
0380: // window was inactive it expects to receive focus
0381: // after activation
0382: toFocus.requestFocusInWindow();
0383: }
0384: }
0385:
0386: Window realOppositeWindow = this .realOppositeWindow;
0387: if (realOppositeWindow != we.getOppositeWindow()) {
0388: we = new WindowEvent(newFocusedWindow,
0389: WindowEvent.WINDOW_GAINED_FOCUS,
0390: realOppositeWindow);
0391: }
0392: boolean retval = typeAheadAssertions(newFocusedWindow, we);
0393: return retval;
0394: }
0395:
0396: case FocusEvent.FOCUS_GAINED: {
0397: FocusEvent fe = (FocusEvent) e;
0398: Component oldFocusOwner = getGlobalFocusOwner();
0399: Component newFocusOwner = fe.getComponent();
0400: if (oldFocusOwner == newFocusOwner) {
0401: break;
0402: }
0403:
0404: // If there exists a current focus owner, then notify it that
0405: // it has lost focus.
0406: if (oldFocusOwner != null) {
0407: boolean isEventDispatched = sendMessage(oldFocusOwner,
0408: new FocusEvent(oldFocusOwner,
0409: FocusEvent.FOCUS_LOST,
0410: fe.isTemporary(), newFocusOwner));
0411: // Failed to dispatch, clear by ourselfves
0412: if (!isEventDispatched) {
0413: setGlobalFocusOwner(null);
0414: if (!fe.isTemporary()) {
0415: setGlobalPermanentFocusOwner(null);
0416: }
0417: }
0418: }
0419:
0420: // Because the native windowing system has a different notion
0421: // of the current focus and activation states, it is possible
0422: // that a Component outside of the focused Window receives a
0423: // FOCUS_GAINED event. We synthesize a WINDOW_GAINED_FOCUS
0424: // event in that case.
0425: Component newFocusedWindow = newFocusOwner;
0426: while (newFocusedWindow != null
0427: && !(newFocusedWindow instanceof Window)) {
0428: newFocusedWindow = newFocusedWindow.parent;
0429: }
0430: // Bug 6188289
0431: /*
0432: Window currentFocusedWindow = getGlobalFocusedWindow();
0433: if (newFocusedWindow != null &&
0434: newFocusedWindow != currentFocusedWindow)
0435: {
0436: sendMessage(newFocusedWindow,
0437: new WindowEvent((Window)newFocusedWindow,
0438: WindowEvent.WINDOW_GAINED_FOCUS,
0439: currentFocusedWindow));
0440: if (newFocusedWindow != getGlobalFocusedWindow()) {
0441: // Focus change was rejected. Will happen if
0442: // newFocusedWindow is not a focusable Window.
0443:
0444: // Need to recover type-ahead, but don't bother
0445: // restoring focus. That was done by the
0446: // WINDOW_GAINED_FOCUS handler
0447: dequeueKeyEvents(-1, newFocusOwner);
0448: break;
0449: }
0450: }
0451:
0452: */
0453: setGlobalFocusOwner(newFocusOwner);
0454: if (newFocusOwner != getGlobalFocusOwner()) {
0455: // roll back the change
0456: // Bug 6211287 - we were calling the wrong version of
0457: // the restoreFocus method - here is the correct call and
0458: // the add'l necessary call to dequeueKeyEvents
0459: dequeueKeyEvents(-1, newFocusOwner);
0460: restoreFocus(fe, (Window) newFocusedWindow);
0461: break;
0462: }
0463: if (!fe.isTemporary()) {
0464: setGlobalPermanentFocusOwner(newFocusOwner);
0465: // what if it was vetoed...?
0466: if (newFocusOwner != getGlobalFocusOwner()) {
0467: // Focus change was rejected. Will happen if
0468: // newFocusOwner is not focus traversable.
0469: dequeueKeyEvents(-1, newFocusOwner);
0470: restoreFocus(fe, (Window) newFocusedWindow);
0471: break;
0472: }
0473: }
0474: Component realOppositeComponent = this .realOppositeComponent;
0475: if (realOppositeComponent != null
0476: && realOppositeComponent != fe
0477: .getOppositeComponent()) {
0478: fe = new FocusEvent(newFocusOwner,
0479: FocusEvent.FOCUS_GAINED, fe.isTemporary(),
0480: realOppositeComponent);
0481: }
0482:
0483: boolean retval = typeAheadAssertions(newFocusOwner, fe);
0484: return retval;
0485: }
0486:
0487: case FocusEvent.FOCUS_LOST: {
0488: FocusEvent fe = (FocusEvent) e;
0489: Component currentFocusOwner = getGlobalFocusOwner();
0490:
0491: if (currentFocusOwner == null) {
0492: break;
0493: }
0494:
0495: // Ignore cases where a Component loses focus to itself.
0496: // If we make a mistake because of retargeting, then the
0497: // FOCUS_GAINED handler will correct it.
0498: if (currentFocusOwner == fe.getOppositeComponent()) {
0499: break;
0500: }
0501:
0502: setGlobalFocusOwner(null);
0503:
0504: if (getGlobalFocusOwner() != null) {
0505: // Focus change was rejected. Unlikely, but possible.
0506: restoreFocus(currentFocusOwner, true);
0507: break;
0508: }
0509:
0510: if (!fe.isTemporary()) {
0511: setGlobalPermanentFocusOwner(null);
0512: // what if it was vetoed...?
0513: if (getGlobalPermanentFocusOwner() != null) {
0514: // Focus change was rejected. Unlikely, but possible.
0515: restoreFocus(currentFocusOwner, true);
0516: break;
0517: }
0518:
0519: } else {
0520: Window owningWindow = getContainingWindow(currentFocusOwner);
0521: if (owningWindow != null) {
0522: owningWindow
0523: .setTemporaryLostComponent(currentFocusOwner);
0524: }
0525: }
0526:
0527: // 6238261 - now that AWTEvent.setSource is package protected,
0528: // need to cast focus event as AWTEvent so we're in the same
0529: // package before calling setSource
0530: ((AWTEvent) fe).setSource(currentFocusOwner);
0531:
0532: realOppositeComponent = (fe.getOppositeComponent() != null) ? currentFocusOwner
0533: : null;
0534:
0535: return typeAheadAssertions(currentFocusOwner, fe);
0536: }
0537:
0538: case WindowEvent.WINDOW_LOST_FOCUS: {
0539:
0540: WindowEvent we = (WindowEvent) e;
0541: Window currentFocusedWindow = getGlobalFocusedWindow();
0542: if (currentFocusedWindow == null) {
0543: break;
0544: }
0545:
0546: // Special case -- if the native windowing system posts an
0547: // event claiming that the active Window has lost focus to the
0548: // focused Window, then discard the event. This is an artifact
0549: // of the native windowing system not knowing which Window is
0550: // really focused.
0551: Window losingFocusWindow = we.getWindow();
0552: Window activeWindow = getGlobalActiveWindow();
0553: Window oppositeWindow = we.getOppositeWindow();
0554: if (inSendMessage == 0 && losingFocusWindow == activeWindow
0555: && oppositeWindow == currentFocusedWindow) {
0556: break;
0557: }
0558:
0559: Component currentFocusOwner = getGlobalFocusOwner();
0560: if (currentFocusOwner != null) {
0561: // The focus owner should always receive a FOCUS_LOST event
0562: // before the Window is defocused.
0563: Component oppositeComp = null;
0564: if (oppositeWindow != null) {
0565: oppositeComp = oppositeWindow
0566: .getTemporaryLostComponent();
0567: if (oppositeComp == null) {
0568: oppositeComp = oppositeWindow
0569: .getMostRecentFocusOwner();
0570: }
0571: }
0572: if (oppositeComp == null) {
0573: oppositeComp = oppositeWindow;
0574: }
0575: sendMessage(currentFocusOwner, new FocusEvent(
0576: currentFocusOwner, FocusEvent.FOCUS_LOST, true,
0577: oppositeComp));
0578: }
0579: // LMK added - opposite info isn't available in pp1.1 focus events
0580: realOppositeWindow = currentFocusedWindow;
0581: setGlobalFocusedWindow(null);
0582: if (getGlobalFocusedWindow() != null) {
0583: // Focus change was rejected. Unlikely, but possible.
0584: restoreFocus(currentFocusedWindow, null, true);
0585: break;
0586: }
0587:
0588: // 6238261 - now that AWTEvent.setSource is package protected,
0589: // need to cast focus event as AWTEvent so we're in the same
0590: // package before calling setSource
0591: ((AWTEvent) we).setSource(currentFocusedWindow);
0592: /* LMK added code above - in pp1.1 we never have opposite window info in an
0593: * event
0594: realOppositeWindow = (oppositeWindow != null)
0595: ? currentFocusedWindow
0596: : null;
0597: */
0598: typeAheadAssertions(currentFocusedWindow, we);
0599:
0600: // if (oppositeWindow == null) {
0601: // oppositeWindow is always null for personal. So we also need to
0602: // check if activeWindow is NOT null before we send this event
0603: if (oppositeWindow == null && activeWindow != null) {
0604: // Then we need to deactive the active Window as well.
0605: // No need to synthesize in other cases, because
0606: // WINDOW_ACTIVATED will handle it if necessary.
0607: sendMessage(activeWindow, new WindowEvent(activeWindow,
0608: WindowEvent.WINDOW_DEACTIVATED, null));
0609: if (getGlobalActiveWindow() != null) {
0610: // Activation change was rejected. Unlikely,
0611: // but possible.
0612: restoreFocus(currentFocusedWindow, null, true);
0613: }
0614: }
0615: break;
0616: }
0617:
0618: case WindowEvent.WINDOW_DEACTIVATED: {
0619: WindowEvent we = (WindowEvent) e;
0620: Window currentActiveWindow = getGlobalActiveWindow();
0621: if (currentActiveWindow == null) {
0622: break;
0623: }
0624:
0625: setGlobalActiveWindow(null);
0626: if (getGlobalActiveWindow() != null) {
0627: // Activation change was rejected. Unlikely, but possible.
0628: break;
0629: }
0630:
0631: // 6238261 - now that AWTEvent.setSource is package protected,
0632: // need to cast focus event as AWTEvent so we're in the same
0633: // package before calling setSource
0634: ((AWTEvent) we).setSource(currentActiveWindow);
0635: return typeAheadAssertions(currentActiveWindow, we);
0636: }
0637:
0638: case KeyEvent.KEY_TYPED:
0639: case KeyEvent.KEY_PRESSED:
0640: case KeyEvent.KEY_RELEASED: {
0641: return typeAheadAssertions(null, e);
0642: }
0643:
0644: default:
0645: return false;
0646: }
0647: return true;
0648: }
0649:
0650: public boolean dispatchKeyEvent(KeyEvent e) {
0651: Component focusOwner = getFocusOwner();
0652: if (focusOwner != null && focusOwner.isShowing()
0653: && focusOwner.isFocusable() && focusOwner.isEnabled()) {
0654: if (!e.isConsumed()) {
0655: Component comp = e.getComponent();
0656: if (comp != null && comp.isEnabled()) {
0657: redispatchEvent(comp, e);
0658: }
0659: }
0660: }
0661: boolean stopPostProcessing = false;
0662: java.util.List processors = getKeyEventPostProcessors();
0663: if (processors != null) {
0664: for (java.util.Iterator iter = processors.iterator(); !stopPostProcessing
0665: && iter.hasNext();) {
0666: stopPostProcessing = (((KeyEventPostProcessor) (iter
0667: .next())).postProcessKeyEvent(e));
0668: }
0669: }
0670: if (!stopPostProcessing) {
0671: postProcessKeyEvent(e);
0672: }
0673: /*
0674: // Allow the peer to process KeyEvent
0675: Component source = e.getComponent();
0676: ComponentPeer peer = source.peer;
0677:
0678: if (peer == null || peer instanceof LightweightPeer) {
0679: // if focus owner is lightweight then its native container
0680: // processes event
0681: Container target = source.getNativeContainer();
0682: if (target != null) {
0683: peer = target.peer;
0684: }
0685: }
0686: if (peer != null) {
0687: peer.handleEvent(e);
0688: }
0689:
0690: */
0691: return true;
0692: }
0693:
0694: public boolean postProcessKeyEvent(KeyEvent e) {
0695: if (!e.isConsumed()) {
0696: Component target = e.getComponent();
0697: if (target != null) {
0698: Container p = (Container) (target instanceof Container ? target
0699: : target.getParent());
0700: if (p != null) {
0701: p.postProcessKeyEvent(e);
0702: }
0703: }
0704: }
0705: Component source = e.getComponent();
0706: if (source != null) {
0707: sun.awt.peer.ComponentPeer peer = source.peer;
0708: if (peer == null
0709: || peer instanceof sun.awt.peer.LightweightPeer) {
0710: Container target = source.getNativeContainer();
0711: if (target != null) {
0712: peer = target.peer;
0713: }
0714: }
0715: if (peer != null) {
0716: peer.handleEvent(e);
0717: }
0718: }
0719: return true;
0720: }
0721:
0722: private void pumpApprovedKeyEvents() {
0723: KeyEvent ke;
0724: if (requestCount() == 0) {
0725: synchronized (this ) {
0726: typeAheadMarkers.clear();
0727: }
0728: }
0729:
0730: do {
0731: ke = null;
0732: synchronized (this ) {
0733: if (enqueuedKeyEvents.size() != 0) {
0734: ke = (KeyEvent) enqueuedKeyEvents.getFirst();
0735: if (typeAheadMarkers.size() != 0) {
0736: TypeAheadMarker marker = (TypeAheadMarker) typeAheadMarkers
0737: .getFirst();
0738: if (ke.getWhen() > marker.after) {
0739: ke = null;
0740: }
0741: }
0742: if (ke != null) {
0743: enqueuedKeyEvents.removeFirst();
0744: }
0745: }
0746: }
0747: if (ke != null) {
0748: preDispatchKeyEvent(ke);
0749: }
0750: } while (ke != null);
0751: }
0752:
0753: private boolean typeAheadAssertions(Component target, AWTEvent e) {
0754: // Clear any pending events here as well as in the FOCUS_GAINED
0755: // handler. We need this call here in case a marker was removed in
0756: // response to a call to dequeueKeyEvents.
0757: pumpApprovedKeyEvents();
0758: switch (e.getID()) {
0759: case KeyEvent.KEY_TYPED:
0760: case KeyEvent.KEY_PRESSED:
0761: case KeyEvent.KEY_RELEASED: {
0762: KeyEvent ke = (KeyEvent) e;
0763: synchronized (this ) {
0764: if (typeAheadMarkers.size() != 0) {
0765: TypeAheadMarker marker = (TypeAheadMarker) typeAheadMarkers
0766: .getFirst();
0767: if (ke.getWhen() > marker.after) {
0768: enqueuedKeyEvents.addLast(ke);
0769: return true;
0770: }
0771: }
0772: }
0773: // KeyEvent was posted before focus change request
0774: boolean retval = preDispatchKeyEvent(ke);
0775: return retval;
0776: //return preDispatchKeyEvent(ke);
0777: }
0778: case FocusEvent.FOCUS_GAINED:
0779: // Search the marker list for the first marker tied to the
0780: // Component which just gained focus. Then remove that marker
0781: // and any markers which immediately follow and are tied to
0782: // the same Component. This handles the case where multiple
0783: // focus requests were made for the same Component in a row.
0784: // Since FOCUS_GAINED events will not be generated for these
0785: // additional requests, we need to clear those markers too.
0786: synchronized (this ) {
0787: boolean found = false;
0788: for (Iterator iter = typeAheadMarkers.iterator(); iter
0789: .hasNext();) {
0790: if (((TypeAheadMarker) iter.next()).untilFocused == target) {
0791: iter.remove();
0792: found = true;
0793: } else if (found) {
0794: break;
0795: }
0796: }
0797: }
0798: redispatchEvent(target, e);
0799: // Now, dispatch any pending KeyEvents which have been
0800: // released because of the FOCUS_GAINED event so that we don't
0801: // have to wait for another event to be posted to the queue.
0802: pumpApprovedKeyEvents();
0803: return true;
0804: default:
0805: redispatchEvent(target, e);
0806: return true;
0807: }
0808: }
0809:
0810: private boolean preDispatchKeyEvent(KeyEvent ke) {
0811: Component focusOwner = getFocusOwner();
0812: // 6238261 - now that AWTEvent.setSource is package protected,
0813: // need to cast focus event as AWTEvent so we're in the same
0814: // package before calling setSource
0815: ke.setSource(((focusOwner != null) ? focusOwner
0816: : getFocusedWindow()));
0817: if (ke.getSource() == null) {
0818: return true;
0819: }
0820: EventQueue.setCurrentEventAndMostRecentTime(ke);
0821: java.util.List dispatchers = getKeyEventDispatchers();
0822: if (dispatchers != null) {
0823: for (java.util.Iterator iter = dispatchers.iterator(); iter
0824: .hasNext();) {
0825: if (((KeyEventDispatcher) (iter.next()))
0826: .dispatchKeyEvent(ke)) {
0827: return true;
0828: }
0829: }
0830: }
0831: return dispatchKeyEvent(ke);
0832: }
0833:
0834: public void processKeyEvent(Component focusedComponent, KeyEvent e) {
0835: if (e.getID() == KeyEvent.KEY_TYPED) {
0836: if (consumeNextKeyTyped) {
0837: e.consume();
0838: consumeNextKeyTyped = false;
0839: }
0840: return;
0841: }
0842: if (focusedComponent.getFocusTraversalKeysEnabled()
0843: && !e.isConsumed()) {
0844: AWTKeyStroke stroke = AWTKeyStroke
0845: .getAWTKeyStrokeForEvent(e), oppStroke = AWTKeyStroke
0846: .getAWTKeyStroke(stroke.getKeyCode(), stroke
0847: .getModifiers(), !stroke.isOnKeyRelease());
0848: Set toTest;
0849: boolean contains, containsOpp;
0850: toTest = focusedComponent
0851: .getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
0852: contains = toTest.contains(stroke);
0853: containsOpp = toTest.contains(oppStroke);
0854: if (contains || containsOpp) {
0855: if (contains) {
0856: focusNextComponent(focusedComponent);
0857: }
0858: e.consume();
0859: consumeNextKeyTyped = (e.getID() == KeyEvent.KEY_PRESSED);
0860: return;
0861: }
0862: toTest = focusedComponent
0863: .getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
0864: contains = toTest.contains(stroke);
0865: containsOpp = toTest.contains(oppStroke);
0866: if (contains || containsOpp) {
0867: if (contains) {
0868: focusPreviousComponent(focusedComponent);
0869: }
0870: e.consume();
0871: consumeNextKeyTyped = (e.getID() == KeyEvent.KEY_PRESSED);
0872: return;
0873: }
0874: toTest = focusedComponent
0875: .getFocusTraversalKeys(KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);
0876: contains = toTest.contains(stroke);
0877: containsOpp = toTest.contains(oppStroke);
0878: if (contains || containsOpp) {
0879: if (contains) {
0880: upFocusCycle(focusedComponent);
0881: }
0882: e.consume();
0883: consumeNextKeyTyped = (e.getID() == KeyEvent.KEY_PRESSED);
0884: return;
0885: }
0886: if (!((focusedComponent instanceof Container) && ((Container) focusedComponent)
0887: .isFocusCycleRoot())) {
0888: return;
0889: }
0890: toTest = focusedComponent
0891: .getFocusTraversalKeys(KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS);
0892: contains = toTest.contains(stroke);
0893: containsOpp = toTest.contains(oppStroke);
0894: if (contains || containsOpp) {
0895: if (contains) {
0896: downFocusCycle((Container) focusedComponent);
0897: }
0898: e.consume();
0899: consumeNextKeyTyped = (e.getID() == KeyEvent.KEY_PRESSED);
0900: }
0901: }
0902: }
0903:
0904: protected synchronized void enqueueKeyEvents(long after,
0905: Component untilFocused) {
0906: if (untilFocused == null) {
0907: return;
0908: }
0909: int insertionIndex = 0, i = typeAheadMarkers.size();
0910: ListIterator iter = typeAheadMarkers.listIterator(i);
0911: for (; i > 0; i--) {
0912: TypeAheadMarker marker = (TypeAheadMarker) iter.previous();
0913: if (marker.after <= after) {
0914: insertionIndex = i;
0915: break;
0916: }
0917: }
0918: typeAheadMarkers.add(insertionIndex, new TypeAheadMarker(after,
0919: untilFocused));
0920: }
0921:
0922: protected synchronized void dequeueKeyEvents(long after,
0923: Component untilFocused) {
0924: if (untilFocused == null) {
0925: return;
0926: }
0927: TypeAheadMarker marker;
0928: ListIterator iter = typeAheadMarkers
0929: .listIterator((after >= 0) ? typeAheadMarkers.size()
0930: : 0);
0931: if (after < 0) {
0932: while (iter.hasNext()) {
0933: marker = (TypeAheadMarker) iter.next();
0934: if (marker.untilFocused == untilFocused) {
0935: iter.remove();
0936: return;
0937: }
0938: }
0939: } else {
0940: while (iter.hasPrevious()) {
0941: marker = (TypeAheadMarker) iter.previous();
0942: if (marker.untilFocused == untilFocused
0943: && marker.after == after) {
0944: iter.remove();
0945: return;
0946: }
0947: }
0948: }
0949: }
0950:
0951: protected synchronized void discardKeyEvents(Component comp) {
0952: if (comp == null) {
0953: return;
0954: }
0955: long start = -1;
0956: for (Iterator iter = typeAheadMarkers.iterator(); iter
0957: .hasNext();) {
0958: TypeAheadMarker marker = (TypeAheadMarker) iter.next();
0959: Component toTest = marker.untilFocused;
0960: boolean match = (toTest == comp);
0961: while (!match && toTest != null
0962: && !(toTest instanceof Window)) {
0963: toTest = toTest.getParent();
0964: match = (toTest == comp);
0965: }
0966: if (match) {
0967: if (start < 0) {
0968: start = marker.after;
0969: }
0970: iter.remove();
0971: } else if (start >= 0) {
0972: purgeStampedEvents(start, marker.after);
0973: start = -1;
0974: }
0975: }
0976: purgeStampedEvents(start, -1);
0977: }
0978:
0979: // Notes:
0980: // * must be called inside a synchronized block
0981: // * if 'start' is < 0, then this function does nothing
0982: // * if 'end' is < 0, then all KeyEvents from 'start' to the end of the
0983: // queue will be removed
0984: private void purgeStampedEvents(long start, long end) {
0985: if (start < 0) {
0986: return;
0987: }
0988: for (Iterator iter = enqueuedKeyEvents.iterator(); iter
0989: .hasNext();) {
0990: KeyEvent ke = (KeyEvent) iter.next();
0991: long time = ke.getWhen();
0992: if (start < time && (end < 0 || time <= end)) {
0993: iter.remove();
0994: }
0995: if (end >= 0 && time > end) {
0996: break;
0997: }
0998: }
0999: }
1000:
1001: public void focusPreviousComponent(Component aComponent) {
1002: if (aComponent != null) {
1003: aComponent.transferFocusBackward();
1004: }
1005: }
1006:
1007: public void focusNextComponent(Component aComponent) {
1008: if (aComponent != null) {
1009: aComponent.transferFocus();
1010: }
1011: }
1012:
1013: public void upFocusCycle(Component aComponent) {
1014: if (aComponent != null) {
1015: aComponent.transferFocusUpCycle();
1016: }
1017: }
1018:
1019: public void downFocusCycle(Container aContainer) {
1020: if (aContainer != null && aContainer.isFocusCycleRoot()) {
1021: aContainer.transferFocusDownCycle();
1022: }
1023: }
1024: }
|