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