1 /* 2 * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.awt; 27 28 import java.awt.event.*; 29 30 import java.awt.peer.ComponentPeer; 31 32 import java.lang.ref.WeakReference; 33 import java.lang.reflect.InvocationTargetException; 34 35 import java.security.AccessController; 36 import java.security.PrivilegedAction; 37 38 import java.util.EmptyStackException; 39 import sun.util.logging.PlatformLogger; 40 41 import sun.awt.AppContext; 42 import sun.awt.AWTAutoShutdown; 43 import sun.awt.PeerEvent; 44 import sun.awt.SunToolkit; 45 import sun.awt.EventQueueItem; 46 import sun.awt.AWTAccessor; 47 48 import java.util.concurrent.locks.Condition; 49 import java.util.concurrent.locks.Lock; 50 import java.util.concurrent.atomic.AtomicInteger; 51 52 import java.security.AccessControlContext; 53 import java.security.ProtectionDomain; 54 55 import sun.misc.SharedSecrets; 56 import sun.misc.JavaSecurityAccess; 57 58 /** 59 * <code>EventQueue</code> is a platform-independent class 60 * that queues events, both from the underlying peer classes 61 * and from trusted application classes. 62 * <p> 63 * It encapsulates asynchronous event dispatch machinery which 64 * extracts events from the queue and dispatches them by calling 65 * {@link #dispatchEvent(AWTEvent) dispatchEvent(AWTEvent)} method 66 * on this <code>EventQueue</code> with the event to be dispatched 67 * as an argument. The particular behavior of this machinery is 68 * implementation-dependent. The only requirements are that events 69 * which were actually enqueued to this queue (note that events 70 * being posted to the <code>EventQueue</code> can be coalesced) 71 * are dispatched: 72 * <dl> 73 * <dt> Sequentially. 74 * <dd> That is, it is not permitted that several events from 75 * this queue are dispatched simultaneously. 76 * <dt> In the same order as they are enqueued. 77 * <dd> That is, if <code>AWTEvent</code> A is enqueued 78 * to the <code>EventQueue</code> before 79 * <code>AWTEvent</code> B then event B will not be 80 * dispatched before event A. 81 * </dl> 82 * <p> 83 * Some browsers partition applets in different code bases into 84 * separate contexts, and establish walls between these contexts. 85 * In such a scenario, there will be one <code>EventQueue</code> 86 * per context. Other browsers place all applets into the same 87 * context, implying that there will be only a single, global 88 * <code>EventQueue</code> for all applets. This behavior is 89 * implementation-dependent. Consult your browser's documentation 90 * for more information. 91 * <p> 92 * For information on the threading issues of the event dispatch 93 * machinery, see <a href="doc-files/AWTThreadIssues.html#Autoshutdown" 94 * >AWT Threading Issues</a>. 95 * 96 * @author Thomas Ball 97 * @author Fred Ecks 98 * @author David Mendenhall 99 * 100 * @since 1.1 101 */ 102 public class EventQueue { 103 private static final AtomicInteger threadInitNumber = new AtomicInteger(0); 104 105 private static final int LOW_PRIORITY = 0; 106 private static final int NORM_PRIORITY = 1; 107 private static final int HIGH_PRIORITY = 2; 108 private static final int ULTIMATE_PRIORITY = 3; 109 110 private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1; 111 112 /* 113 * We maintain one Queue for each priority that the EventQueue supports. 114 * That is, the EventQueue object is actually implemented as 115 * NUM_PRIORITIES queues and all Events on a particular internal Queue 116 * have identical priority. Events are pulled off the EventQueue starting 117 * with the Queue of highest priority. We progress in decreasing order 118 * across all Queues. 119 */ 120 private Queue[] queues = new Queue[NUM_PRIORITIES]; 121 122 /* 123 * The next EventQueue on the stack, or null if this EventQueue is 124 * on the top of the stack. If nextQueue is non-null, requests to post 125 * an event are forwarded to nextQueue. 126 */ 127 private EventQueue nextQueue; 128 129 /* 130 * The previous EventQueue on the stack, or null if this is the 131 * "base" EventQueue. 132 */ 133 private EventQueue previousQueue; 134 135 /* 136 * A single lock to synchronize the push()/pop() and related operations with 137 * all the EventQueues from the AppContext. Synchronization on any particular 138 * event queue(s) is not enough: we should lock the whole stack. 139 */ 140 private final Lock pushPopLock; 141 private final Condition pushPopCond; 142 143 /* 144 * Dummy runnable to wake up EDT from getNextEvent() after 145 push/pop is performed 146 */ 147 private final static Runnable dummyRunnable = new Runnable() { 148 public void run() { 149 } 150 }; 151 152 private EventDispatchThread dispatchThread; 153 154 private final ThreadGroup threadGroup = 155 Thread.currentThread().getThreadGroup(); 156 private final ClassLoader classLoader = 157 Thread.currentThread().getContextClassLoader(); 158 159 /* 160 * The time stamp of the last dispatched InputEvent or ActionEvent. 161 */ 162 private long mostRecentEventTime = System.currentTimeMillis(); 163 164 /* 165 * The time stamp of the last KeyEvent . 166 */ 167 private long mostRecentKeyEventTime = System.currentTimeMillis(); 168 169 /** 170 * The modifiers field of the current event, if the current event is an 171 * InputEvent or ActionEvent. 172 */ 173 private WeakReference currentEvent; 174 175 /* 176 * Non-zero if a thread is waiting in getNextEvent(int) for an event of 177 * a particular ID to be posted to the queue. 178 */ 179 private volatile int waitForID; 180 181 private final String name = "AWT-EventQueue-" + threadInitNumber.getAndIncrement(); 182 183 private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventQueue"); 184 185 static { 186 AWTAccessor.setEventQueueAccessor( 187 new AWTAccessor.EventQueueAccessor() { 188 public Thread getDispatchThread(EventQueue eventQueue) { 189 return eventQueue.getDispatchThread(); 190 } 191 public boolean isDispatchThreadImpl(EventQueue eventQueue) { 192 return eventQueue.isDispatchThreadImpl(); 193 } 194 }); 195 } 196 197 public EventQueue() { 198 for (int i = 0; i < NUM_PRIORITIES; i++) { 199 queues[i] = new Queue(); 200 } 201 /* 202 * NOTE: if you ever have to start the associated event dispatch 203 * thread at this point, be aware of the following problem: 204 * If this EventQueue instance is created in 205 * SunToolkit.createNewAppContext() the started dispatch thread 206 * may call AppContext.getAppContext() before createNewAppContext() 207 * completes thus causing mess in thread group to appcontext mapping. 208 */ 209 210 pushPopLock = (Lock)AppContext.getAppContext().get(AppContext.EVENT_QUEUE_LOCK_KEY); 211 pushPopCond = (Condition)AppContext.getAppContext().get(AppContext.EVENT_QUEUE_COND_KEY); 212 } 213 214 /** 215 * Posts a 1.1-style event to the <code>EventQueue</code>. 216 * If there is an existing event on the queue with the same ID 217 * and event source, the source <code>Component</code>'s 218 * <code>coalesceEvents</code> method will be called. 219 * 220 * @param theEvent an instance of <code>java.awt.AWTEvent</code>, 221 * or a subclass of it 222 * @throws NullPointerException if <code>theEvent</code> is <code>null</code> 223 */ 224 public void postEvent(AWTEvent theEvent) { 225 SunToolkit.flushPendingEvents(); 226 postEventPrivate(theEvent); 227 } 228 229 /** 230 * Posts a 1.1-style event to the <code>EventQueue</code>. 231 * If there is an existing event on the queue with the same ID 232 * and event source, the source <code>Component</code>'s 233 * <code>coalesceEvents</code> method will be called. 234 * 235 * @param theEvent an instance of <code>java.awt.AWTEvent</code>, 236 * or a subclass of it 237 */ 238 private final void postEventPrivate(AWTEvent theEvent) { 239 theEvent.isPosted = true; 240 pushPopLock.lock(); 241 try { 242 if (nextQueue != null) { 243 // Forward the event to the top of EventQueue stack 244 nextQueue.postEventPrivate(theEvent); 245 return; 246 } 247 if (dispatchThread == null) { 248 if (theEvent.getSource() == AWTAutoShutdown.getInstance()) { 249 return; 250 } else { 251 initDispatchThread(); 252 } 253 } 254 postEvent(theEvent, getPriority(theEvent)); 255 } finally { 256 pushPopLock.unlock(); 257 } 258 } 259 260 private static int getPriority(AWTEvent theEvent) { 261 if (theEvent instanceof PeerEvent) { 262 PeerEvent peerEvent = (PeerEvent)theEvent; 263 if ((peerEvent.getFlags() & PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0) { 264 return ULTIMATE_PRIORITY; 265 } 266 if ((peerEvent.getFlags() & PeerEvent.PRIORITY_EVENT) != 0) { 267 return HIGH_PRIORITY; 268 } 269 if ((peerEvent.getFlags() & PeerEvent.LOW_PRIORITY_EVENT) != 0) { 270 return LOW_PRIORITY; 271 } 272 } 273 int id = theEvent.getID(); 274 if ((id >= PaintEvent.PAINT_FIRST) && (id <= PaintEvent.PAINT_LAST)) { 275 return LOW_PRIORITY; 276 } 277 return NORM_PRIORITY; 278 } 279 280 /** 281 * Posts the event to the internal Queue of specified priority, 282 * coalescing as appropriate. 283 * 284 * @param theEvent an instance of <code>java.awt.AWTEvent</code>, 285 * or a subclass of it 286 * @param priority the desired priority of the event 287 */ 288 private void postEvent(AWTEvent theEvent, int priority) { 289 if (coalesceEvent(theEvent, priority)) { 290 return; 291 } 292 293 EventQueueItem newItem = new EventQueueItem(theEvent); 294 295 cacheEQItem(newItem); 296 297 boolean notifyID = (theEvent.getID() == this.waitForID); 298 299 if (queues[priority].head == null) { 300 boolean shouldNotify = noEvents(); 301 queues[priority].head = queues[priority].tail = newItem; 302 303 if (shouldNotify) { 304 if (theEvent.getSource() != AWTAutoShutdown.getInstance()) { 305 AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread); 306 } 307 pushPopCond.signalAll(); 308 } else if (notifyID) { 309 pushPopCond.signalAll(); 310 } 311 } else { 312 // The event was not coalesced or has non-Component source. 313 // Insert it at the end of the appropriate Queue. 314 queues[priority].tail.next = newItem; 315 queues[priority].tail = newItem; 316 if (notifyID) { 317 pushPopCond.signalAll(); 318 } 319 } 320 } 321 322 private boolean coalescePaintEvent(PaintEvent e) { 323 ComponentPeer sourcePeer = ((Component)e.getSource()).peer; 324 if (sourcePeer != null) { 325 sourcePeer.coalescePaintEvent(e); 326 } 327 EventQueueItem[] cache = ((Component)e.getSource()).eventCache; 328 if (cache == null) { 329 return false; 330 } 331 int index = eventToCacheIndex(e); 332 333 if (index != -1 && cache[index] != null) { 334 PaintEvent merged = mergePaintEvents(e, (PaintEvent)cache[index].event); 335 if (merged != null) { 336 cache[index].event = merged; 337 return true; 338 } 339 } 340 return false; 341 } 342 343 private PaintEvent mergePaintEvents(PaintEvent a, PaintEvent b) { 344 Rectangle aRect = a.getUpdateRect(); 345 Rectangle bRect = b.getUpdateRect(); 346 if (bRect.contains(aRect)) { 347 return b; 348 } 349 if (aRect.contains(bRect)) { 350 return a; 351 } 352 return null; 353 } 354 355 private boolean coalesceMouseEvent(MouseEvent e) { 356 EventQueueItem[] cache = ((Component)e.getSource()).eventCache; 357 if (cache == null) { 358 return false; 359 } 360 int index = eventToCacheIndex(e); 361 if (index != -1 && cache[index] != null) { 362 cache[index].event = e; 363 return true; 364 } 365 return false; 366 } 367 368 private boolean coalescePeerEvent(PeerEvent e) { 369 EventQueueItem[] cache = ((Component)e.getSource()).eventCache; 370 if (cache == null) { 371 return false; 372 } 373 int index = eventToCacheIndex(e); 374 if (index != -1 && cache[index] != null) { 375 e = e.coalesceEvents((PeerEvent)cache[index].event); 376 if (e != null) { 377 cache[index].event = e; 378 return true; 379 } else { 380 cache[index] = null; 381 } 382 } 383 return false; 384 } 385 386 /* 387 * Should avoid of calling this method by any means 388 * as it's working time is dependant on EQ length. 389 * In the wors case this method alone can slow down the entire application 390 * 10 times by stalling the Event processing. 391 * Only here by backward compatibility reasons. 392 */ 393 private boolean coalesceOtherEvent(AWTEvent e, int priority) { 394 int id = e.getID(); 395 Component source = (Component)e.getSource(); 396 for (EventQueueItem entry = queues[priority].head; 397 entry != null; entry = entry.next) 398 { 399 // Give Component.coalesceEvents a chance 400 if (entry.event.getSource() == source && entry.event.getID() == id) { 401 AWTEvent coalescedEvent = source.coalesceEvents( 402 entry.event, e); 403 if (coalescedEvent != null) { 404 entry.event = coalescedEvent; 405 return true; 406 } 407 } 408 } 409 return false; 410 } 411 412 private boolean coalesceEvent(AWTEvent e, int priority) { 413 if (!(e.getSource() instanceof Component)) { 414 return false; 415 } 416 if (e instanceof PeerEvent) { 417 return coalescePeerEvent((PeerEvent)e); 418 } 419 // The worst case 420 if (((Component)e.getSource()).isCoalescingEnabled() 421 && coalesceOtherEvent(e, priority)) 422 { 423 return true; 424 } 425 if (e instanceof PaintEvent) { 426 return coalescePaintEvent((PaintEvent)e); 427 } 428 if (e instanceof MouseEvent) { 429 return coalesceMouseEvent((MouseEvent)e); 430 } 431 return false; 432 } 433 434 private void cacheEQItem(EventQueueItem entry) { 435 int index = eventToCacheIndex(entry.event); 436 if (index != -1 && entry.event.getSource() instanceof Component) { 437 Component source = (Component)entry.event.getSource(); 438 if (source.eventCache == null) { 439 source.eventCache = new EventQueueItem[CACHE_LENGTH]; 440 } 441 source.eventCache[index] = entry; 442 } 443 } 444 445 private void uncacheEQItem(EventQueueItem entry) { 446 int index = eventToCacheIndex(entry.event); 447 if (index != -1 && entry.event.getSource() instanceof Component) { 448 Component source = (Component)entry.event.getSource(); 449 if (source.eventCache == null) { 450 return; 451 } 452 source.eventCache[index] = null; 453 } 454 } 455 456 private static final int PAINT = 0; 457 private static final int UPDATE = 1; 458 private static final int MOVE = 2; 459 private static final int DRAG = 3; 460 private static final int PEER = 4; 461 private static final int CACHE_LENGTH = 5; 462 463 private static int eventToCacheIndex(AWTEvent e) { 464 switch(e.getID()) { 465 case PaintEvent.PAINT: 466 return PAINT; 467 case PaintEvent.UPDATE: 468 return UPDATE; 469 case MouseEvent.MOUSE_MOVED: 470 return MOVE; 471 case MouseEvent.MOUSE_DRAGGED: 472 return DRAG; 473 default: 474 return e instanceof PeerEvent ? PEER : -1; 475 } 476 } 477 478 /** 479 * Returns whether an event is pending on any of the separate 480 * Queues. 481 * @return whether an event is pending on any of the separate Queues 482 */ 483 private boolean noEvents() { 484 for (int i = 0; i < NUM_PRIORITIES; i++) { 485 if (queues[i].head != null) { 486 return false; 487 } 488 } 489 490 return true; 491 } 492 493 /** 494 * Removes an event from the <code>EventQueue</code> and 495 * returns it. This method will block until an event has 496 * been posted by another thread. 497 * @return the next <code>AWTEvent</code> 498 * @exception InterruptedException 499 * if any thread has interrupted this thread 500 */ 501 public AWTEvent getNextEvent() throws InterruptedException { 502 do { 503 /* 504 * SunToolkit.flushPendingEvents must be called outside 505 * of the synchronized block to avoid deadlock when 506 * event queues are nested with push()/pop(). 507 */ 508 SunToolkit.flushPendingEvents(); 509 pushPopLock.lock(); 510 try { 511 AWTEvent event = getNextEventPrivate(); 512 if (event != null) { 513 return event; 514 } 515 AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread); 516 pushPopCond.await(); 517 } finally { 518 pushPopLock.unlock(); 519 } 520 } while(true); 521 } 522 523 /* 524 * Must be called under the lock. Doesn't call flushPendingEvents() 525 */ 526 AWTEvent getNextEventPrivate() throws InterruptedException { 527 for (int i = NUM_PRIORITIES - 1; i >= 0; i--) { 528 if (queues[i].head != null) { 529 EventQueueItem entry = queues[i].head; 530 queues[i].head = entry.next; 531 if (entry.next == null) { 532 queues[i].tail = null; 533 } 534 uncacheEQItem(entry); 535 return entry.event; 536 } 537 } 538 return null; 539 } 540 541 AWTEvent getNextEvent(int id) throws InterruptedException { 542 do { 543 /* 544 * SunToolkit.flushPendingEvents must be called outside 545 * of the synchronized block to avoid deadlock when 546 * event queues are nested with push()/pop(). 547 */ 548 SunToolkit.flushPendingEvents(); 549 pushPopLock.lock(); 550 try { 551 for (int i = 0; i < NUM_PRIORITIES; i++) { 552 for (EventQueueItem entry = queues[i].head, prev = null; 553 entry != null; prev = entry, entry = entry.next) 554 { 555 if (entry.event.getID() == id) { 556 if (prev == null) { 557 queues[i].head = entry.next; 558 } else { 559 prev.next = entry.next; 560 } 561 if (queues[i].tail == entry) { 562 queues[i].tail = prev; 563 } 564 uncacheEQItem(entry); 565 return entry.event; 566 } 567 } 568 } 569 waitForID = id; 570 pushPopCond.await(); 571 waitForID = 0; 572 } finally { 573 pushPopLock.unlock(); 574 } 575 } while(true); 576 } 577 578 /** 579 * Returns the first event on the <code>EventQueue</code> 580 * without removing it. 581 * @return the first event 582 */ 583 public AWTEvent peekEvent() { 584 pushPopLock.lock(); 585 try { 586 for (int i = NUM_PRIORITIES - 1; i >= 0; i--) { 587 if (queues[i].head != null) { 588 return queues[i].head.event; 589 } 590 } 591 } finally { 592 pushPopLock.unlock(); 593 } 594 595 return null; 596 } 597 598 /** 599 * Returns the first event with the specified id, if any. 600 * @param id the id of the type of event desired 601 * @return the first event of the specified id or <code>null</code> 602 * if there is no such event 603 */ 604 public AWTEvent peekEvent(int id) { 605 pushPopLock.lock(); 606 try { 607 for (int i = NUM_PRIORITIES - 1; i >= 0; i--) { 608 EventQueueItem q = queues[i].head; 609 for (; q != null; q = q.next) { 610 if (q.event.getID() == id) { 611 return q.event; 612 } 613 } 614 } 615 } finally { 616 pushPopLock.unlock(); 617 } 618 619 return null; 620 } 621 622 private static final JavaSecurityAccess javaSecurityAccess = 623 SharedSecrets.getJavaSecurityAccess(); 624 625 /** 626 * Dispatches an event. The manner in which the event is 627 * dispatched depends upon the type of the event and the 628 * type of the event's source object: 629 * <p> </p> 630 * <table border=1 summary="Event types, source types, and dispatch methods"> 631 * <tr> 632 * <th>Event Type</th> 633 * <th>Source Type</th> 634 * <th>Dispatched To</th> 635 * </tr> 636 * <tr> 637 * <td>ActiveEvent</td> 638 * <td>Any</td> 639 * <td>event.dispatch()</td> 640 * </tr> 641 * <tr> 642 * <td>Other</td> 643 * <td>Component</td> 644 * <td>source.dispatchEvent(AWTEvent)</td> 645 * </tr> 646 * <tr> 647 * <td>Other</td> 648 * <td>MenuComponent</td> 649 * <td>source.dispatchEvent(AWTEvent)</td> 650 * </tr> 651 * <tr> 652 * <td>Other</td> 653 * <td>Other</td> 654 * <td>No action (ignored)</td> 655 * </tr> 656 * </table> 657 * <p> </p> 658 * @param event an instance of <code>java.awt.AWTEvent</code>, 659 * or a subclass of it 660 * @throws NullPointerException if <code>event</code> is <code>null</code> 661 * @since 1.2 662 */ 663 protected void dispatchEvent(final AWTEvent event) { 664 final Object src = event.getSource(); 665 final PrivilegedAction<Void> action = new PrivilegedAction<Void>() { 666 public Void run() { 667 dispatchEventImpl(event, src); 668 return null; 669 } 670 }; 671 672 final AccessControlContext stack = AccessController.getContext(); 673 final AccessControlContext srcAcc = getAccessControlContextFrom(src); 674 final AccessControlContext eventAcc = event.getAccessControlContext(); 675 if (srcAcc == null) { 676 javaSecurityAccess.doIntersectionPrivilege(action, stack, eventAcc); 677 } else { 678 javaSecurityAccess.doIntersectionPrivilege( 679 new PrivilegedAction<Void>() { 680 public Void run() { 681 javaSecurityAccess.doIntersectionPrivilege(action, eventAcc); 682 return null; 683 } 684 }, stack, srcAcc); 685 } 686 } 687 688 private static AccessControlContext getAccessControlContextFrom(Object src) { 689 return src instanceof Component ? 690 ((Component)src).getAccessControlContext() : 691 src instanceof MenuComponent ? 692 ((MenuComponent)src).getAccessControlContext() : 693 src instanceof TrayIcon ? 694 ((TrayIcon)src).getAccessControlContext() : 695 null; 696 } 697 698 /** 699 * Called from dispatchEvent() under a correct AccessControlContext 700 */ 701 private void dispatchEventImpl(final AWTEvent event, final Object src) { 702 event.isPosted = true; 703 if (event instanceof ActiveEvent) { 704 // This could become the sole method of dispatching in time. 705 setCurrentEventAndMostRecentTimeImpl(event); 706 ((ActiveEvent)event).dispatch(); 707 } else if (src instanceof Component) { 708 ((Component)src).dispatchEvent(event); 709 event.dispatched(); 710 } else if (src instanceof MenuComponent) { 711 ((MenuComponent)src).dispatchEvent(event); 712 } else if (src instanceof TrayIcon) { 713 ((TrayIcon)src).dispatchEvent(event); 714 } else if (src instanceof AWTAutoShutdown) { 715 if (noEvents()) { 716 dispatchThread.stopDispatching(); 717 } 718 } else { 719 if (eventLog.isLoggable(PlatformLogger.FINE)) { 720 eventLog.fine("Unable to dispatch event: " + event); 721 } 722 } 723 } 724 725 /** 726 * Returns the timestamp of the most recent event that had a timestamp, and 727 * that was dispatched from the <code>EventQueue</code> associated with the 728 * calling thread. If an event with a timestamp is currently being 729 * dispatched, its timestamp will be returned. If no events have yet 730 * been dispatched, the EventQueue's initialization time will be 731 * returned instead.In the current version of 732 * the JDK, only <code>InputEvent</code>s, 733 * <code>ActionEvent</code>s, and <code>InvocationEvent</code>s have 734 * timestamps; however, future versions of the JDK may add timestamps to 735 * additional event types. Note that this method should only be invoked 736 * from an application's {@link #isDispatchThread event dispatching thread}. 737 * If this method is 738 * invoked from another thread, the current system time (as reported by 739 * <code>System.currentTimeMillis()</code>) will be returned instead. 740 * 741 * @return the timestamp of the last <code>InputEvent</code>, 742 * <code>ActionEvent</code>, or <code>InvocationEvent</code> to be 743 * dispatched, or <code>System.currentTimeMillis()</code> if this 744 * method is invoked on a thread other than an event dispatching 745 * thread 746 * @see java.awt.event.InputEvent#getWhen 747 * @see java.awt.event.ActionEvent#getWhen 748 * @see java.awt.event.InvocationEvent#getWhen 749 * @see #isDispatchThread 750 * 751 * @since 1.4 752 */ 753 public static long getMostRecentEventTime() { 754 return Toolkit.getEventQueue().getMostRecentEventTimeImpl(); 755 } 756 private long getMostRecentEventTimeImpl() { 757 pushPopLock.lock(); 758 try { 759 return (Thread.currentThread() == dispatchThread) 760 ? mostRecentEventTime 761 : System.currentTimeMillis(); 762 } finally { 763 pushPopLock.unlock(); 764 } 765 } 766 767 /** 768 * @return most recent event time on all threads. 769 */ 770 long getMostRecentEventTimeEx() { 771 pushPopLock.lock(); 772 try { 773 return mostRecentEventTime; 774 } finally { 775 pushPopLock.unlock(); 776 } 777 } 778 779 /** 780 * Returns the the event currently being dispatched by the 781 * <code>EventQueue</code> associated with the calling thread. This is 782 * useful if a method needs access to the event, but was not designed to 783 * receive a reference to it as an argument. Note that this method should 784 * only be invoked from an application's event dispatching thread. If this 785 * method is invoked from another thread, null will be returned. 786 * 787 * @return the event currently being dispatched, or null if this method is 788 * invoked on a thread other than an event dispatching thread 789 * @since 1.4 790 */ 791 public static AWTEvent getCurrentEvent() { 792 return Toolkit.getEventQueue().getCurrentEventImpl(); 793 } 794 private AWTEvent getCurrentEventImpl() { 795 pushPopLock.lock(); 796 try { 797 return (Thread.currentThread() == dispatchThread) 798 ? ((AWTEvent)currentEvent.get()) 799 : null; 800 } finally { 801 pushPopLock.unlock(); 802 } 803 } 804 805 /** 806 * Replaces the existing <code>EventQueue</code> with the specified one. 807 * Any pending events are transferred to the new <code>EventQueue</code> 808 * for processing by it. 809 * 810 * @param newEventQueue an <code>EventQueue</code> 811 * (or subclass thereof) instance to be use 812 * @see java.awt.EventQueue#pop 813 * @throws NullPointerException if <code>newEventQueue</code> is <code>null</code> 814 * @since 1.2 815 */ 816 public void push(EventQueue newEventQueue) { 817 if (eventLog.isLoggable(PlatformLogger.FINE)) { 818 eventLog.fine("EventQueue.push(" + newEventQueue + ")"); 819 } 820 821 pushPopLock.lock(); 822 try { 823 EventQueue topQueue = this; 824 while (topQueue.nextQueue != null) { 825 topQueue = topQueue.nextQueue; 826 } 827 828 if ((topQueue.dispatchThread != null) && 829 (topQueue.dispatchThread.getEventQueue() == this)) 830 { 831 newEventQueue.dispatchThread = topQueue.dispatchThread; 832 topQueue.dispatchThread.setEventQueue(newEventQueue); 833 } 834 835 // Transfer all events forward to new EventQueue. 836 while (topQueue.peekEvent() != null) { 837 try { 838 // Use getNextEventPrivate() as it doesn't call flushPendingEvents() 839 newEventQueue.postEventPrivate(topQueue.getNextEventPrivate()); 840 } catch (InterruptedException ie) { 841 if (eventLog.isLoggable(PlatformLogger.FINE)) { 842 eventLog.fine("Interrupted push", ie); 843 } 844 } 845 } 846 847 // Wake up EDT waiting in getNextEvent(), so it can 848 // pick up a new EventQueue. Post the waking event before 849 // topQueue.nextQueue is assigned, otherwise the event would 850 // go newEventQueue 851 topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable)); 852 853 newEventQueue.previousQueue = topQueue; 854 topQueue.nextQueue = newEventQueue; 855 856 AppContext appContext = AppContext.getAppContext(); 857 if (appContext.get(AppContext.EVENT_QUEUE_KEY) == topQueue) { 858 appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue); 859 } 860 861 pushPopCond.signalAll(); 862 } finally { 863 pushPopLock.unlock(); 864 } 865 } 866 867 /** 868 * Stops dispatching events using this <code>EventQueue</code>. 869 * Any pending events are transferred to the previous 870 * <code>EventQueue</code> for processing. 871 * <p> 872 * Warning: To avoid deadlock, do not declare this method 873 * synchronized in a subclass. 874 * 875 * @exception EmptyStackException if no previous push was made 876 * on this <code>EventQueue</code> 877 * @see java.awt.EventQueue#push 878 * @since 1.2 879 */ 880 protected void pop() throws EmptyStackException { 881 if (eventLog.isLoggable(PlatformLogger.FINE)) { 882 eventLog.fine("EventQueue.pop(" + this + ")"); 883 } 884 885 pushPopLock.lock(); 886 try { 887 EventQueue topQueue = this; 888 while (topQueue.nextQueue != null) { 889 topQueue = topQueue.nextQueue; 890 } 891 EventQueue prevQueue = topQueue.previousQueue; 892 if (prevQueue == null) { 893 throw new EmptyStackException(); 894 } 895 896 topQueue.previousQueue = null; 897 prevQueue.nextQueue = null; 898 899 // Transfer all events back to previous EventQueue. 900 while (topQueue.peekEvent() != null) { 901 try { 902 prevQueue.postEventPrivate(topQueue.getNextEventPrivate()); 903 } catch (InterruptedException ie) { 904 if (eventLog.isLoggable(PlatformLogger.FINE)) { 905 eventLog.fine("Interrupted pop", ie); 906 } 907 } 908 } 909 910 if ((topQueue.dispatchThread != null) && 911 (topQueue.dispatchThread.getEventQueue() == this)) 912 { 913 prevQueue.dispatchThread = topQueue.dispatchThread; 914 topQueue.dispatchThread.setEventQueue(prevQueue); 915 } 916 917 AppContext appContext = AppContext.getAppContext(); 918 if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) { 919 appContext.put(AppContext.EVENT_QUEUE_KEY, prevQueue); 920 } 921 922 // Wake up EDT waiting in getNextEvent(), so it can 923 // pick up a new EventQueue 924 topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable)); 925 926 pushPopCond.signalAll(); 927 } finally { 928 pushPopLock.unlock(); 929 } 930 } 931 932 /** 933 * Creates a new {@code secondary loop} associated with this 934 * event queue. Use the {@link SecondaryLoop#enter} and 935 * {@link SecondaryLoop#exit} methods to start and stop the 936 * event loop and dispatch the events from this queue. 937 * 938 * @return secondaryLoop A new secondary loop object, which can 939 * be used to launch a new nested event 940 * loop and dispatch events from this queue 941 * 942 * @see SecondaryLoop#enter 943 * @see SecondaryLoop#exit 944 * 945 * @since 1.7 946 */ 947 public SecondaryLoop createSecondaryLoop() { 948 return createSecondaryLoop(null, null, 0); 949 } 950 951 SecondaryLoop createSecondaryLoop(Conditional cond, EventFilter filter, long interval) { 952 pushPopLock.lock(); 953 try { 954 if (nextQueue != null) { 955 // Forward the request to the top of EventQueue stack 956 return nextQueue.createSecondaryLoop(cond, filter, interval); 957 } 958 if (dispatchThread == null) { 959 initDispatchThread(); 960 } 961 return new WaitDispatchSupport(dispatchThread, cond, filter, interval); 962 } finally { 963 pushPopLock.unlock(); 964 } 965 } 966 967 /** 968 * Returns true if the calling thread is 969 * {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s 970 * dispatch thread. Use this method to ensure that a particular 971 * task is being executed (or not being) there. 972 * <p> 973 * Note: use the {@link #invokeLater} or {@link #invokeAndWait} 974 * methods to execute a task in 975 * {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s 976 * dispatch thread. 977 * <p> 978 * 979 * @return true if running in 980 * {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s 981 * dispatch thread 982 * @see #invokeLater 983 * @see #invokeAndWait 984 * @see Toolkit#getSystemEventQueue 985 * @since 1.2 986 */ 987 public static boolean isDispatchThread() { 988 EventQueue eq = Toolkit.getEventQueue(); 989 return eq.isDispatchThreadImpl(); 990 } 991 992 final boolean isDispatchThreadImpl() { 993 EventQueue eq = this; 994 pushPopLock.lock(); 995 try { 996 EventQueue next = eq.nextQueue; 997 while (next != null) { 998 eq = next; 999 next = eq.nextQueue; 1000 } 1001 return (Thread.currentThread() == eq.dispatchThread); 1002 } finally { 1003 pushPopLock.unlock(); 1004 } 1005 } 1006 1007 final void initDispatchThread() { 1008 pushPopLock.lock(); 1009 try { 1010 AppContext appContext = AppContext.getAppContext(); 1011 if (dispatchThread == null && !threadGroup.isDestroyed() && !appContext.isDisposed()) { 1012 dispatchThread = AccessController.doPrivileged( 1013 new PrivilegedAction<EventDispatchThread>() { 1014 public EventDispatchThread run() { 1015 EventDispatchThread t = 1016 new EventDispatchThread(threadGroup, 1017 name, 1018 EventQueue.this); 1019 t.setContextClassLoader(classLoader); 1020 t.setPriority(Thread.NORM_PRIORITY + 1); 1021 t.setDaemon(false); 1022 return t; 1023 } 1024 } 1025 ); 1026 AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread); 1027 dispatchThread.start(); 1028 } 1029 } finally { 1030 pushPopLock.unlock(); 1031 } 1032 } 1033 1034 final boolean detachDispatchThread(EventDispatchThread edt, boolean forceDetach) { 1035 /* 1036 * This synchronized block is to secure that the event dispatch 1037 * thread won't die in the middle of posting a new event to the 1038 * associated event queue. It is important because we notify 1039 * that the event dispatch thread is busy after posting a new event 1040 * to its queue, so the EventQueue.dispatchThread reference must 1041 * be valid at that point. 1042 */ 1043 pushPopLock.lock(); 1044 try { 1045 if (edt == dispatchThread) { 1046 /* 1047 * Don't detach the thread if any events are pending. Not 1048 * sure if it's a possible scenario, though. 1049 * 1050 * Fix for 4648733. Check both the associated java event 1051 * queue and the PostEventQueue. 1052 */ 1053 if (!forceDetach && (peekEvent() != null) || !SunToolkit.isPostEventQueueEmpty()) { 1054 return false; 1055 } 1056 dispatchThread = null; 1057 } 1058 AWTAutoShutdown.getInstance().notifyThreadFree(edt); 1059 return true; 1060 } finally { 1061 pushPopLock.unlock(); 1062 } 1063 } 1064 1065 /* 1066 * Gets the <code>EventDispatchThread</code> for this 1067 * <code>EventQueue</code>. 1068 * @return the event dispatch thread associated with this event queue 1069 * or <code>null</code> if this event queue doesn't have a 1070 * working thread associated with it 1071 * @see java.awt.EventQueue#initDispatchThread 1072 * @see java.awt.EventQueue#detachDispatchThread 1073 */ 1074 final EventDispatchThread getDispatchThread() { 1075 pushPopLock.lock(); 1076 try { 1077 return dispatchThread; 1078 } finally { 1079 pushPopLock.unlock(); 1080 } 1081 } 1082 1083 /* 1084 * Removes any pending events for the specified source object. 1085 * If removeAllEvents parameter is <code>true</code> then all 1086 * events for the specified source object are removed, if it 1087 * is <code>false</code> then <code>SequencedEvent</code>, <code>SentEvent</code>, 1088 * <code>FocusEvent</code>, <code>WindowEvent</code>, <code>KeyEvent</code>, 1089 * and <code>InputMethodEvent</code> are kept in the queue, but all other 1090 * events are removed. 1091 * 1092 * This method is normally called by the source's 1093 * <code>removeNotify</code> method. 1094 */ 1095 final void removeSourceEvents(Object source, boolean removeAllEvents) { 1096 SunToolkit.flushPendingEvents(); 1097 pushPopLock.lock(); 1098 try { 1099 for (int i = 0; i < NUM_PRIORITIES; i++) { 1100 EventQueueItem entry = queues[i].head; 1101 EventQueueItem prev = null; 1102 while (entry != null) { 1103 if ((entry.event.getSource() == source) 1104 && (removeAllEvents 1105 || ! (entry.event instanceof SequencedEvent 1106 || entry.event instanceof SentEvent 1107 || entry.event instanceof FocusEvent 1108 || entry.event instanceof WindowEvent 1109 || entry.event instanceof KeyEvent 1110 || entry.event instanceof InputMethodEvent))) 1111 { 1112 if (entry.event instanceof SequencedEvent) { 1113 ((SequencedEvent)entry.event).dispose(); 1114 } 1115 if (entry.event instanceof SentEvent) { 1116 ((SentEvent)entry.event).dispose(); 1117 } 1118 if (prev == null) { 1119 queues[i].head = entry.next; 1120 } else { 1121 prev.next = entry.next; 1122 } 1123 uncacheEQItem(entry); 1124 } else { 1125 prev = entry; 1126 } 1127 entry = entry.next; 1128 } 1129 queues[i].tail = prev; 1130 } 1131 } finally { 1132 pushPopLock.unlock(); 1133 } 1134 } 1135 1136 synchronized long getMostRecentKeyEventTime() { 1137 pushPopLock.lock(); 1138 try { 1139 return mostRecentKeyEventTime; 1140 } finally { 1141 pushPopLock.unlock(); 1142 } 1143 } 1144 1145 static void setCurrentEventAndMostRecentTime(AWTEvent e) { 1146 Toolkit.getEventQueue().setCurrentEventAndMostRecentTimeImpl(e); 1147 } 1148 private void setCurrentEventAndMostRecentTimeImpl(AWTEvent e) { 1149 pushPopLock.lock(); 1150 try { 1151 if (Thread.currentThread() != dispatchThread) { 1152 return; 1153 } 1154 1155 currentEvent = new WeakReference(e); 1156 1157 // This series of 'instanceof' checks should be replaced with a 1158 // polymorphic type (for example, an interface which declares a 1159 // getWhen() method). However, this would require us to make such 1160 // a type public, or to place it in sun.awt. Both of these approaches 1161 // have been frowned upon. So for now, we hack. 1162 // 1163 // In tiger, we will probably give timestamps to all events, so this 1164 // will no longer be an issue. 1165 long mostRecentEventTime2 = Long.MIN_VALUE; 1166 if (e instanceof InputEvent) { 1167 InputEvent ie = (InputEvent)e; 1168 mostRecentEventTime2 = ie.getWhen(); 1169 if (e instanceof KeyEvent) { 1170 mostRecentKeyEventTime = ie.getWhen(); 1171 } 1172 } else if (e instanceof InputMethodEvent) { 1173 InputMethodEvent ime = (InputMethodEvent)e; 1174 mostRecentEventTime2 = ime.getWhen(); 1175 } else if (e instanceof ActionEvent) { 1176 ActionEvent ae = (ActionEvent)e; 1177 mostRecentEventTime2 = ae.getWhen(); 1178 } else if (e instanceof InvocationEvent) { 1179 InvocationEvent ie = (InvocationEvent)e; 1180 mostRecentEventTime2 = ie.getWhen(); 1181 } 1182 mostRecentEventTime = Math.max(mostRecentEventTime, mostRecentEventTime2); 1183 } finally { 1184 pushPopLock.unlock(); 1185 } 1186 } 1187 1188 /** 1189 * Causes <code>runnable</code> to have its <code>run</code> 1190 * method called in the {@link #isDispatchThread dispatch thread} of 1191 * {@link Toolkit#getSystemEventQueue the system EventQueue}. 1192 * This will happen after all pending events are processed. 1193 * 1194 * @param runnable the <code>Runnable</code> whose <code>run</code> 1195 * method should be executed 1196 * asynchronously in the 1197 * {@link #isDispatchThread event dispatch thread} 1198 * of {@link Toolkit#getSystemEventQueue the system EventQueue} 1199 * @see #invokeAndWait 1200 * @see Toolkit#getSystemEventQueue 1201 * @see #isDispatchThread 1202 * @since 1.2 1203 */ 1204 public static void invokeLater(Runnable runnable) { 1205 Toolkit.getEventQueue().postEvent( 1206 new InvocationEvent(Toolkit.getDefaultToolkit(), runnable)); 1207 } 1208 1209 /** 1210 * Causes <code>runnable</code> to have its <code>run</code> 1211 * method called in the {@link #isDispatchThread dispatch thread} of 1212 * {@link Toolkit#getSystemEventQueue the system EventQueue}. 1213 * This will happen after all pending events are processed. 1214 * The call blocks until this has happened. This method 1215 * will throw an Error if called from the 1216 * {@link #isDispatchThread event dispatcher thread}. 1217 * 1218 * @param runnable the <code>Runnable</code> whose <code>run</code> 1219 * method should be executed 1220 * synchronously in the 1221 * {@link #isDispatchThread event dispatch thread} 1222 * of {@link Toolkit#getSystemEventQueue the system EventQueue} 1223 * @exception InterruptedException if any thread has 1224 * interrupted this thread 1225 * @exception InvocationTargetException if an throwable is thrown 1226 * when running <code>runnable</code> 1227 * @see #invokeLater 1228 * @see Toolkit#getSystemEventQueue 1229 * @see #isDispatchThread 1230 * @since 1.2 1231 */ 1232 public static void invokeAndWait(Runnable runnable) 1233 throws InterruptedException, InvocationTargetException { 1234 1235 if (EventQueue.isDispatchThread()) { 1236 throw new Error("Cannot call invokeAndWait from the event dispatcher thread"); 1237 } 1238 1239 class AWTInvocationLock {} 1240 Object lock = new AWTInvocationLock(); 1241 1242 InvocationEvent event = 1243 new InvocationEvent(Toolkit.getDefaultToolkit(), runnable, lock, 1244 true); 1245 1246 synchronized (lock) { 1247 Toolkit.getEventQueue().postEvent(event); 1248 while (!event.isDispatched()) { 1249 lock.wait(); 1250 } 1251 } 1252 1253 Throwable eventThrowable = event.getThrowable(); 1254 if (eventThrowable != null) { 1255 throw new InvocationTargetException(eventThrowable); 1256 } 1257 } 1258 1259 /* 1260 * Called from PostEventQueue.postEvent to notify that a new event 1261 * appeared. First it proceeds to the EventQueue on the top of the 1262 * stack, then notifies the associated dispatch thread if it exists 1263 * or starts a new one otherwise. 1264 */ 1265 private void wakeup(boolean isShutdown) { 1266 pushPopLock.lock(); 1267 try { 1268 if (nextQueue != null) { 1269 // Forward call to the top of EventQueue stack. 1270 nextQueue.wakeup(isShutdown); 1271 } else if (dispatchThread != null) { 1272 pushPopCond.signalAll(); 1273 } else if (!isShutdown) { 1274 initDispatchThread(); 1275 } 1276 } finally { 1277 pushPopLock.unlock(); 1278 } 1279 } 1280 } 1281 1282 /** 1283 * The Queue object holds pointers to the beginning and end of one internal 1284 * queue. An EventQueue object is composed of multiple internal Queues, one 1285 * for each priority supported by the EventQueue. All Events on a particular 1286 * internal Queue have identical priority. 1287 */ 1288 class Queue { 1289 EventQueueItem head; 1290 EventQueueItem tail; 1291 }