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