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