src/share/classes/java/awt/EventQueue.java

Print this page




  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 import sun.util.logging.PlatformLogger;
  40 
  41 import sun.awt.AppContext;
  42 import sun.awt.AWTAutoShutdown;
  43 import sun.awt.PeerEvent;
  44 import sun.awt.SunToolkit;
  45 import sun.awt.EventQueueItem;
  46 import sun.awt.AWTAccessor;
  47 
  48 import java.util.concurrent.locks.Condition;
  49 import java.util.concurrent.locks.Lock;

  50 
  51 import java.security.AccessControlContext;
  52 import java.security.ProtectionDomain;
  53 
  54 import sun.misc.SharedSecrets;
  55 import sun.misc.JavaSecurityAccess;
  56 
  57 /**
  58  * <code>EventQueue</code> is a platform-independent class
  59  * that queues events, both from the underlying peer classes
  60  * and from trusted application classes.
  61  * <p>
  62  * It encapsulates asynchronous event dispatch machinery which
  63  * extracts events from the queue and dispatches them by calling
  64  * {@link #dispatchEvent(AWTEvent) dispatchEvent(AWTEvent)} method
  65  * on this <code>EventQueue</code> with the event to be dispatched
  66  * as an argument.  The particular behavior of this machinery is
  67  * implementation-dependent.  The only requirements are that events
  68  * which were actually enqueued to this queue (note that events
  69  * being posted to the <code>EventQueue</code> can be coalesced)


  82  * Some browsers partition applets in different code bases into
  83  * separate contexts, and establish walls between these contexts.
  84  * In such a scenario, there will be one <code>EventQueue</code>
  85  * per context. Other browsers place all applets into the same
  86  * context, implying that there will be only a single, global
  87  * <code>EventQueue</code> for all applets. This behavior is
  88  * implementation-dependent.  Consult your browser's documentation
  89  * for more information.
  90  * <p>
  91  * For information on the threading issues of the event dispatch
  92  * machinery, see <a href="doc-files/AWTThreadIssues.html#Autoshutdown"
  93  * >AWT Threading Issues</a>.
  94  *
  95  * @author Thomas Ball
  96  * @author Fred Ecks
  97  * @author David Mendenhall
  98  *
  99  * @since       1.1
 100  */
 101 public class EventQueue {
 102 
 103     // From Thread.java
 104     private static int threadInitNumber;
 105     private static synchronized int nextThreadNum() {
 106         return threadInitNumber++;
 107     }
 108 
 109     private static final int LOW_PRIORITY = 0;
 110     private static final int NORM_PRIORITY = 1;
 111     private static final int HIGH_PRIORITY = 2;
 112     private static final int ULTIMATE_PRIORITY = 3;
 113 
 114     private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1;
 115 
 116     /*
 117      * We maintain one Queue for each priority that the EventQueue supports.
 118      * That is, the EventQueue object is actually implemented as
 119      * NUM_PRIORITIES queues and all Events on a particular internal Queue
 120      * have identical priority. Events are pulled off the EventQueue starting
 121      * with the Queue of highest priority. We progress in decreasing order
 122      * across all Queues.
 123      */
 124     private Queue[] queues = new Queue[NUM_PRIORITIES];
 125 
 126     /*
 127      * The next EventQueue on the stack, or null if this EventQueue is
 128      * on the top of the stack.  If nextQueue is non-null, requests to post
 129      * an event are forwarded to nextQueue.
 130      */
 131     private EventQueue nextQueue;
 132 
 133     /*
 134      * The previous EventQueue on the stack, or null if this is the
 135      * "base" EventQueue.
 136      */
 137     private EventQueue previousQueue;
 138 
 139     /*
 140      * A single lock to synchronize the push()/pop() and related operations with
 141      * all the EventQueues from the AppContext. Synchronization on any particular
 142      * event queue(s) is not enough: we should lock the whole stack.
 143      */
 144     private final Lock pushPopLock;
 145     private final Condition pushPopCond;
 146 
 147     /*
 148      * Dummy runnable to wake up EDT from getNextEvent() after
 149      push/pop is performed
 150      */
 151     private final static Runnable dummyRunnable = new Runnable() {
 152         public void run() {
 153         }
 154     };
 155 
 156     private EventDispatchThread dispatchThread;
 157 
 158     private final ThreadGroup threadGroup =
 159         Thread.currentThread().getThreadGroup();
 160     private final ClassLoader classLoader =
 161         Thread.currentThread().getContextClassLoader();
 162 
 163     /*
 164      * The time stamp of the last dispatched InputEvent or ActionEvent.
 165      */
 166     private long mostRecentEventTime = System.currentTimeMillis();
 167 
 168     /**
 169      * The modifiers field of the current event, if the current event is an
 170      * InputEvent or ActionEvent.
 171      */
 172     private WeakReference currentEvent;
 173 
 174     /*
 175      * Non-zero if a thread is waiting in getNextEvent(int) for an event of
 176      * a particular ID to be posted to the queue.
 177      */
 178     private int waitForID;
 179 
 180     private final String name = "AWT-EventQueue-" + nextThreadNum();
 181 
 182     private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventQueue");
 183 
 184     static {
 185         AWTAccessor.setEventQueueAccessor(
 186             new AWTAccessor.EventQueueAccessor() {
 187                 public Thread getDispatchThread(EventQueue eventQueue) {
 188                     return eventQueue.getDispatchThread();
 189                 }
 190                 public boolean isDispatchThreadImpl(EventQueue eventQueue) {
 191                     return eventQueue.isDispatchThreadImpl();
 192                 }
 193             });
 194     }
 195 
 196     public EventQueue() {
 197         for (int i = 0; i < NUM_PRIORITIES; i++) {
 198             queues[i] = new Queue();
 199         }
 200         /*
 201          * NOTE: if you ever have to start the associated event dispatch
 202          * thread at this point, be aware of the following problem:
 203          * If this EventQueue instance is created in
 204          * SunToolkit.createNewAppContext() the started dispatch thread
 205          * may call AppContext.getAppContext() before createNewAppContext()
 206          * completes thus causing mess in thread group to appcontext mapping.
 207          */
 208 
 209         pushPopLock = (Lock)AppContext.getAppContext().get(AppContext.EVENT_QUEUE_LOCK_KEY);
 210         pushPopCond = (Condition)AppContext.getAppContext().get(AppContext.EVENT_QUEUE_COND_KEY);
 211     }
 212 
 213     /**
 214      * Posts a 1.1-style event to the <code>EventQueue</code>.
 215      * If there is an existing event on the queue with the same ID
 216      * and event source, the source <code>Component</code>'s
 217      * <code>coalesceEvents</code> method will be called.
 218      *
 219      * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
 220      *          or a subclass of it
 221      * @throws NullPointerException if <code>theEvent</code> is <code>null</code>
 222      */
 223     public void postEvent(AWTEvent theEvent) {
 224         SunToolkit.flushPendingEvents();
 225         postEventPrivate(theEvent);
 226     }
 227 
 228     /**
 229      * Posts a 1.1-style event to the <code>EventQueue</code>.


 497      * @exception InterruptedException
 498      *            if any thread has interrupted this thread
 499      */
 500     public AWTEvent getNextEvent() throws InterruptedException {
 501         do {
 502             /*
 503              * SunToolkit.flushPendingEvents must be called outside
 504              * of the synchronized block to avoid deadlock when
 505              * event queues are nested with push()/pop().
 506              */
 507             SunToolkit.flushPendingEvents();
 508             pushPopLock.lock();
 509             try {
 510                 AWTEvent event = getNextEventPrivate();
 511                 if (event != null) {
 512                     return event;
 513                 }
 514                 AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
 515                 pushPopCond.await();
 516             } finally {

 517                 pushPopLock.unlock();
 518             }

 519         } while(true);
 520     }
 521 
 522     /*
 523      * Must be called under the lock. Doesn't call flushPendingEvents()
 524      */
 525     AWTEvent getNextEventPrivate() throws InterruptedException {
 526         for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
 527             if (queues[i].head != null) {
 528                 EventQueueItem entry = queues[i].head;
 529                 queues[i].head = entry.next;
 530                 if (entry.next == null) {
 531                     queues[i].tail = null;
 532                 }
 533                 uncacheEQItem(entry);
 534                 return entry.event;
 535             }
 536         }
 537         return null;
 538     }


 552                          entry != null; prev = entry, entry = entry.next)
 553                     {
 554                         if (entry.event.getID() == id) {
 555                             if (prev == null) {
 556                                 queues[i].head = entry.next;
 557                             } else {
 558                                 prev.next = entry.next;
 559                             }
 560                             if (queues[i].tail == entry) {
 561                                 queues[i].tail = prev;
 562                             }
 563                             uncacheEQItem(entry);
 564                             return entry.event;
 565                         }
 566                     }
 567                 }
 568                 waitForID = id;
 569                 pushPopCond.await();
 570                 waitForID = 0;
 571             } finally {

 572                 pushPopLock.unlock();
 573             }

 574         } while(true);
 575     }
 576 
 577     /**
 578      * Returns the first event on the <code>EventQueue</code>
 579      * without removing it.
 580      * @return the first event
 581      */
 582     public AWTEvent peekEvent() {
 583         pushPopLock.lock();
 584         try {
 585             for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
 586                 if (queues[i].head != null) {
 587                     return queues[i].head.event;
 588                 }
 589             }
 590         } finally {
 591             pushPopLock.unlock();
 592         }
 593 


1013                         public EventDispatchThread run() {
1014                             EventDispatchThread t =
1015                                 new EventDispatchThread(threadGroup,
1016                                                         name,
1017                                                         EventQueue.this);
1018                             t.setContextClassLoader(classLoader);
1019                             t.setPriority(Thread.NORM_PRIORITY + 1);
1020                             t.setDaemon(false);
1021                             return t;
1022                         }
1023                     }
1024                 );
1025                 AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
1026                 dispatchThread.start();
1027             }
1028         } finally {
1029             pushPopLock.unlock();
1030         }
1031     }
1032 
1033     final boolean detachDispatchThread(EventDispatchThread edt) {
1034         /*
1035          * This synchronized block is to secure that the event dispatch
1036          * thread won't die in the middle of posting a new event to the
1037          * associated event queue. It is important because we notify
1038          * that the event dispatch thread is busy after posting a new event
1039          * to its queue, so the EventQueue.dispatchThread reference must
1040          * be valid at that point.
1041          */
1042         pushPopLock.lock();
1043         try {
1044             if (edt == dispatchThread) {
1045                 /*
1046                  * Don't detach the thread if any events are pending. Not
1047                  * sure if it's a possible scenario, though.
1048                  *
1049                  * Fix for 4648733. Check both the associated java event
1050                  * queue and the PostEventQueue.
1051                  */
1052                 if ((peekEvent() != null) || !SunToolkit.isPostEventQueueEmpty()) {
1053                     return false;
1054                 }
1055                 dispatchThread = null;
1056             }
1057             AWTAutoShutdown.getInstance().notifyThreadFree(edt);
1058             return true;
1059         } finally {
1060             pushPopLock.unlock();
1061         }
1062     }
1063 
1064     /*
1065      * Gets the <code>EventDispatchThread</code> for this
1066      * <code>EventQueue</code>.
1067      * @return the event dispatch thread associated with this event queue
1068      *         or <code>null</code> if this event queue doesn't have a
1069      *         working thread associated with it
1070      * @see    java.awt.EventQueue#initDispatchThread
1071      * @see    java.awt.EventQueue#detachDispatchThread
1072      */




  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 import sun.util.logging.PlatformLogger;
  40 
  41 import sun.awt.AppContext;
  42 import sun.awt.AWTAutoShutdown;
  43 import sun.awt.PeerEvent;
  44 import sun.awt.SunToolkit;
  45 import sun.awt.EventQueueItem;
  46 import sun.awt.AWTAccessor;
  47 
  48 import java.util.concurrent.locks.Condition;
  49 import java.util.concurrent.locks.ReentrantLock;
  50 import java.util.concurrent.atomic.AtomicInteger;
  51 
  52 import java.security.AccessControlContext;
  53 import java.security.ProtectionDomain;
  54 
  55 import sun.misc.SharedSecrets;
  56 import sun.misc.JavaSecurityAccess;
  57 
  58 /**
  59  * <code>EventQueue</code> is a platform-independent class
  60  * that queues events, both from the underlying peer classes
  61  * and from trusted application classes.
  62  * <p>
  63  * It encapsulates asynchronous event dispatch machinery which
  64  * extracts events from the queue and dispatches them by calling
  65  * {@link #dispatchEvent(AWTEvent) dispatchEvent(AWTEvent)} method
  66  * on this <code>EventQueue</code> with the event to be dispatched
  67  * as an argument.  The particular behavior of this machinery is
  68  * implementation-dependent.  The only requirements are that events
  69  * which were actually enqueued to this queue (note that events
  70  * being posted to the <code>EventQueue</code> can be coalesced)


  83  * Some browsers partition applets in different code bases into
  84  * separate contexts, and establish walls between these contexts.
  85  * In such a scenario, there will be one <code>EventQueue</code>
  86  * per context. Other browsers place all applets into the same
  87  * context, implying that there will be only a single, global
  88  * <code>EventQueue</code> for all applets. This behavior is
  89  * implementation-dependent.  Consult your browser's documentation
  90  * for more information.
  91  * <p>
  92  * For information on the threading issues of the event dispatch
  93  * machinery, see <a href="doc-files/AWTThreadIssues.html#Autoshutdown"
  94  * >AWT Threading Issues</a>.
  95  *
  96  * @author Thomas Ball
  97  * @author Fred Ecks
  98  * @author David Mendenhall
  99  *
 100  * @since       1.1
 101  */
 102 public class EventQueue {
 103     private static final AtomicInteger threadInitNumber = new AtomicInteger(0);





 104 
 105     private static final int LOW_PRIORITY = 0;
 106     private static final int NORM_PRIORITY = 1;
 107     private static final int HIGH_PRIORITY = 2;
 108     private static final int ULTIMATE_PRIORITY = 3;
 109 
 110     private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1;
 111 
 112     /*
 113      * We maintain one Queue for each priority that the EventQueue supports.
 114      * That is, the EventQueue object is actually implemented as
 115      * NUM_PRIORITIES queues and all Events on a particular internal Queue
 116      * have identical priority. Events are pulled off the EventQueue starting
 117      * with the Queue of highest priority. We progress in decreasing order
 118      * across all Queues.
 119      */
 120     private Queue[] queues = new Queue[NUM_PRIORITIES];
 121 
 122     /*
 123      * The next EventQueue on the stack, or null if this EventQueue is
 124      * on the top of the stack.  If nextQueue is non-null, requests to post
 125      * an event are forwarded to nextQueue.
 126      */
 127     private EventQueue nextQueue;
 128 
 129     /*
 130      * The previous EventQueue on the stack, or null if this is the
 131      * "base" EventQueue.
 132      */
 133     private EventQueue previousQueue;
 134 
 135     /*
 136      * A single lock to synchronize the push()/pop() and related operations with
 137      * all the EventQueues from the AppContext. Synchronization on any particular
 138      * event queue(s) is not enough: we should lock the whole stack.
 139      */
 140     private final ReentrantLock pushPopLock;
 141     private final Condition pushPopCond;
 142 
 143     /*
 144      * Dummy runnable to wake up EDT from getNextEvent() after
 145      push/pop is performed
 146      */
 147     private final static Runnable dummyRunnable = new Runnable() {
 148         public void run() {
 149         }
 150     };
 151 
 152     private EventDispatchThread dispatchThread;
 153 
 154     private final ThreadGroup threadGroup =
 155         Thread.currentThread().getThreadGroup();
 156     private final ClassLoader classLoader =
 157         Thread.currentThread().getContextClassLoader();
 158 
 159     /*
 160      * The time stamp of the last dispatched InputEvent or ActionEvent.
 161      */
 162     private long mostRecentEventTime = 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 currentEvent;
 169 
 170     /*
 171      * Non-zero if a thread is waiting in getNextEvent(int) for an event of
 172      * a particular ID to be posted to the queue.
 173      */
 174     private volatile int waitForID;
 175 
 176     private final String name = "AWT-EventQueue-" + threadInitNumber.getAndIncrement();
 177 
 178     private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventQueue");
 179 
 180     static {
 181         AWTAccessor.setEventQueueAccessor(
 182             new AWTAccessor.EventQueueAccessor() {
 183                 public Thread getDispatchThread(EventQueue eventQueue) {
 184                     return eventQueue.getDispatchThread();
 185                 }
 186                 public boolean isDispatchThreadImpl(EventQueue eventQueue) {
 187                     return eventQueue.isDispatchThreadImpl();
 188                 }
 189             });
 190     }
 191 
 192     public EventQueue() {
 193         for (int i = 0; i < NUM_PRIORITIES; i++) {
 194             queues[i] = new Queue();
 195         }
 196         /*
 197          * NOTE: if you ever have to start the associated event dispatch
 198          * thread at this point, be aware of the following problem:
 199          * If this EventQueue instance is created in
 200          * SunToolkit.createNewAppContext() the started dispatch thread
 201          * may call AppContext.getAppContext() before createNewAppContext()
 202          * completes thus causing mess in thread group to appcontext mapping.
 203          */
 204 
 205         pushPopLock = (ReentrantLock)AppContext.getAppContext().get(AppContext.EVENT_QUEUE_LOCK_KEY);
 206         pushPopCond = (Condition)AppContext.getAppContext().get(AppContext.EVENT_QUEUE_COND_KEY);
 207     }
 208 
 209     /**
 210      * Posts a 1.1-style event to the <code>EventQueue</code>.
 211      * If there is an existing event on the queue with the same ID
 212      * and event source, the source <code>Component</code>'s
 213      * <code>coalesceEvents</code> method will be called.
 214      *
 215      * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
 216      *          or a subclass of it
 217      * @throws NullPointerException if <code>theEvent</code> is <code>null</code>
 218      */
 219     public void postEvent(AWTEvent theEvent) {
 220         SunToolkit.flushPendingEvents();
 221         postEventPrivate(theEvent);
 222     }
 223 
 224     /**
 225      * Posts a 1.1-style event to the <code>EventQueue</code>.


 493      * @exception InterruptedException
 494      *            if any thread has interrupted this thread
 495      */
 496     public AWTEvent getNextEvent() throws InterruptedException {
 497         do {
 498             /*
 499              * SunToolkit.flushPendingEvents must be called outside
 500              * of the synchronized block to avoid deadlock when
 501              * event queues are nested with push()/pop().
 502              */
 503             SunToolkit.flushPendingEvents();
 504             pushPopLock.lock();
 505             try {
 506                 AWTEvent event = getNextEventPrivate();
 507                 if (event != null) {
 508                     return event;
 509                 }
 510                 AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
 511                 pushPopCond.await();
 512             } finally {
 513                 if(pushPopLock.isHeldByCurrentThread()) {
 514                    pushPopLock.unlock();
 515                 }
 516             }
 517         } while(true);
 518     }
 519 
 520     /*
 521      * Must be called under the lock. Doesn't call flushPendingEvents()
 522      */
 523     AWTEvent getNextEventPrivate() throws InterruptedException {
 524         for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
 525             if (queues[i].head != null) {
 526                 EventQueueItem entry = queues[i].head;
 527                 queues[i].head = entry.next;
 528                 if (entry.next == null) {
 529                     queues[i].tail = null;
 530                 }
 531                 uncacheEQItem(entry);
 532                 return entry.event;
 533             }
 534         }
 535         return null;
 536     }


 550                          entry != null; prev = entry, entry = entry.next)
 551                     {
 552                         if (entry.event.getID() == id) {
 553                             if (prev == null) {
 554                                 queues[i].head = entry.next;
 555                             } else {
 556                                 prev.next = entry.next;
 557                             }
 558                             if (queues[i].tail == entry) {
 559                                 queues[i].tail = prev;
 560                             }
 561                             uncacheEQItem(entry);
 562                             return entry.event;
 563                         }
 564                     }
 565                 }
 566                 waitForID = id;
 567                 pushPopCond.await();
 568                 waitForID = 0;
 569             } finally {
 570                 if(pushPopLock.isHeldByCurrentThread()) {
 571                    pushPopLock.unlock();
 572                 }
 573             }
 574         } while(true);
 575     }
 576 
 577     /**
 578      * Returns the first event on the <code>EventQueue</code>
 579      * without removing it.
 580      * @return the first event
 581      */
 582     public AWTEvent peekEvent() {
 583         pushPopLock.lock();
 584         try {
 585             for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
 586                 if (queues[i].head != null) {
 587                     return queues[i].head.event;
 588                 }
 589             }
 590         } finally {
 591             pushPopLock.unlock();
 592         }
 593 


1013                         public EventDispatchThread run() {
1014                             EventDispatchThread t =
1015                                 new EventDispatchThread(threadGroup,
1016                                                         name,
1017                                                         EventQueue.this);
1018                             t.setContextClassLoader(classLoader);
1019                             t.setPriority(Thread.NORM_PRIORITY + 1);
1020                             t.setDaemon(false);
1021                             return t;
1022                         }
1023                     }
1024                 );
1025                 AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
1026                 dispatchThread.start();
1027             }
1028         } finally {
1029             pushPopLock.unlock();
1030         }
1031     }
1032 
1033     final boolean detachDispatchThread(EventDispatchThread edt, boolean forceDetach) {
1034         /*
1035          * This synchronized block is to secure that the event dispatch
1036          * thread won't die in the middle of posting a new event to the
1037          * associated event queue. It is important because we notify
1038          * that the event dispatch thread is busy after posting a new event
1039          * to its queue, so the EventQueue.dispatchThread reference must
1040          * be valid at that point.
1041          */
1042         pushPopLock.lock();
1043         try {
1044             if (edt == dispatchThread) {
1045                 /*
1046                  * Don't detach the thread if any events are pending. Not
1047                  * sure if it's a possible scenario, though.
1048                  *
1049                  * Fix for 4648733. Check both the associated java event
1050                  * queue and the PostEventQueue.
1051                  */
1052                 if (!forceDetach && (peekEvent() != null) || !SunToolkit.isPostEventQueueEmpty()) {
1053                     return false;
1054                 }
1055                 dispatchThread = null;
1056             }
1057             AWTAutoShutdown.getInstance().notifyThreadFree(edt);
1058             return true;
1059         } finally {
1060             pushPopLock.unlock();
1061         }
1062     }
1063 
1064     /*
1065      * Gets the <code>EventDispatchThread</code> for this
1066      * <code>EventQueue</code>.
1067      * @return the event dispatch thread associated with this event queue
1068      *         or <code>null</code> if this event queue doesn't have a
1069      *         working thread associated with it
1070      * @see    java.awt.EventQueue#initDispatchThread
1071      * @see    java.awt.EventQueue#detachDispatchThread
1072      */