Source for java.awt.EventQueue

   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:     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: }