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)
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>.
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 }
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
|
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.ReentrantLock;
50 import java.util.concurrent.atomic.AtomicInteger;
51
52 import java.security.AccessControlContext;
53 import java.security.ProtectionDomain;
54
55 import sun.misc.SharedSecrets;
56 import sun.misc.JavaSecurityAccess;
57
58 /**
59 * <code>EventQueue</code> is a platform-independent class
60 * that queues events, both from the underlying peer classes
61 * and from trusted application classes.
62 * <p>
63 * It encapsulates asynchronous event dispatch machinery which
64 * extracts events from the queue and dispatches them by calling
65 * {@link #dispatchEvent(AWTEvent) dispatchEvent(AWTEvent)} method
66 * on this <code>EventQueue</code> with the event to be dispatched
67 * as an argument. The particular behavior of this machinery is
68 * implementation-dependent. The only requirements are that events
69 * which were actually enqueued to this queue (note that events
70 * being posted to the <code>EventQueue</code> can be coalesced)
83 * Some browsers partition applets in different code bases into
84 * separate contexts, and establish walls between these contexts.
85 * In such a scenario, there will be one <code>EventQueue</code>
86 * per context. Other browsers place all applets into the same
87 * context, implying that there will be only a single, global
88 * <code>EventQueue</code> for all applets. This behavior is
89 * implementation-dependent. Consult your browser's documentation
90 * for more information.
91 * <p>
92 * For information on the threading issues of the event dispatch
93 * machinery, see <a href="doc-files/AWTThreadIssues.html#Autoshutdown"
94 * >AWT Threading Issues</a>.
95 *
96 * @author Thomas Ball
97 * @author Fred Ecks
98 * @author David Mendenhall
99 *
100 * @since 1.1
101 */
102 public class EventQueue {
103 private static final AtomicInteger threadInitNumber = new AtomicInteger(0);
104
105 private static final int LOW_PRIORITY = 0;
106 private static final int NORM_PRIORITY = 1;
107 private static final int HIGH_PRIORITY = 2;
108 private static final int ULTIMATE_PRIORITY = 3;
109
110 private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1;
111
112 /*
113 * We maintain one Queue for each priority that the EventQueue supports.
114 * That is, the EventQueue object is actually implemented as
115 * NUM_PRIORITIES queues and all Events on a particular internal Queue
116 * have identical priority. Events are pulled off the EventQueue starting
117 * with the Queue of highest priority. We progress in decreasing order
118 * across all Queues.
119 */
120 private Queue[] queues = new Queue[NUM_PRIORITIES];
121
122 /*
123 * The next EventQueue on the stack, or null if this EventQueue is
124 * on the top of the stack. If nextQueue is non-null, requests to post
125 * an event are forwarded to nextQueue.
126 */
127 private EventQueue nextQueue;
128
129 /*
130 * The previous EventQueue on the stack, or null if this is the
131 * "base" EventQueue.
132 */
133 private EventQueue previousQueue;
134
135 /*
136 * A single lock to synchronize the push()/pop() and related operations with
137 * all the EventQueues from the AppContext. Synchronization on any particular
138 * event queue(s) is not enough: we should lock the whole stack.
139 */
140 private final ReentrantLock pushPopLock;
141 private final Condition pushPopCond;
142
143 /*
144 * Dummy runnable to wake up EDT from getNextEvent() after
145 push/pop is performed
146 */
147 private final static Runnable dummyRunnable = new Runnable() {
148 public void run() {
149 }
150 };
151
152 private EventDispatchThread dispatchThread;
153
154 private final ThreadGroup threadGroup =
155 Thread.currentThread().getThreadGroup();
156 private final ClassLoader classLoader =
157 Thread.currentThread().getContextClassLoader();
158
159 /*
160 * The time stamp of the last dispatched InputEvent or ActionEvent.
161 */
162 private long mostRecentEventTime = 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 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 private final String name = "AWT-EventQueue-" + threadInitNumber.getAndIncrement();
177
178 private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventQueue");
179
180 static {
181 AWTAccessor.setEventQueueAccessor(
182 new AWTAccessor.EventQueueAccessor() {
183 public Thread getDispatchThread(EventQueue eventQueue) {
184 return eventQueue.getDispatchThread();
185 }
186 public boolean isDispatchThreadImpl(EventQueue eventQueue) {
187 return eventQueue.isDispatchThreadImpl();
188 }
189 });
190 }
191
192 public EventQueue() {
193 for (int i = 0; i < NUM_PRIORITIES; i++) {
194 queues[i] = new Queue();
195 }
196 /*
197 * NOTE: if you ever have to start the associated event dispatch
198 * thread at this point, be aware of the following problem:
199 * If this EventQueue instance is created in
200 * SunToolkit.createNewAppContext() the started dispatch thread
201 * may call AppContext.getAppContext() before createNewAppContext()
202 * completes thus causing mess in thread group to appcontext mapping.
203 */
204
205 pushPopLock = (ReentrantLock)AppContext.getAppContext().get(AppContext.EVENT_QUEUE_LOCK_KEY);
206 pushPopCond = (Condition)AppContext.getAppContext().get(AppContext.EVENT_QUEUE_COND_KEY);
207 }
208
209 /**
210 * Posts a 1.1-style event to the <code>EventQueue</code>.
211 * If there is an existing event on the queue with the same ID
212 * and event source, the source <code>Component</code>'s
213 * <code>coalesceEvents</code> method will be called.
214 *
215 * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
216 * or a subclass of it
217 * @throws NullPointerException if <code>theEvent</code> is <code>null</code>
218 */
219 public void postEvent(AWTEvent theEvent) {
220 SunToolkit.flushPendingEvents();
221 postEventPrivate(theEvent);
222 }
223
224 /**
225 * Posts a 1.1-style event to the <code>EventQueue</code>.
493 * @exception InterruptedException
494 * if any thread has interrupted this thread
495 */
496 public AWTEvent getNextEvent() throws InterruptedException {
497 do {
498 /*
499 * SunToolkit.flushPendingEvents must be called outside
500 * of the synchronized block to avoid deadlock when
501 * event queues are nested with push()/pop().
502 */
503 SunToolkit.flushPendingEvents();
504 pushPopLock.lock();
505 try {
506 AWTEvent event = getNextEventPrivate();
507 if (event != null) {
508 return event;
509 }
510 AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
511 pushPopCond.await();
512 } finally {
513 if(pushPopLock.isHeldByCurrentThread()) {
514 pushPopLock.unlock();
515 }
516 }
517 } while(true);
518 }
519
520 /*
521 * Must be called under the lock. Doesn't call flushPendingEvents()
522 */
523 AWTEvent getNextEventPrivate() throws InterruptedException {
524 for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
525 if (queues[i].head != null) {
526 EventQueueItem entry = queues[i].head;
527 queues[i].head = entry.next;
528 if (entry.next == null) {
529 queues[i].tail = null;
530 }
531 uncacheEQItem(entry);
532 return entry.event;
533 }
534 }
535 return null;
536 }
550 entry != null; prev = entry, entry = entry.next)
551 {
552 if (entry.event.getID() == id) {
553 if (prev == null) {
554 queues[i].head = entry.next;
555 } else {
556 prev.next = entry.next;
557 }
558 if (queues[i].tail == entry) {
559 queues[i].tail = prev;
560 }
561 uncacheEQItem(entry);
562 return entry.event;
563 }
564 }
565 }
566 waitForID = id;
567 pushPopCond.await();
568 waitForID = 0;
569 } finally {
570 if(pushPopLock.isHeldByCurrentThread()) {
571 pushPopLock.unlock();
572 }
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
|