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