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