OSDN Git Service

Merged gcj-eclipse branch to trunk.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / java / awt / EventQueue.java
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
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     Frame[] frames = Frame.getFrames();
132     for (int i = 0; i < frames.length; ++i)
133       if (frames[i].isDisplayable())
134         return false;
135
136     return true;
137   }
138
139   /**
140    * Initializes a new instance of <code>EventQueue</code>.
141    */
142   public EventQueue()
143   {
144     queues = new Queue[2];
145     queues[NORM_PRIORITY] = new Queue();
146     queues[LOW_PRIORITY] = new Queue();
147   }
148
149   /**
150    * Returns the next event in the queue.  This method will block until
151    * an event is available or until the thread is interrupted.
152    *
153    * @return The next event in the queue.
154    *
155    * @exception InterruptedException If this thread is interrupted while
156    * waiting for an event to be posted to the queue.
157    */
158   public synchronized AWTEvent getNextEvent()
159     throws InterruptedException
160   {
161     if (next != null)
162       return next.getNextEvent();
163
164     AWTEvent res = getNextEventImpl(true);
165
166     while (res == null)
167       {
168         if (isShutdown())
169           {
170             // Explicitly set dispathThread to null.  If we don't do
171             // this, there is a race condition where dispatchThread
172             // can be != null even after the event dispatch thread has
173             // stopped running.  If that happens, then the
174             // dispatchThread == null check in postEventImpl will
175             // fail, and a new event dispatch thread will not be
176             // created, leaving invokeAndWaits waiting indefinitely.
177             dispatchThread = null;
178
179             // Interrupt the event dispatch thread.
180             throw new InterruptedException();
181           }
182
183         wait();
184         res = getNextEventImpl(true);
185       }
186
187     return res;
188   }
189
190   /**
191    * Fetches and possibly removes the next event from the internal queues.
192    * This method returns immediately. When all queues are empty, this returns
193    * <code>null</code>:
194    *
195    * @param remove <true> when the event should be removed from the queue,
196    *        <code>false</code> otherwise
197    *
198    * @return the next event or <code>null</code> when all internal queues
199    *         are empty
200    */
201   private AWTEvent getNextEventImpl(boolean remove)
202   {
203     AWTEvent next = null;
204     for (int i = 0; i < queues.length && next == null; i++)
205       {
206         Queue q = queues[i];
207         if (q.queueHead != null)
208           {
209             // Got an event, remove it.
210             next = q.queueHead;
211             if (remove)
212               {
213                 // Unlink event from the queue.
214                 q.queueHead = next.queueNext;
215                 if (q.queueHead == null)
216                   q.queueTail = null;
217                 next.queueNext = null;
218               }
219           }
220       }
221     return next;
222   }
223
224   /**
225    * Returns the next event in the queue without removing it from the queue.
226    * This method will block until an event is available or until the thread
227    * is interrupted.
228    *
229    * @return The next event in the queue.
230    * @specnote Does not block. Returns null if there are no events on the 
231    *            queue. 
232    */ 
233   public synchronized AWTEvent peekEvent()
234   {
235     if (next != null)
236       return next.peekEvent();
237
238     return getNextEventImpl(false);
239   }
240
241   /**
242    * Returns the next event in the queue that has the specified id
243    * without removing it from the queue.
244    * This method will block until an event is available or until the thread
245    * is interrupted.
246    *
247    * @param id The event id to return.
248    *
249    * @return The next event in the queue.
250    *
251    * @specnote Does not block. Returns null if there are no matching events 
252    *            on the queue. 
253    */ 
254   public synchronized AWTEvent peekEvent(int id)
255   {
256     if (next != null)
257       return next.peekEvent(id);
258
259     AWTEvent evt = null;
260     for (int i = 0; i < queues.length && evt == null; i++)
261       {
262         Queue q = queues[i];
263         evt = q.queueHead;
264         while (evt != null && evt.id != id)
265           evt = evt.queueNext;
266         // At this point we either have found an event (evt != null -> exit
267         // for loop), or we have found no event (evt == null -> search next
268         // internal queue).
269       }
270     return evt;
271   }
272
273   /**
274    * Posts a new event to the queue.
275    *
276    * @param evt The event to post to the queue.
277    *
278    * @exception NullPointerException If event is null.
279    */
280   public void postEvent(AWTEvent evt)
281   {
282     postEventImpl(evt);
283   }
284
285   /**
286    * Sorts events to their priority and calls
287    * {@link #postEventImpl(AWTEvent, int)}.
288    *
289    * @param evt the event to post
290    */
291   private synchronized final void postEventImpl(AWTEvent evt)
292   {
293     int priority = NORM_PRIORITY;
294     if (evt instanceof PaintEvent || evt instanceof LowPriorityEvent)
295       priority = LOW_PRIORITY;
296     // TODO: Maybe let Swing RepaintManager events also be processed with
297     // low priority.
298     if (evt instanceof NativeEventLoopRunningEvent)
299       {
300         nativeLoopRunning = ((NativeEventLoopRunningEvent) evt).isRunning();
301         notify();
302         return;
303       }
304     postEventImpl(evt, priority);
305   }
306
307   /**
308    * Actually performs the event posting. This is needed because the
309    * RI doesn't use the public postEvent() method when transferring events
310    * between event queues in push() and pop().
311    * 
312    * @param evt the event to post
313    * @param priority the priority of the event
314    */
315   private final void postEventImpl(AWTEvent evt, int priority)
316   {
317     if (evt == null)
318       throw new NullPointerException();
319
320     if (next != null)
321       {
322         next.postEvent(evt);
323         return;
324       }
325
326     Object source = evt.getSource();
327
328     Queue q = queues[priority];
329     if (source instanceof Component)
330       {
331         // For PaintEvents, ask the ComponentPeer to coalesce the event
332         // when the component is heavyweight.
333         Component comp = (Component) source;
334         ComponentPeer peer = comp.peer;
335         if (peer != null && evt instanceof PaintEvent
336             && ! (peer instanceof LightweightPeer))
337           peer.coalescePaintEvent((PaintEvent) evt);
338
339         // Check for any events already on the queue with the same source
340         // and ID.
341         AWTEvent previous = null;
342         for (AWTEvent qevt = q.queueHead; qevt != null; qevt = qevt.queueNext)
343           {
344             Object src = qevt.getSource();
345             if (qevt.id == evt.id && src == comp)
346               {
347                 // If there are, call coalesceEvents on the source component 
348                 // to see if they can be combined.
349                 Component srccmp = (Component) src;
350                 AWTEvent coalescedEvt = srccmp.coalesceEvents(qevt, evt);
351                 if (coalescedEvt != null)
352                   {
353                     // Yes. Replace the existing event with the combined event.
354                     if (qevt != coalescedEvt)
355                       {
356                         if (previous != null)
357                           {
358                             assert previous.queueNext == qevt;
359                             previous.queueNext = coalescedEvt;
360                           }
361                         else
362                           {
363                             assert q.queueHead == qevt;
364                             q.queueHead = coalescedEvt;
365                           }
366                         coalescedEvt.queueNext = qevt.queueNext;
367                         if (q.queueTail == qevt)
368                           q.queueTail = coalescedEvt;
369                         qevt.queueNext = null;
370                       }
371                     return;
372                   }
373               }
374             previous = qevt;
375           }
376       }
377
378     if (q.queueHead == null)
379       {
380         // We have an empty queue. Set this event both as head and as tail.
381         q.queueHead = evt;
382         q.queueTail = evt;
383       }
384     else
385       {
386         // Note: queueTail should not be null here.
387         q.queueTail.queueNext = evt;
388         q.queueTail = evt;
389       }
390
391     if (dispatchThread == null || !dispatchThread.isAlive())
392       {
393         dispatchThread = new EventDispatchThread(this);
394         dispatchThread.start();
395       }
396
397     notify();
398   }
399
400   /**
401    * Causes runnable to have its run method called in the dispatch thread of the
402    * EventQueue. This will happen after all pending events are processed. The
403    * call blocks until this has happened. This method will throw an Error if
404    * called from the event dispatcher thread.
405    *
406    * @exception InterruptedException If another thread has interrupted
407    * this thread.
408    * @exception InvocationTargetException If an exception is thrown when running
409    * runnable.
410    *
411    * @since 1.2
412    */
413   public static void invokeAndWait(Runnable runnable)
414     throws InterruptedException, InvocationTargetException
415   {
416     if (isDispatchThread ())
417       throw new Error("Can't call invokeAndWait from event dispatch thread");
418
419     EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); 
420     Object notifyObject = new Object();
421
422     InvocationEvent ie =
423       new InvocationEvent(eq, runnable, notifyObject, true);
424
425     synchronized (notifyObject)
426       {
427         eq.postEvent(ie);
428         notifyObject.wait();
429       }
430
431     Exception exception;
432
433     if ((exception = ie.getException()) != null)
434       throw new InvocationTargetException(exception);
435   }
436
437   /**
438    * This arranges for runnable to have its run method called in the
439    * dispatch thread of the EventQueue.  This will happen after all
440    * pending events are processed.
441    *
442    * @since 1.2
443    */
444   public static void invokeLater(Runnable runnable)
445   {
446     EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); 
447
448     InvocationEvent ie = 
449       new InvocationEvent(eq, runnable, null, false);
450
451     eq.postEvent(ie);
452   }
453
454   /**
455    * Return true if the current thread is the current AWT event dispatch
456    * thread.
457    */
458   public static boolean isDispatchThread()
459   {
460     EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
461     
462     /* Find last EventQueue in chain */ 
463     while (eq.next != null)
464       eq = eq.next;
465
466     return (Thread.currentThread() == eq.dispatchThread);
467   }
468
469   /**
470    * Return the event currently being dispatched by the event
471    * dispatch thread.  If the current thread is not the event
472    * dispatch thread, this method returns null.
473    *
474    * @since 1.4
475    */
476   public static AWTEvent getCurrentEvent()
477   {
478     EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); 
479     Thread ct = Thread.currentThread();
480     
481     /* Find out if this thread is the dispatch thread for any of the
482        EventQueues in the chain */ 
483     while (ct != eq.dispatchThread)
484       {
485         // Try next EventQueue, if any
486         if (eq.next == null)
487            return null;  // Not an event dispatch thread
488         eq = eq.next;
489       }
490
491     return eq.currentEvent;
492   }
493
494   /**
495    * Allows a custom EventQueue implementation to replace this one. 
496    * All pending events are transferred to the new queue. Calls to postEvent,
497    * getNextEvent, and peekEvent and others are forwarded to the pushed queue
498    * until it is removed with a pop().
499    *
500    * @exception NullPointerException if newEventQueue is null.
501    */
502   public synchronized void push(EventQueue newEventQueue)
503   {
504     if (newEventQueue == null)
505       throw new NullPointerException ();
506
507     /* Make sure we are at the top of the stack because callers can
508        only get a reference to the one at the bottom using
509        Toolkit.getDefaultToolkit().getSystemEventQueue() */
510     if (next != null)
511       {
512         next.push (newEventQueue);
513         return;
514       }
515
516     /* Make sure we have a live dispatch thread to drive the queue */
517     if (dispatchThread == null)
518       dispatchThread = new EventDispatchThread(this);
519
520     synchronized (newEventQueue)
521       {
522         // The RI transfers the events without calling the new eventqueue's
523         // push(), but using getNextEvent().
524         while (peekEvent() != null)
525           {
526             try
527               {
528                 newEventQueue.postEventImpl(getNextEvent());
529               }
530             catch (InterruptedException ex)
531               {
532                 // What should we do with this?
533                 ex.printStackTrace();
534               }
535           }
536         newEventQueue.prev = this;
537       }
538
539     next = newEventQueue;
540   }
541
542   /** Transfer any pending events from this queue back to the parent queue that
543     * was previously push()ed. Event dispatch from this queue is suspended.
544     *
545     * @exception EmptyStackException If no previous push was made on this
546     * EventQueue.
547     */
548   protected void pop() throws EmptyStackException
549   {
550     /* The order is important here, we must get the prev lock first,
551        or deadlock could occur as callers usually get here following
552        prev's next pointer, and thus obtain prev's lock before trying
553        to get this lock. */
554     EventQueue previous = prev;
555     if (previous == null)
556       throw new EmptyStackException();
557     synchronized (previous)
558       {
559         synchronized (this)
560           {
561             EventQueue nextQueue = next;
562             if (nextQueue != null)
563               {
564                 nextQueue.pop();
565               }
566             else
567               {
568                 previous.next = null;
569
570                 // The RI transfers the events without calling the new eventqueue's
571                 // push(), so this should be OK and most effective.
572                 while (peekEvent() != null)
573                   {
574                     try
575                       {
576                         previous.postEventImpl(getNextEvent());
577                       }
578                     catch (InterruptedException ex)
579                       {
580                         // What should we do with this?
581                         ex.printStackTrace();
582                       }
583                   }
584                 prev = null;
585                 // Tell our EventDispatchThread that it can end
586                 // execution.
587                 if (dispatchThread != null)
588                   {
589                     dispatchThread.interrupt();
590                     dispatchThread = null;
591                   }
592               }
593           }
594       }
595   }
596
597   /**
598    * Dispatches an event. The manner in which the event is dispatched depends
599    * upon the type of the event and the type of the event's source object.
600    *
601    * @exception NullPointerException If event is null.
602    */
603   protected void dispatchEvent(AWTEvent evt)
604   {
605     currentEvent = evt;
606
607     if (evt instanceof InputEvent)
608       lastWhen = ((InputEvent) evt).getWhen();
609     else if (evt instanceof ActionEvent)
610       lastWhen = ((ActionEvent) evt).getWhen();
611     else if (evt instanceof InvocationEvent)
612       lastWhen = ((InvocationEvent) evt).getWhen();
613
614     if (evt instanceof ActiveEvent)
615       {
616         ActiveEvent active_evt = (ActiveEvent) evt;
617         active_evt.dispatch();
618       }
619     else
620       {
621         Object source = evt.getSource();
622
623         if (source instanceof Component)
624           {
625             Component srccmp = (Component) source;
626             srccmp.dispatchEvent(evt);
627           }
628         else if (source instanceof MenuComponent)
629           {
630             MenuComponent srccmp = (MenuComponent) source;
631             srccmp.dispatchEvent(evt);
632           }
633       }
634   }
635
636   /**
637    * Returns the timestamp of the most recent event that had a timestamp, or
638    * the initialization time of the event queue if no events have been fired.
639    * At present, only <code>InputEvent</code>s, <code>ActionEvent</code>s,
640    * <code>InputMethodEvent</code>s, and <code>InvocationEvent</code>s have
641    * timestamps, but this may be added to other events in future versions.
642    * If this is called by the event dispatching thread, it can be any
643    * (sequential) value, but to other threads, the safest bet is to return
644    * System.currentTimeMillis().
645    *
646    * @return the most recent timestamp
647    * @see InputEvent#getWhen()
648    * @see ActionEvent#getWhen()
649    * @see InvocationEvent#getWhen()
650    * @see InputMethodEvent#getWhen()
651    * @since 1.4
652    */
653   public static long getMostRecentEventTime()
654   {
655     EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); 
656     if (Thread.currentThread() != eq.dispatchThread)
657       return System.currentTimeMillis();
658     return eq.lastWhen;
659   }
660 }