001: /*
002: * @(#)EventQueue.java 1.19 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.awt;
029:
030: import java.awt.event.PaintEvent;
031: import java.awt.event.InvocationEvent;
032: import java.awt.event.KeyEvent;
033: import java.awt.event.ActionEvent;
034: import java.awt.event.FocusEvent;
035: import java.awt.event.InputEvent;
036: import java.awt.event.WindowEvent;
037: import java.awt.ActiveEvent;
038: import java.util.EmptyStackException;
039: import java.lang.reflect.InvocationTargetException;
040: import java.lang.ref.WeakReference;
041:
042: import sun.awt.AppContext;
043: import sun.awt.SunToolkit;
044:
045: /*
046: * Fix for 6370528 - EventQueue race condition or synchronization bug
047: * Both the EventQueue class and EventQueueProxy class were used for
048: * synchronization, which caused the race condition. Fixed by changing
049: * all synchronization using the EventQueueProxy class, since that is
050: * the class that contains the core logic of EventQueue after the
051: * refactoring to fix 6261461
052: */
053:
054: /**
055: * EventQueue is a platform-independent class that queues events, both
056: * from the underlying peer classes and from trusted application classes.
057: * There is only one EventQueue for each AppContext.
058: *
059: * @author Thomas Ball
060: * @author Fred Ecks
061: * @author David Mendenhall
062: *
063: * @version 1.67, 02/11/00
064: * @since 1.1
065: */
066: public class EventQueue {
067: // From Thread.java
068: private static int threadInitNumber;
069:
070: private static synchronized int nextThreadNum() {
071: return threadInitNumber++;
072: }
073:
074: private static final int LOW_PRIORITY = 0;
075: private static final int NORM_PRIORITY = 1;
076: private static final int HIGH_PRIORITY = 2;
077: static final int NUM_PRIORITIES = HIGH_PRIORITY + 1; // 6261461
078:
079: /*
080: * We maintain one Queue for each priority that the EventQueue supports.
081: * That is, the EventQueue object is actually implemented as
082: * NUM_PRIORITIES queues and all Events on a particular internal Queue
083: * have identical priority. Events are pulled off the EventQueue starting
084: * with the Queue of highest priority. We progress in decreasing order
085: * across all Queues.
086: */
087: Queue[] queues = new Queue[NUM_PRIORITIES]; // 6261461
088:
089: /*
090: * The next EventQueue on the stack, or null if this EventQueue is
091: * on the top of the stack. If nextQueue is non-null, requests to post
092: * an event are forwarded to nextQueue.
093: */
094: private EventQueue nextQueue;
095: /*
096: * The previous EventQueue on the stack, or null if this is the
097: * "base" EventQueue.
098: */
099: private EventQueue previousQueue;
100: private EventDispatchThread dispatchThread;
101: /*
102: * Debugging flag -- set true and recompile to enable checking.
103: */
104: private final static boolean debug = false;
105:
106: private WeakReference currentEvent;
107: private long mostRecentEventTime = System.currentTimeMillis();
108:
109: private EventQueueProxy proxy = null; // 6261461
110:
111: public EventQueue() {
112: for (int i = 0; i < NUM_PRIORITIES; i++) {
113: queues[i] = new Queue();
114: }
115: String name = "AWT-EventQueue-" + nextThreadNum();
116: dispatchThread = new EventDispatchThread(name,
117: this .proxy = new EventQueueProxy(this )); // 6261461
118: dispatchThread.setPriority(Thread.NORM_PRIORITY + 1);
119: dispatchThread.start();
120: }
121:
122: /**
123: * Post a 1.1-style event to the EventQueue. If there is an
124: * existing event on the queue with the same ID and event source,
125: * the source Component's coalesceEvents method will be called.
126: *
127: * @param theEvent an instance of java.awt.AWTEvent, or a
128: * subclass of it.
129: */
130: public void postEvent(AWTEvent theEvent) {
131: postEventPrivate(theEvent);
132: }
133:
134: /**
135: * Post a 1.1-style event to the EventQueue. If there is an
136: * existing event on the queue with the same ID and event source,
137: * the source Component's coalesceEvents method will be called.
138: *
139: * @param theEvent an instance of java.awt.AWTEvent, or a
140: * subclass of it.
141: */
142: final void postEventPrivate(AWTEvent theEvent) {
143: synchronized (this .proxy) { // 6261461
144: int id = theEvent.getID();
145: if (nextQueue != null) {
146: // Forward event to top of EventQueue stack.
147: nextQueue.postEventPrivate(theEvent);
148: } else if (id == PaintEvent.PAINT
149: || id == PaintEvent.UPDATE) {
150: postEvent(theEvent, LOW_PRIORITY);
151: } else {
152: postEvent(theEvent, NORM_PRIORITY);
153: }
154: }
155: }
156:
157: /**
158: * Posts the event to the internal Queue of specified priority,
159: * coalescing as appropriate.
160: */
161: private void postEvent(AWTEvent theEvent, int priority) {
162: EventQueueItem newItem = new EventQueueItem(theEvent);
163: boolean notifyID = (theEvent.getID() == this .proxy.waitForID);//6261461
164: if (queues[priority].head == null) {
165: boolean shouldNotify = noEvents();
166: queues[priority].head = queues[priority].tail = newItem;
167: // This component doesn't have any events of this type on the
168: // queue, so we have to initialize the RepaintArea with theEvent
169: if (theEvent.getID() == PaintEvent.PAINT
170: || theEvent.getID() == PaintEvent.UPDATE) {
171: Object source = theEvent.getSource();
172: ((Component) source).coalesceEvents(theEvent, theEvent);
173: }
174: if (shouldNotify) {
175: proxy.notifyAll(); // 6261461
176: }
177: if (notifyID) {
178: proxy.notifyAll(); // 6261461
179: }
180: } else {
181: Object source = theEvent.getSource();
182: // For Component source events, traverse the entire list,
183: // trying to coalesce events
184: if (source instanceof Component) {
185: EventQueueItem q = queues[priority].head;
186: for (;;) {
187: if (q.id == newItem.id
188: && q.event.getSource() == source) {
189: AWTEvent coalescedEvent;
190: coalescedEvent = ((Component) source)
191: .coalesceEvents(q.event, theEvent);
192: if (coalescedEvent != null) {
193: q.event = coalescedEvent;
194: return;
195: }
196: }
197: if (q.next != null) {
198: q = q.next;
199: } else {
200: break;
201: }
202: }
203: }
204: // The event was not coalesced or has non-Component source.
205: // Insert it at the end of the appropriate Queue.
206: if (theEvent.getID() == PaintEvent.PAINT
207: || theEvent.getID() == PaintEvent.UPDATE) {
208: // This component doesn't have any events of this type on the
209: // queue, so we have to initialize the RepaintArea with theEvent
210: ((Component) source).coalesceEvents(theEvent, theEvent);
211: }
212: queues[priority].tail.next = newItem;
213: queues[priority].tail = newItem;
214: if (notifyID) {
215: proxy.notifyAll(); // 6261461
216: }
217: }
218: }
219:
220: /**
221: * @return whether an event is pending on any of the separate Queues
222: */
223: private boolean noEvents() {
224: for (int i = 0; i < NUM_PRIORITIES; i++) {
225: if (queues[i].head != null) {
226: return false;
227: }
228: }
229: return true;
230: }
231:
232: /**
233: * Remove an event from the EventQueue and return it. This method will
234: * block until an event has been posted by another thread.
235: * @return the next AWTEvent
236: * @exception InterruptedException
237: * if another thread has interrupted this thread.
238: */
239: public AWTEvent getNextEvent() throws InterruptedException {
240: return this .proxy.getNextEvent(); // 6261461
241: }
242:
243: /**
244: * Return the first event on the EventQueue without removing it.
245: * @return the first event
246: */
247: public AWTEvent peekEvent() {
248: synchronized (this .proxy) { // 6370528
249: for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
250: if (queues[i].head != null) {
251: return queues[i].head.event;
252: }
253: }
254: return null;
255: }
256: }
257:
258: /**
259: * Return the first event with the specified id, if any.
260: * @param id the id of the type of event desired.
261: * @return the first event of the specified id
262: */
263: public AWTEvent peekEvent(int id) {
264: synchronized (this .proxy) { // 6370528
265: for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
266: EventQueueItem q = queues[i].head;
267: for (; q != null; q = q.next) {
268: if (q.id == id) {
269: return q.event;
270: }
271: }
272: }
273: return null;
274: }
275: }
276:
277: /**
278: * Dispatch an event. The manner in which the event is
279: * dispatched depends upon the type of the event and the
280: * type of the event's source
281: * object:
282: * <p> </p>
283: * <table border>
284: * <tr>
285: * <th>Event Type</th>
286: * <th>Source Type</th>
287: * <th>Dispatched To</th>
288: * </tr>
289: * <tr>
290: * <td>ActiveEvent</td>
291: * <td>Any</td>
292: * <td>event.dispatch()</td>
293: * </tr>
294: * <tr>
295: * <td>Other</td>
296: * <td>Component</td>
297: * <td>source.dispatchEvent(AWTEvent)</td>
298: * </tr>
299: * <tr>
300: * <td>Other</td>
301: * <td>MenuComponent</td>
302: * <td>source.dispatchEvent(AWTEvent)</td>
303: * </tr>
304: * <tr>
305: * <td>Other</td>
306: * <td>Other</td>
307: * <td>No action (ignored)</td>
308: * </tr>
309: * </table>
310: * <p> </p>
311: * @param theEvent an instance of java.awt.AWTEvent, or a
312: * subclass of it.
313: */
314: protected void dispatchEvent(AWTEvent event) {
315: Object src = event.getSource();
316: if (event instanceof ActiveEvent) {
317: // This could become the sole method of dispatching in time.
318: ((ActiveEvent) event).dispatch();
319: } else if (src instanceof Component) {
320: ((Component) src).dispatchEvent(event);
321: } else if (src instanceof MenuComponent) {
322: ((MenuComponent) src).dispatchEvent(event);
323: } else {
324: System.err.println("unable to dispatch event: " + event);
325: }
326: }
327:
328: /**
329: * Replace the existing EventQueue with the specified one.
330: * Any pending events are transferred to the new EventQueue
331: * for processing by it.
332: *
333: * @param an EventQueue (or subclass thereof) instance to be used.
334: * @see java.awt.EventQueue#pop
335: */
336: public void push(EventQueue newEventQueue) {
337: synchronized (this .proxy) { // 6370528
338: if (debug) {
339: System.out.println("EventQueue.push(" + newEventQueue
340: + ")");
341: }
342: if (nextQueue != null) {
343: nextQueue.push(newEventQueue);
344: return;
345: }
346: synchronized (newEventQueue.proxy) { // 6370528
347: // Transfer all events forward to new EventQueue.
348: while (peekEvent() != null) {
349: try {
350: newEventQueue.postEventPrivate(getNextEvent());
351: } catch (InterruptedException ie) {
352: if (debug) {
353: System.err.println("interrupted push:");
354: ie.printStackTrace(System.err);
355: }
356: }
357: }
358: newEventQueue.previousQueue = this ;
359: }
360: nextQueue = newEventQueue;
361:
362: AppContext appContext = AppContext.getAppContext();
363: if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this ) {
364: appContext.put(AppContext.EVENT_QUEUE_KEY,
365: newEventQueue);
366: }
367: }
368:
369: }
370:
371: /**
372: * Stop dispatching events using this EventQueue instance.
373: * Any pending events are transferred to the previous
374: * EventQueue for processing by it.
375: *
376: * @exception if no previous push was made on this EventQueue.
377: * @see java.awt.EventQueue#push
378: */
379: protected void pop() throws EmptyStackException {
380: if (debug) {
381: System.out.println("EventQueue.pop(" + this + ")");
382: }
383: // To prevent deadlock, we lock on the previous EventQueue before
384: // this one. This uses the same locking order as everything else
385: // in EventQueue.java, so deadlock isn't possible.
386: EventQueue prev = previousQueue;
387: synchronized ((prev != null) ? prev.proxy : this .proxy) { // 6370528
388: synchronized (this .proxy) { // 6370528
389: if (nextQueue != null) {
390: nextQueue.pop();
391: return;
392: }
393: if (previousQueue == null) {
394: throw new EmptyStackException();
395: }
396: // Transfer all events back to previous EventQueue.
397: previousQueue.nextQueue = null;
398: while (peekEvent() != null) {
399: try {
400: previousQueue.postEventPrivate(getNextEvent());
401: } catch (InterruptedException ie) {
402: if (debug) {
403: System.err.println("interrupted pop:");
404: ie.printStackTrace(System.err);
405: }
406: }
407: }
408:
409: AppContext appContext = AppContext.getAppContext();
410: if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this ) {
411: appContext.put(AppContext.EVENT_QUEUE_KEY,
412: previousQueue);
413: }
414: previousQueue = null;
415: }
416: }
417: dispatchThread.stopDispatching(); // Must be done outside synchronized
418: // block to avoid possible deadlock
419: }
420:
421: /**
422: * Returns true if the calling thread is the current AWT EventQueue's
423: * dispatch thread. Use this call the ensure that a given
424: * task is being executed (or not being) on the current AWT
425: * EventDispatchThread.
426: *
427: * @return true if running on the current AWT EventQueue's dispatch thread.
428: */
429: public static boolean isDispatchThread() {
430: EventQueue eq = Toolkit.getEventQueue();
431: EventQueue next = eq.nextQueue;
432: while (next != null) {
433: eq = next;
434: next = eq.nextQueue;
435: }
436: return (Thread.currentThread() == eq.dispatchThread);
437: }
438:
439: /*
440: * Get the EventDispatchThread for this EventQueue.
441: */
442: final EventDispatchThread getDispatchThread() {
443: return dispatchThread;
444: }
445:
446: /*
447: * Change the target of any pending KeyEvents because of a focus change.
448: */
449: final void changeKeyEventFocus(Object newSource) {
450: synchronized (this .proxy) { // 6370528
451: for (int i = 0; i < NUM_PRIORITIES; i++) {
452: EventQueueItem q = queues[i].head;
453: for (; q != null; q = q.next) {
454: if (q.event instanceof KeyEvent) {
455: q.event.setSource(newSource);
456: }
457: }
458: }
459: }
460: }
461:
462: /*
463: * Remove any pending events for the specified source object.
464: * This method is normally called by the source's removeNotify method.
465: */
466: final void removeSourceEvents(Object source) {
467: synchronized (this .proxy) { // 6370528
468: for (int i = 0; i < NUM_PRIORITIES; i++) {
469: EventQueueItem entry = queues[i].head;
470: EventQueueItem prev = null;
471: while (entry != null) {
472: if (entry.event.getSource() == source) {
473: if (entry.event instanceof SequencedEvent) {
474: ((SequencedEvent) entry.event).dispose();
475: }
476: if (entry.event instanceof SentEvent) {
477: ((SentEvent) entry.event).dispose();
478: }
479: if (prev == null) {
480: queues[i].head = entry.next;
481: } else {
482: prev.next = entry.next;
483: }
484: } else {
485: prev = entry;
486: }
487: entry = entry.next;
488: }
489: queues[i].tail = prev;
490: }
491: }
492: }
493:
494: /*
495: * Remove any pending events for the specified source object.
496: * This method is normally called by the source's removeNotify method.
497: */
498: final void removeEvents(Class type, int id) {
499: synchronized (this .proxy) { // 6370528
500: for (int i = 0; i < NUM_PRIORITIES; i++) {
501: EventQueueItem entry = queues[i].head;
502: EventQueueItem prev = null;
503: while (entry != null) {
504: if (entry.event.getClass().equals(type)
505: && entry.event.id == id) {
506: if (prev == null) {
507: queues[i].head = entry.next;
508: } else {
509: prev.next = entry.next;
510: }
511: } else {
512: prev = entry;
513: }
514: entry = entry.next;
515: }
516: queues[i].tail = prev;
517: }
518: }
519: }
520:
521: /**
522: * Causes <i>runnable</i> to have its run() method called in the dispatch
523: * thread of the EventQueue. This will happen after all pending events
524: * are processed.
525: *
526: * @param runnable the Runnable whose run() method should be executed
527: * synchronously on the EventQueue
528: * @see #invokeAndWait
529: * @since 1.2
530: */
531: public static void invokeLater(Runnable runnable) {
532: Toolkit.getEventQueue().postEvent(
533: new InvocationEvent(Toolkit.getDefaultToolkit(),
534: runnable));
535: }
536:
537: /**
538: * Causes <i>runnable</i> to have its run() method called in the dispatch
539: * thread of the EventQueue. This will happen after all pending events
540: * are processed. The call blocks until this has happened. This method
541: * will throw an Error if called from the event dispatcher thread.
542: *
543: * @param runnable the Runnable whose run() method should be executed
544: * synchronously on the EventQueue
545: * @exception InterruptedException if another thread has
546: * interrupted this thread
547: * @exception InvocationTargetException if an exception is thrown
548: * when running <i>runnable</i>
549: * @see #invokeLater
550: * @since 1.2
551: */
552: public static void invokeAndWait(Runnable runnable)
553: throws InterruptedException, InvocationTargetException {
554: if (EventQueue.isDispatchThread()) {
555: throw new Error(
556: "Cannot call invokeAndWait from the event dispatcher thread");
557: }
558: class AWTInvocationLock {
559: }
560: Object lock = new AWTInvocationLock();
561: EventQueue queue = Toolkit.getEventQueue();
562: InvocationEvent event = new InvocationEvent(Toolkit
563: .getDefaultToolkit(), runnable, lock, true);
564: synchronized (lock) {
565: Toolkit.getEventQueue().postEvent(event);
566: lock.wait();
567: }
568: Exception eventException = event.getException();
569: if (eventException != null) {
570: throw new InvocationTargetException(eventException);
571: }
572: }
573:
574: static void setCurrentEventAndMostRecentTime(AWTEvent e) {
575: Toolkit.getEventQueue().setCurrentEventAndMostRecentTimeImpl(e);
576: }
577:
578: private void setCurrentEventAndMostRecentTimeImpl(AWTEvent e) {
579: synchronized (this .proxy) { // 6370528
580: if (Thread.currentThread() != dispatchThread) {
581: return;
582: }
583:
584: currentEvent = new WeakReference(e);
585:
586: // This series of 'instanceof' checks should be replaced with a
587: // polymorphic type (for example, an interface which declares a
588: // getWhen() method). However, this would require us to make such
589: // a type public, or to place it in sun.awt. Both of these approaches
590: // have been frowned upon.
591:
592: // In tiger, we will probably give timestamps to all events, so this
593: // will no longer be an issue.
594: if (e instanceof InputEvent) {
595: InputEvent ie = (InputEvent) e;
596: mostRecentEventTime = ie.getWhen();
597: } else if (e instanceof ActionEvent) {
598: ActionEvent ae = (ActionEvent) e;
599: mostRecentEventTime = ae.getWhen();
600: } else if (e instanceof InvocationEvent) {
601: InvocationEvent ie = (InvocationEvent) e;
602: mostRecentEventTime = ie.getWhen();
603: }
604: }
605: }
606:
607: final void removeSourceEvents(Object source, boolean removeAllEvents) {
608: synchronized (this .proxy) { // 6370528
609: for (int i = 0; i < NUM_PRIORITIES; i++) {
610: EventQueueItem entry = queues[i].head;
611: EventQueueItem prev = null;
612: while (entry != null) {
613: if ((entry.event.getSource() == source)
614: && (removeAllEvents || !(entry.event instanceof SentEvent
615: || entry.event instanceof SequencedEvent
616: || entry.event instanceof FocusEvent
617: || entry.event instanceof WindowEvent || entry.event instanceof KeyEvent))) {
618: if (entry.event instanceof SequencedEvent) {
619: ((SequencedEvent) entry.event).dispose();
620: }
621: if (entry.event instanceof SentEvent) {
622: ((SentEvent) entry.event).dispose();
623: }
624: if (prev == null) {
625: queues[i].head = entry.next;
626: } else {
627: prev.next = entry.next;
628: }
629: } else {
630: prev = entry;
631: }
632: entry = entry.next;
633: }
634: queues[i].tail = prev;
635: }
636: }
637: }
638:
639: public static long getMostRecentEventTime() {
640: return Toolkit.getEventQueue().getMostRecentEventTimeImpl();
641: }
642:
643: private long getMostRecentEventTimeImpl() {
644: synchronized (this .proxy) { // 6370528
645: return (Thread.currentThread() == dispatchThread) ? mostRecentEventTime
646: : System.currentTimeMillis();
647: }
648: }
649:
650: /**
651: * Returns the the event currently being dispatched by the
652: * <code>EventQueue</code> associated with the calling thread. This is
653: * useful if a method needs access to the event, but was not designed to
654: * receive a reference to it as an argument. Note that this method should
655: * only be invoked from an application's event dispatching thread. If this
656: * method is invoked from another thread, null will be returned.
657: *
658: * @return the event currently being dispatched, or null if this method is
659: * invoked on a thread other than an event dispatching thread
660: * @since 1.4
661: */
662: public static AWTEvent getCurrentEvent() {
663: return Toolkit.getEventQueue().getCurrentEventImpl();
664: }
665:
666: private AWTEvent getCurrentEventImpl() {
667: synchronized (this .proxy) { // 6370528
668:
669: return (Thread.currentThread() == dispatchThread) ? ((AWTEvent) currentEvent
670: .get())
671: : null;
672: }
673: }
674:
675: AWTEvent getNextEvent(int id) throws InterruptedException {
676: return this .proxy.getNextEvent(id); // 6261461
677: }
678:
679: // 6261461
680: // EffectiveJava Pattern : Finalizer Guardian Idiom.
681: private final Object finalizerGuardian = new Object() {
682: protected void finalize() throws Throwable {
683: try {
684: EventQueue.this .dispatchThread.stopDispatching();
685: } finally {
686: super .finalize();
687: }
688: }
689: };
690: // 6261461
691: }
692:
693: /**
694: * The Queue object holds pointers to the beginning and end of one internal
695: * queue. An EventQueue object is composed of multiple internal Queues, one
696: * for each priority supported by the EventQueue. All Events on a particular
697: * internal Queue have identical priority.
698: */
699: class Queue {
700: EventQueueItem head;
701: EventQueueItem tail;
702: }
703:
704: class EventQueueItem {
705: AWTEvent event;
706: int id;
707: EventQueueItem next;
708:
709: EventQueueItem(AWTEvent evt) {
710: event = evt;
711: id = evt.getID();
712: }
713: }
|