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