History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/awt/DefaultKeyboardFocusManager.java (1 of 18352 files). Show all

Unified · Split

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