History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/awt/EventQueue.java (1 of 18352 files). Show all

Unified · Split

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