/*
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.awt;
import java.awt.event.
FocusEvent;
import java.awt.event.
KeyEvent;
import java.awt.event.
WindowEvent;
import java.awt.peer.
ComponentPeer;
import java.awt.peer.
LightweightPeer;
import java.lang.ref.
WeakReference;
import java.util.
Iterator;
import java.util.
LinkedList;
import java.util.
ListIterator;
import java.util.
Set;
import sun.awt.
AWTAccessor;
import sun.awt.
AppContext;
import sun.awt.
SunToolkit;
import sun.awt.
CausedFocusEvent;
import sun.awt.
TimedWindowEvent;
import sun.util.logging.
PlatformLogger;
/**
* The default KeyboardFocusManager for AWT applications. Focus traversal is
* done in response to a Component's focus traversal keys, and using a
* Container's FocusTraversalPolicy.
* <p>
* Please see
* <a href="https://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html">
* How to Use the Focus Subsystem</a>,
* a section in <em>The Java Tutorial</em>, and the
* <a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a>
* for more information.
*
* @author David Mendenhall
*
* @see FocusTraversalPolicy
* @see Component#setFocusTraversalKeys
* @see Component#getFocusTraversalKeys
* @since 1.4
*/
public class
DefaultKeyboardFocusManager extends
KeyboardFocusManager {
private static final
PlatformLogger focusLog =
PlatformLogger.
getLogger("java.awt.focus.DefaultKeyboardFocusManager");
// null weak references to not create too many objects
private static final
WeakReference<
Window>
NULL_WINDOW_WR =
new
WeakReference<
Window>(null);
private static final
WeakReference<
Component>
NULL_COMPONENT_WR =
new
WeakReference<
Component>(null);
private
WeakReference<
Window>
realOppositeWindowWR =
NULL_WINDOW_WR;
private
WeakReference<
Component>
realOppositeComponentWR =
NULL_COMPONENT_WR;
private int
inSendMessage;
private
LinkedList<
KeyEvent>
enqueuedKeyEvents = new
LinkedList<
KeyEvent>();
private
LinkedList<
TypeAheadMarker>
typeAheadMarkers = new
LinkedList<
TypeAheadMarker>();
private boolean
consumeNextKeyTyped;
private
Component restoreFocusTo;
static {
AWTAccessor.
setDefaultKeyboardFocusManagerAccessor(
new
AWTAccessor.
DefaultKeyboardFocusManagerAccessor() {
public void
consumeNextKeyTyped(
DefaultKeyboardFocusManager dkfm,
KeyEvent e) {
dkfm.
consumeNextKeyTyped(
e);
}
});
}
private static class
TypeAheadMarker {
long
after;
Component untilFocused;
TypeAheadMarker(long
after,
Component untilFocused) {
this.
after =
after;
this.
untilFocused =
untilFocused;
}
/**
* Returns string representation of the marker
*/
public
String toString() {
return ">>> Marker after " +
after + " on " +
untilFocused;
}
}
private
Window getOwningFrameDialog(
Window window) {
while (
window != null && !(
window instanceof
Frame ||
window instanceof
Dialog)) {
window = (
Window)
window.
getParent();
}
return
window;
}
/*
* This series of restoreFocus methods is used for recovering from a
* rejected focus or activation change. Rejections typically occur when
* the user attempts to focus a non-focusable Component or Window.
*/
private void
restoreFocus(
FocusEvent fe,
Window newFocusedWindow) {
Component realOppositeComponent = this.
realOppositeComponentWR.
get();
Component vetoedComponent =
fe.
getComponent();
if (
newFocusedWindow != null &&
restoreFocus(
newFocusedWindow,
vetoedComponent, false))
{
} else if (
realOppositeComponent != null &&
doRestoreFocus(
realOppositeComponent,
vetoedComponent, false)) {
} else if (
fe.
getOppositeComponent() != null &&
doRestoreFocus(
fe.
getOppositeComponent(),
vetoedComponent, false)) {
} else {
clearGlobalFocusOwnerPriv();
}
}
private void
restoreFocus(
WindowEvent we) {
Window realOppositeWindow = this.
realOppositeWindowWR.
get();
if (
realOppositeWindow != null
&&
restoreFocus(
realOppositeWindow, null, false))
{
// do nothing, everything is done in restoreFocus()
} else if (
we.
getOppositeWindow() != null &&
restoreFocus(
we.
getOppositeWindow(), null, false))
{
// do nothing, everything is done in restoreFocus()
} else {
clearGlobalFocusOwnerPriv();
}
}
private boolean
restoreFocus(
Window aWindow,
Component vetoedComponent,
boolean
clearOnFailure) {
restoreFocusTo = null;
Component toFocus =
KeyboardFocusManager.
getMostRecentFocusOwner(
aWindow);
if (
toFocus != null &&
toFocus !=
vetoedComponent) {
if (
getHeavyweight(
aWindow) !=
getNativeFocusOwner()) {
// cannot restore focus synchronously
if (!
toFocus.
isShowing() || !
toFocus.
canBeFocusOwner()) {
toFocus =
toFocus.
getNextFocusCandidate();
}
if (
toFocus != null &&
toFocus !=
vetoedComponent) {
if (!
toFocus.
requestFocus(false,
CausedFocusEvent.
Cause.
ROLLBACK)) {
restoreFocusTo =
toFocus;
}
return true;
}
} else if (
doRestoreFocus(
toFocus,
vetoedComponent, false)) {
return true;
}
}
if (
clearOnFailure) {
clearGlobalFocusOwnerPriv();
return true;
} else {
return false;
}
}
private boolean
restoreFocus(
Component toFocus, boolean
clearOnFailure) {
return
doRestoreFocus(
toFocus, null,
clearOnFailure);
}
private boolean
doRestoreFocus(
Component toFocus,
Component vetoedComponent,
boolean
clearOnFailure)
{
boolean
success = true;
if (
toFocus !=
vetoedComponent &&
toFocus.
isShowing() &&
toFocus.
canBeFocusOwner() &&
(
success =
toFocus.
requestFocus(false,
CausedFocusEvent.
Cause.
ROLLBACK)))
{
return true;
} else {
if (!
success &&
getGlobalFocusedWindow() !=
SunToolkit.
getContainingWindow(
toFocus)) {
restoreFocusTo =
toFocus;
return true;
}
Component nextFocus =
toFocus.
getNextFocusCandidate();
if (
nextFocus != null &&
nextFocus !=
vetoedComponent &&
nextFocus.
requestFocusInWindow(
CausedFocusEvent.
Cause.
ROLLBACK))
{
return true;
} else if (
clearOnFailure) {
clearGlobalFocusOwnerPriv();
return true;
} else {
return false;
}
}
}
/**
* A special type of SentEvent which updates a counter in the target
* KeyboardFocusManager if it is an instance of
* DefaultKeyboardFocusManager.
*/
private static class
DefaultKeyboardFocusManagerSentEvent
extends
SentEvent
{
/*
* serialVersionUID
*/
private static final long
serialVersionUID = -2924743257508701758L;
public
DefaultKeyboardFocusManagerSentEvent(
AWTEvent nested,
AppContext toNotify) {
super(
nested,
toNotify);
}
public final void
dispatch() {
KeyboardFocusManager manager =
KeyboardFocusManager.
getCurrentKeyboardFocusManager();
DefaultKeyboardFocusManager defaultManager =
(
manager instanceof
DefaultKeyboardFocusManager)
? (
DefaultKeyboardFocusManager)
manager
: null;
if (
defaultManager != null) {
synchronized (
defaultManager) {
defaultManager.
inSendMessage++;
}
}
super.dispatch();
if (
defaultManager != null) {
synchronized (
defaultManager) {
defaultManager.
inSendMessage--;
}
}
}
}
/**
* Sends a synthetic AWTEvent to a Component. If the Component is in
* the current AppContext, then the event is immediately dispatched.
* If the Component is in a different AppContext, then the event is
* posted to the other AppContext's EventQueue, and this method blocks
* until the event is handled or target AppContext is disposed.
* Returns true if successfuly dispatched event, false if failed
* to dispatch.
*/
static boolean
sendMessage(
Component target,
AWTEvent e) {
e.
isPosted = true;
AppContext myAppContext =
AppContext.
getAppContext();
final
AppContext targetAppContext =
target.
appContext;
final
SentEvent se =
new
DefaultKeyboardFocusManagerSentEvent(
e,
myAppContext);
if (
myAppContext ==
targetAppContext) {
se.
dispatch();
} else {
if (
targetAppContext.
isDisposed()) {
return false;
}
SunToolkit.
postEvent(
targetAppContext,
se);
if (
EventQueue.
isDispatchThread()) {
EventDispatchThread edt = (
EventDispatchThread)
Thread.
currentThread();
edt.
pumpEvents(
SentEvent.
ID, new
Conditional() {
public boolean
evaluate() {
return !
se.
dispatched && !
targetAppContext.
isDisposed();
}
});
} else {
synchronized (
se) {
while (!
se.
dispatched && !
targetAppContext.
isDisposed()) {
try {
se.
wait(1000);
} catch (
InterruptedException ie) {
break;
}
}
}
}
}
return
se.
dispatched;
}
/*
* Checks if the focus window event follows key events waiting in the type-ahead
* queue (if any). This may happen when a user types ahead in the window, the client
* listeners hang EDT for a while, and the user switches b/w toplevels. In that
* case the focus window events may be dispatched before the type-ahead events
* get handled. This may lead to wrong focus behavior and in order to avoid it,
* the focus window events are reposted to the end of the event queue. See 6981400.
*/
private boolean
repostIfFollowsKeyEvents(
WindowEvent e) {
if (!(
e instanceof
TimedWindowEvent)) {
return false;
}
TimedWindowEvent we = (
TimedWindowEvent)
e;
long
time =
we.
getWhen();
synchronized (this) {
KeyEvent ke =
enqueuedKeyEvents.
isEmpty() ? null :
enqueuedKeyEvents.
getFirst();
if (
ke != null &&
time >=
ke.
getWhen()) {
TypeAheadMarker marker =
typeAheadMarkers.
isEmpty() ? null :
typeAheadMarkers.
getFirst();
if (
marker != null) {
Window toplevel =
marker.
untilFocused.
getContainingWindow();
// Check that the component awaiting focus belongs to
// the current focused window. See 8015454.
if (
toplevel != null &&
toplevel.
isFocused()) {
SunToolkit.
postEvent(
AppContext.
getAppContext(), new
SequencedEvent(
e));
return true;
}
}
}
}
return false;
}
/**
* This method is called by the AWT event dispatcher requesting that the
* current KeyboardFocusManager dispatch the specified event on its behalf.
* DefaultKeyboardFocusManagers dispatch all FocusEvents, all WindowEvents
* related to focus, and all KeyEvents. These events are dispatched based
* on the KeyboardFocusManager's notion of the focus owner and the focused
* and active Windows, sometimes overriding the source of the specified
* AWTEvent. If this method returns <code>false</code>, then the AWT event
* dispatcher will attempt to dispatch the event itself.
*
* @param e the AWTEvent to be dispatched
* @return <code>true</code> if this method dispatched the event;
* <code>false</code> otherwise
*/
public boolean
dispatchEvent(
AWTEvent e) {
if (
focusLog.
isLoggable(
PlatformLogger.
Level.
FINE) && (
e instanceof
WindowEvent ||
e instanceof
FocusEvent)) {
focusLog.
fine("" +
e);
}
switch (
e.
getID()) {
case
WindowEvent.
WINDOW_GAINED_FOCUS: {
if (
repostIfFollowsKeyEvents((
WindowEvent)
e)) {
break;
}
WindowEvent we = (
WindowEvent)
e;
Window oldFocusedWindow =
getGlobalFocusedWindow();
Window newFocusedWindow =
we.
getWindow();
if (
newFocusedWindow ==
oldFocusedWindow) {
break;
}
if (!(
newFocusedWindow.
isFocusableWindow()
&&
newFocusedWindow.
isVisible()
&&
newFocusedWindow.
isDisplayable()))
{
// we can not accept focus on such window, so reject it.
restoreFocus(
we);
break;
}
// If there exists a current focused window, then notify it
// that it has lost focus.
if (
oldFocusedWindow != null) {
boolean
isEventDispatched =
sendMessage(
oldFocusedWindow,
new
WindowEvent(
oldFocusedWindow,
WindowEvent.
WINDOW_LOST_FOCUS,
newFocusedWindow));
// Failed to dispatch, clear by ourselfves
if (!
isEventDispatched) {
setGlobalFocusOwner(null);
setGlobalFocusedWindow(null);
}
}
// Because the native libraries do not post WINDOW_ACTIVATED
// events, we need to synthesize one if the active Window
// changed.
Window newActiveWindow =
getOwningFrameDialog(
newFocusedWindow);
Window currentActiveWindow =
getGlobalActiveWindow();
if (
newActiveWindow !=
currentActiveWindow) {
sendMessage(
newActiveWindow,
new
WindowEvent(
newActiveWindow,
WindowEvent.
WINDOW_ACTIVATED,
currentActiveWindow));
if (
newActiveWindow !=
getGlobalActiveWindow()) {
// Activation change was rejected. Unlikely, but
// possible.
restoreFocus(
we);
break;
}
}
setGlobalFocusedWindow(
newFocusedWindow);
if (
newFocusedWindow !=
getGlobalFocusedWindow()) {
// Focus change was rejected. Will happen if
// newFocusedWindow is not a focusable Window.
restoreFocus(
we);
break;
}
// Restore focus to the Component which last held it. We do
// this here so that client code can override our choice in
// a WINDOW_GAINED_FOCUS handler.
//
// Make sure that the focus change request doesn't change the
// focused Window in case we are no longer the focused Window
// when the request is handled.
if (
inSendMessage == 0) {
// Identify which Component should initially gain focus
// in the Window.
//
// * If we're in SendMessage, then this is a synthetic
// WINDOW_GAINED_FOCUS message which was generated by a
// the FOCUS_GAINED handler. Allow the Component to
// which the FOCUS_GAINED message was targeted to
// receive the focus.
// * Otherwise, look up the correct Component here.
// We don't use Window.getMostRecentFocusOwner because
// window is focused now and 'null' will be returned
// Calculating of most recent focus owner and focus
// request should be synchronized on KeyboardFocusManager.class
// to prevent from thread race when user will request
// focus between calculation and our request.
// But if focus transfer is synchronous, this synchronization
// may cause deadlock, thus we don't synchronize this block.
Component toFocus =
KeyboardFocusManager.
getMostRecentFocusOwner(
newFocusedWindow);
boolean
isFocusRestore =
restoreFocusTo != null &&
toFocus ==
restoreFocusTo;
if ((
toFocus == null) &&
newFocusedWindow.
isFocusableWindow())
{
toFocus =
newFocusedWindow.
getFocusTraversalPolicy().
getInitialComponent(
newFocusedWindow);
}
Component tempLost = null;
synchronized(
KeyboardFocusManager.class) {
tempLost =
newFocusedWindow.
setTemporaryLostComponent(null);
}
// The component which last has the focus when this window was focused
// should receive focus first
if (
focusLog.
isLoggable(
PlatformLogger.
Level.
FINER)) {
focusLog.
finer("tempLost {0}, toFocus {1}",
tempLost,
toFocus);
}
if (
tempLost != null) {
tempLost.
requestFocusInWindow(
isFocusRestore &&
tempLost ==
toFocus ?
CausedFocusEvent.
Cause.
ROLLBACK :
CausedFocusEvent.
Cause.
ACTIVATION);
}
if (
toFocus != null &&
toFocus !=
tempLost) {
// If there is a component which requested focus when this window
// was inactive it expects to receive focus after activation.
toFocus.
requestFocusInWindow(
CausedFocusEvent.
Cause.
ACTIVATION);
}
}
restoreFocusTo = null;
Window realOppositeWindow = this.
realOppositeWindowWR.
get();
if (
realOppositeWindow !=
we.
getOppositeWindow()) {
we = new
WindowEvent(
newFocusedWindow,
WindowEvent.
WINDOW_GAINED_FOCUS,
realOppositeWindow);
}
return
typeAheadAssertions(
newFocusedWindow,
we);
}
case
WindowEvent.
WINDOW_ACTIVATED: {
WindowEvent we = (
WindowEvent)
e;
Window oldActiveWindow =
getGlobalActiveWindow();
Window newActiveWindow =
we.
getWindow();
if (
oldActiveWindow ==
newActiveWindow) {
break;
}
// If there exists a current active window, then notify it that
// it has lost activation.
if (
oldActiveWindow != null) {
boolean
isEventDispatched =
sendMessage(
oldActiveWindow,
new
WindowEvent(
oldActiveWindow,
WindowEvent.
WINDOW_DEACTIVATED,
newActiveWindow));
// Failed to dispatch, clear by ourselfves
if (!
isEventDispatched) {
setGlobalActiveWindow(null);
}
if (
getGlobalActiveWindow() != null) {
// Activation change was rejected. Unlikely, but
// possible.
break;
}
}
setGlobalActiveWindow(
newActiveWindow);
if (
newActiveWindow !=
getGlobalActiveWindow()) {
// Activation change was rejected. Unlikely, but
// possible.
break;
}
return
typeAheadAssertions(
newActiveWindow,
we);
}
case
FocusEvent.
FOCUS_GAINED: {
restoreFocusTo = null;
FocusEvent fe = (
FocusEvent)
e;
CausedFocusEvent.
Cause cause = (
fe instanceof
CausedFocusEvent) ?
((
CausedFocusEvent)
fe).
getCause() :
CausedFocusEvent.
Cause.
UNKNOWN;
Component oldFocusOwner =
getGlobalFocusOwner();
Component newFocusOwner =
fe.
getComponent();
if (
oldFocusOwner ==
newFocusOwner) {
if (
focusLog.
isLoggable(
PlatformLogger.
Level.
FINE)) {
focusLog.
fine("Skipping {0} because focus owner is the same",
e);
}
// We can't just drop the event - there could be
// type-ahead markers associated with it.
dequeueKeyEvents(-1,
newFocusOwner);
break;
}
// If there exists a current focus owner, then notify it that
// it has lost focus.
if (
oldFocusOwner != null) {
boolean
isEventDispatched =
sendMessage(
oldFocusOwner,
new
CausedFocusEvent(
oldFocusOwner,
FocusEvent.
FOCUS_LOST,
fe.
isTemporary(),
newFocusOwner,
cause));
// Failed to dispatch, clear by ourselfves
if (!
isEventDispatched) {
setGlobalFocusOwner(null);
if (!
fe.
isTemporary()) {
setGlobalPermanentFocusOwner(null);
}
}
}
// Because the native windowing system has a different notion
// of the current focus and activation states, it is possible
// that a Component outside of the focused Window receives a
// FOCUS_GAINED event. We synthesize a WINDOW_GAINED_FOCUS
// event in that case.
final
Window newFocusedWindow =
SunToolkit.
getContainingWindow(
newFocusOwner);
final
Window currentFocusedWindow =
getGlobalFocusedWindow();
if (
newFocusedWindow != null &&
newFocusedWindow !=
currentFocusedWindow)
{
sendMessage(
newFocusedWindow,
new
WindowEvent(
newFocusedWindow,
WindowEvent.
WINDOW_GAINED_FOCUS,
currentFocusedWindow));
if (
newFocusedWindow !=
getGlobalFocusedWindow()) {
// Focus change was rejected. Will happen if
// newFocusedWindow is not a focusable Window.
// Need to recover type-ahead, but don't bother
// restoring focus. That was done by the
// WINDOW_GAINED_FOCUS handler
dequeueKeyEvents(-1,
newFocusOwner);
break;
}
}
if (!(
newFocusOwner.
isFocusable() &&
newFocusOwner.
isShowing() &&
// Refuse focus on a disabled component if the focus event
// isn't of UNKNOWN reason (i.e. not a result of a direct request
// but traversal, activation or system generated).
(
newFocusOwner.
isEnabled() ||
cause.
equals(
CausedFocusEvent.
Cause.
UNKNOWN))))
{
// we should not accept focus on such component, so reject it.
dequeueKeyEvents(-1,
newFocusOwner);
if (
KeyboardFocusManager.
isAutoFocusTransferEnabled()) {
// If FOCUS_GAINED is for a disposed component (however
// it shouldn't happen) its toplevel parent is null. In this
// case we have to try to restore focus in the current focused
// window (for the details: 6607170).
if (
newFocusedWindow == null) {
restoreFocus(
fe,
currentFocusedWindow);
} else {
restoreFocus(
fe,
newFocusedWindow);
}
setMostRecentFocusOwner(
newFocusedWindow, null); // see: 8013773
}
break;
}
setGlobalFocusOwner(
newFocusOwner);
if (
newFocusOwner !=
getGlobalFocusOwner()) {
// Focus change was rejected. Will happen if
// newFocusOwner is not focus traversable.
dequeueKeyEvents(-1,
newFocusOwner);
if (
KeyboardFocusManager.
isAutoFocusTransferEnabled()) {
restoreFocus(
fe, (
Window)
newFocusedWindow);
}
break;
}
if (!
fe.
isTemporary()) {
setGlobalPermanentFocusOwner(
newFocusOwner);
if (
newFocusOwner !=
getGlobalPermanentFocusOwner()) {
// Focus change was rejected. Unlikely, but possible.
dequeueKeyEvents(-1,
newFocusOwner);
if (
KeyboardFocusManager.
isAutoFocusTransferEnabled()) {
restoreFocus(
fe, (
Window)
newFocusedWindow);
}
break;
}
}
setNativeFocusOwner(
getHeavyweight(
newFocusOwner));
Component realOppositeComponent = this.
realOppositeComponentWR.
get();
if (
realOppositeComponent != null &&
realOppositeComponent !=
fe.
getOppositeComponent()) {
fe = new
CausedFocusEvent(
newFocusOwner,
FocusEvent.
FOCUS_GAINED,
fe.
isTemporary(),
realOppositeComponent,
cause);
((
AWTEvent)
fe).
isPosted = true;
}
return
typeAheadAssertions(
newFocusOwner,
fe);
}
case
FocusEvent.
FOCUS_LOST: {
FocusEvent fe = (
FocusEvent)
e;
Component currentFocusOwner =
getGlobalFocusOwner();
if (
currentFocusOwner == null) {
if (
focusLog.
isLoggable(
PlatformLogger.
Level.
FINE))
focusLog.
fine("Skipping {0} because focus owner is null",
e);
break;
}
// Ignore cases where a Component loses focus to itself.
// If we make a mistake because of retargeting, then the
// FOCUS_GAINED handler will correct it.
if (
currentFocusOwner ==
fe.
getOppositeComponent()) {
if (
focusLog.
isLoggable(
PlatformLogger.
Level.
FINE))
focusLog.
fine("Skipping {0} because current focus owner is equal to opposite",
e);
break;
}
setGlobalFocusOwner(null);
if (
getGlobalFocusOwner() != null) {
// Focus change was rejected. Unlikely, but possible.
restoreFocus(
currentFocusOwner, true);
break;
}
if (!
fe.
isTemporary()) {
setGlobalPermanentFocusOwner(null);
if (
getGlobalPermanentFocusOwner() != null) {
// Focus change was rejected. Unlikely, but possible.
restoreFocus(
currentFocusOwner, true);
break;
}
} else {
Window owningWindow =
currentFocusOwner.
getContainingWindow();
if (
owningWindow != null) {
owningWindow.
setTemporaryLostComponent(
currentFocusOwner);
}
}
setNativeFocusOwner(null);
fe.
setSource(
currentFocusOwner);
realOppositeComponentWR = (
fe.
getOppositeComponent() != null)
? new
WeakReference<
Component>(
currentFocusOwner)
:
NULL_COMPONENT_WR;
return
typeAheadAssertions(
currentFocusOwner,
fe);
}
case
WindowEvent.
WINDOW_DEACTIVATED: {
WindowEvent we = (
WindowEvent)
e;
Window currentActiveWindow =
getGlobalActiveWindow();
if (
currentActiveWindow == null) {
break;
}
if (
currentActiveWindow !=
e.
getSource()) {
// The event is lost in time.
// Allow listeners to precess the event but do not
// change any global states
break;
}
setGlobalActiveWindow(null);
if (
getGlobalActiveWindow() != null) {
// Activation change was rejected. Unlikely, but possible.
break;
}
we.
setSource(
currentActiveWindow);
return
typeAheadAssertions(
currentActiveWindow,
we);
}
case
WindowEvent.
WINDOW_LOST_FOCUS: {
if (
repostIfFollowsKeyEvents((
WindowEvent)
e)) {
break;
}
WindowEvent we = (
WindowEvent)
e;
Window currentFocusedWindow =
getGlobalFocusedWindow();
Window losingFocusWindow =
we.
getWindow();
Window activeWindow =
getGlobalActiveWindow();
Window oppositeWindow =
we.
getOppositeWindow();
if (
focusLog.
isLoggable(
PlatformLogger.
Level.
FINE))
focusLog.
fine("Active {0}, Current focused {1}, losing focus {2} opposite {3}",
activeWindow,
currentFocusedWindow,
losingFocusWindow,
oppositeWindow);
if (
currentFocusedWindow == null) {
break;
}
// Special case -- if the native windowing system posts an
// event claiming that the active Window has lost focus to the
// focused Window, then discard the event. This is an artifact
// of the native windowing system not knowing which Window is
// really focused.
if (
inSendMessage == 0 &&
losingFocusWindow ==
activeWindow &&
oppositeWindow ==
currentFocusedWindow)
{
break;
}
Component currentFocusOwner =
getGlobalFocusOwner();
if (
currentFocusOwner != null) {
// The focus owner should always receive a FOCUS_LOST event
// before the Window is defocused.
Component oppositeComp = null;
if (
oppositeWindow != null) {
oppositeComp =
oppositeWindow.
getTemporaryLostComponent();
if (
oppositeComp == null) {
oppositeComp =
oppositeWindow.
getMostRecentFocusOwner();
}
}
if (
oppositeComp == null) {
oppositeComp =
oppositeWindow;
}
sendMessage(
currentFocusOwner,
new
CausedFocusEvent(
currentFocusOwner,
FocusEvent.
FOCUS_LOST,
true,
oppositeComp,
CausedFocusEvent.
Cause.
ACTIVATION));
}
setGlobalFocusedWindow(null);
if (
getGlobalFocusedWindow() != null) {
// Focus change was rejected. Unlikely, but possible.
restoreFocus(
currentFocusedWindow, null, true);
break;
}
we.
setSource(
currentFocusedWindow);
realOppositeWindowWR = (
oppositeWindow != null)
? new
WeakReference<
Window>(
currentFocusedWindow)
:
NULL_WINDOW_WR;
typeAheadAssertions(
currentFocusedWindow,
we);
if (
oppositeWindow == null &&
activeWindow != null) {
// Then we need to deactive the active Window as well.
// No need to synthesize in other cases, because
// WINDOW_ACTIVATED will handle it if necessary.
sendMessage(
activeWindow,
new
WindowEvent(
activeWindow,
WindowEvent.
WINDOW_DEACTIVATED,
null));
if (
getGlobalActiveWindow() != null) {
// Activation change was rejected. Unlikely,
// but possible.
restoreFocus(
currentFocusedWindow, null, true);
}
}
break;
}
case
KeyEvent.
KEY_TYPED:
case
KeyEvent.
KEY_PRESSED:
case
KeyEvent.
KEY_RELEASED:
return
typeAheadAssertions(null,
e);
default:
return false;
}
return true;
}
/**
* Called by <code>dispatchEvent</code> if no other
* KeyEventDispatcher in the dispatcher chain dispatched the KeyEvent, or
* if no other KeyEventDispatchers are registered. If the event has not
* been consumed, its target is enabled, and the focus owner is not null,
* this method dispatches the event to its target. This method will also
* subsequently dispatch the event to all registered
* KeyEventPostProcessors. After all this operations are finished,
* the event is passed to peers for processing.
* <p>
* In all cases, this method returns <code>true</code>, since
* DefaultKeyboardFocusManager is designed so that neither
* <code>dispatchEvent</code>, nor the AWT event dispatcher, should take
* further action on the event in any situation.
*
* @param e the KeyEvent to be dispatched
* @return <code>true</code>
* @see Component#dispatchEvent
*/
public boolean
dispatchKeyEvent(
KeyEvent e) {
Component focusOwner = (((
AWTEvent)
e).
isPosted) ?
getFocusOwner() :
e.
getComponent();
if (
focusOwner != null &&
focusOwner.
isShowing() &&
focusOwner.
canBeFocusOwner()) {
if (!
e.
isConsumed()) {
Component comp =
e.
getComponent();
if (
comp != null &&
comp.
isEnabled()) {
redispatchEvent(
comp,
e);
}
}
}
boolean
stopPostProcessing = false;
java.util.
List<
KeyEventPostProcessor>
processors =
getKeyEventPostProcessors();
if (
processors != null) {
for (java.util.
Iterator<
KeyEventPostProcessor>
iter =
processors.
iterator();
!
stopPostProcessing &&
iter.
hasNext(); )
{
stopPostProcessing =
iter.
next().
postProcessKeyEvent(
e);
}
}
if (!
stopPostProcessing) {
postProcessKeyEvent(
e);
}
// Allow the peer to process KeyEvent
Component source =
e.
getComponent();
ComponentPeer peer =
source.
getPeer();
if (
peer == null ||
peer instanceof
LightweightPeer) {
// if focus owner is lightweight then its native container
// processes event
Container target =
source.
getNativeContainer();
if (
target != null) {
peer =
target.
getPeer();
}
}
if (
peer != null) {
peer.
handleEvent(
e);
}
return true;
}
/**
* This method will be called by <code>dispatchKeyEvent</code>. It will
* handle any unconsumed KeyEvents that map to an AWT
* <code>MenuShortcut</code> by consuming the event and activating the
* shortcut.
*
* @param e the KeyEvent to post-process
* @return <code>true</code>
* @see #dispatchKeyEvent
* @see MenuShortcut
*/
public boolean
postProcessKeyEvent(
KeyEvent e) {
if (!
e.
isConsumed()) {
Component target =
e.
getComponent();
Container p = (
Container)
(
target instanceof
Container ?
target :
target.
getParent());
if (
p != null) {
p.
postProcessKeyEvent(
e);
}
}
return true;
}
private void
pumpApprovedKeyEvents() {
KeyEvent ke;
do {
ke = null;
synchronized (this) {
if (
enqueuedKeyEvents.
size() != 0) {
ke =
enqueuedKeyEvents.
getFirst();
if (
typeAheadMarkers.
size() != 0) {
TypeAheadMarker marker =
typeAheadMarkers.
getFirst();
// Fixed 5064013: may appears that the events have the same time
// if (ke.getWhen() >= marker.after) {
// The fix is rolled out.
if (
ke.
getWhen() >
marker.
after) {
ke = null;
}
}
if (
ke != null) {
if (
focusLog.
isLoggable(
PlatformLogger.
Level.
FINER)) {
focusLog.
finer("Pumping approved event {0}",
ke);
}
enqueuedKeyEvents.
removeFirst();
}
}
}
if (
ke != null) {
preDispatchKeyEvent(
ke);
}
} while (
ke != null);
}
/**
* Dumps the list of type-ahead queue markers to stderr
*/
void
dumpMarkers() {
if (
focusLog.
isLoggable(
PlatformLogger.
Level.
FINEST)) {
focusLog.
finest(">>> Markers dump, time: {0}",
System.
currentTimeMillis());
synchronized (this) {
if (
typeAheadMarkers.
size() != 0) {
Iterator<
TypeAheadMarker>
iter =
typeAheadMarkers.
iterator();
while (
iter.
hasNext()) {
TypeAheadMarker marker =
iter.
next();
focusLog.
finest(" {0}",
marker);
}
}
}
}
}
private boolean
typeAheadAssertions(
Component target,
AWTEvent e) {
// Clear any pending events here as well as in the FOCUS_GAINED
// handler. We need this call here in case a marker was removed in
// response to a call to dequeueKeyEvents.
pumpApprovedKeyEvents();
switch (
e.
getID()) {
case
KeyEvent.
KEY_TYPED:
case
KeyEvent.
KEY_PRESSED:
case
KeyEvent.
KEY_RELEASED: {
KeyEvent ke = (
KeyEvent)
e;
synchronized (this) {
if (
e.
isPosted &&
typeAheadMarkers.
size() != 0) {
TypeAheadMarker marker =
typeAheadMarkers.
getFirst();
// Fixed 5064013: may appears that the events have the same time
// if (ke.getWhen() >= marker.after) {
// The fix is rolled out.
if (
ke.
getWhen() >
marker.
after) {
if (
focusLog.
isLoggable(
PlatformLogger.
Level.
FINER)) {
focusLog.
finer("Storing event {0} because of marker {1}",
ke,
marker);
}
enqueuedKeyEvents.
addLast(
ke);
return true;
}
}
}
// KeyEvent was posted before focus change request
return
preDispatchKeyEvent(
ke);
}
case
FocusEvent.
FOCUS_GAINED:
if (
focusLog.
isLoggable(
PlatformLogger.
Level.
FINEST)) {
focusLog.
finest("Markers before FOCUS_GAINED on {0}",
target);
}
dumpMarkers();
// Search the marker list for the first marker tied to
// the Component which just gained focus. Then remove
// that marker, any markers which immediately follow
// and are tied to the same component, and all markers
// that preceed it. This handles the case where
// multiple focus requests were made for the same
// Component in a row and when we lost some of the
// earlier requests. Since FOCUS_GAINED events will
// not be generated for these additional requests, we
// need to clear those markers too.
synchronized (this) {
boolean
found = false;
if (
hasMarker(
target)) {
for (
Iterator<
TypeAheadMarker>
iter =
typeAheadMarkers.
iterator();
iter.
hasNext(); )
{
if (
iter.
next().
untilFocused ==
target) {
found = true;
} else if (
found) {
break;
}
iter.
remove();
}
} else {
// Exception condition - event without marker
if (
focusLog.
isLoggable(
PlatformLogger.
Level.
FINER)) {
focusLog.
finer("Event without marker {0}",
e);
}
}
}
focusLog.
finest("Markers after FOCUS_GAINED");
dumpMarkers();
redispatchEvent(
target,
e);
// Now, dispatch any pending KeyEvents which have been
// released because of the FOCUS_GAINED event so that we don't
// have to wait for another event to be posted to the queue.
pumpApprovedKeyEvents();
return true;
default:
redispatchEvent(
target,
e);
return true;
}
}
/**
* Returns true if there are some marker associated with component <code>comp</code>
* in a markers' queue
* @since 1.5
*/
private boolean
hasMarker(
Component comp) {
for (
Iterator<
TypeAheadMarker>
iter =
typeAheadMarkers.
iterator();
iter.
hasNext(); ) {
if (
iter.
next().
untilFocused ==
comp) {
return true;
}
}
return false;
}
/**
* Clears markers queue
* @since 1.5
*/
void
clearMarkers() {
synchronized(this) {
typeAheadMarkers.
clear();
}
}
private boolean
preDispatchKeyEvent(
KeyEvent ke) {
if (((
AWTEvent)
ke).
isPosted) {
Component focusOwner =
getFocusOwner();
ke.
setSource(((
focusOwner != null) ?
focusOwner :
getFocusedWindow()));
}
if (
ke.
getSource() == null) {
return true;
}
// Explicitly set the key event timestamp here (not in Component.dispatchEventImpl):
// - A key event is anyway passed to this method which starts its actual dispatching.
// - If a key event is put to the type ahead queue, its time stamp should not be registered
// until its dispatching actually starts (by this method).
EventQueue.
setCurrentEventAndMostRecentTime(
ke);
/**
* Fix for 4495473.
* This fix allows to correctly dispatch events when native
* event proxying mechanism is active.
* If it is active we should redispatch key events after
* we detected its correct target.
*/
if (
KeyboardFocusManager.
isProxyActive(
ke)) {
Component source = (
Component)
ke.
getSource();
Container target =
source.
getNativeContainer();
if (
target != null) {
ComponentPeer peer =
target.
getPeer();
if (
peer != null) {
peer.
handleEvent(
ke);
/**
* Fix for 4478780 - consume event after it was dispatched by peer.
*/
ke.
consume();
}
}
return true;
}
java.util.
List<
KeyEventDispatcher>
dispatchers =
getKeyEventDispatchers();
if (
dispatchers != null) {
for (java.util.
Iterator<
KeyEventDispatcher>
iter =
dispatchers.
iterator();
iter.
hasNext(); )
{
if (
iter.
next().
dispatchKeyEvent(
ke))
{
return true;
}
}
}
return
dispatchKeyEvent(
ke);
}
/*
* @param e is a KEY_PRESSED event that can be used
* to track the next KEY_TYPED related.
*/
private void
consumeNextKeyTyped(
KeyEvent e) {
consumeNextKeyTyped = true;
}
private void
consumeTraversalKey(
KeyEvent e) {
e.
consume();
consumeNextKeyTyped = (
e.
getID() ==
KeyEvent.
KEY_PRESSED) &&
!
e.
isActionKey();
}
/*
* return true if event was consumed
*/
private boolean
consumeProcessedKeyEvent(
KeyEvent e) {
if ((
e.
getID() ==
KeyEvent.
KEY_TYPED) &&
consumeNextKeyTyped) {
e.
consume();
consumeNextKeyTyped = false;
return true;
}
return false;
}
/**
* This method initiates a focus traversal operation if and only if the
* KeyEvent represents a focus traversal key for the specified
* focusedComponent. It is expected that focusedComponent is the current
* focus owner, although this need not be the case. If it is not,
* focus traversal will nevertheless proceed as if focusedComponent
* were the focus owner.
*
* @param focusedComponent the Component that is the basis for a focus
* traversal operation if the specified event represents a focus
* traversal key for the Component
* @param e the event that may represent a focus traversal key
*/
public void
processKeyEvent(
Component focusedComponent,
KeyEvent e) {
// consume processed event if needed
if (
consumeProcessedKeyEvent(
e)) {
return;
}
// KEY_TYPED events cannot be focus traversal keys
if (
e.
getID() ==
KeyEvent.
KEY_TYPED) {
return;
}
if (
focusedComponent.
getFocusTraversalKeysEnabled() &&
!
e.
isConsumed())
{
AWTKeyStroke stroke =
AWTKeyStroke.
getAWTKeyStrokeForEvent(
e),
oppStroke =
AWTKeyStroke.
getAWTKeyStroke(
stroke.
getKeyCode(),
stroke.
getModifiers(),
!
stroke.
isOnKeyRelease());
Set<
AWTKeyStroke>
toTest;
boolean
contains,
containsOpp;
toTest =
focusedComponent.
getFocusTraversalKeys(
KeyboardFocusManager.
FORWARD_TRAVERSAL_KEYS);
contains =
toTest.
contains(
stroke);
containsOpp =
toTest.
contains(
oppStroke);
if (
contains ||
containsOpp) {
consumeTraversalKey(
e);
if (
contains) {
focusNextComponent(
focusedComponent);
}
return;
} else if (
e.
getID() ==
KeyEvent.
KEY_PRESSED) {
// Fix for 6637607: consumeNextKeyTyped should be reset.
consumeNextKeyTyped = false;
}
toTest =
focusedComponent.
getFocusTraversalKeys(
KeyboardFocusManager.
BACKWARD_TRAVERSAL_KEYS);
contains =
toTest.
contains(
stroke);
containsOpp =
toTest.
contains(
oppStroke);
if (
contains ||
containsOpp) {
consumeTraversalKey(
e);
if (
contains) {
focusPreviousComponent(
focusedComponent);
}
return;
}
toTest =
focusedComponent.
getFocusTraversalKeys(
KeyboardFocusManager.
UP_CYCLE_TRAVERSAL_KEYS);
contains =
toTest.
contains(
stroke);
containsOpp =
toTest.
contains(
oppStroke);
if (
contains ||
containsOpp) {
consumeTraversalKey(
e);
if (
contains) {
upFocusCycle(
focusedComponent);
}
return;
}
if (!((
focusedComponent instanceof
Container) &&
((
Container)
focusedComponent).
isFocusCycleRoot())) {
return;
}
toTest =
focusedComponent.
getFocusTraversalKeys(
KeyboardFocusManager.
DOWN_CYCLE_TRAVERSAL_KEYS);
contains =
toTest.
contains(
stroke);
containsOpp =
toTest.
contains(
oppStroke);
if (
contains ||
containsOpp) {
consumeTraversalKey(
e);
if (
contains) {
downFocusCycle((
Container)
focusedComponent);
}
}
}
}
/**
* Delays dispatching of KeyEvents until the specified Component becomes
* the focus owner. KeyEvents with timestamps later than the specified
* timestamp will be enqueued until the specified Component receives a
* FOCUS_GAINED event, or the AWT cancels the delay request by invoking
* <code>dequeueKeyEvents</code> or <code>discardKeyEvents</code>.
*
* @param after timestamp of current event, or the current, system time if
* the current event has no timestamp, or the AWT cannot determine
* which event is currently being handled
* @param untilFocused Component which will receive a FOCUS_GAINED event
* before any pending KeyEvents
* @see #dequeueKeyEvents
* @see #discardKeyEvents
*/
protected synchronized void
enqueueKeyEvents(long
after,
Component untilFocused) {
if (
untilFocused == null) {
return;
}
if (
focusLog.
isLoggable(
PlatformLogger.
Level.
FINER)) {
focusLog.
finer("Enqueue at {0} for {1}",
after,
untilFocused);
}
int
insertionIndex = 0,
i =
typeAheadMarkers.
size();
ListIterator<
TypeAheadMarker>
iter =
typeAheadMarkers.
listIterator(
i);
for (;
i > 0;
i--) {
TypeAheadMarker marker =
iter.
previous();
if (
marker.
after <=
after) {
insertionIndex =
i;
break;
}
}
typeAheadMarkers.
add(
insertionIndex,
new
TypeAheadMarker(
after,
untilFocused));
}
/**
* Releases for normal dispatching to the current focus owner all
* KeyEvents which were enqueued because of a call to
* <code>enqueueKeyEvents</code> with the same timestamp and Component.
* If the given timestamp is less than zero, the outstanding enqueue
* request for the given Component with the <b>oldest</b> timestamp (if
* any) should be cancelled.
*
* @param after the timestamp specified in the call to
* <code>enqueueKeyEvents</code>, or any value < 0
* @param untilFocused the Component specified in the call to
* <code>enqueueKeyEvents</code>
* @see #enqueueKeyEvents
* @see #discardKeyEvents
*/
protected synchronized void
dequeueKeyEvents(long
after,
Component untilFocused) {
if (
untilFocused == null) {
return;
}
if (
focusLog.
isLoggable(
PlatformLogger.
Level.
FINER)) {
focusLog.
finer("Dequeue at {0} for {1}",
after,
untilFocused);
}
TypeAheadMarker marker;
ListIterator<
TypeAheadMarker>
iter =
typeAheadMarkers.
listIterator
((
after >= 0) ?
typeAheadMarkers.
size() : 0);
if (
after < 0) {
while (
iter.
hasNext()) {
marker =
iter.
next();
if (
marker.
untilFocused ==
untilFocused)
{
iter.
remove();
return;
}
}
} else {
while (
iter.
hasPrevious()) {
marker =
iter.
previous();
if (
marker.
untilFocused ==
untilFocused &&
marker.
after ==
after)
{
iter.
remove();
return;
}
}
}
}
/**
* Discards all KeyEvents which were enqueued because of one or more calls
* to <code>enqueueKeyEvents</code> with the specified Component, or one of
* its descendants.
*
* @param comp the Component specified in one or more calls to
* <code>enqueueKeyEvents</code>, or a parent of such a Component
* @see #enqueueKeyEvents
* @see #dequeueKeyEvents
*/
protected synchronized void
discardKeyEvents(
Component comp) {
if (
comp == null) {
return;
}
long
start = -1;
for (
Iterator<
TypeAheadMarker>
iter =
typeAheadMarkers.
iterator();
iter.
hasNext(); ) {
TypeAheadMarker marker =
iter.
next();
Component toTest =
marker.
untilFocused;
boolean
match = (
toTest ==
comp);
while (!
match &&
toTest != null && !(
toTest instanceof
Window)) {
toTest =
toTest.
getParent();
match = (
toTest ==
comp);
}
if (
match) {
if (
start < 0) {
start =
marker.
after;
}
iter.
remove();
} else if (
start >= 0) {
purgeStampedEvents(
start,
marker.
after);
start = -1;
}
}
purgeStampedEvents(
start, -1);
}
// Notes:
// * must be called inside a synchronized block
// * if 'start' is < 0, then this function does nothing
// * if 'end' is < 0, then all KeyEvents from 'start' to the end of the
// queue will be removed
private void
purgeStampedEvents(long
start, long
end) {
if (
start < 0) {
return;
}
for (
Iterator<
KeyEvent>
iter =
enqueuedKeyEvents.
iterator();
iter.
hasNext(); ) {
KeyEvent ke =
iter.
next();
long
time =
ke.
getWhen();
if (
start <
time && (
end < 0 ||
time <=
end)) {
iter.
remove();
}
if (
end >= 0 &&
time >
end) {
break;
}
}
}
/**
* Focuses the Component before aComponent, typically based on a
* FocusTraversalPolicy.
*
* @param aComponent the Component that is the basis for the focus
* traversal operation
* @see FocusTraversalPolicy
* @see Component#transferFocusBackward
*/
public void
focusPreviousComponent(
Component aComponent) {
if (
aComponent != null) {
aComponent.
transferFocusBackward();
}
}
/**
* Focuses the Component after aComponent, typically based on a
* FocusTraversalPolicy.
*
* @param aComponent the Component that is the basis for the focus
* traversal operation
* @see FocusTraversalPolicy
* @see Component#transferFocus
*/
public void
focusNextComponent(
Component aComponent) {
if (
aComponent != null) {
aComponent.
transferFocus();
}
}
/**
* Moves the focus up one focus traversal cycle. Typically, the focus owner
* is set to aComponent's focus cycle root, and the current focus cycle
* root is set to the new focus owner's focus cycle root. If, however,
* aComponent's focus cycle root is a Window, then the focus owner is set
* to the focus cycle root's default Component to focus, and the current
* focus cycle root is unchanged.
*
* @param aComponent the Component that is the basis for the focus
* traversal operation
* @see Component#transferFocusUpCycle
*/
public void
upFocusCycle(
Component aComponent) {
if (
aComponent != null) {
aComponent.
transferFocusUpCycle();
}
}
/**
* Moves the focus down one focus traversal cycle. If aContainer is a focus
* cycle root, then the focus owner is set to aContainer's default
* Component to focus, and the current focus cycle root is set to
* aContainer. If aContainer is not a focus cycle root, then no focus
* traversal operation occurs.
*
* @param aContainer the Container that is the basis for the focus
* traversal operation
* @see Container#transferFocusDownCycle
*/
public void
downFocusCycle(
Container aContainer) {
if (
aContainer != null &&
aContainer.
isFocusCycleRoot()) {
aContainer.
transferFocusDownCycle();
}
}
}