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.ClasspathToolkit;
  42: 
  43: import java.awt.event.ActionEvent;
  44: import java.awt.event.InputEvent;
  45: import java.awt.event.InputMethodEvent;
  46: import java.awt.event.InvocationEvent;
  47: import java.awt.event.WindowEvent;
  48: import java.lang.reflect.InvocationTargetException;
  49: import java.util.EmptyStackException;
  50: 
  51: /* Written using on-line Java 2 Platform Standard Edition v1.3 API 
  52:  * Specification, as well as "The Java Class Libraries", 2nd edition 
  53:  * (Addison-Wesley, 1998).
  54:  * Status:  Believed complete, but untested.
  55:  */
  56: 
  57: /**
  58:  * This class manages a queue of <code>AWTEvent</code> objects that
  59:  * are posted to it.  The AWT system uses only one event queue for all
  60:  * events.
  61:  *
  62:  * @author Bryce McKinlay
  63:  * @author Aaron M. Renn (arenn@urbanophile.com)
  64:  */
  65: public class EventQueue
  66: {
  67:   private static final int INITIAL_QUEUE_DEPTH = 8;
  68:   private AWTEvent[] queue = new AWTEvent[INITIAL_QUEUE_DEPTH];
  69: 
  70:   private int next_in = 0; // Index where next event will be added to queue
  71:   private int next_out = 0; // Index of next event to be removed from queue
  72: 
  73:   private EventQueue next;
  74:   private EventQueue prev;
  75:   private AWTEvent currentEvent;
  76:   private long lastWhen = System.currentTimeMillis();
  77: 
  78:   private EventDispatchThread dispatchThread = new EventDispatchThread(this);
  79:   private boolean shutdown = false;
  80: 
  81:   private long lastNativeQueueAccess = 0;
  82:   private long humanLatencyThreshold = 100;
  83: 
  84:   synchronized void setShutdown (boolean b) 
  85:   {
  86:     shutdown = b;
  87:   }
  88: 
  89:   synchronized boolean isShutdown ()
  90:   {
  91:     if (shutdown)
  92:       return true;
  93: 
  94:     // This is the exact self-shutdown condition specified in J2SE:
  95:     // http://java.sun.com/j2se/1.4.2/docs/api/java/awt/doc-files/AWTThreadIssues.html
  96:     
  97:     if (peekEvent() == null
  98:         && ((ClasspathToolkit) Toolkit.getDefaultToolkit()).nativeQueueEmpty())
  99:       {
 100:         Frame[] frames = Frame.getFrames();
 101:         for (int i = 0; i < frames.length; ++i)
 102:           if (frames[i].isDisplayable())
 103:             return false;
 104:         return true;
 105:       }
 106:     return false;
 107:   }
 108: 
 109:   /**
 110:    * Initializes a new instance of <code>EventQueue</code>.
 111:    */
 112:   public EventQueue()
 113:   {
 114:   }
 115: 
 116:   /**
 117:    * Returns the next event in the queue.  This method will block until
 118:    * an event is available or until the thread is interrupted.
 119:    *
 120:    * @return The next event in the queue.
 121:    *
 122:    * @exception InterruptedException If this thread is interrupted while
 123:    * waiting for an event to be posted to the queue.
 124:    */
 125:   public synchronized AWTEvent getNextEvent()
 126:     throws InterruptedException
 127:   {
 128:     if (next != null)
 129:       return next.getNextEvent();
 130:     
 131:     ClasspathToolkit tk = ((ClasspathToolkit) Toolkit.getDefaultToolkit());
 132:     long curr = System.currentTimeMillis();
 133: 
 134:     if (! tk.nativeQueueEmpty() &&
 135:         (curr - lastNativeQueueAccess > humanLatencyThreshold))
 136:       {
 137:         tk.iterateNativeQueue(this, false);
 138:         lastNativeQueueAccess = curr;
 139:       }
 140: 
 141:     while (next_in == next_out)
 142:       {
 143:         // Only the EventDispatchThread associated with the top of the stack is
 144:         // allowed to get events from the native source; everyone else just
 145:         // waits on the head of the queue.
 146: 
 147:         if (isDispatchThread())
 148:           {
 149:             // We are not allowed to return null from this method, yet it
 150:             // is possible that we actually have run out of native events
 151:             // in the enclosing while() loop, and none of the native events
 152:             // happened to cause AWT events. We therefore ought to check
 153:             // the isShutdown() condition here, before risking a "native
 154:             // wait". If we check it before entering this function we may
 155:             // wait forever for events after the shutdown condition has
 156:             // arisen.
 157: 
 158:             if (isShutdown())
 159:               throw new InterruptedException();
 160: 
 161:             tk.iterateNativeQueue(this, true);
 162:             lastNativeQueueAccess = System.currentTimeMillis();
 163:           }
 164:         else
 165:           {
 166:             try
 167:               {
 168:                 wait();
 169:               }
 170:             catch (InterruptedException ie)
 171:               {
 172:               }
 173:           }
 174:       }
 175: 
 176:     AWTEvent res = queue[next_out];
 177: 
 178:     if (++next_out == queue.length)
 179:       next_out = 0;
 180:     return res;
 181:   }
 182: 
 183:   /**
 184:    * Returns the next event in the queue without removing it from the queue.
 185:    * This method will block until an event is available or until the thread
 186:    * is interrupted.
 187:    *
 188:    * @return The next event in the queue.
 189:    * @specnote Does not block. Returns null if there are no events on the 
 190:    *            queue. 
 191:    */ 
 192:   public synchronized AWTEvent peekEvent()
 193:   {
 194:     if (next != null)
 195:       return next.peekEvent();
 196: 
 197:     if (next_in != next_out)
 198:       return queue[next_out];
 199:     else
 200:       return null;
 201:   }
 202: 
 203:   /**
 204:    * Returns the next event in the queue that has the specified id
 205:    * without removing it from the queue.
 206:    * This method will block until an event is available or until the thread
 207:    * is interrupted.
 208:    *
 209:    * @param id The event id to return.
 210:    *
 211:    * @return The next event in the queue.
 212:    *
 213:    * @specnote Does not block. Returns null if there are no matching events 
 214:    *            on the queue. 
 215:    */ 
 216:   public synchronized AWTEvent peekEvent(int id)
 217:   {
 218:     if (next != null)
 219:       return next.peekEvent(id);
 220: 
 221:     int i = next_out;
 222:     while (i != next_in)
 223:       {
 224:         AWTEvent qevt = queue[i];
 225:         if (qevt.id == id)
 226:           return qevt;
 227:       }
 228:     return null;
 229:   }
 230: 
 231:   /**
 232:    * Posts a new event to the queue.
 233:    *
 234:    * @param evt The event to post to the queue.
 235:    *
 236:    * @exception NullPointerException If event is null.
 237:    */
 238:   public synchronized void postEvent(AWTEvent evt)
 239:   {
 240:     if (evt == null)
 241:       throw new NullPointerException();
 242: 
 243:     if (next != null)
 244:       {
 245:         next.postEvent(evt);
 246:         return;
 247:       }
 248: 
 249:     /* Check for any events already on the queue with the same source 
 250:        and ID. */    
 251:     int i = next_out;
 252:     while (i != next_in)
 253:       {
 254:         AWTEvent qevt = queue[i];
 255:         Object src;
 256:         if (qevt.id == evt.id
 257:             && (src = qevt.getSource()) == evt.getSource()
 258:             && src instanceof Component)
 259:           {
 260:             /* If there are, call coalesceEvents on the source component 
 261:                to see if they can be combined. */
 262:             Component srccmp = (Component) src;
 263:             AWTEvent coalesced_evt = srccmp.coalesceEvents(qevt, evt);
 264:             if (coalesced_evt != null)
 265:               {
 266:                 /* Yes. Replace the existing event with the combined event. */
 267:                 queue[i] = coalesced_evt;
 268:                 return;
 269:               }
 270:             break;
 271:           }
 272:         if (++i == queue.length)
 273:           i = 0;
 274:       }
 275: 
 276:     queue[next_in] = evt;    
 277:     if (++next_in == queue.length)
 278:       next_in = 0;
 279: 
 280:     if (next_in == next_out)
 281:       {
 282:         /* Queue is full. Extend it. */
 283:         AWTEvent[] oldQueue = queue;
 284:         queue = new AWTEvent[queue.length * 2];
 285: 
 286:         int len = oldQueue.length - next_out;
 287:         System.arraycopy(oldQueue, next_out, queue, 0, len);
 288:         if (next_out != 0)
 289:           System.arraycopy(oldQueue, 0, queue, len, next_out);
 290: 
 291:         next_out = 0;
 292:         next_in = oldQueue.length;
 293:       }
 294:     
 295:     if (dispatchThread == null || !dispatchThread.isAlive())
 296:       {
 297:         dispatchThread = new EventDispatchThread(this);
 298:         dispatchThread.start();
 299:       }
 300: 
 301:     // Window events might represent the closing of a window, which
 302:     // might cause the end of the dispatch thread's life, so we'll wake
 303:     // it up here to give it a chance to check for shutdown.
 304: 
 305:     if (!isDispatchThread() 
 306:         || (evt.getID() == WindowEvent.WINDOW_CLOSED)
 307:         || (evt.getID() == WindowEvent.WINDOW_CLOSING))
 308:       ((ClasspathToolkit) Toolkit.getDefaultToolkit()).wakeNativeQueue();
 309: 
 310:     notify();
 311:   }
 312: 
 313:   /**
 314:    * Causes runnable to have its run method called in the dispatch thread of the
 315:    * EventQueue. This will happen after all pending events are processed. The
 316:    * call blocks until this has happened. This method will throw an Error if
 317:    * called from the event dispatcher thread.
 318:    *
 319:    * @exception InterruptedException If another thread has interrupted
 320:    * this thread.
 321:    * @exception InvocationTargetException If an exception is thrown when running
 322:    * runnable.
 323:    *
 324:    * @since 1.2
 325:    */
 326:   public static void invokeAndWait(Runnable runnable)
 327:     throws InterruptedException, InvocationTargetException
 328:   {
 329:     if (isDispatchThread ())
 330:       throw new Error("Can't call invokeAndWait from event dispatch thread");
 331: 
 332:     EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); 
 333:     Thread current = Thread.currentThread();
 334: 
 335:     InvocationEvent ie = 
 336:       new InvocationEvent(eq, runnable, current, true);
 337: 
 338:     synchronized (current)
 339:       {
 340:         eq.postEvent(ie);
 341:         current.wait();
 342:       }
 343: 
 344:     Exception exception;
 345: 
 346:     if ((exception = ie.getException()) != null)
 347:       throw new InvocationTargetException(exception);
 348:   }
 349: 
 350:   /**
 351:    * This arranges for runnable to have its run method called in the
 352:    * dispatch thread of the EventQueue.  This will happen after all
 353:    * pending events are processed.
 354:    *
 355:    * @since 1.2
 356:    */
 357:   public static void invokeLater(Runnable runnable)
 358:   {
 359:     EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); 
 360: 
 361:     InvocationEvent ie = 
 362:       new InvocationEvent(eq, runnable, null, false);
 363: 
 364:     eq.postEvent(ie);
 365:   }
 366: 
 367:   /**
 368:    * Return true if the current thread is the current AWT event dispatch
 369:    * thread.
 370:    */
 371:   public static boolean isDispatchThread()
 372:   {
 373:     EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
 374:     
 375:     /* Find last EventQueue in chain */ 
 376:     while (eq.next != null)
 377:       eq = eq.next;
 378: 
 379:     return (Thread.currentThread() == eq.dispatchThread);
 380:   }
 381: 
 382:   /**
 383:    * Return the event currently being dispatched by the event
 384:    * dispatch thread.  If the current thread is not the event
 385:    * dispatch thread, this method returns null.
 386:    *
 387:    * @since 1.4
 388:    */
 389:   public static AWTEvent getCurrentEvent()
 390:   {
 391:     EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); 
 392:     Thread ct = Thread.currentThread();
 393:     
 394:     /* Find out if this thread is the dispatch thread for any of the
 395:        EventQueues in the chain */ 
 396:     while (ct != eq.dispatchThread)
 397:       {
 398:         // Try next EventQueue, if any
 399:         if (eq.next == null)
 400:            return null;  // Not an event dispatch thread
 401:         eq = eq.next;
 402:       }
 403: 
 404:     return eq.currentEvent;
 405:   }
 406: 
 407:   /**
 408:    * Allows a custom EventQueue implementation to replace this one. 
 409:    * All pending events are transferred to the new queue. Calls to postEvent,
 410:    * getNextEvent, and peekEvent and others are forwarded to the pushed queue
 411:    * until it is removed with a pop().
 412:    *
 413:    * @exception NullPointerException if newEventQueue is null.
 414:    */
 415:   public synchronized void push(EventQueue newEventQueue)
 416:   {
 417:     if (newEventQueue == null)
 418:       throw new NullPointerException ();
 419: 
 420:     /* Make sure we are at the top of the stack because callers can
 421:        only get a reference to the one at the bottom using
 422:        Toolkit.getDefaultToolkit().getSystemEventQueue() */
 423:     if (next != null)
 424:       {
 425:         next.push (newEventQueue);
 426:         return;
 427:       }
 428: 
 429:     /* Make sure we have a live dispatch thread to drive the queue */
 430:     if (dispatchThread == null)
 431:       dispatchThread = new EventDispatchThread(this);
 432: 
 433:     int i = next_out;
 434:     while (i != next_in)
 435:       {
 436:         newEventQueue.postEvent(queue[i]);
 437:         next_out = i;
 438:         if (++i == queue.length)
 439:           i = 0;
 440:       }
 441: 
 442:     next = newEventQueue;
 443:     newEventQueue.prev = this;    
 444:   }
 445: 
 446:   /** Transfer any pending events from this queue back to the parent queue that
 447:     * was previously push()ed. Event dispatch from this queue is suspended.
 448:     *
 449:     * @exception EmptyStackException If no previous push was made on this
 450:     * EventQueue.
 451:     */
 452:   protected void pop() throws EmptyStackException
 453:   {
 454:     if (prev == null)
 455:       throw new EmptyStackException();
 456: 
 457:     /* The order is important here, we must get the prev lock first,
 458:        or deadlock could occur as callers usually get here following
 459:        prev's next pointer, and thus obtain prev's lock before trying
 460:        to get this lock. */
 461:     synchronized (prev)
 462:       {
 463:         prev.next = next;
 464:         if (next != null)
 465:           next.prev = prev;
 466: 
 467:         synchronized (this)
 468:           {
 469:             int i = next_out;
 470:             while (i != next_in)
 471:               {
 472:                 prev.postEvent(queue[i]);
 473:                 next_out = i;
 474:                 if (++i == queue.length)
 475:                   i = 0;
 476:               }
 477:         // Empty the queue so it can be reused
 478:         next_in = 0;
 479:         next_out = 0;
 480: 
 481:             ((ClasspathToolkit) Toolkit.getDefaultToolkit()).wakeNativeQueue();
 482:             setShutdown(true);
 483:         dispatchThread = null;
 484:             this.notifyAll();
 485:           }
 486:       }
 487:   }
 488: 
 489:   /**
 490:    * Dispatches an event. The manner in which the event is dispatched depends
 491:    * upon the type of the event and the type of the event's source object.
 492:    *
 493:    * @exception NullPointerException If event is null.
 494:    */
 495:   protected void dispatchEvent(AWTEvent evt)
 496:   {
 497:     currentEvent = evt;
 498: 
 499:     if (evt instanceof InputEvent)
 500:       lastWhen = ((InputEvent) evt).getWhen();
 501:     else if (evt instanceof ActionEvent)
 502:       lastWhen = ((ActionEvent) evt).getWhen();
 503:     else if (evt instanceof InvocationEvent)
 504:       lastWhen = ((InvocationEvent) evt).getWhen();
 505: 
 506:     if (evt instanceof ActiveEvent)
 507:       {
 508:         ActiveEvent active_evt = (ActiveEvent) evt;
 509:         active_evt.dispatch();
 510:       }
 511:     else
 512:       {
 513:         Object source = evt.getSource();
 514: 
 515:         if (source instanceof Component)
 516:           {
 517:             Component srccmp = (Component) source;
 518:             srccmp.dispatchEvent(evt);
 519:           }
 520:         else if (source instanceof MenuComponent)
 521:           {
 522:             MenuComponent srccmp = (MenuComponent) source;
 523:             srccmp.dispatchEvent(evt);
 524:           }
 525:       }
 526:   }
 527: 
 528:   /**
 529:    * Returns the timestamp of the most recent event that had a timestamp, or
 530:    * the initialization time of the event queue if no events have been fired.
 531:    * At present, only <code>InputEvent</code>s, <code>ActionEvent</code>s,
 532:    * <code>InputMethodEvent</code>s, and <code>InvocationEvent</code>s have
 533:    * timestamps, but this may be added to other events in future versions.
 534:    * If this is called by the event dispatching thread, it can be any
 535:    * (sequential) value, but to other threads, the safest bet is to return
 536:    * System.currentTimeMillis().
 537:    *
 538:    * @return the most recent timestamp
 539:    * @see InputEvent#getWhen()
 540:    * @see ActionEvent#getWhen()
 541:    * @see InvocationEvent#getWhen()
 542:    * @see InputMethodEvent#getWhen()
 543:    * @since 1.4
 544:    */
 545:   public static long getMostRecentEventTime()
 546:   {
 547:     EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); 
 548:     if (Thread.currentThread() != eq.dispatchThread)
 549:       return System.currentTimeMillis();
 550:     return eq.lastWhen;
 551:   }
 552: }