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