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