1 /* EventQueue.java --
2    Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005  Free Software Foundation
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package java.awt;
40 
41 import gnu.java.awt.LowPriorityEvent;
42 import gnu.java.awt.peer.NativeEventLoopRunningEvent;
43 
44 import java.awt.event.ActionEvent;
45 import java.awt.event.InputEvent;
46 import java.awt.event.InputMethodEvent;
47 import java.awt.event.InvocationEvent;
48 import java.awt.event.PaintEvent;
49 import java.awt.peer.ComponentPeer;
50 import java.awt.peer.LightweightPeer;
51 import java.lang.reflect.InvocationTargetException;
52 import java.util.EmptyStackException;
53 
54 /* Written using on-line Java 2 Platform Standard Edition v1.3 API
55  * Specification, as well as "The Java Class Libraries", 2nd edition
56  * (Addison-Wesley, 1998).
57  * Status:  Believed complete, but untested.
58  */
59 
60 /**
61  * This class manages a queue of <code>AWTEvent</code> objects that
62  * are posted to it.  The AWT system uses only one event queue for all
63  * events.
64  *
65  * @author Bryce McKinlay
66  * @author Aaron M. Renn (arenn@urbanophile.com)
67  */
68 public class EventQueue
69 {
70   /**
71    * Indicates events that are processed with normal priority. This is normally
72    * all events except PaintEvents.
73    */
74   private static final int NORM_PRIORITY = 0;
75 
76   /**
77    * Indicates events that are processed with lowes priority. This is normally
78    * all PaintEvents and LowPriorityEvents.
79    */
80   private static final int LOW_PRIORITY = 1;
81 
82   /**
83    * Implements the actual queue. EventQueue has 2 internal queues for
84    * different priorities:
85    * 1 PaintEvents are always dispatched with low priority.
86    * 2. All other events are dispatched with normal priority.
87    *
88    * This makes sure that the actual painting (output) is performed _after_ all
89    * available input has been processed and that the paint regions are
90    * coalesced as much as possible.
91    */
92   private class Queue
93   {
94     /**
95      * The first item in the queue. This is where events are popped from.
96      */
97     AWTEvent queueHead;
98 
99     /**
100      * The last item. This is where events are posted to.
101      */
102     AWTEvent queueTail;
103   }
104 
105   /**
106    * The three internal event queues.
107    *
108    * @see Queue
109    */
110   private Queue[] queues;
111 
112   private EventQueue next;
113   private EventQueue prev;
114   private AWTEvent currentEvent;
115   private long lastWhen = System.currentTimeMillis();
116 
117   private EventDispatchThread dispatchThread = new EventDispatchThread(this);
118   private boolean nativeLoopRunning = false;
119 
isShutdown()120   private boolean isShutdown ()
121   {
122     // This is the exact self-shutdown condition specified in J2SE:
123     // http://java.sun.com/j2se/1.4.2/docs/api/java/awt/doc-files/AWTThreadIssues.html
124 
125     if (nativeLoopRunning)
126       return false;
127 
128     if (peekEvent() != null)
129       return false;
130 
131     if (Frame.hasDisplayableFrames())
132       return false;
133 
134     return true;
135   }
136 
137   /**
138    * Initializes a new instance of <code>EventQueue</code>.
139    */
EventQueue()140   public EventQueue()
141   {
142     queues = new Queue[2];
143     queues[NORM_PRIORITY] = new Queue();
144     queues[LOW_PRIORITY] = new Queue();
145   }
146 
147   /**
148    * Returns the next event in the queue.  This method will block until
149    * an event is available or until the thread is interrupted.
150    *
151    * @return The next event in the queue.
152    *
153    * @exception InterruptedException If this thread is interrupted while
154    * waiting for an event to be posted to the queue.
155    */
getNextEvent()156   public synchronized AWTEvent getNextEvent()
157     throws InterruptedException
158   {
159     if (next != null)
160       return next.getNextEvent();
161 
162     AWTEvent res = getNextEventImpl(true);
163 
164     while (res == null)
165       {
166         if (isShutdown())
167           {
168             // Explicitly set dispathThread to null.  If we don't do
169             // this, there is a race condition where dispatchThread
170             // can be != null even after the event dispatch thread has
171             // stopped running.  If that happens, then the
172             // dispatchThread == null check in postEventImpl will
173             // fail, and a new event dispatch thread will not be
174             // created, leaving invokeAndWaits waiting indefinitely.
175             dispatchThread = null;
176 
177             // Interrupt the event dispatch thread.
178             throw new InterruptedException();
179           }
180 
181         wait();
182         res = getNextEventImpl(true);
183       }
184 
185     return res;
186   }
187 
188   /**
189    * Fetches and possibly removes the next event from the internal queues.
190    * This method returns immediately. When all queues are empty, this returns
191    * <code>null</code>:
192    *
193    * @param remove <true> when the event should be removed from the queue,
194    *        <code>false</code> otherwise
195    *
196    * @return the next event or <code>null</code> when all internal queues
197    *         are empty
198    */
getNextEventImpl(boolean remove)199   private AWTEvent getNextEventImpl(boolean remove)
200   {
201     AWTEvent next = null;
202     for (int i = 0; i < queues.length && next == null; i++)
203       {
204         Queue q = queues[i];
205         if (q.queueHead != null)
206           {
207             // Got an event, remove it.
208             next = q.queueHead;
209             if (remove)
210               {
211                 // Unlink event from the queue.
212                 q.queueHead = next.queueNext;
213                 if (q.queueHead == null)
214                   q.queueTail = null;
215                 next.queueNext = null;
216               }
217           }
218       }
219     return next;
220   }
221 
222   /**
223    * Returns the next event in the queue without removing it from the queue.
224    * This method will block until an event is available or until the thread
225    * is interrupted.
226    *
227    * @return The next event in the queue.
228    * @specnote Does not block. Returns null if there are no events on the
229    *            queue.
230    */
peekEvent()231   public synchronized AWTEvent peekEvent()
232   {
233     if (next != null)
234       return next.peekEvent();
235 
236     return getNextEventImpl(false);
237   }
238 
239   /**
240    * Returns the next event in the queue that has the specified id
241    * without removing it from the queue.
242    * This method will block until an event is available or until the thread
243    * is interrupted.
244    *
245    * @param id The event id to return.
246    *
247    * @return The next event in the queue.
248    *
249    * @specnote Does not block. Returns null if there are no matching events
250    *            on the queue.
251    */
peekEvent(int id)252   public synchronized AWTEvent peekEvent(int id)
253   {
254     if (next != null)
255       return next.peekEvent(id);
256 
257     AWTEvent evt = null;
258     for (int i = 0; i < queues.length && evt == null; i++)
259       {
260         Queue q = queues[i];
261         evt = q.queueHead;
262         while (evt != null && evt.id != id)
263           evt = evt.queueNext;
264         // At this point we either have found an event (evt != null -> exit
265         // for loop), or we have found no event (evt == null -> search next
266         // internal queue).
267       }
268     return evt;
269   }
270 
271   /**
272    * Posts a new event to the queue.
273    *
274    * @param evt The event to post to the queue.
275    *
276    * @exception NullPointerException If event is null.
277    */
postEvent(AWTEvent evt)278   public void postEvent(AWTEvent evt)
279   {
280     postEventImpl(evt);
281   }
282 
283   /**
284    * Sorts events to their priority and calls
285    * {@link #postEventImpl(AWTEvent, int)}.
286    *
287    * @param evt the event to post
288    */
postEventImpl(AWTEvent evt)289   private synchronized final void postEventImpl(AWTEvent evt)
290   {
291     int priority = NORM_PRIORITY;
292     if (evt instanceof PaintEvent || evt instanceof LowPriorityEvent)
293       priority = LOW_PRIORITY;
294     // TODO: Maybe let Swing RepaintManager events also be processed with
295     // low priority.
296     if (evt instanceof NativeEventLoopRunningEvent)
297       {
298         nativeLoopRunning = ((NativeEventLoopRunningEvent) evt).isRunning();
299         notify();
300         return;
301       }
302     postEventImpl(evt, priority);
303   }
304 
305   /**
306    * Actually performs the event posting. This is needed because the
307    * RI doesn't use the public postEvent() method when transferring events
308    * between event queues in push() and pop().
309    *
310    * @param evt the event to post
311    * @param priority the priority of the event
312    */
postEventImpl(AWTEvent evt, int priority)313   private final void postEventImpl(AWTEvent evt, int priority)
314   {
315     if (evt == null)
316       throw new NullPointerException();
317 
318     if (next != null)
319       {
320         next.postEvent(evt);
321         return;
322       }
323 
324     Object source = evt.getSource();
325 
326     Queue q = queues[priority];
327     if (source instanceof Component)
328       {
329         // For PaintEvents, ask the ComponentPeer to coalesce the event
330         // when the component is heavyweight.
331         Component comp = (Component) source;
332         ComponentPeer peer = comp.peer;
333         if (peer != null && evt instanceof PaintEvent
334             && ! (peer instanceof LightweightPeer))
335           peer.coalescePaintEvent((PaintEvent) evt);
336 
337         // Check for any events already on the queue with the same source
338         // and ID.
339         AWTEvent previous = null;
340         for (AWTEvent qevt = q.queueHead; qevt != null; qevt = qevt.queueNext)
341           {
342             Object src = qevt.getSource();
343             if (qevt.id == evt.id && src == comp)
344               {
345                 // If there are, call coalesceEvents on the source component
346                 // to see if they can be combined.
347                 Component srccmp = (Component) src;
348                 AWTEvent coalescedEvt = srccmp.coalesceEvents(qevt, evt);
349                 if (coalescedEvt != null)
350                   {
351                     // Yes. Replace the existing event with the combined event.
352                     if (qevt != coalescedEvt)
353                       {
354                         if (previous != null)
355                           {
356                             assert previous.queueNext == qevt;
357                             previous.queueNext = coalescedEvt;
358                           }
359                         else
360                           {
361                             assert q.queueHead == qevt;
362                             q.queueHead = coalescedEvt;
363                           }
364                         coalescedEvt.queueNext = qevt.queueNext;
365                         if (q.queueTail == qevt)
366                           q.queueTail = coalescedEvt;
367                         qevt.queueNext = null;
368                       }
369                     return;
370                   }
371               }
372             previous = qevt;
373           }
374       }
375 
376     if (q.queueHead == null)
377       {
378         // We have an empty queue. Set this event both as head and as tail.
379         q.queueHead = evt;
380         q.queueTail = evt;
381       }
382     else
383       {
384         // Note: queueTail should not be null here.
385         q.queueTail.queueNext = evt;
386         q.queueTail = evt;
387       }
388 
389     if (dispatchThread == null || !dispatchThread.isAlive())
390       {
391         dispatchThread = new EventDispatchThread(this);
392         dispatchThread.start();
393       }
394 
395     notify();
396   }
397 
398   /**
399    * Causes runnable to have its run method called in the dispatch thread of the
400    * EventQueue. This will happen after all pending events are processed. The
401    * call blocks until this has happened. This method will throw an Error if
402    * called from the event dispatcher thread.
403    *
404    * @exception InterruptedException If another thread has interrupted
405    * this thread.
406    * @exception InvocationTargetException If an exception is thrown when running
407    * runnable.
408    *
409    * @since 1.2
410    */
invokeAndWait(Runnable runnable)411   public static void invokeAndWait(Runnable runnable)
412     throws InterruptedException, InvocationTargetException
413   {
414     if (isDispatchThread ())
415       throw new Error("Can't call invokeAndWait from event dispatch thread");
416 
417     EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
418     Object notifyObject = new Object();
419 
420     InvocationEvent ie =
421       new InvocationEvent(eq, runnable, notifyObject, true);
422 
423     synchronized (notifyObject)
424       {
425         eq.postEvent(ie);
426         notifyObject.wait();
427       }
428 
429     Exception exception;
430 
431     if ((exception = ie.getException()) != null)
432       throw new InvocationTargetException(exception);
433   }
434 
435   /**
436    * This arranges for runnable to have its run method called in the
437    * dispatch thread of the EventQueue.  This will happen after all
438    * pending events are processed.
439    *
440    * @since 1.2
441    */
invokeLater(Runnable runnable)442   public static void invokeLater(Runnable runnable)
443   {
444     EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
445 
446     InvocationEvent ie =
447       new InvocationEvent(eq, runnable, null, false);
448 
449     eq.postEvent(ie);
450   }
451 
452   /**
453    * Return true if the current thread is the current AWT event dispatch
454    * thread.
455    */
isDispatchThread()456   public static boolean isDispatchThread()
457   {
458     EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
459 
460     /* Find last EventQueue in chain */
461     while (eq.next != null)
462       eq = eq.next;
463 
464     return (Thread.currentThread() == eq.dispatchThread);
465   }
466 
467   /**
468    * Return the event currently being dispatched by the event
469    * dispatch thread.  If the current thread is not the event
470    * dispatch thread, this method returns null.
471    *
472    * @since 1.4
473    */
getCurrentEvent()474   public static AWTEvent getCurrentEvent()
475   {
476     EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
477     Thread ct = Thread.currentThread();
478 
479     /* Find out if this thread is the dispatch thread for any of the
480        EventQueues in the chain */
481     while (ct != eq.dispatchThread)
482       {
483         // Try next EventQueue, if any
484         if (eq.next == null)
485            return null;  // Not an event dispatch thread
486         eq = eq.next;
487       }
488 
489     return eq.currentEvent;
490   }
491 
492   /**
493    * Allows a custom EventQueue implementation to replace this one.
494    * All pending events are transferred to the new queue. Calls to postEvent,
495    * getNextEvent, and peekEvent and others are forwarded to the pushed queue
496    * until it is removed with a pop().
497    *
498    * @exception NullPointerException if newEventQueue is null.
499    */
push(EventQueue newEventQueue)500   public synchronized void push(EventQueue newEventQueue)
501   {
502     if (newEventQueue == null)
503       throw new NullPointerException ();
504 
505     /* Make sure we are at the top of the stack because callers can
506        only get a reference to the one at the bottom using
507        Toolkit.getDefaultToolkit().getSystemEventQueue() */
508     if (next != null)
509       {
510         next.push (newEventQueue);
511         return;
512       }
513 
514     /* Make sure we have a live dispatch thread to drive the queue */
515     if (dispatchThread == null)
516       dispatchThread = new EventDispatchThread(this);
517 
518     synchronized (newEventQueue)
519       {
520         // The RI transfers the events without calling the new eventqueue's
521         // push(), but using getNextEvent().
522         while (peekEvent() != null)
523           {
524             try
525               {
526                 newEventQueue.postEventImpl(getNextEvent());
527               }
528             catch (InterruptedException ex)
529               {
530                 // What should we do with this?
531                 ex.printStackTrace();
532               }
533           }
534         newEventQueue.prev = this;
535       }
536 
537     next = newEventQueue;
538   }
539 
540   /** Transfer any pending events from this queue back to the parent queue that
541     * was previously push()ed. Event dispatch from this queue is suspended.
542     *
543     * @exception EmptyStackException If no previous push was made on this
544     * EventQueue.
545     */
pop()546   protected void pop() throws EmptyStackException
547   {
548     /* The order is important here, we must get the prev lock first,
549        or deadlock could occur as callers usually get here following
550        prev's next pointer, and thus obtain prev's lock before trying
551        to get this lock. */
552     EventQueue previous = prev;
553     if (previous == null)
554       throw new EmptyStackException();
555     synchronized (previous)
556       {
557         synchronized (this)
558           {
559             EventQueue nextQueue = next;
560             if (nextQueue != null)
561               {
562                 nextQueue.pop();
563               }
564             else
565               {
566                 previous.next = null;
567 
568                 // The RI transfers the events without calling the new eventqueue's
569                 // push(), so this should be OK and most effective.
570                 while (peekEvent() != null)
571                   {
572                     try
573                       {
574                         previous.postEventImpl(getNextEvent());
575                       }
576                     catch (InterruptedException ex)
577                       {
578                         // What should we do with this?
579                         ex.printStackTrace();
580                       }
581                   }
582                 prev = null;
583                 // Tell our EventDispatchThread that it can end
584                 // execution.
585                 if (dispatchThread != null)
586                   {
587                     dispatchThread.interrupt();
588                     dispatchThread = null;
589                   }
590               }
591           }
592       }
593   }
594 
595   /**
596    * Dispatches an event. The manner in which the event is dispatched depends
597    * upon the type of the event and the type of the event's source object.
598    *
599    * @exception NullPointerException If event is null.
600    */
dispatchEvent(AWTEvent evt)601   protected void dispatchEvent(AWTEvent evt)
602   {
603     currentEvent = evt;
604 
605     if (evt instanceof InputEvent)
606       lastWhen = ((InputEvent) evt).getWhen();
607     else if (evt instanceof ActionEvent)
608       lastWhen = ((ActionEvent) evt).getWhen();
609     else if (evt instanceof InvocationEvent)
610       lastWhen = ((InvocationEvent) evt).getWhen();
611 
612     if (evt instanceof ActiveEvent)
613       {
614         ActiveEvent active_evt = (ActiveEvent) evt;
615         active_evt.dispatch();
616       }
617     else
618       {
619         Object source = evt.getSource();
620 
621         if (source instanceof Component)
622           {
623             Component srccmp = (Component) source;
624             srccmp.dispatchEvent(evt);
625           }
626         else if (source instanceof MenuComponent)
627           {
628             MenuComponent srccmp = (MenuComponent) source;
629             srccmp.dispatchEvent(evt);
630           }
631       }
632   }
633 
634   /**
635    * Returns the timestamp of the most recent event that had a timestamp, or
636    * the initialization time of the event queue if no events have been fired.
637    * At present, only <code>InputEvent</code>s, <code>ActionEvent</code>s,
638    * <code>InputMethodEvent</code>s, and <code>InvocationEvent</code>s have
639    * timestamps, but this may be added to other events in future versions.
640    * If this is called by the event dispatching thread, it can be any
641    * (sequential) value, but to other threads, the safest bet is to return
642    * System.currentTimeMillis().
643    *
644    * @return the most recent timestamp
645    * @see InputEvent#getWhen()
646    * @see ActionEvent#getWhen()
647    * @see InvocationEvent#getWhen()
648    * @see InputMethodEvent#getWhen()
649    * @since 1.4
650    */
getMostRecentEventTime()651   public static long getMostRecentEventTime()
652   {
653     EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
654     if (Thread.currentThread() != eq.dispatchThread)
655       return System.currentTimeMillis();
656     return eq.lastWhen;
657   }
658 }
659