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