KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > awt > EventQueue


1 /*
2  * @(#)EventQueue.java 1.97 06/07/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.awt;
9
10 import java.awt.event.ActionEvent JavaDoc;
11 import java.awt.event.FocusEvent JavaDoc;
12 import java.awt.event.InputEvent JavaDoc;
13 import java.awt.event.InputMethodEvent JavaDoc;
14 import java.awt.event.InvocationEvent JavaDoc;
15 import java.awt.event.KeyEvent JavaDoc;
16 import java.awt.event.MouseEvent JavaDoc;
17 import java.awt.event.PaintEvent JavaDoc;
18 import java.awt.event.WindowEvent JavaDoc;
19 import java.awt.ActiveEvent JavaDoc;
20 import java.awt.peer.ComponentPeer;
21 import java.awt.peer.LightweightPeer;
22 import java.util.EmptyStackException JavaDoc;
23 import java.lang.ref.WeakReference JavaDoc;
24 import java.lang.reflect.InvocationTargetException JavaDoc;
25 import java.security.AccessController JavaDoc;
26 import java.security.PrivilegedAction JavaDoc;
27 import sun.awt.PeerEvent;
28 import sun.awt.SunToolkit;
29 import sun.awt.DebugHelper;
30 import sun.awt.AWTAutoShutdown;
31 import sun.awt.AppContext;
32
33 /**
34  * <code>EventQueue</code> is a platform-independent class
35  * that queues events, both from the underlying peer classes
36  * and from trusted application classes.
37  * <p>
38  * It encapsulates asynchronous event dispatch machinery which
39  * extracts events from the queue and dispatches them by calling
40  * {@link #dispatchEvent(AWTEvent) dispatchEvent(AWTEvent)} method
41  * on this <code>EventQueue</code> with the event to be dispatched
42  * as an argument. The particular behavior of this machinery is
43  * implementation-dependent. The only requirements are that events
44  * which were actually enqueued to this queue (note that events
45  * being posted to the <code>EventQueue</code> can be coalesced)
46  * are dispatched:
47  * <dl>
48  * <dt> Sequentially.
49  * <dd> That is, it is not permitted that several events from
50  * this queue are dispatched simultaneously.
51  * <dt> In the same order as they are enqueued.
52  * <dd> That is, if <code>AWTEvent</code>&nbsp;A is enqueued
53  * to the <code>EventQueue</code> before
54  * <code>AWTEvent</code>&nbsp;B then event B will not be
55  * dispatched before event A.
56  * </dl>
57  * <p>
58  * Some browsers partition applets in different code bases into
59  * separate contexts, and establish walls between these contexts.
60  * In such a scenario, there will be one <code>EventQueue</code>
61  * per context. Other browsers place all applets into the same
62  * context, implying that there will be only a single, global
63  * <code>EventQueue</code> for all applets. This behavior is
64  * implementation-dependent. Consult your browser's documentation
65  * for more information.
66  * <p>
67  * For information on the threading issues of the event dispatch
68  * machinery, see <a HREF="doc-files/AWTThreadIssues.html">AWT Threading
69  * Issues</a>.
70
71  *
72  * @author Thomas Ball
73  * @author Fred Ecks
74  * @author David Mendenhall
75  *
76  * @version 1.97, 07/19/06
77  * @since 1.1
78  */

79 public class EventQueue {
80     private static final DebugHelper dbg = DebugHelper.create(EventQueue JavaDoc.class);
81
82     // From Thread.java
83
private static int threadInitNumber;
84     private static synchronized int nextThreadNum() {
85     return threadInitNumber++;
86     }
87
88     private static final int LOW_PRIORITY = 0;
89     private static final int NORM_PRIORITY = 1;
90     private static final int HIGH_PRIORITY = 2;
91     private static final int ULTIMATE_PRIORITY = 3;
92
93     private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1;
94
95     /*
96      * We maintain one Queue for each priority that the EventQueue supports.
97      * That is, the EventQueue object is actually implemented as
98      * NUM_PRIORITIES queues and all Events on a particular internal Queue
99      * have identical priority. Events are pulled off the EventQueue starting
100      * with the Queue of highest priority. We progress in decreasing order
101      * across all Queues.
102      */

103     private Queue[] queues = new Queue[NUM_PRIORITIES];
104     
105     /*
106      * The next EventQueue on the stack, or null if this EventQueue is
107      * on the top of the stack. If nextQueue is non-null, requests to post
108      * an event are forwarded to nextQueue.
109      */

110     private EventQueue JavaDoc nextQueue;
111
112     /*
113      * The previous EventQueue on the stack, or null if this is the
114      * "base" EventQueue.
115      */

116     private EventQueue JavaDoc previousQueue;
117
118     private EventDispatchThread JavaDoc dispatchThread;
119
120     private final ThreadGroup JavaDoc threadGroup =
121         Thread.currentThread().getThreadGroup();
122     private final ClassLoader JavaDoc classLoader =
123         Thread.currentThread().getContextClassLoader();
124
125     /*
126      * Debugging flag -- set true and recompile to enable checking.
127      */

128     private final static boolean debug = false;
129
130     /*
131      * The time stamp of the last dispatched InputEvent or ActionEvent.
132      */

133     private long mostRecentEventTime = System.currentTimeMillis();
134
135     /**
136      * The modifiers field of the current event, if the current event is an
137      * InputEvent or ActionEvent.
138      */

139     private WeakReference JavaDoc currentEvent;
140
141     /*
142      * Non-zero if a thread is waiting in getNextEvent(int) for an event of
143      * a particular ID to be posted to the queue.
144      */

145     private int waitForID;
146
147     private final String JavaDoc name = "AWT-EventQueue-" + nextThreadNum();
148
149     public EventQueue() {
150         for (int i = 0; i < NUM_PRIORITIES; i++) {
151         queues[i] = new Queue();
152     }
153         /*
154          * NOTE: if you ever have to start the associated event dispatch
155          * thread at this point, be aware of the following problem:
156          * If this EventQueue instance is created in
157          * SunToolkit.createNewAppContext() the started dispatch thread
158          * may call AppContext.getAppContext() before createNewAppContext()
159          * completes thus causing mess in thread group to appcontext mapping.
160          */

161     }
162
163     /**
164      * Posts a 1.1-style event to the <code>EventQueue</code>.
165      * If there is an existing event on the queue with the same ID
166      * and event source, the source <code>Component</code>'s
167      * <code>coalesceEvents</code> method will be called.
168      *
169      * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
170      * or a subclass of it
171      * @throws NullPointerException if <code>theEvent</code> is <code>null</code>
172      */

173     public void postEvent(AWTEvent JavaDoc theEvent) {
174         SunToolkit.flushPendingEvents();
175         postEventPrivate(theEvent);
176     }
177
178     /**
179      * Posts a 1.1-style event to the <code>EventQueue</code>.
180      * If there is an existing event on the queue with the same ID
181      * and event source, the source <code>Component</code>'s
182      * <code>coalesceEvents</code> method will be called.
183      *
184      * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
185      * or a subclass of it
186      */

187     final void postEventPrivate(AWTEvent JavaDoc theEvent) {
188         theEvent.isPosted = true;
189         synchronized(this) {
190             int id = theEvent.getID();
191             if (nextQueue != null) {
192                 // Forward event to top of EventQueue stack.
193
nextQueue.postEventPrivate(theEvent);
194             } else if (theEvent instanceof PeerEvent &&
195                            (((PeerEvent)theEvent).getFlags() &
196                             PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0) {
197                 postEvent(theEvent, ULTIMATE_PRIORITY);
198             } else if (theEvent instanceof PeerEvent &&
199                        (((PeerEvent)theEvent).getFlags() &
200                                        PeerEvent.PRIORITY_EVENT) != 0) {
201                 postEvent(theEvent, HIGH_PRIORITY);
202             } else if (id == PaintEvent.PAINT ||
203                        id == PaintEvent.UPDATE) {
204                 postEvent(theEvent, LOW_PRIORITY);
205             } else {
206                 postEvent(theEvent, NORM_PRIORITY);
207             }
208         }
209     }
210
211     /**
212      * Posts the event to the internal Queue of specified priority,
213      * coalescing as appropriate.
214      *
215      * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
216      * or a subclass of it
217      * @param priority the desired priority of the event
218      */

219     private void postEvent(AWTEvent JavaDoc theEvent, int priority) {
220
221         if (dispatchThread == null) {
222             if (theEvent.getSource() == AWTAutoShutdown.getInstance()) {
223                 return;
224             } else {
225                 initDispatchThread();
226             }
227         }
228
229     Object JavaDoc source = theEvent.getSource();
230
231     // Expanding RepaintArea
232
if (source instanceof Component JavaDoc) {
233         ComponentPeer sourcePeer = ((Component JavaDoc)source).peer;
234         if (sourcePeer != null && theEvent instanceof PaintEvent JavaDoc &&
235                 !(sourcePeer instanceof LightweightPeer)) {
236         sourcePeer.coalescePaintEvent((PaintEvent JavaDoc)theEvent);
237         }
238     }
239
240         EventQueueItem newItem = new EventQueueItem(theEvent);
241
242         boolean notifyID = (theEvent.getID() == this.waitForID);
243     
244     if (queues[priority].head == null) {
245             boolean shouldNotify = noEvents();
246         queues[priority].head = queues[priority].tail = newItem;
247
248         if (shouldNotify) {
249                 if (theEvent.getSource() != AWTAutoShutdown.getInstance()) {
250                     AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
251                 }
252             notifyAll();
253         } else if (notifyID) {
254                 notifyAll();
255             }
256     } else {
257         boolean isPeerEvent = theEvent instanceof PeerEvent;
258            
259         // For Component source events, traverse the entire list,
260
// trying to coalesce events
261
if (source instanceof Component JavaDoc) {
262                 EventQueueItem q = queues[priority].head;
263
264                 if (theEvent.id == Event.MOUSE_MOVE ||
265                     theEvent.id == Event.MOUSE_DRAG) {
266                     EventQueueItem qm;
267                     for(qm = q; qm != null; qm = qm.next) {
268                         if ((qm.event instanceof MouseEvent JavaDoc) &&
269                             qm.id != theEvent.id) {
270                             q = qm;
271                         }
272                     }
273                 }
274
275         for (; q != null; q = q.next) {
276             // Give Component.coalesceEvents a chance
277
if (q.event.getSource() == source && q.id == newItem.id) {
278             AWTEvent JavaDoc coalescedEvent = ((Component JavaDoc)source).coalesceEvents(q.event, theEvent);
279             if (isPeerEvent && coalescedEvent == null && q.event instanceof PeerEvent) {
280                 coalescedEvent = ((PeerEvent)q.event).coalesceEvents((PeerEvent)theEvent);
281             }
282             if (coalescedEvent != null) {
283                 // Remove debugging statement because
284
// calling AWTEvent.toString here causes a
285
// deadlock.
286
q.event = coalescedEvent;
287                 return;
288             }
289             }
290         }
291         }
292             // The event was not coalesced or has non-Component source.
293
// Insert it at the end of the appropriate Queue.
294
queues[priority].tail.next = newItem;
295         queues[priority].tail = newItem;
296             if (notifyID) {
297                 notifyAll();
298             }
299     }
300     }
301
302     /**
303      * Returns whether an event is pending on any of the separate
304      * Queues.
305      * @return whether an event is pending on any of the separate Queues
306      */

307     private boolean noEvents() {
308         for (int i = 0; i < NUM_PRIORITIES; i++) {
309         if (queues[i].head != null) {
310             return false;
311         }
312     }
313
314     return true;
315     }
316
317     /**
318      * Removes an event from the <code>EventQueue</code> and
319      * returns it. This method will block until an event has
320      * been posted by another thread.
321      * @return the next <code>AWTEvent</code>
322      * @exception InterruptedException
323      * if another thread has interrupted this thread
324      */

325     public AWTEvent JavaDoc getNextEvent() throws InterruptedException JavaDoc {
326         do {
327             /*
328              * SunToolkit.flushPendingEvents must be called outside
329              * of the synchronized block to avoid deadlock when
330              * event queues are nested with push()/pop().
331              */

332             SunToolkit.flushPendingEvents();
333             synchronized (this) {
334                 for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
335                     if (queues[i].head != null) {
336                         EventQueueItem eqi = queues[i].head;
337                         queues[i].head = eqi.next;
338                         if (eqi.next == null) {
339                             queues[i].tail = null;
340                         }
341                         return eqi.event;
342                     }
343                 }
344                 AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
345                 wait();
346             }
347         } while(true);
348     }
349
350     AWTEvent JavaDoc getNextEvent(int id) throws InterruptedException JavaDoc {
351     do {
352             /*
353              * SunToolkit.flushPendingEvents must be called outside
354              * of the synchronized block to avoid deadlock when
355              * event queues are nested with push()/pop().
356              */

357             SunToolkit.flushPendingEvents();
358             synchronized (this) {
359                 for (int i = 0; i < NUM_PRIORITIES; i++) {
360                     for (EventQueueItem entry = queues[i].head, prev = null;
361                          entry != null; prev = entry, entry = entry.next)
362                     {
363                         if (entry.id == id) {
364                             if (prev == null) {
365                                 queues[i].head = entry.next;
366                             } else {
367                                 prev.next = entry.next;
368                             }
369                             if (queues[i].tail == entry) {
370                                 queues[i].tail = prev;
371                             }
372                             return entry.event;
373                         }
374                     }
375                 }
376                 this.waitForID = id;
377                 wait();
378                 this.waitForID = 0;
379             }
380     } while(true);
381     }
382
383     /**
384      * Returns the first event on the <code>EventQueue</code>
385      * without removing it.
386      * @return the first event
387      */

388     public synchronized AWTEvent JavaDoc peekEvent() {
389         for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
390         if (queues[i].head != null) {
391             return queues[i].head.event;
392         }
393     }
394
395     return null;
396     }
397
398     /**
399      * Returns the first event with the specified id, if any.
400      * @param id the id of the type of event desired
401      * @return the first event of the specified id or <code>null</code>
402      * if there is no such event
403      */

404     public synchronized AWTEvent JavaDoc peekEvent(int id) {
405         for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
406         EventQueueItem q = queues[i].head;
407         for (; q != null; q = q.next) {
408             if (q.id == id) {
409             return q.event;
410         }
411         }
412     }
413
414         return null;
415     }
416
417     /**
418      * Dispatches an event. The manner in which the event is
419      * dispatched depends upon the type of the event and the
420      * type of the event's source object:
421      * <p> </p>
422      * <table border=1 summary="Event types, source types, and dispatch methods">
423      * <tr>
424      * <th>Event Type</th>
425      * <th>Source Type</th>
426      * <th>Dispatched To</th>
427      * </tr>
428      * <tr>
429      * <td>ActiveEvent</td>
430      * <td>Any</td>
431      * <td>event.dispatch()</td>
432      * </tr>
433      * <tr>
434      * <td>Other</td>
435      * <td>Component</td>
436      * <td>source.dispatchEvent(AWTEvent)</td>
437      * </tr>
438      * <tr>
439      * <td>Other</td>
440      * <td>MenuComponent</td>
441      * <td>source.dispatchEvent(AWTEvent)</td>
442      * </tr>
443      * <tr>
444      * <td>Other</td>
445      * <td>Other</td>
446      * <td>No action (ignored)</td>
447      * </tr>
448      * </table>
449      * <p> </p>
450      * @param event an instance of <code>java.awt.AWTEvent</code>,
451      * or a subclass of it
452      * @throws NullPointerException if <code>event</code> is <code>null</code>
453      */

454     protected void dispatchEvent(AWTEvent JavaDoc event) {
455         event.isPosted = true;
456         Object JavaDoc src = event.getSource();
457         if (event instanceof ActiveEvent JavaDoc) {
458             // This could become the sole method of dispatching in time.
459
setCurrentEventAndMostRecentTimeImpl(event);
460
461             ((ActiveEvent JavaDoc)event).dispatch();
462         } else if (src instanceof Component JavaDoc) {
463             ((Component JavaDoc)src).dispatchEvent(event);
464             event.dispatched();
465         } else if (src instanceof MenuComponent JavaDoc) {
466             ((MenuComponent JavaDoc)src).dispatchEvent(event);
467         } else if (src instanceof AWTAutoShutdown) {
468             if (noEvents()) {
469                 dispatchThread.stopDispatching();
470             }
471         } else {
472             System.err.println("unable to dispatch event: " + event);
473         }
474     }
475
476     /**
477      * Returns the timestamp of the most recent event that had a timestamp, and
478      * that was dispatched from the <code>EventQueue</code> associated with the
479      * calling thread. If an event with a timestamp is currently being
480      * dispatched, its timestamp will be returned. If no events have yet
481      * been dispatched, the EventQueue's initialization time will be
482      * returned instead.In the current version of
483      * the JDK, only <code>InputEvent</code>s,
484      * <code>ActionEvent</code>s, and <code>InvocationEvent</code>s have
485      * timestamps; however, future versions of the JDK may add timestamps to
486      * additional event types. Note that this method should only be invoked
487      * from an application's event dispatching thread. If this method is
488      * invoked from another thread, the current system time (as reported by
489      * <code>System.currentTimeMillis()</code>) will be returned instead.
490      *
491      * @return the timestamp of the last <code>InputEvent</code>,
492      * <code>ActionEvent</code>, or <code>InvocationEvent</code> to be
493      * dispatched, or <code>System.currentTimeMillis()</code> if this
494      * method is invoked on a thread other than an event dispatching
495      * thread
496      * @see java.awt.event.InputEvent#getWhen
497      * @see java.awt.event.ActionEvent#getWhen
498      * @see java.awt.event.InvocationEvent#getWhen
499      *
500      * @since 1.4
501      */

502     public static long getMostRecentEventTime() {
503         return Toolkit.getEventQueue().getMostRecentEventTimeImpl();
504     }
505     private synchronized long getMostRecentEventTimeImpl() {
506         return (Thread.currentThread() == dispatchThread)
507             ? mostRecentEventTime
508             : System.currentTimeMillis();
509     }
510
511     /**
512      * @return most recent event time on all threads.
513      */

514     synchronized long getMostRecentEventTimeEx() {
515         return mostRecentEventTime;
516     }
517
518     /**
519      * Returns the the event currently being dispatched by the
520      * <code>EventQueue</code> associated with the calling thread. This is
521      * useful if a method needs access to the event, but was not designed to
522      * receive a reference to it as an argument. Note that this method should
523      * only be invoked from an application's event dispatching thread. If this
524      * method is invoked from another thread, null will be returned.
525      *
526      * @return the event currently being dispatched, or null if this method is
527      * invoked on a thread other than an event dispatching thread
528      * @since 1.4
529      */

530     public static AWTEvent JavaDoc getCurrentEvent() {
531         return Toolkit.getEventQueue().getCurrentEventImpl();
532     }
533     private synchronized AWTEvent JavaDoc getCurrentEventImpl() {
534         return (Thread.currentThread() == dispatchThread)
535             ? ((AWTEvent JavaDoc)currentEvent.get())
536             : null;
537     }
538
539     /**
540      * Replaces the existing <code>EventQueue</code> with the specified one.
541      * Any pending events are transferred to the new <code>EventQueue</code>
542      * for processing by it.
543      *
544      * @param newEventQueue an <code>EventQueue</code>
545      * (or subclass thereof) instance to be use
546      * @see java.awt.EventQueue#pop
547      * @throws NullPointerException if <code>newEventQueue</code> is <code>null</code>
548      */

549     public synchronized void push(EventQueue JavaDoc newEventQueue) {
550     if (debug) {
551         System.out.println("EventQueue.push(" + newEventQueue + ")");
552     }
553
554         if (nextQueue != null) {
555             nextQueue.push(newEventQueue);
556             return;
557         }
558
559         synchronized (newEventQueue) {
560         // Transfer all events forward to new EventQueue.
561
while (peekEvent() != null) {
562         try {
563             newEventQueue.postEventPrivate(getNextEvent());
564         } catch (InterruptedException JavaDoc ie) {
565             if (debug) {
566             System.err.println("interrupted push:");
567             ie.printStackTrace(System.err);
568             }
569         }
570         }
571
572         newEventQueue.previousQueue = this;
573         }
574         /*
575          * Stop the event dispatch thread associated with the currently
576          * active event queue, so that after the new queue is pushed
577          * on the top this event dispatch thread won't prevent AWT from
578          * being automatically shut down.
579          * Use stopDispatchingLater() to avoid deadlock: stopDispatching()
580          * waits for the dispatch thread to exit, so if the dispatch
581          * thread attempts to synchronize on this EventQueue object
582          * it will never exit since we already hold this lock.
583          */

584         if (dispatchThread != null) {
585             dispatchThread.stopDispatchingLater();
586         }
587
588     nextQueue = newEventQueue;
589     
590         AppContext appContext = AppContext.getAppContext();
591         if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
592         appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
593         }
594     }
595
596     /**
597      * Stops dispatching events using this <code>EventQueue</code>.
598      * Any pending events are transferred to the previous
599      * <code>EventQueue</code> for processing.
600      * <p>
601      * Warning: To avoid deadlock, do not declare this method
602      * synchronized in a subclass.
603      *
604      * @exception EmptyStackException if no previous push was made
605      * on this <code>EventQueue</code>
606      * @see java.awt.EventQueue#push
607      */

608     protected void pop() throws EmptyStackException JavaDoc {
609     if (debug) {
610         System.out.println("EventQueue.pop(" + this + ")");
611     }
612
613     // To prevent deadlock, we lock on the previous EventQueue before
614
// this one. This uses the same locking order as everything else
615
// in EventQueue.java, so deadlock isn't possible.
616
EventQueue JavaDoc prev = previousQueue;
617     synchronized ((prev != null) ? prev : this) {
618       synchronized(this) {
619             if (nextQueue != null) {
620                 nextQueue.pop();
621                 return;
622             }
623             if (previousQueue == null) {
624                 throw new EmptyStackException JavaDoc();
625             }
626
627         // Transfer all events back to previous EventQueue.
628
previousQueue.nextQueue = null;
629         while (peekEvent() != null) {
630         try {
631             previousQueue.postEventPrivate(getNextEvent());
632         } catch (InterruptedException JavaDoc ie) {
633             if (debug) {
634             System.err.println("interrupted pop:");
635             ie.printStackTrace(System.err);
636             }
637         }
638         }
639             AppContext appContext = AppContext.getAppContext();
640             if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
641                 appContext.put(AppContext.EVENT_QUEUE_KEY, previousQueue);
642             }
643
644         previousQueue = null;
645           }
646         }
647
648         EventDispatchThread JavaDoc dt = this.dispatchThread;
649         if (dt != null) {
650             dt.stopDispatching(); // Must be done outside synchronized
651
// block to avoid possible deadlock
652
}
653     }
654
655     /**
656      * Returns true if the calling thread is the current AWT
657      * <code>EventQueue</code>'s dispatch thread. Use this
658      * call the ensure that a given
659      * task is being executed (or not being) on the current AWT
660      * <code>EventDispatchThread</code>.
661      *
662      * @return true if running on the current AWT
663      * <code>EventQueue</code>'s dispatch thread
664      */

665     public static boolean isDispatchThread() {
666     EventQueue JavaDoc eq = Toolkit.getEventQueue();
667     EventQueue JavaDoc next = eq.nextQueue;
668     while (next != null) {
669         eq = next;
670         next = eq.nextQueue;
671     }
672     return (Thread.currentThread() == eq.dispatchThread);
673     }
674
675     final void initDispatchThread() {
676         synchronized (this) {
677             if (dispatchThread == null && !threadGroup.isDestroyed()) {
678                 dispatchThread = (EventDispatchThread JavaDoc)
679                     AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
680                         public Object JavaDoc run() {
681                             EventDispatchThread JavaDoc t =
682                                 new EventDispatchThread JavaDoc(threadGroup,
683                                                         name,
684                                                         EventQueue.this);
685                             t.setContextClassLoader(classLoader);
686                             t.setPriority(Thread.NORM_PRIORITY + 1);
687                             t.setDaemon(false);
688                             return t;
689                         }
690                     });
691                 AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
692                 dispatchThread.start();
693             }
694         }
695     }
696
697     final void detachDispatchThread() {
698         dispatchThread = null;
699     }
700
701     /*
702      * Gets the <code>EventDispatchThread</code> for this
703      * <code>EventQueue</code>.
704      * @return the event dispatch thread associated with this event queue
705      * or <code>null</code> if this event queue doesn't have a
706      * working thread associated with it
707      * @see java.awt.EventQueue#initDispatchThread
708      * @see java.awt.EventQueue#detachDispatchThread
709      */

710     final EventDispatchThread JavaDoc getDispatchThread() {
711     return dispatchThread;
712     }
713
714     /*
715      * Removes any pending events for the specified source object.
716      * If removeAllEvents parameter is <code>true</code> then all
717      * events for the specified source object are removed, if it
718      * is <code>false</code> then <code>SequencedEvent</code>, <code>SentEvent</code>,
719      * <code>FocusEvent</code>, <code>WindowEvent</code>, <code>KeyEvent</code>,
720      * and <code>InputMethodEvent</code> are kept in the queue, but all other
721      * events are removed.
722      *
723      * This method is normally called by the source's
724      * <code>removeNotify</code> method.
725      */

726     final void removeSourceEvents(Object JavaDoc source, boolean removeAllEvents) {
727         SunToolkit.flushPendingEvents();
728         synchronized (this) {
729             for (int i = 0; i < NUM_PRIORITIES; i++) {
730                 EventQueueItem entry = queues[i].head;
731                 EventQueueItem prev = null;
732                 while (entry != null) {
733                     if ((entry.event.getSource() == source)
734                         && (removeAllEvents
735                             || ! (entry.event instanceof SequencedEvent JavaDoc
736                                   || entry.event instanceof SentEvent JavaDoc
737                                   || entry.event instanceof FocusEvent JavaDoc
738                                   || entry.event instanceof WindowEvent JavaDoc
739                                   || entry.event instanceof KeyEvent JavaDoc
740                                   || entry.event instanceof InputMethodEvent JavaDoc)))
741                     {
742                         if (entry.event instanceof SequencedEvent JavaDoc) {
743                             ((SequencedEvent JavaDoc)entry.event).dispose();
744                         }
745                         if (entry.event instanceof SentEvent JavaDoc) {
746                             ((SentEvent JavaDoc)entry.event).dispose();
747                         }
748                         if (prev == null) {
749                             queues[i].head = entry.next;
750                         } else {
751                             prev.next = entry.next;
752                         }
753                     } else {
754                         prev = entry;
755                     }
756                     entry = entry.next;
757                 }
758                 queues[i].tail = prev;
759             }
760         }
761     }
762
763     static void setCurrentEventAndMostRecentTime(AWTEvent JavaDoc e) {
764         Toolkit.getEventQueue().setCurrentEventAndMostRecentTimeImpl(e);
765     }
766     private synchronized void setCurrentEventAndMostRecentTimeImpl(AWTEvent JavaDoc e)
767     {
768         if (Thread.currentThread() != dispatchThread) {
769             return;
770         }
771
772         currentEvent = new WeakReference JavaDoc(e);
773
774         // This series of 'instanceof' checks should be replaced with a
775
// polymorphic type (for example, an interface which declares a
776
// getWhen() method). However, this would require us to make such
777
// a type public, or to place it in sun.awt. Both of these approaches
778
// have been frowned upon. So for now, we hack.
779
//
780
// In tiger, we will probably give timestamps to all events, so this
781
// will no longer be an issue.
782
long mostRecentEventTime2 = Long.MIN_VALUE;
783         if (e instanceof InputEvent JavaDoc) {
784             InputEvent JavaDoc ie = (InputEvent JavaDoc)e;
785             mostRecentEventTime2 = ie.getWhen();
786         } else if (e instanceof InputMethodEvent JavaDoc) {
787             InputMethodEvent JavaDoc ime = (InputMethodEvent JavaDoc)e;
788             mostRecentEventTime2 = ime.getWhen();
789         } else if (e instanceof ActionEvent JavaDoc) {
790             ActionEvent JavaDoc ae = (ActionEvent JavaDoc)e;
791             mostRecentEventTime2 = ae.getWhen();
792         } else if (e instanceof InvocationEvent JavaDoc) {
793             InvocationEvent JavaDoc ie = (InvocationEvent JavaDoc)e;
794             mostRecentEventTime2 = ie.getWhen();
795         }
796         mostRecentEventTime = Math.max(mostRecentEventTime, mostRecentEventTime2);
797     }
798
799     /**
800      * Causes <code>runnable</code> to have its <code>run</code>
801      * method called in the dispatch thread of the <code>EventQueue</code>.
802      * This will happen after all pending events are processed.
803      *
804      * @param runnable the <code>Runnable</code> whose <code>run</code>
805      * method should be executed
806      * synchronously on the <code>EventQueue</code>
807      * @see #invokeAndWait
808      * @since 1.2
809      */

810     public static void invokeLater(Runnable JavaDoc runnable) {
811         Toolkit.getEventQueue().postEvent(
812             new InvocationEvent JavaDoc(Toolkit.getDefaultToolkit(), runnable));
813     }
814
815     /**
816      * Causes <code>runnable</code> to have its <code>run</code>
817      * method called in the dispatch thread of the <code>EventQueue</code>.
818      * This will happen after all pending events are processed.
819      * The call blocks until this has happened. This method
820      * will throw an Error if called from the event dispatcher thread.
821      *
822      * @param runnable the <code>Runnable</code> whose <code>run</code>
823      * method should be executed
824      * synchronously on the <code>EventQueue</code>
825      * @exception InterruptedException if another thread has
826      * interrupted this thread
827      * @exception InvocationTargetException if an throwable is thrown
828      * when running <code>runnable</code>
829      * @see #invokeLater
830      * @since 1.2
831      */

832     public static void invokeAndWait(Runnable JavaDoc runnable)
833              throws InterruptedException JavaDoc, InvocationTargetException JavaDoc {
834
835         if (EventQueue.isDispatchThread()) {
836             throw new Error JavaDoc("Cannot call invokeAndWait from the event dispatcher thread");
837         }
838
839     class AWTInvocationLock {}
840         Object JavaDoc lock = new AWTInvocationLock();
841
842         InvocationEvent JavaDoc event =
843             new InvocationEvent JavaDoc(Toolkit.getDefaultToolkit(), runnable, lock,
844                 true);
845
846         synchronized (lock) {
847             Toolkit.getEventQueue().postEvent(event);
848             lock.wait();
849         }
850
851         Throwable JavaDoc eventThrowable = event.getThrowable();
852         if (eventThrowable != null) {
853             throw new InvocationTargetException JavaDoc(eventThrowable);
854         }
855     }
856
857     /*
858      * Called from PostEventQueue.postEvent to notify that a new event
859      * appeared. First it proceeds to the EventQueue on the top of the
860      * stack, then notifies the associated dispatch thread if it exists
861      * or starts a new one otherwise.
862      */

863     private void wakeup(boolean isShutdown) {
864         synchronized(this) {
865             if (nextQueue != null) {
866                 // Forward call to the top of EventQueue stack.
867
nextQueue.wakeup(isShutdown);
868             } else if (dispatchThread != null) {
869                 notifyAll();
870             } else if (!isShutdown) {
871                 initDispatchThread();
872             }
873         }
874     }
875 }
876
877 /**
878  * The Queue object holds pointers to the beginning and end of one internal
879  * queue. An EventQueue object is composed of multiple internal Queues, one
880  * for each priority supported by the EventQueue. All Events on a particular
881  * internal Queue have identical priority.
882  */

883 class Queue {
884     EventQueueItem head;
885     EventQueueItem tail;
886 }
887
888 class EventQueueItem {
889     AWTEvent JavaDoc event;
890     int id;
891     EventQueueItem next;
892
893     EventQueueItem(AWTEvent JavaDoc evt) {
894         event = evt;
895         id = evt.getID();
896     }
897 }
898
Popular Tags