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/EventQueue.java
38829 views
1
/*
2
* Copyright (c) 1996, 2014, 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.*;
29
30
import java.awt.peer.ComponentPeer;
31
32
import java.lang.ref.WeakReference;
33
import java.lang.reflect.InvocationTargetException;
34
35
import java.security.AccessController;
36
import java.security.PrivilegedAction;
37
38
import java.util.EmptyStackException;
39
40
import sun.awt.*;
41
import sun.awt.dnd.SunDropTargetEvent;
42
import sun.util.logging.PlatformLogger;
43
44
import java.util.concurrent.locks.Condition;
45
import java.util.concurrent.locks.Lock;
46
import java.util.concurrent.atomic.AtomicInteger;
47
48
import java.security.AccessControlContext;
49
50
import sun.misc.SharedSecrets;
51
import sun.misc.JavaSecurityAccess;
52
53
/**
54
* <code>EventQueue</code> is a platform-independent class
55
* that queues events, both from the underlying peer classes
56
* and from trusted application classes.
57
* <p>
58
* It encapsulates asynchronous event dispatch machinery which
59
* extracts events from the queue and dispatches them by calling
60
* {@link #dispatchEvent(AWTEvent) dispatchEvent(AWTEvent)} method
61
* on this <code>EventQueue</code> with the event to be dispatched
62
* as an argument. The particular behavior of this machinery is
63
* implementation-dependent. The only requirements are that events
64
* which were actually enqueued to this queue (note that events
65
* being posted to the <code>EventQueue</code> can be coalesced)
66
* are dispatched:
67
* <dl>
68
* <dt> Sequentially.
69
* <dd> That is, it is not permitted that several events from
70
* this queue are dispatched simultaneously.
71
* <dt> In the same order as they are enqueued.
72
* <dd> That is, if <code>AWTEvent</code>&nbsp;A is enqueued
73
* to the <code>EventQueue</code> before
74
* <code>AWTEvent</code>&nbsp;B then event B will not be
75
* dispatched before event A.
76
* </dl>
77
* <p>
78
* Some browsers partition applets in different code bases into
79
* separate contexts, and establish walls between these contexts.
80
* In such a scenario, there will be one <code>EventQueue</code>
81
* per context. Other browsers place all applets into the same
82
* context, implying that there will be only a single, global
83
* <code>EventQueue</code> for all applets. This behavior is
84
* implementation-dependent. Consult your browser's documentation
85
* for more information.
86
* <p>
87
* For information on the threading issues of the event dispatch
88
* machinery, see <a href="doc-files/AWTThreadIssues.html#Autoshutdown"
89
* >AWT Threading Issues</a>.
90
*
91
* @author Thomas Ball
92
* @author Fred Ecks
93
* @author David Mendenhall
94
*
95
* @since 1.1
96
*/
97
public class EventQueue {
98
private static final AtomicInteger threadInitNumber = new AtomicInteger(0);
99
100
private static final int LOW_PRIORITY = 0;
101
private static final int NORM_PRIORITY = 1;
102
private static final int HIGH_PRIORITY = 2;
103
private static final int ULTIMATE_PRIORITY = 3;
104
105
private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1;
106
107
/*
108
* We maintain one Queue for each priority that the EventQueue supports.
109
* That is, the EventQueue object is actually implemented as
110
* NUM_PRIORITIES queues and all Events on a particular internal Queue
111
* have identical priority. Events are pulled off the EventQueue starting
112
* with the Queue of highest priority. We progress in decreasing order
113
* across all Queues.
114
*/
115
private Queue[] queues = new Queue[NUM_PRIORITIES];
116
117
/*
118
* The next EventQueue on the stack, or null if this EventQueue is
119
* on the top of the stack. If nextQueue is non-null, requests to post
120
* an event are forwarded to nextQueue.
121
*/
122
private EventQueue nextQueue;
123
124
/*
125
* The previous EventQueue on the stack, or null if this is the
126
* "base" EventQueue.
127
*/
128
private EventQueue previousQueue;
129
130
/*
131
* A single lock to synchronize the push()/pop() and related operations with
132
* all the EventQueues from the AppContext. Synchronization on any particular
133
* event queue(s) is not enough: we should lock the whole stack.
134
*/
135
private final Lock pushPopLock;
136
private final Condition pushPopCond;
137
138
/*
139
* Dummy runnable to wake up EDT from getNextEvent() after
140
push/pop is performed
141
*/
142
private final static Runnable dummyRunnable = new Runnable() {
143
public void run() {
144
}
145
};
146
147
private EventDispatchThread dispatchThread;
148
149
private final ThreadGroup threadGroup =
150
Thread.currentThread().getThreadGroup();
151
private final ClassLoader classLoader =
152
Thread.currentThread().getContextClassLoader();
153
154
/*
155
* The time stamp of the last dispatched InputEvent or ActionEvent.
156
*/
157
private long mostRecentEventTime = System.currentTimeMillis();
158
159
/*
160
* The time stamp of the last KeyEvent .
161
*/
162
private long mostRecentKeyEventTime = System.currentTimeMillis();
163
164
/**
165
* The modifiers field of the current event, if the current event is an
166
* InputEvent or ActionEvent.
167
*/
168
private WeakReference<AWTEvent> currentEvent;
169
170
/*
171
* Non-zero if a thread is waiting in getNextEvent(int) for an event of
172
* a particular ID to be posted to the queue.
173
*/
174
private volatile int waitForID;
175
176
/*
177
* AppContext corresponding to the queue.
178
*/
179
private final AppContext appContext;
180
181
private final String name = "AWT-EventQueue-" + threadInitNumber.getAndIncrement();
182
183
private FwDispatcher fwDispatcher;
184
185
private static volatile PlatformLogger eventLog;
186
187
private static final PlatformLogger getEventLog() {
188
if(eventLog == null) {
189
eventLog = PlatformLogger.getLogger("java.awt.event.EventQueue");
190
}
191
return eventLog;
192
}
193
194
static {
195
AWTAccessor.setEventQueueAccessor(
196
new AWTAccessor.EventQueueAccessor() {
197
public Thread getDispatchThread(EventQueue eventQueue) {
198
return eventQueue.getDispatchThread();
199
}
200
public boolean isDispatchThreadImpl(EventQueue eventQueue) {
201
return eventQueue.isDispatchThreadImpl();
202
}
203
public void removeSourceEvents(EventQueue eventQueue,
204
Object source,
205
boolean removeAllEvents)
206
{
207
eventQueue.removeSourceEvents(source, removeAllEvents);
208
}
209
public boolean noEvents(EventQueue eventQueue) {
210
return eventQueue.noEvents();
211
}
212
public void wakeup(EventQueue eventQueue, boolean isShutdown) {
213
eventQueue.wakeup(isShutdown);
214
}
215
public void invokeAndWait(Object source, Runnable r)
216
throws InterruptedException, InvocationTargetException
217
{
218
EventQueue.invokeAndWait(source, r);
219
}
220
public void setFwDispatcher(EventQueue eventQueue,
221
FwDispatcher dispatcher) {
222
eventQueue.setFwDispatcher(dispatcher);
223
}
224
225
@Override
226
public long getMostRecentEventTime(EventQueue eventQueue) {
227
return eventQueue.getMostRecentEventTimeImpl();
228
}
229
});
230
}
231
232
public EventQueue() {
233
for (int i = 0; i < NUM_PRIORITIES; i++) {
234
queues[i] = new Queue();
235
}
236
/*
237
* NOTE: if you ever have to start the associated event dispatch
238
* thread at this point, be aware of the following problem:
239
* If this EventQueue instance is created in
240
* SunToolkit.createNewAppContext() the started dispatch thread
241
* may call AppContext.getAppContext() before createNewAppContext()
242
* completes thus causing mess in thread group to appcontext mapping.
243
*/
244
245
appContext = AppContext.getAppContext();
246
pushPopLock = (Lock)appContext.get(AppContext.EVENT_QUEUE_LOCK_KEY);
247
pushPopCond = (Condition)appContext.get(AppContext.EVENT_QUEUE_COND_KEY);
248
}
249
250
/**
251
* Posts a 1.1-style event to the <code>EventQueue</code>.
252
* If there is an existing event on the queue with the same ID
253
* and event source, the source <code>Component</code>'s
254
* <code>coalesceEvents</code> method will be called.
255
*
256
* @param theEvent an instance of <code>java.awt.AWTEvent</code>,
257
* or a subclass of it
258
* @throws NullPointerException if <code>theEvent</code> is <code>null</code>
259
*/
260
public void postEvent(AWTEvent theEvent) {
261
SunToolkit.flushPendingEvents(appContext);
262
postEventPrivate(theEvent);
263
}
264
265
/**
266
* Posts a 1.1-style event to the <code>EventQueue</code>.
267
* If there is an existing event on the queue with the same ID
268
* and event source, the source <code>Component</code>'s
269
* <code>coalesceEvents</code> method will be called.
270
*
271
* @param theEvent an instance of <code>java.awt.AWTEvent</code>,
272
* or a subclass of it
273
*/
274
private final void postEventPrivate(AWTEvent theEvent) {
275
theEvent.isPosted = true;
276
pushPopLock.lock();
277
try {
278
if (nextQueue != null) {
279
// Forward the event to the top of EventQueue stack
280
nextQueue.postEventPrivate(theEvent);
281
return;
282
}
283
if (dispatchThread == null) {
284
if (theEvent.getSource() == AWTAutoShutdown.getInstance()) {
285
return;
286
} else {
287
initDispatchThread();
288
}
289
}
290
postEvent(theEvent, getPriority(theEvent));
291
} finally {
292
pushPopLock.unlock();
293
}
294
}
295
296
private static int getPriority(AWTEvent theEvent) {
297
if (theEvent instanceof PeerEvent) {
298
PeerEvent peerEvent = (PeerEvent)theEvent;
299
if ((peerEvent.getFlags() & PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0) {
300
return ULTIMATE_PRIORITY;
301
}
302
if ((peerEvent.getFlags() & PeerEvent.PRIORITY_EVENT) != 0) {
303
return HIGH_PRIORITY;
304
}
305
if ((peerEvent.getFlags() & PeerEvent.LOW_PRIORITY_EVENT) != 0) {
306
return LOW_PRIORITY;
307
}
308
}
309
int id = theEvent.getID();
310
if ((id >= PaintEvent.PAINT_FIRST) && (id <= PaintEvent.PAINT_LAST)) {
311
return LOW_PRIORITY;
312
}
313
return NORM_PRIORITY;
314
}
315
316
/**
317
* Posts the event to the internal Queue of specified priority,
318
* coalescing as appropriate.
319
*
320
* @param theEvent an instance of <code>java.awt.AWTEvent</code>,
321
* or a subclass of it
322
* @param priority the desired priority of the event
323
*/
324
private void postEvent(AWTEvent theEvent, int priority) {
325
if (coalesceEvent(theEvent, priority)) {
326
return;
327
}
328
329
EventQueueItem newItem = new EventQueueItem(theEvent);
330
331
cacheEQItem(newItem);
332
333
boolean notifyID = (theEvent.getID() == this.waitForID);
334
335
if (queues[priority].head == null) {
336
boolean shouldNotify = noEvents();
337
queues[priority].head = queues[priority].tail = newItem;
338
339
if (shouldNotify) {
340
if (theEvent.getSource() != AWTAutoShutdown.getInstance()) {
341
AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
342
}
343
pushPopCond.signalAll();
344
} else if (notifyID) {
345
pushPopCond.signalAll();
346
}
347
} else {
348
// The event was not coalesced or has non-Component source.
349
// Insert it at the end of the appropriate Queue.
350
queues[priority].tail.next = newItem;
351
queues[priority].tail = newItem;
352
if (notifyID) {
353
pushPopCond.signalAll();
354
}
355
}
356
}
357
358
private boolean coalescePaintEvent(PaintEvent e) {
359
ComponentPeer sourcePeer = ((Component)e.getSource()).peer;
360
if (sourcePeer != null) {
361
sourcePeer.coalescePaintEvent(e);
362
}
363
EventQueueItem[] cache = ((Component)e.getSource()).eventCache;
364
if (cache == null) {
365
return false;
366
}
367
int index = eventToCacheIndex(e);
368
369
if (index != -1 && cache[index] != null) {
370
PaintEvent merged = mergePaintEvents(e, (PaintEvent)cache[index].event);
371
if (merged != null) {
372
cache[index].event = merged;
373
return true;
374
}
375
}
376
return false;
377
}
378
379
private PaintEvent mergePaintEvents(PaintEvent a, PaintEvent b) {
380
Rectangle aRect = a.getUpdateRect();
381
Rectangle bRect = b.getUpdateRect();
382
if (bRect.contains(aRect)) {
383
return b;
384
}
385
if (aRect.contains(bRect)) {
386
return a;
387
}
388
return null;
389
}
390
391
private boolean coalesceMouseEvent(MouseEvent e) {
392
EventQueueItem[] cache = ((Component)e.getSource()).eventCache;
393
if (cache == null) {
394
return false;
395
}
396
int index = eventToCacheIndex(e);
397
if (index != -1 && cache[index] != null) {
398
cache[index].event = e;
399
return true;
400
}
401
return false;
402
}
403
404
private boolean coalescePeerEvent(PeerEvent e) {
405
EventQueueItem[] cache = ((Component)e.getSource()).eventCache;
406
if (cache == null) {
407
return false;
408
}
409
int index = eventToCacheIndex(e);
410
if (index != -1 && cache[index] != null) {
411
e = e.coalesceEvents((PeerEvent)cache[index].event);
412
if (e != null) {
413
cache[index].event = e;
414
return true;
415
} else {
416
cache[index] = null;
417
}
418
}
419
return false;
420
}
421
422
/*
423
* Should avoid of calling this method by any means
424
* as it's working time is dependant on EQ length.
425
* In the wors case this method alone can slow down the entire application
426
* 10 times by stalling the Event processing.
427
* Only here by backward compatibility reasons.
428
*/
429
private boolean coalesceOtherEvent(AWTEvent e, int priority) {
430
int id = e.getID();
431
Component source = (Component)e.getSource();
432
for (EventQueueItem entry = queues[priority].head;
433
entry != null; entry = entry.next)
434
{
435
// Give Component.coalesceEvents a chance
436
if (entry.event.getSource() == source && entry.event.getID() == id) {
437
AWTEvent coalescedEvent = source.coalesceEvents(
438
entry.event, e);
439
if (coalescedEvent != null) {
440
entry.event = coalescedEvent;
441
return true;
442
}
443
}
444
}
445
return false;
446
}
447
448
private boolean coalesceEvent(AWTEvent e, int priority) {
449
if (!(e.getSource() instanceof Component)) {
450
return false;
451
}
452
if (e instanceof PeerEvent) {
453
return coalescePeerEvent((PeerEvent)e);
454
}
455
// The worst case
456
if (((Component)e.getSource()).isCoalescingEnabled()
457
&& coalesceOtherEvent(e, priority))
458
{
459
return true;
460
}
461
if (e instanceof PaintEvent) {
462
return coalescePaintEvent((PaintEvent)e);
463
}
464
if (e instanceof MouseEvent) {
465
return coalesceMouseEvent((MouseEvent)e);
466
}
467
return false;
468
}
469
470
private void cacheEQItem(EventQueueItem entry) {
471
int index = eventToCacheIndex(entry.event);
472
if (index != -1 && entry.event.getSource() instanceof Component) {
473
Component source = (Component)entry.event.getSource();
474
if (source.eventCache == null) {
475
source.eventCache = new EventQueueItem[CACHE_LENGTH];
476
}
477
source.eventCache[index] = entry;
478
}
479
}
480
481
private void uncacheEQItem(EventQueueItem entry) {
482
int index = eventToCacheIndex(entry.event);
483
if (index != -1 && entry.event.getSource() instanceof Component) {
484
Component source = (Component)entry.event.getSource();
485
if (source.eventCache == null) {
486
return;
487
}
488
source.eventCache[index] = null;
489
}
490
}
491
492
private static final int PAINT = 0;
493
private static final int UPDATE = 1;
494
private static final int MOVE = 2;
495
private static final int DRAG = 3;
496
private static final int PEER = 4;
497
private static final int CACHE_LENGTH = 5;
498
499
private static int eventToCacheIndex(AWTEvent e) {
500
switch(e.getID()) {
501
case PaintEvent.PAINT:
502
return PAINT;
503
case PaintEvent.UPDATE:
504
return UPDATE;
505
case MouseEvent.MOUSE_MOVED:
506
return MOVE;
507
case MouseEvent.MOUSE_DRAGGED:
508
// Return -1 for SunDropTargetEvent since they are usually synchronous
509
// and we don't want to skip them by coalescing with MouseEvent or other drag events
510
return e instanceof SunDropTargetEvent ? -1 : DRAG;
511
default:
512
return e instanceof PeerEvent ? PEER : -1;
513
}
514
}
515
516
/**
517
* Returns whether an event is pending on any of the separate
518
* Queues.
519
* @return whether an event is pending on any of the separate Queues
520
*/
521
private boolean noEvents() {
522
for (int i = 0; i < NUM_PRIORITIES; i++) {
523
if (queues[i].head != null) {
524
return false;
525
}
526
}
527
528
return true;
529
}
530
531
/**
532
* Removes an event from the <code>EventQueue</code> and
533
* returns it. This method will block until an event has
534
* been posted by another thread.
535
* @return the next <code>AWTEvent</code>
536
* @exception InterruptedException
537
* if any thread has interrupted this thread
538
*/
539
public AWTEvent getNextEvent() throws InterruptedException {
540
do {
541
/*
542
* SunToolkit.flushPendingEvents must be called outside
543
* of the synchronized block to avoid deadlock when
544
* event queues are nested with push()/pop().
545
*/
546
SunToolkit.flushPendingEvents(appContext);
547
pushPopLock.lock();
548
try {
549
AWTEvent event = getNextEventPrivate();
550
if (event != null) {
551
return event;
552
}
553
AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
554
pushPopCond.await();
555
} finally {
556
pushPopLock.unlock();
557
}
558
} while(true);
559
}
560
561
/*
562
* Must be called under the lock. Doesn't call flushPendingEvents()
563
*/
564
AWTEvent getNextEventPrivate() throws InterruptedException {
565
for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
566
if (queues[i].head != null) {
567
EventQueueItem entry = queues[i].head;
568
queues[i].head = entry.next;
569
if (entry.next == null) {
570
queues[i].tail = null;
571
}
572
uncacheEQItem(entry);
573
return entry.event;
574
}
575
}
576
return null;
577
}
578
579
AWTEvent getNextEvent(int id) throws InterruptedException {
580
do {
581
/*
582
* SunToolkit.flushPendingEvents must be called outside
583
* of the synchronized block to avoid deadlock when
584
* event queues are nested with push()/pop().
585
*/
586
SunToolkit.flushPendingEvents(appContext);
587
pushPopLock.lock();
588
try {
589
for (int i = 0; i < NUM_PRIORITIES; i++) {
590
for (EventQueueItem entry = queues[i].head, prev = null;
591
entry != null; prev = entry, entry = entry.next)
592
{
593
if (entry.event.getID() == id) {
594
if (prev == null) {
595
queues[i].head = entry.next;
596
} else {
597
prev.next = entry.next;
598
}
599
if (queues[i].tail == entry) {
600
queues[i].tail = prev;
601
}
602
uncacheEQItem(entry);
603
return entry.event;
604
}
605
}
606
}
607
waitForID = id;
608
pushPopCond.await();
609
waitForID = 0;
610
} finally {
611
pushPopLock.unlock();
612
}
613
} while(true);
614
}
615
616
/**
617
* Returns the first event on the <code>EventQueue</code>
618
* without removing it.
619
* @return the first event
620
*/
621
public AWTEvent peekEvent() {
622
pushPopLock.lock();
623
try {
624
for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
625
if (queues[i].head != null) {
626
return queues[i].head.event;
627
}
628
}
629
} finally {
630
pushPopLock.unlock();
631
}
632
633
return null;
634
}
635
636
/**
637
* Returns the first event with the specified id, if any.
638
* @param id the id of the type of event desired
639
* @return the first event of the specified id or <code>null</code>
640
* if there is no such event
641
*/
642
public AWTEvent peekEvent(int id) {
643
pushPopLock.lock();
644
try {
645
for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
646
EventQueueItem q = queues[i].head;
647
for (; q != null; q = q.next) {
648
if (q.event.getID() == id) {
649
return q.event;
650
}
651
}
652
}
653
} finally {
654
pushPopLock.unlock();
655
}
656
657
return null;
658
}
659
660
private static final JavaSecurityAccess javaSecurityAccess =
661
SharedSecrets.getJavaSecurityAccess();
662
663
/**
664
* Dispatches an event. The manner in which the event is
665
* dispatched depends upon the type of the event and the
666
* type of the event's source object:
667
*
668
* <table border=1 summary="Event types, source types, and dispatch methods">
669
* <tr>
670
* <th>Event Type</th>
671
* <th>Source Type</th>
672
* <th>Dispatched To</th>
673
* </tr>
674
* <tr>
675
* <td>ActiveEvent</td>
676
* <td>Any</td>
677
* <td>event.dispatch()</td>
678
* </tr>
679
* <tr>
680
* <td>Other</td>
681
* <td>Component</td>
682
* <td>source.dispatchEvent(AWTEvent)</td>
683
* </tr>
684
* <tr>
685
* <td>Other</td>
686
* <td>MenuComponent</td>
687
* <td>source.dispatchEvent(AWTEvent)</td>
688
* </tr>
689
* <tr>
690
* <td>Other</td>
691
* <td>Other</td>
692
* <td>No action (ignored)</td>
693
* </tr>
694
* </table>
695
* <p>
696
* @param event an instance of <code>java.awt.AWTEvent</code>,
697
* or a subclass of it
698
* @throws NullPointerException if <code>event</code> is <code>null</code>
699
* @since 1.2
700
*/
701
protected void dispatchEvent(final AWTEvent event) {
702
final Object src = event.getSource();
703
final PrivilegedAction<Void> action = new PrivilegedAction<Void>() {
704
public Void run() {
705
// In case fwDispatcher is installed and we're already on the
706
// dispatch thread (e.g. performing DefaultKeyboardFocusManager.sendMessage),
707
// dispatch the event straight away.
708
if (fwDispatcher == null || isDispatchThreadImpl()) {
709
dispatchEventImpl(event, src);
710
} else {
711
fwDispatcher.scheduleDispatch(new Runnable() {
712
@Override
713
public void run() {
714
if (dispatchThread.filterAndCheckEvent(event)) {
715
dispatchEventImpl(event, src);
716
}
717
}
718
});
719
}
720
return null;
721
}
722
};
723
724
final AccessControlContext stack = AccessController.getContext();
725
final AccessControlContext srcAcc = getAccessControlContextFrom(src);
726
final AccessControlContext eventAcc = event.getAccessControlContext();
727
if (srcAcc == null) {
728
javaSecurityAccess.doIntersectionPrivilege(action, stack, eventAcc);
729
} else {
730
javaSecurityAccess.doIntersectionPrivilege(
731
new PrivilegedAction<Void>() {
732
public Void run() {
733
javaSecurityAccess.doIntersectionPrivilege(action, eventAcc);
734
return null;
735
}
736
}, stack, srcAcc);
737
}
738
}
739
740
private static AccessControlContext getAccessControlContextFrom(Object src) {
741
return src instanceof Component ?
742
((Component)src).getAccessControlContext() :
743
src instanceof MenuComponent ?
744
((MenuComponent)src).getAccessControlContext() :
745
src instanceof TrayIcon ?
746
((TrayIcon)src).getAccessControlContext() :
747
null;
748
}
749
750
/**
751
* Called from dispatchEvent() under a correct AccessControlContext
752
*/
753
private void dispatchEventImpl(final AWTEvent event, final Object src) {
754
event.isPosted = true;
755
if (event instanceof ActiveEvent) {
756
// This could become the sole method of dispatching in time.
757
setCurrentEventAndMostRecentTimeImpl(event);
758
((ActiveEvent)event).dispatch();
759
} else if (src instanceof Component) {
760
((Component)src).dispatchEvent(event);
761
event.dispatched();
762
} else if (src instanceof MenuComponent) {
763
((MenuComponent)src).dispatchEvent(event);
764
} else if (src instanceof TrayIcon) {
765
((TrayIcon)src).dispatchEvent(event);
766
} else if (src instanceof AWTAutoShutdown) {
767
if (noEvents()) {
768
dispatchThread.stopDispatching();
769
}
770
} else {
771
if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
772
getEventLog().fine("Unable to dispatch event: " + event);
773
}
774
}
775
}
776
777
/**
778
* Returns the timestamp of the most recent event that had a timestamp, and
779
* that was dispatched from the <code>EventQueue</code> associated with the
780
* calling thread. If an event with a timestamp is currently being
781
* dispatched, its timestamp will be returned. If no events have yet
782
* been dispatched, the EventQueue's initialization time will be
783
* returned instead.In the current version of
784
* the JDK, only <code>InputEvent</code>s,
785
* <code>ActionEvent</code>s, and <code>InvocationEvent</code>s have
786
* timestamps; however, future versions of the JDK may add timestamps to
787
* additional event types. Note that this method should only be invoked
788
* from an application's {@link #isDispatchThread event dispatching thread}.
789
* If this method is
790
* invoked from another thread, the current system time (as reported by
791
* <code>System.currentTimeMillis()</code>) will be returned instead.
792
*
793
* @return the timestamp of the last <code>InputEvent</code>,
794
* <code>ActionEvent</code>, or <code>InvocationEvent</code> to be
795
* dispatched, or <code>System.currentTimeMillis()</code> if this
796
* method is invoked on a thread other than an event dispatching
797
* thread
798
* @see java.awt.event.InputEvent#getWhen
799
* @see java.awt.event.ActionEvent#getWhen
800
* @see java.awt.event.InvocationEvent#getWhen
801
* @see #isDispatchThread
802
*
803
* @since 1.4
804
*/
805
public static long getMostRecentEventTime() {
806
return Toolkit.getEventQueue().getMostRecentEventTimeImpl();
807
}
808
private long getMostRecentEventTimeImpl() {
809
pushPopLock.lock();
810
try {
811
return (Thread.currentThread() == dispatchThread)
812
? mostRecentEventTime
813
: System.currentTimeMillis();
814
} finally {
815
pushPopLock.unlock();
816
}
817
}
818
819
/**
820
* @return most recent event time on all threads.
821
*/
822
long getMostRecentEventTimeEx() {
823
pushPopLock.lock();
824
try {
825
return mostRecentEventTime;
826
} finally {
827
pushPopLock.unlock();
828
}
829
}
830
831
/**
832
* Returns the the event currently being dispatched by the
833
* <code>EventQueue</code> associated with the calling thread. This is
834
* useful if a method needs access to the event, but was not designed to
835
* receive a reference to it as an argument. Note that this method should
836
* only be invoked from an application's event dispatching thread. If this
837
* method is invoked from another thread, null will be returned.
838
*
839
* @return the event currently being dispatched, or null if this method is
840
* invoked on a thread other than an event dispatching thread
841
* @since 1.4
842
*/
843
public static AWTEvent getCurrentEvent() {
844
return Toolkit.getEventQueue().getCurrentEventImpl();
845
}
846
private AWTEvent getCurrentEventImpl() {
847
pushPopLock.lock();
848
try {
849
return (Thread.currentThread() == dispatchThread)
850
? currentEvent.get()
851
: null;
852
} finally {
853
pushPopLock.unlock();
854
}
855
}
856
857
/**
858
* Replaces the existing <code>EventQueue</code> with the specified one.
859
* Any pending events are transferred to the new <code>EventQueue</code>
860
* for processing by it.
861
*
862
* @param newEventQueue an <code>EventQueue</code>
863
* (or subclass thereof) instance to be use
864
* @see java.awt.EventQueue#pop
865
* @throws NullPointerException if <code>newEventQueue</code> is <code>null</code>
866
* @since 1.2
867
*/
868
public void push(EventQueue newEventQueue) {
869
if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
870
getEventLog().fine("EventQueue.push(" + newEventQueue + ")");
871
}
872
873
pushPopLock.lock();
874
try {
875
EventQueue topQueue = this;
876
while (topQueue.nextQueue != null) {
877
topQueue = topQueue.nextQueue;
878
}
879
if (topQueue.fwDispatcher != null) {
880
throw new RuntimeException("push() to queue with fwDispatcher");
881
}
882
if ((topQueue.dispatchThread != null) &&
883
(topQueue.dispatchThread.getEventQueue() == this))
884
{
885
newEventQueue.dispatchThread = topQueue.dispatchThread;
886
topQueue.dispatchThread.setEventQueue(newEventQueue);
887
}
888
889
// Transfer all events forward to new EventQueue.
890
while (topQueue.peekEvent() != null) {
891
try {
892
// Use getNextEventPrivate() as it doesn't call flushPendingEvents()
893
newEventQueue.postEventPrivate(topQueue.getNextEventPrivate());
894
} catch (InterruptedException ie) {
895
if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
896
getEventLog().fine("Interrupted push", ie);
897
}
898
}
899
}
900
901
if (topQueue.dispatchThread != null) {
902
// Wake up EDT waiting in getNextEvent(), so it can
903
// pick up a new EventQueue. Post the waking event before
904
// topQueue.nextQueue is assigned, otherwise the event would
905
// go newEventQueue
906
topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
907
}
908
909
newEventQueue.previousQueue = topQueue;
910
topQueue.nextQueue = newEventQueue;
911
912
if (appContext.get(AppContext.EVENT_QUEUE_KEY) == topQueue) {
913
appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
914
}
915
916
pushPopCond.signalAll();
917
} finally {
918
pushPopLock.unlock();
919
}
920
}
921
922
/**
923
* Stops dispatching events using this <code>EventQueue</code>.
924
* Any pending events are transferred to the previous
925
* <code>EventQueue</code> for processing.
926
* <p>
927
* Warning: To avoid deadlock, do not declare this method
928
* synchronized in a subclass.
929
*
930
* @exception EmptyStackException if no previous push was made
931
* on this <code>EventQueue</code>
932
* @see java.awt.EventQueue#push
933
* @since 1.2
934
*/
935
protected void pop() throws EmptyStackException {
936
if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
937
getEventLog().fine("EventQueue.pop(" + this + ")");
938
}
939
940
pushPopLock.lock();
941
try {
942
EventQueue topQueue = this;
943
while (topQueue.nextQueue != null) {
944
topQueue = topQueue.nextQueue;
945
}
946
EventQueue prevQueue = topQueue.previousQueue;
947
if (prevQueue == null) {
948
throw new EmptyStackException();
949
}
950
951
topQueue.previousQueue = null;
952
prevQueue.nextQueue = null;
953
954
// Transfer all events back to previous EventQueue.
955
while (topQueue.peekEvent() != null) {
956
try {
957
prevQueue.postEventPrivate(topQueue.getNextEventPrivate());
958
} catch (InterruptedException ie) {
959
if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
960
getEventLog().fine("Interrupted pop", ie);
961
}
962
}
963
}
964
965
if ((topQueue.dispatchThread != null) &&
966
(topQueue.dispatchThread.getEventQueue() == this))
967
{
968
prevQueue.dispatchThread = topQueue.dispatchThread;
969
topQueue.dispatchThread.setEventQueue(prevQueue);
970
}
971
972
if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
973
appContext.put(AppContext.EVENT_QUEUE_KEY, prevQueue);
974
}
975
976
// Wake up EDT waiting in getNextEvent(), so it can
977
// pick up a new EventQueue
978
topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
979
980
pushPopCond.signalAll();
981
} finally {
982
pushPopLock.unlock();
983
}
984
}
985
986
/**
987
* Creates a new {@code secondary loop} associated with this
988
* event queue. Use the {@link SecondaryLoop#enter} and
989
* {@link SecondaryLoop#exit} methods to start and stop the
990
* event loop and dispatch the events from this queue.
991
*
992
* @return secondaryLoop A new secondary loop object, which can
993
* be used to launch a new nested event
994
* loop and dispatch events from this queue
995
*
996
* @see SecondaryLoop#enter
997
* @see SecondaryLoop#exit
998
*
999
* @since 1.7
1000
*/
1001
public SecondaryLoop createSecondaryLoop() {
1002
return createSecondaryLoop(null, null, 0);
1003
}
1004
1005
private class FwSecondaryLoopWrapper implements SecondaryLoop {
1006
final private SecondaryLoop loop;
1007
final private EventFilter filter;
1008
1009
public FwSecondaryLoopWrapper(SecondaryLoop loop, EventFilter filter) {
1010
this.loop = loop;
1011
this.filter = filter;
1012
}
1013
1014
@Override
1015
public boolean enter() {
1016
if (filter != null) {
1017
dispatchThread.addEventFilter(filter);
1018
}
1019
return loop.enter();
1020
}
1021
1022
@Override
1023
public boolean exit() {
1024
if (filter != null) {
1025
dispatchThread.removeEventFilter(filter);
1026
}
1027
return loop.exit();
1028
}
1029
}
1030
1031
SecondaryLoop createSecondaryLoop(Conditional cond, EventFilter filter, long interval) {
1032
pushPopLock.lock();
1033
try {
1034
if (nextQueue != null) {
1035
// Forward the request to the top of EventQueue stack
1036
return nextQueue.createSecondaryLoop(cond, filter, interval);
1037
}
1038
if (fwDispatcher != null) {
1039
return new FwSecondaryLoopWrapper(fwDispatcher.createSecondaryLoop(), filter);
1040
}
1041
if (dispatchThread == null) {
1042
initDispatchThread();
1043
}
1044
return new WaitDispatchSupport(dispatchThread, cond, filter, interval);
1045
} finally {
1046
pushPopLock.unlock();
1047
}
1048
}
1049
1050
/**
1051
* Returns true if the calling thread is
1052
* {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s
1053
* dispatch thread. Use this method to ensure that a particular
1054
* task is being executed (or not being) there.
1055
* <p>
1056
* Note: use the {@link #invokeLater} or {@link #invokeAndWait}
1057
* methods to execute a task in
1058
* {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s
1059
* dispatch thread.
1060
* <p>
1061
*
1062
* @return true if running in
1063
* {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s
1064
* dispatch thread
1065
* @see #invokeLater
1066
* @see #invokeAndWait
1067
* @see Toolkit#getSystemEventQueue
1068
* @since 1.2
1069
*/
1070
public static boolean isDispatchThread() {
1071
EventQueue eq = Toolkit.getEventQueue();
1072
return eq.isDispatchThreadImpl();
1073
}
1074
1075
final boolean isDispatchThreadImpl() {
1076
EventQueue eq = this;
1077
pushPopLock.lock();
1078
try {
1079
EventQueue next = eq.nextQueue;
1080
while (next != null) {
1081
eq = next;
1082
next = eq.nextQueue;
1083
}
1084
if (eq.fwDispatcher != null) {
1085
return eq.fwDispatcher.isDispatchThread();
1086
}
1087
return (Thread.currentThread() == eq.dispatchThread);
1088
} finally {
1089
pushPopLock.unlock();
1090
}
1091
}
1092
1093
final void initDispatchThread() {
1094
pushPopLock.lock();
1095
try {
1096
if (dispatchThread == null && !threadGroup.isDestroyed() && !appContext.isDisposed()) {
1097
dispatchThread = AccessController.doPrivileged(
1098
new PrivilegedAction<EventDispatchThread>() {
1099
public EventDispatchThread run() {
1100
EventDispatchThread t =
1101
new EventDispatchThread(threadGroup,
1102
name,
1103
EventQueue.this);
1104
t.setContextClassLoader(classLoader);
1105
t.setPriority(Thread.NORM_PRIORITY + 1);
1106
t.setDaemon(false);
1107
AWTAutoShutdown.getInstance().notifyThreadBusy(t);
1108
return t;
1109
}
1110
}
1111
);
1112
dispatchThread.start();
1113
}
1114
} finally {
1115
pushPopLock.unlock();
1116
}
1117
}
1118
1119
final void detachDispatchThread(EventDispatchThread edt) {
1120
/*
1121
* Minimize discard possibility for non-posted events
1122
*/
1123
SunToolkit.flushPendingEvents(appContext);
1124
/*
1125
* This synchronized block is to secure that the event dispatch
1126
* thread won't die in the middle of posting a new event to the
1127
* associated event queue. It is important because we notify
1128
* that the event dispatch thread is busy after posting a new event
1129
* to its queue, so the EventQueue.dispatchThread reference must
1130
* be valid at that point.
1131
*/
1132
pushPopLock.lock();
1133
try {
1134
if (edt == dispatchThread) {
1135
dispatchThread = null;
1136
}
1137
AWTAutoShutdown.getInstance().notifyThreadFree(edt);
1138
/*
1139
* Event was posted after EDT events pumping had stopped, so start
1140
* another EDT to handle this event
1141
*/
1142
if (peekEvent() != null) {
1143
initDispatchThread();
1144
}
1145
} finally {
1146
pushPopLock.unlock();
1147
}
1148
}
1149
1150
/*
1151
* Gets the <code>EventDispatchThread</code> for this
1152
* <code>EventQueue</code>.
1153
* @return the event dispatch thread associated with this event queue
1154
* or <code>null</code> if this event queue doesn't have a
1155
* working thread associated with it
1156
* @see java.awt.EventQueue#initDispatchThread
1157
* @see java.awt.EventQueue#detachDispatchThread
1158
*/
1159
final EventDispatchThread getDispatchThread() {
1160
pushPopLock.lock();
1161
try {
1162
return dispatchThread;
1163
} finally {
1164
pushPopLock.unlock();
1165
}
1166
}
1167
1168
/*
1169
* Removes any pending events for the specified source object.
1170
* If removeAllEvents parameter is <code>true</code> then all
1171
* events for the specified source object are removed, if it
1172
* is <code>false</code> then <code>SequencedEvent</code>, <code>SentEvent</code>,
1173
* <code>FocusEvent</code>, <code>WindowEvent</code>, <code>KeyEvent</code>,
1174
* and <code>InputMethodEvent</code> are kept in the queue, but all other
1175
* events are removed.
1176
*
1177
* This method is normally called by the source's
1178
* <code>removeNotify</code> method.
1179
*/
1180
final void removeSourceEvents(Object source, boolean removeAllEvents) {
1181
SunToolkit.flushPendingEvents(appContext);
1182
pushPopLock.lock();
1183
try {
1184
for (int i = 0; i < NUM_PRIORITIES; i++) {
1185
EventQueueItem entry = queues[i].head;
1186
EventQueueItem prev = null;
1187
while (entry != null) {
1188
if ((entry.event.getSource() == source)
1189
&& (removeAllEvents
1190
|| ! (entry.event instanceof SequencedEvent
1191
|| entry.event instanceof SentEvent
1192
|| entry.event instanceof FocusEvent
1193
|| entry.event instanceof WindowEvent
1194
|| entry.event instanceof KeyEvent
1195
|| entry.event instanceof InputMethodEvent)))
1196
{
1197
if (entry.event instanceof SequencedEvent) {
1198
((SequencedEvent)entry.event).dispose();
1199
}
1200
if (entry.event instanceof SentEvent) {
1201
((SentEvent)entry.event).dispose();
1202
}
1203
if (entry.event instanceof InvocationEvent) {
1204
AWTAccessor.getInvocationEventAccessor()
1205
.dispose((InvocationEvent)entry.event);
1206
}
1207
if (prev == null) {
1208
queues[i].head = entry.next;
1209
} else {
1210
prev.next = entry.next;
1211
}
1212
uncacheEQItem(entry);
1213
} else {
1214
prev = entry;
1215
}
1216
entry = entry.next;
1217
}
1218
queues[i].tail = prev;
1219
}
1220
} finally {
1221
pushPopLock.unlock();
1222
}
1223
}
1224
1225
synchronized long getMostRecentKeyEventTime() {
1226
pushPopLock.lock();
1227
try {
1228
return mostRecentKeyEventTime;
1229
} finally {
1230
pushPopLock.unlock();
1231
}
1232
}
1233
1234
static void setCurrentEventAndMostRecentTime(AWTEvent e) {
1235
Toolkit.getEventQueue().setCurrentEventAndMostRecentTimeImpl(e);
1236
}
1237
private void setCurrentEventAndMostRecentTimeImpl(AWTEvent e) {
1238
pushPopLock.lock();
1239
try {
1240
if (Thread.currentThread() != dispatchThread) {
1241
return;
1242
}
1243
1244
currentEvent = new WeakReference<>(e);
1245
1246
// This series of 'instanceof' checks should be replaced with a
1247
// polymorphic type (for example, an interface which declares a
1248
// getWhen() method). However, this would require us to make such
1249
// a type public, or to place it in sun.awt. Both of these approaches
1250
// have been frowned upon. So for now, we hack.
1251
//
1252
// In tiger, we will probably give timestamps to all events, so this
1253
// will no longer be an issue.
1254
long mostRecentEventTime2 = Long.MIN_VALUE;
1255
if (e instanceof InputEvent) {
1256
InputEvent ie = (InputEvent)e;
1257
mostRecentEventTime2 = ie.getWhen();
1258
if (e instanceof KeyEvent) {
1259
mostRecentKeyEventTime = ie.getWhen();
1260
}
1261
} else if (e instanceof InputMethodEvent) {
1262
InputMethodEvent ime = (InputMethodEvent)e;
1263
mostRecentEventTime2 = ime.getWhen();
1264
} else if (e instanceof ActionEvent) {
1265
ActionEvent ae = (ActionEvent)e;
1266
mostRecentEventTime2 = ae.getWhen();
1267
} else if (e instanceof InvocationEvent) {
1268
InvocationEvent ie = (InvocationEvent)e;
1269
mostRecentEventTime2 = ie.getWhen();
1270
}
1271
mostRecentEventTime = Math.max(mostRecentEventTime, mostRecentEventTime2);
1272
} finally {
1273
pushPopLock.unlock();
1274
}
1275
}
1276
1277
/**
1278
* Causes <code>runnable</code> to have its <code>run</code>
1279
* method called in the {@link #isDispatchThread dispatch thread} of
1280
* {@link Toolkit#getSystemEventQueue the system EventQueue}.
1281
* This will happen after all pending events are processed.
1282
*
1283
* @param runnable the <code>Runnable</code> whose <code>run</code>
1284
* method should be executed
1285
* asynchronously in the
1286
* {@link #isDispatchThread event dispatch thread}
1287
* of {@link Toolkit#getSystemEventQueue the system EventQueue}
1288
* @see #invokeAndWait
1289
* @see Toolkit#getSystemEventQueue
1290
* @see #isDispatchThread
1291
* @since 1.2
1292
*/
1293
public static void invokeLater(Runnable runnable) {
1294
Toolkit.getEventQueue().postEvent(
1295
new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
1296
}
1297
1298
/**
1299
* Causes <code>runnable</code> to have its <code>run</code>
1300
* method called in the {@link #isDispatchThread dispatch thread} of
1301
* {@link Toolkit#getSystemEventQueue the system EventQueue}.
1302
* This will happen after all pending events are processed.
1303
* The call blocks until this has happened. This method
1304
* will throw an Error if called from the
1305
* {@link #isDispatchThread event dispatcher thread}.
1306
*
1307
* @param runnable the <code>Runnable</code> whose <code>run</code>
1308
* method should be executed
1309
* synchronously in the
1310
* {@link #isDispatchThread event dispatch thread}
1311
* of {@link Toolkit#getSystemEventQueue the system EventQueue}
1312
* @exception InterruptedException if any thread has
1313
* interrupted this thread
1314
* @exception InvocationTargetException if an throwable is thrown
1315
* when running <code>runnable</code>
1316
* @see #invokeLater
1317
* @see Toolkit#getSystemEventQueue
1318
* @see #isDispatchThread
1319
* @since 1.2
1320
*/
1321
public static void invokeAndWait(Runnable runnable)
1322
throws InterruptedException, InvocationTargetException
1323
{
1324
invokeAndWait(Toolkit.getDefaultToolkit(), runnable);
1325
}
1326
1327
static void invokeAndWait(Object source, Runnable runnable)
1328
throws InterruptedException, InvocationTargetException
1329
{
1330
if (EventQueue.isDispatchThread()) {
1331
throw new Error("Cannot call invokeAndWait from the event dispatcher thread");
1332
}
1333
1334
class AWTInvocationLock {}
1335
Object lock = new AWTInvocationLock();
1336
1337
InvocationEvent event =
1338
new InvocationEvent(source, runnable, lock, true);
1339
1340
synchronized (lock) {
1341
Toolkit.getEventQueue().postEvent(event);
1342
while (!event.isDispatched()) {
1343
lock.wait();
1344
}
1345
}
1346
1347
Throwable eventThrowable = event.getThrowable();
1348
if (eventThrowable != null) {
1349
throw new InvocationTargetException(eventThrowable);
1350
}
1351
}
1352
1353
/*
1354
* Called from PostEventQueue.postEvent to notify that a new event
1355
* appeared. First it proceeds to the EventQueue on the top of the
1356
* stack, then notifies the associated dispatch thread if it exists
1357
* or starts a new one otherwise.
1358
*/
1359
private void wakeup(boolean isShutdown) {
1360
pushPopLock.lock();
1361
try {
1362
if (nextQueue != null) {
1363
// Forward call to the top of EventQueue stack.
1364
nextQueue.wakeup(isShutdown);
1365
} else if (dispatchThread != null) {
1366
pushPopCond.signalAll();
1367
} else if (!isShutdown) {
1368
initDispatchThread();
1369
}
1370
} finally {
1371
pushPopLock.unlock();
1372
}
1373
}
1374
1375
// The method is used by AWTAccessor for javafx/AWT single threaded mode.
1376
private void setFwDispatcher(FwDispatcher dispatcher) {
1377
if (nextQueue != null) {
1378
nextQueue.setFwDispatcher(dispatcher);
1379
} else {
1380
fwDispatcher = dispatcher;
1381
}
1382
}
1383
}
1384
1385
/**
1386
* The Queue object holds pointers to the beginning and end of one internal
1387
* queue. An EventQueue object is composed of multiple internal Queues, one
1388
* for each priority supported by the EventQueue. All Events on a particular
1389
* internal Queue have identical priority.
1390
*/
1391
class Queue {
1392
EventQueueItem head;
1393
EventQueueItem tail;
1394
}
1395
1396