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