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