src/share/classes/java/awt/EventQueue.java
author Jaroslav Tulach <jtulach@netbeans.org>
Wed, 23 May 2012 11:51:09 +0200
branchjavafx
changeset 5229 4ed8674de305
parent 4611 d72ac458b2b7
permissions -rw-r--r--
Allowing JavaFX to dispatchEvent in its own, dedicated FX dispatch thread
duke@0
     1
/*
ohair@3942
     2
 * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
duke@0
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@0
     4
 *
duke@0
     5
 * This code is free software; you can redistribute it and/or modify it
duke@0
     6
 * under the terms of the GNU General Public License version 2 only, as
ohair@2395
     7
 * published by the Free Software Foundation.  Oracle designates this
duke@0
     8
 * particular file as subject to the "Classpath" exception as provided
ohair@2395
     9
 * by Oracle in the LICENSE file that accompanied this code.
duke@0
    10
 *
duke@0
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@0
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@0
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
duke@0
    14
 * version 2 for more details (a copy is included in the LICENSE file that
duke@0
    15
 * accompanied this code).
duke@0
    16
 *
duke@0
    17
 * You should have received a copy of the GNU General Public License version
duke@0
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
duke@0
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@0
    20
 *
ohair@2395
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@2395
    22
 * or visit www.oracle.com if you need additional information or have any
ohair@2395
    23
 * questions.
duke@0
    24
 */
duke@0
    25
duke@0
    26
package java.awt;
duke@0
    27
duke@0
    28
import java.awt.event.*;
duke@0
    29
duke@0
    30
import java.awt.peer.ComponentPeer;
duke@0
    31
duke@0
    32
import java.lang.ref.WeakReference;
duke@0
    33
import java.lang.reflect.InvocationTargetException;
duke@0
    34
duke@0
    35
import java.security.AccessController;
duke@0
    36
import java.security.PrivilegedAction;
duke@0
    37
duke@0
    38
import java.util.EmptyStackException;
mchung@1729
    39
import sun.util.logging.PlatformLogger;
duke@0
    40
duke@0
    41
import sun.awt.AppContext;
duke@0
    42
import sun.awt.AWTAutoShutdown;
duke@0
    43
import sun.awt.PeerEvent;
duke@0
    44
import sun.awt.SunToolkit;
dav@553
    45
import sun.awt.EventQueueItem;
dcherepanov@1371
    46
import sun.awt.AWTAccessor;
duke@0
    47
art@2003
    48
import java.util.concurrent.locks.Condition;
art@2003
    49
import java.util.concurrent.locks.Lock;
anthony@4611
    50
import java.util.concurrent.atomic.AtomicInteger;
art@2003
    51
denis@3820
    52
import java.security.AccessControlContext;
denis@3820
    53
import java.security.ProtectionDomain;
denis@3820
    54
denis@3820
    55
import sun.misc.SharedSecrets;
denis@3820
    56
import sun.misc.JavaSecurityAccess;
denis@3820
    57
duke@0
    58
/**
duke@0
    59
 * <code>EventQueue</code> is a platform-independent class
duke@0
    60
 * that queues events, both from the underlying peer classes
duke@0
    61
 * and from trusted application classes.
duke@0
    62
 * <p>
duke@0
    63
 * It encapsulates asynchronous event dispatch machinery which
duke@0
    64
 * extracts events from the queue and dispatches them by calling
duke@0
    65
 * {@link #dispatchEvent(AWTEvent) dispatchEvent(AWTEvent)} method
duke@0
    66
 * on this <code>EventQueue</code> with the event to be dispatched
duke@0
    67
 * as an argument.  The particular behavior of this machinery is
duke@0
    68
 * implementation-dependent.  The only requirements are that events
duke@0
    69
 * which were actually enqueued to this queue (note that events
duke@0
    70
 * being posted to the <code>EventQueue</code> can be coalesced)
duke@0
    71
 * are dispatched:
duke@0
    72
 * <dl>
duke@0
    73
 *   <dt> Sequentially.
duke@0
    74
 *   <dd> That is, it is not permitted that several events from
duke@0
    75
 *        this queue are dispatched simultaneously.
duke@0
    76
 *   <dt> In the same order as they are enqueued.
duke@0
    77
 *   <dd> That is, if <code>AWTEvent</code>&nbsp;A is enqueued
duke@0
    78
 *        to the <code>EventQueue</code> before
duke@0
    79
 *        <code>AWTEvent</code>&nbsp;B then event B will not be
duke@0
    80
 *        dispatched before event A.
duke@0
    81
 * </dl>
duke@0
    82
 * <p>
duke@0
    83
 * Some browsers partition applets in different code bases into
duke@0
    84
 * separate contexts, and establish walls between these contexts.
duke@0
    85
 * In such a scenario, there will be one <code>EventQueue</code>
duke@0
    86
 * per context. Other browsers place all applets into the same
duke@0
    87
 * context, implying that there will be only a single, global
duke@0
    88
 * <code>EventQueue</code> for all applets. This behavior is
duke@0
    89
 * implementation-dependent.  Consult your browser's documentation
duke@0
    90
 * for more information.
duke@0
    91
 * <p>
duke@0
    92
 * For information on the threading issues of the event dispatch
duke@0
    93
 * machinery, see <a href="doc-files/AWTThreadIssues.html#Autoshutdown"
duke@0
    94
 * >AWT Threading Issues</a>.
duke@0
    95
 *
duke@0
    96
 * @author Thomas Ball
duke@0
    97
 * @author Fred Ecks
duke@0
    98
 * @author David Mendenhall
duke@0
    99
 *
duke@0
   100
 * @since       1.1
duke@0
   101
 */
duke@0
   102
public class EventQueue {
anthony@4611
   103
    private static final AtomicInteger threadInitNumber = new AtomicInteger(0);
duke@0
   104
duke@0
   105
    private static final int LOW_PRIORITY = 0;
duke@0
   106
    private static final int NORM_PRIORITY = 1;
duke@0
   107
    private static final int HIGH_PRIORITY = 2;
duke@0
   108
    private static final int ULTIMATE_PRIORITY = 3;
duke@0
   109
duke@0
   110
    private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1;
duke@0
   111
duke@0
   112
    /*
duke@0
   113
     * We maintain one Queue for each priority that the EventQueue supports.
duke@0
   114
     * That is, the EventQueue object is actually implemented as
duke@0
   115
     * NUM_PRIORITIES queues and all Events on a particular internal Queue
duke@0
   116
     * have identical priority. Events are pulled off the EventQueue starting
duke@0
   117
     * with the Queue of highest priority. We progress in decreasing order
duke@0
   118
     * across all Queues.
duke@0
   119
     */
duke@0
   120
    private Queue[] queues = new Queue[NUM_PRIORITIES];
duke@0
   121
duke@0
   122
    /*
duke@0
   123
     * The next EventQueue on the stack, or null if this EventQueue is
duke@0
   124
     * on the top of the stack.  If nextQueue is non-null, requests to post
duke@0
   125
     * an event are forwarded to nextQueue.
duke@0
   126
     */
duke@0
   127
    private EventQueue nextQueue;
duke@0
   128
duke@0
   129
    /*
duke@0
   130
     * The previous EventQueue on the stack, or null if this is the
duke@0
   131
     * "base" EventQueue.
duke@0
   132
     */
duke@0
   133
    private EventQueue previousQueue;
duke@0
   134
art@2003
   135
    /*
art@2003
   136
     * A single lock to synchronize the push()/pop() and related operations with
art@2003
   137
     * all the EventQueues from the AppContext. Synchronization on any particular
art@2003
   138
     * event queue(s) is not enough: we should lock the whole stack.
art@2003
   139
     */
art@2003
   140
    private final Lock pushPopLock;
art@2003
   141
    private final Condition pushPopCond;
art@2003
   142
art@2551
   143
    /*
art@2551
   144
     * Dummy runnable to wake up EDT from getNextEvent() after
art@2551
   145
     push/pop is performed
art@2551
   146
     */
art@2551
   147
    private final static Runnable dummyRunnable = new Runnable() {
art@2551
   148
        public void run() {
art@2551
   149
        }
art@2551
   150
    };
art@2551
   151
duke@0
   152
    private EventDispatchThread dispatchThread;
duke@0
   153
duke@0
   154
    private final ThreadGroup threadGroup =
duke@0
   155
        Thread.currentThread().getThreadGroup();
duke@0
   156
    private final ClassLoader classLoader =
duke@0
   157
        Thread.currentThread().getContextClassLoader();
duke@0
   158
duke@0
   159
    /*
duke@0
   160
     * The time stamp of the last dispatched InputEvent or ActionEvent.
duke@0
   161
     */
duke@0
   162
    private long mostRecentEventTime = System.currentTimeMillis();
duke@0
   163
duke@0
   164
    /**
duke@0
   165
     * The modifiers field of the current event, if the current event is an
duke@0
   166
     * InputEvent or ActionEvent.
duke@0
   167
     */
duke@0
   168
    private WeakReference currentEvent;
duke@0
   169
duke@0
   170
    /*
duke@0
   171
     * Non-zero if a thread is waiting in getNextEvent(int) for an event of
duke@0
   172
     * a particular ID to be posted to the queue.
duke@0
   173
     */
anthony@4611
   174
    private volatile int waitForID;
duke@0
   175
anthony@4611
   176
    private final String name = "AWT-EventQueue-" + threadInitNumber.getAndIncrement();
duke@0
   177
mchung@1729
   178
    private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventQueue");
duke@0
   179
dcherepanov@1371
   180
    static {
dcherepanov@1371
   181
        AWTAccessor.setEventQueueAccessor(
dcherepanov@1371
   182
            new AWTAccessor.EventQueueAccessor() {
art@2003
   183
                public Thread getDispatchThread(EventQueue eventQueue) {
art@2003
   184
                    return eventQueue.getDispatchThread();
dcherepanov@1371
   185
                }
art@2003
   186
                public boolean isDispatchThreadImpl(EventQueue eventQueue) {
art@2003
   187
                    return eventQueue.isDispatchThreadImpl();
dcherepanov@1371
   188
                }
dcherepanov@1371
   189
            });
dcherepanov@1371
   190
    }
dcherepanov@1371
   191
duke@0
   192
    public EventQueue() {
duke@0
   193
        for (int i = 0; i < NUM_PRIORITIES; i++) {
duke@0
   194
            queues[i] = new Queue();
duke@0
   195
        }
duke@0
   196
        /*
duke@0
   197
         * NOTE: if you ever have to start the associated event dispatch
duke@0
   198
         * thread at this point, be aware of the following problem:
duke@0
   199
         * If this EventQueue instance is created in
duke@0
   200
         * SunToolkit.createNewAppContext() the started dispatch thread
duke@0
   201
         * may call AppContext.getAppContext() before createNewAppContext()
duke@0
   202
         * completes thus causing mess in thread group to appcontext mapping.
duke@0
   203
         */
art@2003
   204
art@2003
   205
        pushPopLock = (Lock)AppContext.getAppContext().get(AppContext.EVENT_QUEUE_LOCK_KEY);
art@2003
   206
        pushPopCond = (Condition)AppContext.getAppContext().get(AppContext.EVENT_QUEUE_COND_KEY);
duke@0
   207
    }
duke@0
   208
duke@0
   209
    /**
duke@0
   210
     * Posts a 1.1-style event to the <code>EventQueue</code>.
duke@0
   211
     * If there is an existing event on the queue with the same ID
duke@0
   212
     * and event source, the source <code>Component</code>'s
duke@0
   213
     * <code>coalesceEvents</code> method will be called.
duke@0
   214
     *
duke@0
   215
     * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
duke@0
   216
     *          or a subclass of it
duke@0
   217
     * @throws NullPointerException if <code>theEvent</code> is <code>null</code>
duke@0
   218
     */
duke@0
   219
    public void postEvent(AWTEvent theEvent) {
duke@0
   220
        SunToolkit.flushPendingEvents();
duke@0
   221
        postEventPrivate(theEvent);
duke@0
   222
    }
duke@0
   223
duke@0
   224
    /**
duke@0
   225
     * Posts a 1.1-style event to the <code>EventQueue</code>.
duke@0
   226
     * If there is an existing event on the queue with the same ID
duke@0
   227
     * and event source, the source <code>Component</code>'s
duke@0
   228
     * <code>coalesceEvents</code> method will be called.
duke@0
   229
     *
duke@0
   230
     * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
duke@0
   231
     *          or a subclass of it
duke@0
   232
     */
art@2551
   233
    private final void postEventPrivate(AWTEvent theEvent) {
duke@0
   234
        theEvent.isPosted = true;
art@2003
   235
        pushPopLock.lock();
art@2003
   236
        try {
art@2551
   237
            if (nextQueue != null) {
art@2551
   238
                // Forward the event to the top of EventQueue stack
art@2551
   239
                nextQueue.postEventPrivate(theEvent);
art@2551
   240
                return;
art@2551
   241
            }
art@2551
   242
            if (dispatchThread == null) {
duke@0
   243
                if (theEvent.getSource() == AWTAutoShutdown.getInstance()) {
duke@0
   244
                    return;
duke@0
   245
                } else {
duke@0
   246
                    initDispatchThread();
duke@0
   247
                }
duke@0
   248
            }
duke@0
   249
            postEvent(theEvent, getPriority(theEvent));
art@2003
   250
        } finally {
art@2003
   251
            pushPopLock.unlock();
duke@0
   252
        }
duke@0
   253
    }
duke@0
   254
duke@0
   255
    private static int getPriority(AWTEvent theEvent) {
art@2551
   256
        if (theEvent instanceof PeerEvent) {
art@2551
   257
            PeerEvent peerEvent = (PeerEvent)theEvent;
art@2551
   258
            if ((peerEvent.getFlags() & PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0) {
art@2551
   259
                return ULTIMATE_PRIORITY;
art@2551
   260
            }
art@2551
   261
            if ((peerEvent.getFlags() & PeerEvent.PRIORITY_EVENT) != 0) {
art@2551
   262
                return HIGH_PRIORITY;
art@2551
   263
            }
art@2551
   264
            if ((peerEvent.getFlags() & PeerEvent.LOW_PRIORITY_EVENT) != 0) {
art@2551
   265
                return LOW_PRIORITY;
art@2551
   266
            }
duke@0
   267
        }
duke@0
   268
        int id = theEvent.getID();
art@2551
   269
        if ((id >= PaintEvent.PAINT_FIRST) && (id <= PaintEvent.PAINT_LAST)) {
duke@0
   270
            return LOW_PRIORITY;
duke@0
   271
        }
duke@0
   272
        return NORM_PRIORITY;
duke@0
   273
    }
duke@0
   274
duke@0
   275
    /**
duke@0
   276
     * Posts the event to the internal Queue of specified priority,
duke@0
   277
     * coalescing as appropriate.
duke@0
   278
     *
duke@0
   279
     * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
duke@0
   280
     *          or a subclass of it
duke@0
   281
     * @param priority  the desired priority of the event
duke@0
   282
     */
duke@0
   283
    private void postEvent(AWTEvent theEvent, int priority) {
duke@0
   284
        if (coalesceEvent(theEvent, priority)) {
duke@0
   285
            return;
duke@0
   286
        }
duke@0
   287
duke@0
   288
        EventQueueItem newItem = new EventQueueItem(theEvent);
duke@0
   289
duke@0
   290
        cacheEQItem(newItem);
duke@0
   291
duke@0
   292
        boolean notifyID = (theEvent.getID() == this.waitForID);
duke@0
   293
duke@0
   294
        if (queues[priority].head == null) {
duke@0
   295
            boolean shouldNotify = noEvents();
duke@0
   296
            queues[priority].head = queues[priority].tail = newItem;
duke@0
   297
duke@0
   298
            if (shouldNotify) {
duke@0
   299
                if (theEvent.getSource() != AWTAutoShutdown.getInstance()) {
duke@0
   300
                    AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
duke@0
   301
                }
jtulach@5229
   302
                signalAll();
duke@0
   303
            } else if (notifyID) {
jtulach@5229
   304
                signalAll();
duke@0
   305
            }
duke@0
   306
        } else {
duke@0
   307
            // The event was not coalesced or has non-Component source.
duke@0
   308
            // Insert it at the end of the appropriate Queue.
duke@0
   309
            queues[priority].tail.next = newItem;
duke@0
   310
            queues[priority].tail = newItem;
duke@0
   311
            if (notifyID) {
jtulach@5229
   312
                signalAll();
duke@0
   313
            }
duke@0
   314
        }
duke@0
   315
    }
duke@0
   316
duke@0
   317
    private boolean coalescePaintEvent(PaintEvent e) {
duke@0
   318
        ComponentPeer sourcePeer = ((Component)e.getSource()).peer;
duke@0
   319
        if (sourcePeer != null) {
duke@0
   320
            sourcePeer.coalescePaintEvent(e);
duke@0
   321
        }
duke@0
   322
        EventQueueItem[] cache = ((Component)e.getSource()).eventCache;
duke@0
   323
        if (cache == null) {
duke@0
   324
            return false;
duke@0
   325
        }
duke@0
   326
        int index = eventToCacheIndex(e);
duke@0
   327
duke@0
   328
        if (index != -1 && cache[index] != null) {
duke@0
   329
            PaintEvent merged = mergePaintEvents(e, (PaintEvent)cache[index].event);
duke@0
   330
            if (merged != null) {
duke@0
   331
                cache[index].event = merged;
duke@0
   332
                return true;
duke@0
   333
            }
duke@0
   334
        }
duke@0
   335
        return false;
duke@0
   336
    }
duke@0
   337
duke@0
   338
    private PaintEvent mergePaintEvents(PaintEvent a, PaintEvent b) {
duke@0
   339
        Rectangle aRect = a.getUpdateRect();
duke@0
   340
        Rectangle bRect = b.getUpdateRect();
duke@0
   341
        if (bRect.contains(aRect)) {
duke@0
   342
            return b;
duke@0
   343
        }
duke@0
   344
        if (aRect.contains(bRect)) {
duke@0
   345
            return a;
duke@0
   346
        }
duke@0
   347
        return null;
duke@0
   348
    }
duke@0
   349
duke@0
   350
    private boolean coalesceMouseEvent(MouseEvent e) {
duke@0
   351
        EventQueueItem[] cache = ((Component)e.getSource()).eventCache;
duke@0
   352
        if (cache == null) {
duke@0
   353
            return false;
duke@0
   354
        }
duke@0
   355
        int index = eventToCacheIndex(e);
duke@0
   356
        if (index != -1 && cache[index] != null) {
duke@0
   357
            cache[index].event = e;
duke@0
   358
            return true;
duke@0
   359
        }
duke@0
   360
        return false;
duke@0
   361
    }
duke@0
   362
duke@0
   363
    private boolean coalescePeerEvent(PeerEvent e) {
duke@0
   364
        EventQueueItem[] cache = ((Component)e.getSource()).eventCache;
duke@0
   365
        if (cache == null) {
duke@0
   366
            return false;
duke@0
   367
        }
duke@0
   368
        int index = eventToCacheIndex(e);
duke@0
   369
        if (index != -1 && cache[index] != null) {
duke@0
   370
            e = e.coalesceEvents((PeerEvent)cache[index].event);
duke@0
   371
            if (e != null) {
duke@0
   372
                cache[index].event = e;
duke@0
   373
                return true;
duke@0
   374
            } else {
duke@0
   375
                cache[index] = null;
duke@0
   376
            }
duke@0
   377
        }
duke@0
   378
        return false;
duke@0
   379
    }
duke@0
   380
duke@0
   381
    /*
duke@0
   382
     * Should avoid of calling this method by any means
duke@0
   383
     * as it's working time is dependant on EQ length.
duke@0
   384
     * In the wors case this method alone can slow down the entire application
duke@0
   385
     * 10 times by stalling the Event processing.
duke@0
   386
     * Only here by backward compatibility reasons.
duke@0
   387
     */
duke@0
   388
    private boolean coalesceOtherEvent(AWTEvent e, int priority) {
duke@0
   389
        int id = e.getID();
duke@0
   390
        Component source = (Component)e.getSource();
duke@0
   391
        for (EventQueueItem entry = queues[priority].head;
duke@0
   392
            entry != null; entry = entry.next)
duke@0
   393
        {
duke@0
   394
            // Give Component.coalesceEvents a chance
dav@553
   395
            if (entry.event.getSource() == source && entry.event.getID() == id) {
duke@0
   396
                AWTEvent coalescedEvent = source.coalesceEvents(
duke@0
   397
                    entry.event, e);
duke@0
   398
                if (coalescedEvent != null) {
duke@0
   399
                    entry.event = coalescedEvent;
duke@0
   400
                    return true;
duke@0
   401
                }
duke@0
   402
            }
duke@0
   403
        }
duke@0
   404
        return false;
duke@0
   405
    }
duke@0
   406
duke@0
   407
    private boolean coalesceEvent(AWTEvent e, int priority) {
duke@0
   408
        if (!(e.getSource() instanceof Component)) {
duke@0
   409
            return false;
duke@0
   410
        }
duke@0
   411
        if (e instanceof PeerEvent) {
duke@0
   412
            return coalescePeerEvent((PeerEvent)e);
duke@0
   413
        }
duke@0
   414
        // The worst case
duke@0
   415
        if (((Component)e.getSource()).isCoalescingEnabled()
duke@0
   416
            && coalesceOtherEvent(e, priority))
duke@0
   417
        {
duke@0
   418
            return true;
duke@0
   419
        }
duke@0
   420
        if (e instanceof PaintEvent) {
duke@0
   421
            return coalescePaintEvent((PaintEvent)e);
duke@0
   422
        }
duke@0
   423
        if (e instanceof MouseEvent) {
duke@0
   424
            return coalesceMouseEvent((MouseEvent)e);
duke@0
   425
        }
duke@0
   426
        return false;
duke@0
   427
    }
duke@0
   428
duke@0
   429
    private void cacheEQItem(EventQueueItem entry) {
duke@0
   430
        int index = eventToCacheIndex(entry.event);
duke@0
   431
        if (index != -1 && entry.event.getSource() instanceof Component) {
duke@0
   432
            Component source = (Component)entry.event.getSource();
duke@0
   433
            if (source.eventCache == null) {
duke@0
   434
                source.eventCache = new EventQueueItem[CACHE_LENGTH];
duke@0
   435
            }
duke@0
   436
            source.eventCache[index] = entry;
duke@0
   437
        }
duke@0
   438
    }
duke@0
   439
duke@0
   440
    private void uncacheEQItem(EventQueueItem entry) {
duke@0
   441
        int index = eventToCacheIndex(entry.event);
duke@0
   442
        if (index != -1 && entry.event.getSource() instanceof Component) {
duke@0
   443
            Component source = (Component)entry.event.getSource();
duke@0
   444
            if (source.eventCache == null) {
duke@0
   445
                return;
duke@0
   446
            }
duke@0
   447
            source.eventCache[index] = null;
duke@0
   448
        }
duke@0
   449
    }
duke@0
   450
duke@0
   451
    private static final int PAINT = 0;
duke@0
   452
    private static final int UPDATE = 1;
duke@0
   453
    private static final int MOVE = 2;
duke@0
   454
    private static final int DRAG = 3;
duke@0
   455
    private static final int PEER = 4;
duke@0
   456
    private static final int CACHE_LENGTH = 5;
duke@0
   457
duke@0
   458
    private static int eventToCacheIndex(AWTEvent e) {
duke@0
   459
        switch(e.getID()) {
duke@0
   460
        case PaintEvent.PAINT:
duke@0
   461
            return PAINT;
duke@0
   462
        case PaintEvent.UPDATE:
duke@0
   463
            return UPDATE;
duke@0
   464
        case MouseEvent.MOUSE_MOVED:
duke@0
   465
            return MOVE;
duke@0
   466
        case MouseEvent.MOUSE_DRAGGED:
duke@0
   467
            return DRAG;
duke@0
   468
        default:
duke@0
   469
            return e instanceof PeerEvent ? PEER : -1;
duke@0
   470
        }
duke@0
   471
    }
duke@0
   472
duke@0
   473
    /**
duke@0
   474
     * Returns whether an event is pending on any of the separate
duke@0
   475
     * Queues.
duke@0
   476
     * @return whether an event is pending on any of the separate Queues
duke@0
   477
     */
duke@0
   478
    private boolean noEvents() {
duke@0
   479
        for (int i = 0; i < NUM_PRIORITIES; i++) {
duke@0
   480
            if (queues[i].head != null) {
duke@0
   481
                return false;
duke@0
   482
            }
duke@0
   483
        }
duke@0
   484
duke@0
   485
        return true;
duke@0
   486
    }
jtulach@5229
   487
    
jtulach@5229
   488
    final AWTEvent getNextEvent(int id, boolean block) throws InterruptedException {
jtulach@5229
   489
        if (block) {
jtulach@5229
   490
            return (id == EventDispatchThread.ANY_EVENT) ? getNextEvent() : getNextEvent(id);
jtulach@5229
   491
        }
jtulach@5229
   492
        try {
jtulach@5229
   493
            pushPopLock.lock();
jtulach@5229
   494
            if (id == EventDispatchThread.ANY_EVENT) {
jtulach@5229
   495
                if (noEvents()) {
jtulach@5229
   496
                    return null;
jtulach@5229
   497
                }
jtulach@5229
   498
                // XXX: calls SunToolkit.flushPendingEvents under lock now
jtulach@5229
   499
                return getNextEvent();
jtulach@5229
   500
            } else {
jtulach@5229
   501
                AWTEvent peek = peekEvent(id);
jtulach@5229
   502
                if (peek == null) {
jtulach@5229
   503
                    return null;
jtulach@5229
   504
                }
jtulach@5229
   505
                // XXX: calls SunToolkit.flushPendingEvents under lock now
jtulach@5229
   506
                return getNextEvent(id);
jtulach@5229
   507
            }
jtulach@5229
   508
        } finally {
jtulach@5229
   509
            pushPopLock.unlock();
jtulach@5229
   510
        }
jtulach@5229
   511
    }
duke@0
   512
duke@0
   513
    /**
duke@0
   514
     * Removes an event from the <code>EventQueue</code> and
duke@0
   515
     * returns it.  This method will block until an event has
duke@0
   516
     * been posted by another thread.
duke@0
   517
     * @return the next <code>AWTEvent</code>
duke@0
   518
     * @exception InterruptedException
duke@0
   519
     *            if any thread has interrupted this thread
duke@0
   520
     */
duke@0
   521
    public AWTEvent getNextEvent() throws InterruptedException {
duke@0
   522
        do {
duke@0
   523
            /*
duke@0
   524
             * SunToolkit.flushPendingEvents must be called outside
duke@0
   525
             * of the synchronized block to avoid deadlock when
duke@0
   526
             * event queues are nested with push()/pop().
duke@0
   527
             */
duke@0
   528
            SunToolkit.flushPendingEvents();
art@2003
   529
            pushPopLock.lock();
art@2003
   530
            try {
art@2551
   531
                AWTEvent event = getNextEventPrivate();
art@2551
   532
                if (event != null) {
art@2551
   533
                    return event;
duke@0
   534
                }
duke@0
   535
                AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
art@2003
   536
                pushPopCond.await();
art@2003
   537
            } finally {
art@2003
   538
                pushPopLock.unlock();
duke@0
   539
            }
duke@0
   540
        } while(true);
duke@0
   541
    }
duke@0
   542
art@2551
   543
    /*
art@2551
   544
     * Must be called under the lock. Doesn't call flushPendingEvents()
art@2551
   545
     */
art@2551
   546
    AWTEvent getNextEventPrivate() throws InterruptedException {
art@2551
   547
        for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
art@2551
   548
            if (queues[i].head != null) {
art@2551
   549
                EventQueueItem entry = queues[i].head;
art@2551
   550
                queues[i].head = entry.next;
art@2551
   551
                if (entry.next == null) {
art@2551
   552
                    queues[i].tail = null;
art@2551
   553
                }
art@2551
   554
                uncacheEQItem(entry);
art@2551
   555
                return entry.event;
art@2551
   556
            }
art@2551
   557
        }
art@2551
   558
        return null;
art@2551
   559
    }
art@2551
   560
duke@0
   561
    AWTEvent getNextEvent(int id) throws InterruptedException {
duke@0
   562
        do {
duke@0
   563
            /*
duke@0
   564
             * SunToolkit.flushPendingEvents must be called outside
duke@0
   565
             * of the synchronized block to avoid deadlock when
duke@0
   566
             * event queues are nested with push()/pop().
duke@0
   567
             */
duke@0
   568
            SunToolkit.flushPendingEvents();
art@2003
   569
            pushPopLock.lock();
art@2003
   570
            try {
duke@0
   571
                for (int i = 0; i < NUM_PRIORITIES; i++) {
duke@0
   572
                    for (EventQueueItem entry = queues[i].head, prev = null;
duke@0
   573
                         entry != null; prev = entry, entry = entry.next)
duke@0
   574
                    {
dav@553
   575
                        if (entry.event.getID() == id) {
duke@0
   576
                            if (prev == null) {
duke@0
   577
                                queues[i].head = entry.next;
duke@0
   578
                            } else {
duke@0
   579
                                prev.next = entry.next;
duke@0
   580
                            }
duke@0
   581
                            if (queues[i].tail == entry) {
duke@0
   582
                                queues[i].tail = prev;
duke@0
   583
                            }
duke@0
   584
                            uncacheEQItem(entry);
duke@0
   585
                            return entry.event;
duke@0
   586
                        }
duke@0
   587
                    }
duke@0
   588
                }
art@2003
   589
                waitForID = id;
art@2003
   590
                pushPopCond.await();
art@2003
   591
                waitForID = 0;
art@2003
   592
            } finally {
art@2003
   593
                pushPopLock.unlock();
duke@0
   594
            }
duke@0
   595
        } while(true);
duke@0
   596
    }
duke@0
   597
duke@0
   598
    /**
duke@0
   599
     * Returns the first event on the <code>EventQueue</code>
duke@0
   600
     * without removing it.
duke@0
   601
     * @return the first event
duke@0
   602
     */
art@2003
   603
    public AWTEvent peekEvent() {
art@2003
   604
        pushPopLock.lock();
art@2003
   605
        try {
art@2003
   606
            for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
art@2003
   607
                if (queues[i].head != null) {
art@2003
   608
                    return queues[i].head.event;
art@2003
   609
                }
duke@0
   610
            }
art@2003
   611
        } finally {
art@2003
   612
            pushPopLock.unlock();
duke@0
   613
        }
duke@0
   614
duke@0
   615
        return null;
duke@0
   616
    }
duke@0
   617
duke@0
   618
    /**
duke@0
   619
     * Returns the first event with the specified id, if any.
duke@0
   620
     * @param id the id of the type of event desired
duke@0
   621
     * @return the first event of the specified id or <code>null</code>
duke@0
   622
     *    if there is no such event
duke@0
   623
     */
art@2003
   624
    public AWTEvent peekEvent(int id) {
art@2003
   625
        pushPopLock.lock();
art@2003
   626
        try {
art@2003
   627
            for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
art@2003
   628
                EventQueueItem q = queues[i].head;
art@2003
   629
                for (; q != null; q = q.next) {
art@2003
   630
                    if (q.event.getID() == id) {
art@2003
   631
                        return q.event;
art@2003
   632
                    }
duke@0
   633
                }
duke@0
   634
            }
art@2003
   635
        } finally {
art@2003
   636
            pushPopLock.unlock();
duke@0
   637
        }
duke@0
   638
duke@0
   639
        return null;
duke@0
   640
    }
duke@0
   641
denis@3820
   642
    private static final JavaSecurityAccess javaSecurityAccess =
denis@3820
   643
        SharedSecrets.getJavaSecurityAccess();
denis@3820
   644
duke@0
   645
    /**
duke@0
   646
     * Dispatches an event. The manner in which the event is
duke@0
   647
     * dispatched depends upon the type of the event and the
duke@0
   648
     * type of the event's source object:
duke@0
   649
     * <p> </p>
duke@0
   650
     * <table border=1 summary="Event types, source types, and dispatch methods">
duke@0
   651
     * <tr>
duke@0
   652
     *     <th>Event Type</th>
duke@0
   653
     *     <th>Source Type</th>
duke@0
   654
     *     <th>Dispatched To</th>
duke@0
   655
     * </tr>
duke@0
   656
     * <tr>
duke@0
   657
     *     <td>ActiveEvent</td>
duke@0
   658
     *     <td>Any</td>
duke@0
   659
     *     <td>event.dispatch()</td>
duke@0
   660
     * </tr>
duke@0
   661
     * <tr>
duke@0
   662
     *     <td>Other</td>
duke@0
   663
     *     <td>Component</td>
duke@0
   664
     *     <td>source.dispatchEvent(AWTEvent)</td>
duke@0
   665
     * </tr>
duke@0
   666
     * <tr>
duke@0
   667
     *     <td>Other</td>
duke@0
   668
     *     <td>MenuComponent</td>
duke@0
   669
     *     <td>source.dispatchEvent(AWTEvent)</td>
duke@0
   670
     * </tr>
duke@0
   671
     * <tr>
duke@0
   672
     *     <td>Other</td>
duke@0
   673
     *     <td>Other</td>
duke@0
   674
     *     <td>No action (ignored)</td>
duke@0
   675
     * </tr>
duke@0
   676
     * </table>
duke@0
   677
     * <p> </p>
duke@0
   678
     * @param event an instance of <code>java.awt.AWTEvent</code>,
duke@0
   679
     *          or a subclass of it
duke@0
   680
     * @throws NullPointerException if <code>event</code> is <code>null</code>
duke@0
   681
     * @since           1.2
duke@0
   682
     */
denis@3820
   683
    protected void dispatchEvent(final AWTEvent event) {
denis@3820
   684
        final Object src = event.getSource();
denis@3820
   685
        final PrivilegedAction<Void> action = new PrivilegedAction<Void>() {
denis@3820
   686
            public Void run() {
denis@3820
   687
                dispatchEventImpl(event, src);
denis@3820
   688
                return null;
denis@3820
   689
            }
denis@3820
   690
        };
denis@3820
   691
denis@3820
   692
        final AccessControlContext stack = AccessController.getContext();
denis@3820
   693
        final AccessControlContext srcAcc = getAccessControlContextFrom(src);
denis@3820
   694
        final AccessControlContext eventAcc = event.getAccessControlContext();
denis@3820
   695
        if (srcAcc == null) {
denis@3820
   696
            javaSecurityAccess.doIntersectionPrivilege(action, stack, eventAcc);
denis@3820
   697
        } else {
denis@3820
   698
            javaSecurityAccess.doIntersectionPrivilege(
denis@3820
   699
                new PrivilegedAction<Void>() {
denis@3820
   700
                    public Void run() {
denis@3820
   701
                        javaSecurityAccess.doIntersectionPrivilege(action, eventAcc);
denis@3820
   702
                        return null;
denis@3820
   703
                    }
denis@3820
   704
                }, stack, srcAcc);
denis@3820
   705
        }
denis@3820
   706
    }
denis@3820
   707
denis@3820
   708
    private static AccessControlContext getAccessControlContextFrom(Object src) {
denis@3820
   709
        return src instanceof Component ?
denis@3820
   710
            ((Component)src).getAccessControlContext() :
denis@3820
   711
            src instanceof MenuComponent ?
denis@3820
   712
                ((MenuComponent)src).getAccessControlContext() :
denis@3820
   713
                src instanceof TrayIcon ?
denis@3820
   714
                    ((TrayIcon)src).getAccessControlContext() :
denis@3820
   715
                    null;
denis@3820
   716
    }
denis@3820
   717
denis@3820
   718
    /**
denis@3820
   719
     * Called from dispatchEvent() under a correct AccessControlContext
denis@3820
   720
     */
denis@3820
   721
    private void dispatchEventImpl(final AWTEvent event, final Object src) {
duke@0
   722
        event.isPosted = true;
duke@0
   723
        if (event instanceof ActiveEvent) {
duke@0
   724
            // This could become the sole method of dispatching in time.
duke@0
   725
            setCurrentEventAndMostRecentTimeImpl(event);
duke@0
   726
            ((ActiveEvent)event).dispatch();
duke@0
   727
        } else if (src instanceof Component) {
duke@0
   728
            ((Component)src).dispatchEvent(event);
duke@0
   729
            event.dispatched();
duke@0
   730
        } else if (src instanceof MenuComponent) {
duke@0
   731
            ((MenuComponent)src).dispatchEvent(event);
duke@0
   732
        } else if (src instanceof TrayIcon) {
duke@0
   733
            ((TrayIcon)src).dispatchEvent(event);
duke@0
   734
        } else if (src instanceof AWTAutoShutdown) {
duke@0
   735
            if (noEvents()) {
duke@0
   736
                dispatchThread.stopDispatching();
duke@0
   737
            }
duke@0
   738
        } else {
art@2551
   739
            if (eventLog.isLoggable(PlatformLogger.FINE)) {
art@2551
   740
                eventLog.fine("Unable to dispatch event: " + event);
art@2551
   741
            }
duke@0
   742
        }
duke@0
   743
    }
duke@0
   744
duke@0
   745
    /**
duke@0
   746
     * Returns the timestamp of the most recent event that had a timestamp, and
duke@0
   747
     * that was dispatched from the <code>EventQueue</code> associated with the
duke@0
   748
     * calling thread. If an event with a timestamp is currently being
duke@0
   749
     * dispatched, its timestamp will be returned. If no events have yet
duke@0
   750
     * been dispatched, the EventQueue's initialization time will be
duke@0
   751
     * returned instead.In the current version of
duke@0
   752
     * the JDK, only <code>InputEvent</code>s,
duke@0
   753
     * <code>ActionEvent</code>s, and <code>InvocationEvent</code>s have
duke@0
   754
     * timestamps; however, future versions of the JDK may add timestamps to
duke@0
   755
     * additional event types. Note that this method should only be invoked
duke@0
   756
     * from an application's {@link #isDispatchThread event dispatching thread}.
duke@0
   757
     * If this method is
duke@0
   758
     * invoked from another thread, the current system time (as reported by
duke@0
   759
     * <code>System.currentTimeMillis()</code>) will be returned instead.
duke@0
   760
     *
duke@0
   761
     * @return the timestamp of the last <code>InputEvent</code>,
duke@0
   762
     *         <code>ActionEvent</code>, or <code>InvocationEvent</code> to be
duke@0
   763
     *         dispatched, or <code>System.currentTimeMillis()</code> if this
duke@0
   764
     *         method is invoked on a thread other than an event dispatching
duke@0
   765
     *         thread
duke@0
   766
     * @see java.awt.event.InputEvent#getWhen
duke@0
   767
     * @see java.awt.event.ActionEvent#getWhen
duke@0
   768
     * @see java.awt.event.InvocationEvent#getWhen
duke@0
   769
     * @see #isDispatchThread
duke@0
   770
     *
duke@0
   771
     * @since 1.4
duke@0
   772
     */
duke@0
   773
    public static long getMostRecentEventTime() {
duke@0
   774
        return Toolkit.getEventQueue().getMostRecentEventTimeImpl();
duke@0
   775
    }
art@2003
   776
    private long getMostRecentEventTimeImpl() {
art@2003
   777
        pushPopLock.lock();
art@2003
   778
        try {
art@2003
   779
            return (Thread.currentThread() == dispatchThread)
art@2003
   780
                ? mostRecentEventTime
art@2003
   781
                : System.currentTimeMillis();
art@2003
   782
        } finally {
art@2003
   783
            pushPopLock.unlock();
art@2003
   784
        }
duke@0
   785
    }
duke@0
   786
duke@0
   787
    /**
duke@0
   788
     * @return most recent event time on all threads.
duke@0
   789
     */
art@2003
   790
    long getMostRecentEventTimeEx() {
art@2003
   791
        pushPopLock.lock();
art@2003
   792
        try {
art@2003
   793
            return mostRecentEventTime;
art@2003
   794
        } finally {
art@2003
   795
            pushPopLock.unlock();
art@2003
   796
        }
duke@0
   797
    }
duke@0
   798
duke@0
   799
    /**
duke@0
   800
     * Returns the the event currently being dispatched by the
duke@0
   801
     * <code>EventQueue</code> associated with the calling thread. This is
duke@0
   802
     * useful if a method needs access to the event, but was not designed to
duke@0
   803
     * receive a reference to it as an argument. Note that this method should
duke@0
   804
     * only be invoked from an application's event dispatching thread. If this
duke@0
   805
     * method is invoked from another thread, null will be returned.
duke@0
   806
     *
duke@0
   807
     * @return the event currently being dispatched, or null if this method is
duke@0
   808
     *         invoked on a thread other than an event dispatching thread
duke@0
   809
     * @since 1.4
duke@0
   810
     */
duke@0
   811
    public static AWTEvent getCurrentEvent() {
duke@0
   812
        return Toolkit.getEventQueue().getCurrentEventImpl();
duke@0
   813
    }
art@2003
   814
    private AWTEvent getCurrentEventImpl() {
art@2003
   815
        pushPopLock.lock();
art@2003
   816
        try {
art@2003
   817
                return (Thread.currentThread() == dispatchThread)
art@2003
   818
                ? ((AWTEvent)currentEvent.get())
art@2003
   819
                : null;
art@2003
   820
        } finally {
art@2003
   821
            pushPopLock.unlock();
art@2003
   822
        }
duke@0
   823
    }
duke@0
   824
duke@0
   825
    /**
duke@0
   826
     * Replaces the existing <code>EventQueue</code> with the specified one.
duke@0
   827
     * Any pending events are transferred to the new <code>EventQueue</code>
duke@0
   828
     * for processing by it.
duke@0
   829
     *
duke@0
   830
     * @param newEventQueue an <code>EventQueue</code>
duke@0
   831
     *          (or subclass thereof) instance to be use
duke@0
   832
     * @see      java.awt.EventQueue#pop
duke@0
   833
     * @throws NullPointerException if <code>newEventQueue</code> is <code>null</code>
duke@0
   834
     * @since           1.2
duke@0
   835
     */
art@2003
   836
    public void push(EventQueue newEventQueue) {
mchung@1729
   837
        if (eventLog.isLoggable(PlatformLogger.FINE)) {
mchung@1729
   838
            eventLog.fine("EventQueue.push(" + newEventQueue + ")");
duke@0
   839
        }
duke@0
   840
art@2003
   841
        pushPopLock.lock();
art@2003
   842
        try {
art@2551
   843
            EventQueue topQueue = this;
art@2551
   844
            while (topQueue.nextQueue != null) {
art@2551
   845
                topQueue = topQueue.nextQueue;
art@2551
   846
            }
art@2551
   847
art@2551
   848
            if ((topQueue.dispatchThread != null) &&
art@2551
   849
                (topQueue.dispatchThread.getEventQueue() == this))
art@2551
   850
            {
art@2551
   851
                newEventQueue.dispatchThread = topQueue.dispatchThread;
art@2551
   852
                topQueue.dispatchThread.setEventQueue(newEventQueue);
art@2003
   853
            }
duke@0
   854
duke@0
   855
            // Transfer all events forward to new EventQueue.
art@2551
   856
            while (topQueue.peekEvent() != null) {
duke@0
   857
                try {
art@2551
   858
                    // Use getNextEventPrivate() as it doesn't call flushPendingEvents()
art@2551
   859
                    newEventQueue.postEventPrivate(topQueue.getNextEventPrivate());
duke@0
   860
                } catch (InterruptedException ie) {
mchung@1729
   861
                    if (eventLog.isLoggable(PlatformLogger.FINE)) {
mchung@1729
   862
                        eventLog.fine("Interrupted push", ie);
duke@0
   863
                    }
duke@0
   864
                }
duke@0
   865
            }
duke@0
   866
art@2551
   867
            // Wake up EDT waiting in getNextEvent(), so it can
art@2551
   868
            // pick up a new EventQueue. Post the waking event before
art@2551
   869
            // topQueue.nextQueue is assigned, otherwise the event would
art@2551
   870
            // go newEventQueue
art@2551
   871
            topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
duke@0
   872
art@2551
   873
            newEventQueue.previousQueue = topQueue;
art@2551
   874
            topQueue.nextQueue = newEventQueue;
art@2551
   875
art@2551
   876
            AppContext appContext = AppContext.getAppContext();
art@2551
   877
            if (appContext.get(AppContext.EVENT_QUEUE_KEY) == topQueue) {
art@2551
   878
                appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
art@2003
   879
            }
duke@0
   880
jtulach@5229
   881
            signalAll();
art@2003
   882
        } finally {
art@2003
   883
            pushPopLock.unlock();
duke@0
   884
        }
duke@0
   885
    }
duke@0
   886
duke@0
   887
    /**
duke@0
   888
     * Stops dispatching events using this <code>EventQueue</code>.
duke@0
   889
     * Any pending events are transferred to the previous
duke@0
   890
     * <code>EventQueue</code> for processing.
duke@0
   891
     * <p>
duke@0
   892
     * Warning: To avoid deadlock, do not declare this method
duke@0
   893
     * synchronized in a subclass.
duke@0
   894
     *
duke@0
   895
     * @exception EmptyStackException if no previous push was made
duke@0
   896
     *  on this <code>EventQueue</code>
duke@0
   897
     * @see      java.awt.EventQueue#push
duke@0
   898
     * @since           1.2
duke@0
   899
     */
duke@0
   900
    protected void pop() throws EmptyStackException {
mchung@1729
   901
        if (eventLog.isLoggable(PlatformLogger.FINE)) {
mchung@1729
   902
            eventLog.fine("EventQueue.pop(" + this + ")");
duke@0
   903
        }
duke@0
   904
art@2003
   905
        pushPopLock.lock();
art@2003
   906
        try {
art@2551
   907
            EventQueue topQueue = this;
art@2551
   908
            while (topQueue.nextQueue != null) {
art@2551
   909
                topQueue = topQueue.nextQueue;
duke@0
   910
            }
art@2551
   911
            EventQueue prevQueue = topQueue.previousQueue;
art@2551
   912
            if (prevQueue == null) {
duke@0
   913
                throw new EmptyStackException();
duke@0
   914
            }
art@2551
   915
art@2551
   916
            topQueue.previousQueue = null;
art@2551
   917
            prevQueue.nextQueue = null;
duke@0
   918
duke@0
   919
            // Transfer all events back to previous EventQueue.
art@2551
   920
            while (topQueue.peekEvent() != null) {
duke@0
   921
                try {
art@2551
   922
                    prevQueue.postEventPrivate(topQueue.getNextEventPrivate());
duke@0
   923
                } catch (InterruptedException ie) {
mchung@1729
   924
                    if (eventLog.isLoggable(PlatformLogger.FINE)) {
mchung@1729
   925
                        eventLog.fine("Interrupted pop", ie);
duke@0
   926
                    }
duke@0
   927
                }
duke@0
   928
            }
art@2551
   929
art@2551
   930
            if ((topQueue.dispatchThread != null) &&
art@2551
   931
                (topQueue.dispatchThread.getEventQueue() == this))
art@2551
   932
            {
art@2551
   933
                prevQueue.dispatchThread = topQueue.dispatchThread;
art@2551
   934
                topQueue.dispatchThread.setEventQueue(prevQueue);
art@2551
   935
            }
art@2551
   936
duke@0
   937
            AppContext appContext = AppContext.getAppContext();
duke@0
   938
            if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
art@2551
   939
                appContext.put(AppContext.EVENT_QUEUE_KEY, prevQueue);
duke@0
   940
            }
duke@0
   941
art@2551
   942
            // Wake up EDT waiting in getNextEvent(), so it can
art@2551
   943
            // pick up a new EventQueue
art@2551
   944
            topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
art@2551
   945
jtulach@5229
   946
            signalAll();
art@2003
   947
        } finally {
art@2003
   948
            pushPopLock.unlock();
duke@0
   949
        }
duke@0
   950
    }
duke@0
   951
duke@0
   952
    /**
art@2728
   953
     * Creates a new {@code secondary loop} associated with this
art@2728
   954
     * event queue. Use the {@link SecondaryLoop#enter} and
art@2728
   955
     * {@link SecondaryLoop#exit} methods to start and stop the
art@2728
   956
     * event loop and dispatch the events from this queue.
art@2728
   957
     *
art@2728
   958
     * @return secondaryLoop A new secondary loop object, which can
art@2728
   959
     *                       be used to launch a new nested event
art@2728
   960
     *                       loop and dispatch events from this queue
art@2728
   961
     *
art@2728
   962
     * @see SecondaryLoop#enter
art@2728
   963
     * @see SecondaryLoop#exit
art@2728
   964
     *
art@2728
   965
     * @since 1.7
art@2728
   966
     */
art@2728
   967
    public SecondaryLoop createSecondaryLoop() {
art@2728
   968
        return createSecondaryLoop(null, null, 0);
art@2728
   969
    }
art@2728
   970
art@2728
   971
    SecondaryLoop createSecondaryLoop(Conditional cond, EventFilter filter, long interval) {
art@2728
   972
        pushPopLock.lock();
art@2728
   973
        try {
art@2728
   974
            if (nextQueue != null) {
art@2728
   975
                // Forward the request to the top of EventQueue stack
art@2728
   976
                return nextQueue.createSecondaryLoop(cond, filter, interval);
art@2728
   977
            }
art@2728
   978
            if (dispatchThread == null) {
art@2728
   979
                initDispatchThread();
art@2728
   980
            }
art@2728
   981
            return new WaitDispatchSupport(dispatchThread, cond, filter, interval);
art@2728
   982
        } finally {
art@2728
   983
            pushPopLock.unlock();
art@2728
   984
        }
art@2728
   985
    }
art@2728
   986
art@2728
   987
    /**
duke@0
   988
     * Returns true if the calling thread is
duke@0
   989
     * {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s
duke@0
   990
     * dispatch thread. Use this method to ensure that a particular
duke@0
   991
     * task is being executed (or not being) there.
duke@0
   992
     * <p>
duke@0
   993
     * Note: use the {@link #invokeLater} or {@link #invokeAndWait}
duke@0
   994
     * methods to execute a task in
duke@0
   995
     * {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s
duke@0
   996
     * dispatch thread.
duke@0
   997
     * <p>
duke@0
   998
     *
duke@0
   999
     * @return true if running in
duke@0
  1000
     * {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s
duke@0
  1001
     * dispatch thread
duke@0
  1002
     * @see             #invokeLater
duke@0
  1003
     * @see             #invokeAndWait
duke@0
  1004
     * @see             Toolkit#getSystemEventQueue
duke@0
  1005
     * @since           1.2
duke@0
  1006
     */
duke@0
  1007
    public static boolean isDispatchThread() {
duke@0
  1008
        EventQueue eq = Toolkit.getEventQueue();
art@2003
  1009
        return eq.isDispatchThreadImpl();
art@2003
  1010
    }
art@2003
  1011
art@2003
  1012
    final boolean isDispatchThreadImpl() {
art@2003
  1013
        EventQueue eq = this;
art@2003
  1014
        pushPopLock.lock();
art@2003
  1015
        try {
art@2003
  1016
            EventQueue next = eq.nextQueue;
art@2003
  1017
            while (next != null) {
art@2003
  1018
                eq = next;
art@2003
  1019
                next = eq.nextQueue;
art@2003
  1020
            }
art@2003
  1021
            return (Thread.currentThread() == eq.dispatchThread);
art@2003
  1022
        } finally {
art@2003
  1023
            pushPopLock.unlock();
duke@0
  1024
        }
duke@0
  1025
    }
duke@0
  1026
duke@0
  1027
    final void initDispatchThread() {
art@2003
  1028
        pushPopLock.lock();
art@2003
  1029
        try {
dcherepanov@1760
  1030
            AppContext appContext = AppContext.getAppContext();
dcherepanov@1760
  1031
            if (dispatchThread == null && !threadGroup.isDestroyed() && !appContext.isDisposed()) {
art@2551
  1032
                dispatchThread = AccessController.doPrivileged(
art@2551
  1033
                    new PrivilegedAction<EventDispatchThread>() {
art@2551
  1034
                        public EventDispatchThread run() {
duke@0
  1035
                            EventDispatchThread t =
duke@0
  1036
                                new EventDispatchThread(threadGroup,
duke@0
  1037
                                                        name,
jtulach@5229
  1038
                                                        EventQueue.this,
jtulach@5229
  1039
                                                        classLoader
jtulach@5229
  1040
                                );
duke@0
  1041
                            return t;
duke@0
  1042
                        }
art@2551
  1043
                    }
art@2551
  1044
                );
duke@0
  1045
                AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
duke@0
  1046
            }
art@2003
  1047
        } finally {
art@2003
  1048
            pushPopLock.unlock();
duke@0
  1049
        }
duke@0
  1050
    }
duke@0
  1051
anthony@4611
  1052
    final boolean detachDispatchThread(EventDispatchThread edt, boolean forceDetach) {
art@2003
  1053
        /*
art@2003
  1054
         * This synchronized block is to secure that the event dispatch
art@2003
  1055
         * thread won't die in the middle of posting a new event to the
art@2003
  1056
         * associated event queue. It is important because we notify
art@2003
  1057
         * that the event dispatch thread is busy after posting a new event
art@2003
  1058
         * to its queue, so the EventQueue.dispatchThread reference must
art@2003
  1059
         * be valid at that point.
art@2003
  1060
         */
art@2003
  1061
        pushPopLock.lock();
art@2003
  1062
        try {
art@2551
  1063
            if (edt == dispatchThread) {
art@2003
  1064
                /*
art@2551
  1065
                 * Don't detach the thread if any events are pending. Not
art@2551
  1066
                 * sure if it's a possible scenario, though.
art@2003
  1067
                 *
art@2003
  1068
                 * Fix for 4648733. Check both the associated java event
art@2003
  1069
                 * queue and the PostEventQueue.
art@2003
  1070
                 */
anthony@4611
  1071
                if (!forceDetach && (peekEvent() != null) || !SunToolkit.isPostEventQueueEmpty()) {
art@2551
  1072
                    return false;
art@2003
  1073
                }
art@2551
  1074
                dispatchThread = null;
art@2003
  1075
            }
art@2551
  1076
            AWTAutoShutdown.getInstance().notifyThreadFree(edt);
art@2551
  1077
            return true;
art@2003
  1078
        } finally {
art@2003
  1079
            pushPopLock.unlock();
art@2003
  1080
        }
duke@0
  1081
    }
duke@0
  1082
duke@0
  1083
    /*
duke@0
  1084
     * Gets the <code>EventDispatchThread</code> for this
duke@0
  1085
     * <code>EventQueue</code>.
duke@0
  1086
     * @return the event dispatch thread associated with this event queue
duke@0
  1087
     *         or <code>null</code> if this event queue doesn't have a
duke@0
  1088
     *         working thread associated with it
duke@0
  1089
     * @see    java.awt.EventQueue#initDispatchThread
duke@0
  1090
     * @see    java.awt.EventQueue#detachDispatchThread
duke@0
  1091
     */
duke@0
  1092
    final EventDispatchThread getDispatchThread() {
art@2003
  1093
        pushPopLock.lock();
art@2003
  1094
        try {
art@2003
  1095
            return dispatchThread;
art@2003
  1096
        } finally {
art@2003
  1097
            pushPopLock.unlock();
art@2003
  1098
        }
duke@0
  1099
    }
duke@0
  1100
duke@0
  1101
    /*
duke@0
  1102
     * Removes any pending events for the specified source object.
duke@0
  1103
     * If removeAllEvents parameter is <code>true</code> then all
duke@0
  1104
     * events for the specified source object are removed, if it
duke@0
  1105
     * is <code>false</code> then <code>SequencedEvent</code>, <code>SentEvent</code>,
duke@0
  1106
     * <code>FocusEvent</code>, <code>WindowEvent</code>, <code>KeyEvent</code>,
duke@0
  1107
     * and <code>InputMethodEvent</code> are kept in the queue, but all other
duke@0
  1108
     * events are removed.
duke@0
  1109
     *
duke@0
  1110
     * This method is normally called by the source's
duke@0
  1111
     * <code>removeNotify</code> method.
duke@0
  1112
     */
duke@0
  1113
    final void removeSourceEvents(Object source, boolean removeAllEvents) {
duke@0
  1114
        SunToolkit.flushPendingEvents();
art@2003
  1115
        pushPopLock.lock();
art@2003
  1116
        try {
duke@0
  1117
            for (int i = 0; i < NUM_PRIORITIES; i++) {
duke@0
  1118
                EventQueueItem entry = queues[i].head;
duke@0
  1119
                EventQueueItem prev = null;
duke@0
  1120
                while (entry != null) {
duke@0
  1121
                    if ((entry.event.getSource() == source)
duke@0
  1122
                        && (removeAllEvents
duke@0
  1123
                            || ! (entry.event instanceof SequencedEvent
duke@0
  1124
                                  || entry.event instanceof SentEvent
duke@0
  1125
                                  || entry.event instanceof FocusEvent
duke@0
  1126
                                  || entry.event instanceof WindowEvent
duke@0
  1127
                                  || entry.event instanceof KeyEvent
duke@0
  1128
                                  || entry.event instanceof InputMethodEvent)))
duke@0
  1129
                    {
duke@0
  1130
                        if (entry.event instanceof SequencedEvent) {
duke@0
  1131
                            ((SequencedEvent)entry.event).dispose();
duke@0
  1132
                        }
duke@0
  1133
                        if (entry.event instanceof SentEvent) {
duke@0
  1134
                            ((SentEvent)entry.event).dispose();
duke@0
  1135
                        }
duke@0
  1136
                        if (prev == null) {
duke@0
  1137
                            queues[i].head = entry.next;
duke@0
  1138
                        } else {
duke@0
  1139
                            prev.next = entry.next;
duke@0
  1140
                        }
duke@0
  1141
                        uncacheEQItem(entry);
duke@0
  1142
                    } else {
duke@0
  1143
                        prev = entry;
duke@0
  1144
                    }
duke@0
  1145
                    entry = entry.next;
duke@0
  1146
                }
duke@0
  1147
                queues[i].tail = prev;
duke@0
  1148
            }
art@2003
  1149
        } finally {
art@2003
  1150
            pushPopLock.unlock();
duke@0
  1151
        }
duke@0
  1152
    }
duke@0
  1153
duke@0
  1154
    static void setCurrentEventAndMostRecentTime(AWTEvent e) {
duke@0
  1155
        Toolkit.getEventQueue().setCurrentEventAndMostRecentTimeImpl(e);
duke@0
  1156
    }
art@2003
  1157
    private void setCurrentEventAndMostRecentTimeImpl(AWTEvent e) {
art@2003
  1158
        pushPopLock.lock();
art@2003
  1159
        try {
art@2003
  1160
            if (Thread.currentThread() != dispatchThread) {
art@2003
  1161
                return;
art@2003
  1162
            }
art@2003
  1163
art@2003
  1164
            currentEvent = new WeakReference(e);
art@2003
  1165
art@2003
  1166
            // This series of 'instanceof' checks should be replaced with a
art@2003
  1167
            // polymorphic type (for example, an interface which declares a
art@2003
  1168
            // getWhen() method). However, this would require us to make such
art@2003
  1169
            // a type public, or to place it in sun.awt. Both of these approaches
art@2003
  1170
            // have been frowned upon. So for now, we hack.
art@2003
  1171
            //
art@2003
  1172
            // In tiger, we will probably give timestamps to all events, so this
art@2003
  1173
            // will no longer be an issue.
art@2003
  1174
            long mostRecentEventTime2 = Long.MIN_VALUE;
art@2003
  1175
            if (e instanceof InputEvent) {
art@2003
  1176
                InputEvent ie = (InputEvent)e;
art@2003
  1177
                mostRecentEventTime2 = ie.getWhen();
art@2003
  1178
            } else if (e instanceof InputMethodEvent) {
art@2003
  1179
                InputMethodEvent ime = (InputMethodEvent)e;
art@2003
  1180
                mostRecentEventTime2 = ime.getWhen();
art@2003
  1181
            } else if (e instanceof ActionEvent) {
art@2003
  1182
                ActionEvent ae = (ActionEvent)e;
art@2003
  1183
                mostRecentEventTime2 = ae.getWhen();
art@2003
  1184
            } else if (e instanceof InvocationEvent) {
art@2003
  1185
                InvocationEvent ie = (InvocationEvent)e;
art@2003
  1186
                mostRecentEventTime2 = ie.getWhen();
art@2003
  1187
            }
art@2003
  1188
            mostRecentEventTime = Math.max(mostRecentEventTime, mostRecentEventTime2);
art@2003
  1189
        } finally {
art@2003
  1190
            pushPopLock.unlock();
duke@0
  1191
        }
duke@0
  1192
    }
duke@0
  1193
duke@0
  1194
    /**
duke@0
  1195
     * Causes <code>runnable</code> to have its <code>run</code>
duke@0
  1196
     * method called in the {@link #isDispatchThread dispatch thread} of
duke@0
  1197
     * {@link Toolkit#getSystemEventQueue the system EventQueue}.
duke@0
  1198
     * This will happen after all pending events are processed.
duke@0
  1199
     *
duke@0
  1200
     * @param runnable  the <code>Runnable</code> whose <code>run</code>
duke@0
  1201
     *                  method should be executed
duke@0
  1202
     *                  asynchronously in the
duke@0
  1203
     *                  {@link #isDispatchThread event dispatch thread}
duke@0
  1204
     *                  of {@link Toolkit#getSystemEventQueue the system EventQueue}
duke@0
  1205
     * @see             #invokeAndWait
duke@0
  1206
     * @see             Toolkit#getSystemEventQueue
duke@0
  1207
     * @see             #isDispatchThread
duke@0
  1208
     * @since           1.2
duke@0
  1209
     */
duke@0
  1210
    public static void invokeLater(Runnable runnable) {
duke@0
  1211
        Toolkit.getEventQueue().postEvent(
duke@0
  1212
            new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
duke@0
  1213
    }
duke@0
  1214
duke@0
  1215
    /**
duke@0
  1216
     * Causes <code>runnable</code> to have its <code>run</code>
duke@0
  1217
     * method called in the {@link #isDispatchThread dispatch thread} of
duke@0
  1218
     * {@link Toolkit#getSystemEventQueue the system EventQueue}.
duke@0
  1219
     * This will happen after all pending events are processed.
duke@0
  1220
     * The call blocks until this has happened.  This method
duke@0
  1221
     * will throw an Error if called from the
duke@0
  1222
     * {@link #isDispatchThread event dispatcher thread}.
duke@0
  1223
     *
duke@0
  1224
     * @param runnable  the <code>Runnable</code> whose <code>run</code>
duke@0
  1225
     *                  method should be executed
duke@0
  1226
     *                  synchronously in the
duke@0
  1227
     *                  {@link #isDispatchThread event dispatch thread}
duke@0
  1228
     *                  of {@link Toolkit#getSystemEventQueue the system EventQueue}
duke@0
  1229
     * @exception       InterruptedException  if any thread has
duke@0
  1230
     *                  interrupted this thread
duke@0
  1231
     * @exception       InvocationTargetException  if an throwable is thrown
duke@0
  1232
     *                  when running <code>runnable</code>
duke@0
  1233
     * @see             #invokeLater
duke@0
  1234
     * @see             Toolkit#getSystemEventQueue
duke@0
  1235
     * @see             #isDispatchThread
duke@0
  1236
     * @since           1.2
duke@0
  1237
     */
duke@0
  1238
    public static void invokeAndWait(Runnable runnable)
duke@0
  1239
             throws InterruptedException, InvocationTargetException {
duke@0
  1240
duke@0
  1241
        if (EventQueue.isDispatchThread()) {
duke@0
  1242
            throw new Error("Cannot call invokeAndWait from the event dispatcher thread");
duke@0
  1243
        }
duke@0
  1244
duke@0
  1245
        class AWTInvocationLock {}
duke@0
  1246
        Object lock = new AWTInvocationLock();
duke@0
  1247
duke@0
  1248
        InvocationEvent event =
duke@0
  1249
            new InvocationEvent(Toolkit.getDefaultToolkit(), runnable, lock,
duke@0
  1250
                                true);
duke@0
  1251
duke@0
  1252
        synchronized (lock) {
duke@0
  1253
            Toolkit.getEventQueue().postEvent(event);
dcherepanov@1931
  1254
            while (!event.isDispatched()) {
dcherepanov@1931
  1255
                lock.wait();
dcherepanov@1931
  1256
            }
duke@0
  1257
        }
duke@0
  1258
duke@0
  1259
        Throwable eventThrowable = event.getThrowable();
duke@0
  1260
        if (eventThrowable != null) {
duke@0
  1261
            throw new InvocationTargetException(eventThrowable);
duke@0
  1262
        }
duke@0
  1263
    }
duke@0
  1264
duke@0
  1265
    /*
duke@0
  1266
     * Called from PostEventQueue.postEvent to notify that a new event
duke@0
  1267
     * appeared. First it proceeds to the EventQueue on the top of the
duke@0
  1268
     * stack, then notifies the associated dispatch thread if it exists
duke@0
  1269
     * or starts a new one otherwise.
duke@0
  1270
     */
duke@0
  1271
    private void wakeup(boolean isShutdown) {
art@2003
  1272
        pushPopLock.lock();
art@2003
  1273
        try {
duke@0
  1274
            if (nextQueue != null) {
duke@0
  1275
                // Forward call to the top of EventQueue stack.
duke@0
  1276
                nextQueue.wakeup(isShutdown);
duke@0
  1277
            } else if (dispatchThread != null) {
jtulach@5229
  1278
                signalAll();
duke@0
  1279
            } else if (!isShutdown) {
duke@0
  1280
                initDispatchThread();
duke@0
  1281
            }
art@2003
  1282
        } finally {
art@2003
  1283
            pushPopLock.unlock();
duke@0
  1284
        }
duke@0
  1285
    }
jtulach@5229
  1286
jtulach@5229
  1287
    private void signalAll() {
jtulach@5229
  1288
        pushPopCond.signalAll();
jtulach@5229
  1289
        
jtulach@5229
  1290
        // new event delivered - requesting new processing
jtulach@5229
  1291
        // of pending events
jtulach@5229
  1292
        dispatchThread.processEvents();
jtulach@5229
  1293
    }
duke@0
  1294
}
duke@0
  1295
/**
duke@0
  1296
 * The Queue object holds pointers to the beginning and end of one internal
duke@0
  1297
 * queue. An EventQueue object is composed of multiple internal Queues, one
duke@0
  1298
 * for each priority supported by the EventQueue. All Events on a particular
duke@0
  1299
 * internal Queue have identical priority.
duke@0
  1300
 */
duke@0
  1301
class Queue {
duke@0
  1302
    EventQueueItem head;
duke@0
  1303
    EventQueueItem tail;
duke@0
  1304
}