001/* EventQueue.java -- 002 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005 Free Software Foundation 003 004This file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037 038 039package java.awt; 040 041import gnu.java.awt.LowPriorityEvent; 042import gnu.java.awt.peer.NativeEventLoopRunningEvent; 043 044import java.awt.event.ActionEvent; 045import java.awt.event.InputEvent; 046import java.awt.event.InputMethodEvent; 047import java.awt.event.InvocationEvent; 048import java.awt.event.PaintEvent; 049import java.awt.peer.ComponentPeer; 050import java.awt.peer.LightweightPeer; 051import java.lang.reflect.InvocationTargetException; 052import java.util.EmptyStackException; 053 054/* Written using on-line Java 2 Platform Standard Edition v1.3 API 055 * Specification, as well as "The Java Class Libraries", 2nd edition 056 * (Addison-Wesley, 1998). 057 * Status: Believed complete, but untested. 058 */ 059 060/** 061 * This class manages a queue of <code>AWTEvent</code> objects that 062 * are posted to it. The AWT system uses only one event queue for all 063 * events. 064 * 065 * @author Bryce McKinlay 066 * @author Aaron M. Renn (arenn@urbanophile.com) 067 */ 068public class EventQueue 069{ 070 /** 071 * Indicates events that are processed with normal priority. This is normally 072 * all events except PaintEvents. 073 */ 074 private static final int NORM_PRIORITY = 0; 075 076 /** 077 * Indicates events that are processed with lowes priority. This is normally 078 * all PaintEvents and LowPriorityEvents. 079 */ 080 private static final int LOW_PRIORITY = 1; 081 082 /** 083 * Implements the actual queue. EventQueue has 2 internal queues for 084 * different priorities: 085 * 1 PaintEvents are always dispatched with low priority. 086 * 2. All other events are dispatched with normal priority. 087 * 088 * This makes sure that the actual painting (output) is performed _after_ all 089 * available input has been processed and that the paint regions are 090 * coalesced as much as possible. 091 */ 092 private class Queue 093 { 094 /** 095 * The first item in the queue. This is where events are popped from. 096 */ 097 AWTEvent queueHead; 098 099 /** 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}