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 PlatformLogger focusLog = PlatformLogger.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<KeyEvent> enqueuedKeyEvents = new LinkedList<KeyEvent>();
76 private LinkedList<TypeAheadMarker> typeAheadMarkers = new LinkedList<TypeAheadMarker>();
77 private boolean consumeNextKeyTyped;
78
79 static {
80 AWTAccessor.setDefaultKeyboardFocusManagerAccessor(
81 new AWTAccessor.DefaultKeyboardFocusManagerAccessor() {
82 public void consumeNextKeyTyped(DefaultKeyboardFocusManager dkfm, KeyEvent e) {
83 dkfm.consumeNextKeyTyped(e);
84 }
85 });
86 }
87
88 private static class TypeAheadMarker {
89 long after;
90 Component untilFocused;
91
92 TypeAheadMarker(long after, Component untilFocused) {
93 this.after = after;
94 this.untilFocused = untilFocused;
95 }
96 /**
97 * Returns string representation of the marker
128 } else {
129 clearGlobalFocusOwnerPriv();
130 }
131 }
132 private void restoreFocus(WindowEvent we) {
133 Window realOppositeWindow = this.realOppositeWindowWR.get();
134 if (realOppositeWindow != null
135 && restoreFocus(realOppositeWindow, null, false))
136 {
137 // do nothing, everything is done in restoreFocus()
138 } else if (we.getOppositeWindow() != null &&
139 restoreFocus(we.getOppositeWindow(), null, false))
140 {
141 // do nothing, everything is done in restoreFocus()
142 } else {
143 clearGlobalFocusOwnerPriv();
144 }
145 }
146 private boolean restoreFocus(Window aWindow, Component vetoedComponent,
147 boolean clearOnFailure) {
148 Component toFocus =
149 KeyboardFocusManager.getMostRecentFocusOwner(aWindow);
150
151 if (toFocus != null && toFocus != vetoedComponent) {
152 Component heavyweight = getHeavyweight(aWindow);
153 if (heavyweight != null) {
154 setNativeFocusOwner(heavyweight);
155 Toolkit.getEventQueue().createSecondaryLoop(
156 () -> getGlobalFocusedWindow() != aWindow, null, 50)
157 .enter();
158 }
159 if (getGlobalFocusedWindow() == aWindow &&
160 doRestoreFocus(toFocus, vetoedComponent, false)) {
161 return true;
162 }
163 }
164 if (clearOnFailure) {
165 clearGlobalFocusOwnerPriv();
166 return true;
167 } else {
168 return false;
169 }
170 }
171 private boolean restoreFocus(Component toFocus, boolean clearOnFailure) {
172 return doRestoreFocus(toFocus, null, clearOnFailure);
173 }
174 private boolean doRestoreFocus(Component toFocus, Component vetoedComponent,
175 boolean clearOnFailure)
176 {
177 if (toFocus != vetoedComponent && toFocus.isShowing() && toFocus.canBeFocusOwner() &&
178 toFocus.requestFocus(false, FocusEvent.Cause.ROLLBACK))
179 {
180 return true;
406 // in the Window.
407 //
408 // * If we're in SendMessage, then this is a synthetic
409 // WINDOW_GAINED_FOCUS message which was generated by a
410 // the FOCUS_GAINED handler. Allow the Component to
411 // which the FOCUS_GAINED message was targeted to
412 // receive the focus.
413 // * Otherwise, look up the correct Component here.
414 // We don't use Window.getMostRecentFocusOwner because
415 // window is focused now and 'null' will be returned
416
417
418 // Calculating of most recent focus owner and focus
419 // request should be synchronized on KeyboardFocusManager.class
420 // to prevent from thread race when user will request
421 // focus between calculation and our request.
422 // But if focus transfer is synchronous, this synchronization
423 // may cause deadlock, thus we don't synchronize this block.
424 Component toFocus = KeyboardFocusManager.
425 getMostRecentFocusOwner(newFocusedWindow);
426 if ((toFocus == null) &&
427 newFocusedWindow.isFocusableWindow())
428 {
429 toFocus = newFocusedWindow.getFocusTraversalPolicy().
430 getInitialComponent(newFocusedWindow);
431 }
432 Component tempLost = null;
433 synchronized(KeyboardFocusManager.class) {
434 tempLost = newFocusedWindow.setTemporaryLostComponent(null);
435 }
436
437 // The component which last has the focus when this window was focused
438 // should receive focus first
439 if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
440 focusLog.finer("tempLost {0}, toFocus {1}",
441 tempLost, toFocus);
442 }
443 if (tempLost != null) {
444 tempLost.requestFocusInWindow(FocusEvent.Cause.ACTIVATION);
445 }
446
447 if (toFocus != null && toFocus != tempLost) {
448 // If there is a component which requested focus when this window
449 // was inactive it expects to receive focus after activation.
450 toFocus.requestFocusInWindow(FocusEvent.Cause.ACTIVATION);
451 }
452 }
453
454 Window realOppositeWindow = this.realOppositeWindowWR.get();
455 if (realOppositeWindow != we.getOppositeWindow()) {
456 we = new WindowEvent(newFocusedWindow,
457 WindowEvent.WINDOW_GAINED_FOCUS,
458 realOppositeWindow);
459 }
460 return typeAheadAssertions(newFocusedWindow, we);
461 }
462
463 case WindowEvent.WINDOW_ACTIVATED: {
464 WindowEvent we = (WindowEvent)e;
465 Window oldActiveWindow = getGlobalActiveWindow();
466 Window newActiveWindow = we.getWindow();
467 if (oldActiveWindow == newActiveWindow) {
468 break;
469 }
470
471 // If there exists a current active window, then notify it that
472 // it has lost activation.
482 }
483 if (getGlobalActiveWindow() != null) {
484 // Activation change was rejected. Unlikely, but
485 // possible.
486 break;
487 }
488 }
489
490 setGlobalActiveWindow(newActiveWindow);
491
492 if (newActiveWindow != getGlobalActiveWindow()) {
493 // Activation change was rejected. Unlikely, but
494 // possible.
495 break;
496 }
497
498 return typeAheadAssertions(newActiveWindow, we);
499 }
500
501 case FocusEvent.FOCUS_GAINED: {
502 FocusEvent fe = (FocusEvent)e;
503 Component oldFocusOwner = getGlobalFocusOwner();
504 Component newFocusOwner = fe.getComponent();
505 if (oldFocusOwner == newFocusOwner) {
506 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
507 focusLog.fine("Skipping {0} because focus owner is the same", e);
508 }
509 // We can't just drop the event - there could be
510 // type-ahead markers associated with it.
511 dequeueKeyEvents(-1, newFocusOwner);
512 break;
513 }
514
515 // If there exists a current focus owner, then notify it that
516 // it has lost focus.
517 if (oldFocusOwner != null) {
518 boolean isEventDispatched =
519 sendMessage(oldFocusOwner,
520 new FocusEvent(oldFocusOwner,
521 FocusEvent.FOCUS_LOST,
|
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 PlatformLogger focusLog = PlatformLogger.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<KeyEvent> enqueuedKeyEvents = new LinkedList<KeyEvent>();
76 private LinkedList<TypeAheadMarker> typeAheadMarkers = new LinkedList<TypeAheadMarker>();
77 private boolean consumeNextKeyTyped;
78 private Component restoreFocusTo;
79
80 static {
81 AWTAccessor.setDefaultKeyboardFocusManagerAccessor(
82 new AWTAccessor.DefaultKeyboardFocusManagerAccessor() {
83 public void consumeNextKeyTyped(DefaultKeyboardFocusManager dkfm, KeyEvent e) {
84 dkfm.consumeNextKeyTyped(e);
85 }
86 });
87 }
88
89 private static class TypeAheadMarker {
90 long after;
91 Component untilFocused;
92
93 TypeAheadMarker(long after, Component untilFocused) {
94 this.after = after;
95 this.untilFocused = untilFocused;
96 }
97 /**
98 * Returns string representation of the marker
129 } else {
130 clearGlobalFocusOwnerPriv();
131 }
132 }
133 private void restoreFocus(WindowEvent we) {
134 Window realOppositeWindow = this.realOppositeWindowWR.get();
135 if (realOppositeWindow != null
136 && restoreFocus(realOppositeWindow, null, false))
137 {
138 // do nothing, everything is done in restoreFocus()
139 } else if (we.getOppositeWindow() != null &&
140 restoreFocus(we.getOppositeWindow(), null, false))
141 {
142 // do nothing, everything is done in restoreFocus()
143 } else {
144 clearGlobalFocusOwnerPriv();
145 }
146 }
147 private boolean restoreFocus(Window aWindow, Component vetoedComponent,
148 boolean clearOnFailure) {
149 restoreFocusTo = null;
150 Component toFocus =
151 KeyboardFocusManager.getMostRecentFocusOwner(aWindow);
152
153 if (toFocus != null && toFocus != vetoedComponent) {
154 if (getHeavyweight(aWindow) != getNativeFocusOwner()) {
155 // cannot restore focus synchronously
156 if (!toFocus.isShowing() || !toFocus.canBeFocusOwner()) {
157 toFocus = toFocus.getNextFocusCandidate();
158 }
159 if (toFocus != null && toFocus != vetoedComponent) {
160 if (!toFocus.requestFocus(false,
161 FocusEvent.Cause.ROLLBACK)) {
162 restoreFocusTo = toFocus;
163 }
164 return true;
165 }
166 } else if (doRestoreFocus(toFocus, vetoedComponent, false)) {
167 return true;
168 }
169 }
170 if (clearOnFailure) {
171 clearGlobalFocusOwnerPriv();
172 return true;
173 } else {
174 return false;
175 }
176 }
177 private boolean restoreFocus(Component toFocus, boolean clearOnFailure) {
178 return doRestoreFocus(toFocus, null, clearOnFailure);
179 }
180 private boolean doRestoreFocus(Component toFocus, Component vetoedComponent,
181 boolean clearOnFailure)
182 {
183 if (toFocus != vetoedComponent && toFocus.isShowing() && toFocus.canBeFocusOwner() &&
184 toFocus.requestFocus(false, FocusEvent.Cause.ROLLBACK))
185 {
186 return true;
412 // in the Window.
413 //
414 // * If we're in SendMessage, then this is a synthetic
415 // WINDOW_GAINED_FOCUS message which was generated by a
416 // the FOCUS_GAINED handler. Allow the Component to
417 // which the FOCUS_GAINED message was targeted to
418 // receive the focus.
419 // * Otherwise, look up the correct Component here.
420 // We don't use Window.getMostRecentFocusOwner because
421 // window is focused now and 'null' will be returned
422
423
424 // Calculating of most recent focus owner and focus
425 // request should be synchronized on KeyboardFocusManager.class
426 // to prevent from thread race when user will request
427 // focus between calculation and our request.
428 // But if focus transfer is synchronous, this synchronization
429 // may cause deadlock, thus we don't synchronize this block.
430 Component toFocus = KeyboardFocusManager.
431 getMostRecentFocusOwner(newFocusedWindow);
432 boolean isFocusRestore = restoreFocusTo != null &&
433 toFocus == restoreFocusTo;
434 if ((toFocus == null) &&
435 newFocusedWindow.isFocusableWindow())
436 {
437 toFocus = newFocusedWindow.getFocusTraversalPolicy().
438 getInitialComponent(newFocusedWindow);
439 }
440 Component tempLost = null;
441 synchronized(KeyboardFocusManager.class) {
442 tempLost = newFocusedWindow.setTemporaryLostComponent(null);
443 }
444
445 // The component which last has the focus when this window was focused
446 // should receive focus first
447 if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
448 focusLog.finer("tempLost {0}, toFocus {1}",
449 tempLost, toFocus);
450 }
451 if (tempLost != null) {
452 tempLost.requestFocusInWindow(isFocusRestore ?
453 FocusEvent.Cause.ROLLBACK :
454 FocusEvent.Cause.ACTIVATION);
455 }
456
457 if (toFocus != null && toFocus != tempLost) {
458 // If there is a component which requested focus when this window
459 // was inactive it expects to receive focus after activation.
460 toFocus.requestFocusInWindow(FocusEvent.Cause.ACTIVATION);
461 }
462 }
463 restoreFocusTo = null;
464
465 Window realOppositeWindow = this.realOppositeWindowWR.get();
466 if (realOppositeWindow != we.getOppositeWindow()) {
467 we = new WindowEvent(newFocusedWindow,
468 WindowEvent.WINDOW_GAINED_FOCUS,
469 realOppositeWindow);
470 }
471 return typeAheadAssertions(newFocusedWindow, we);
472 }
473
474 case WindowEvent.WINDOW_ACTIVATED: {
475 WindowEvent we = (WindowEvent)e;
476 Window oldActiveWindow = getGlobalActiveWindow();
477 Window newActiveWindow = we.getWindow();
478 if (oldActiveWindow == newActiveWindow) {
479 break;
480 }
481
482 // If there exists a current active window, then notify it that
483 // it has lost activation.
493 }
494 if (getGlobalActiveWindow() != null) {
495 // Activation change was rejected. Unlikely, but
496 // possible.
497 break;
498 }
499 }
500
501 setGlobalActiveWindow(newActiveWindow);
502
503 if (newActiveWindow != getGlobalActiveWindow()) {
504 // Activation change was rejected. Unlikely, but
505 // possible.
506 break;
507 }
508
509 return typeAheadAssertions(newActiveWindow, we);
510 }
511
512 case FocusEvent.FOCUS_GAINED: {
513 restoreFocusTo = null;
514 FocusEvent fe = (FocusEvent)e;
515 Component oldFocusOwner = getGlobalFocusOwner();
516 Component newFocusOwner = fe.getComponent();
517 if (oldFocusOwner == newFocusOwner) {
518 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
519 focusLog.fine("Skipping {0} because focus owner is the same", e);
520 }
521 // We can't just drop the event - there could be
522 // type-ahead markers associated with it.
523 dequeueKeyEvents(-1, newFocusOwner);
524 break;
525 }
526
527 // If there exists a current focus owner, then notify it that
528 // it has lost focus.
529 if (oldFocusOwner != null) {
530 boolean isEventDispatched =
531 sendMessage(oldFocusOwner,
532 new FocusEvent(oldFocusOwner,
533 FocusEvent.FOCUS_LOST,
|