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