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