001    /* EventQueue.java --
002       Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005  Free Software Foundation
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath 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 for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package java.awt;
040    
041    import gnu.java.awt.LowPriorityEvent;
042    import gnu.java.awt.peer.NativeEventLoopRunningEvent;
043    
044    import java.awt.event.ActionEvent;
045    import java.awt.event.InputEvent;
046    import java.awt.event.InputMethodEvent;
047    import java.awt.event.InvocationEvent;
048    import java.awt.event.PaintEvent;
049    import java.awt.peer.ComponentPeer;
050    import java.awt.peer.LightweightPeer;
051    import java.lang.reflect.InvocationTargetException;
052    import java.util.EmptyStackException;
053    
054    /* Written using on-line Java 2 Platform Standard Edition v1.3 API 
055     * Specification, as well as "The Java Class Libraries", 2nd edition 
056     * (Addison-Wesley, 1998).
057     * Status:  Believed complete, but untested.
058     */
059    
060    /**
061     * This class manages a queue of <code>AWTEvent</code> objects that
062     * are posted to it.  The AWT system uses only one event queue for all
063     * events.
064     *
065     * @author Bryce McKinlay
066     * @author Aaron M. Renn (arenn@urbanophile.com)
067     */
068    public class EventQueue
069    {
070      /**
071       * Indicates events that are processed with normal priority. This is normally
072       * all events except PaintEvents.
073       */
074      private static final int NORM_PRIORITY = 0;
075    
076      /**
077       * Indicates events that are processed with lowes priority. This is normally
078       * all PaintEvents and LowPriorityEvents.
079       */
080      private static final int LOW_PRIORITY = 1;
081    
082      /**
083       * Implements the actual queue. EventQueue has 2 internal queues for
084       * different priorities:
085       * 1 PaintEvents are always dispatched with low priority.
086       * 2. All other events are dispatched with normal priority.
087       *
088       * This makes sure that the actual painting (output) is performed _after_ all
089       * available input has been processed and that the paint regions are
090       * coalesced as much as possible.
091       */
092      private class Queue
093      {
094        /**
095         * The first item in the queue. This is where events are popped from.
096         */
097        AWTEvent queueHead;
098    
099        /**
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    
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       */
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       */
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       */
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       */ 
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       */ 
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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        */
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       */
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       */
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    }