package java.awt;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.InputEvent;
import java.awt.event.InputMethodEvent;
import java.awt.event.InvocationEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.PaintEvent;
import java.awt.event.WindowEvent;
import java.awt.ActiveEvent;
import java.awt.peer.ComponentPeer;
import java.awt.peer.LightweightPeer;
import java.awt.TrayIcon;
import java.util.EmptyStackException;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import sun.awt.PeerEvent;
import sun.awt.SunToolkit;
import sun.awt.DebugHelper;
import sun.awt.AWTAutoShutdown;
import sun.awt.AppContext;
public class EventQueue {
private static final DebugHelper dbg = DebugHelper.create(EventQueue.class);
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
private static final int LOW_PRIORITY = 0;
private static final int NORM_PRIORITY = 1;
private static final int HIGH_PRIORITY = 2;
private static final int ULTIMATE_PRIORITY = 3;
private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1;
private Queue[] queues = new Queue[NUM_PRIORITIES];
private EventQueue nextQueue;
private EventQueue previousQueue;
private EventDispatchThread dispatchThread;
private final ThreadGroup threadGroup =
Thread.currentThread().getThreadGroup();
private final ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
private final static boolean debug = false;
private long mostRecentEventTime = System.currentTimeMillis();
private WeakReference currentEvent;
private int waitForID;
private final String name = "AWT-EventQueue-" + nextThreadNum();
public EventQueue() {
for (int i = 0; i < NUM_PRIORITIES; i++) {
queues[i] = new Queue();
}
}
public void postEvent(AWTEvent theEvent) {
SunToolkit.flushPendingEvents();
postEventPrivate(theEvent);
}
final void postEventPrivate(AWTEvent theEvent) {
theEvent.isPosted = true;
synchronized(this) {
if (dispatchThread == null && nextQueue == null) {
if (theEvent.getSource() == AWTAutoShutdown.getInstance()) {
return;
} else {
initDispatchThread();
}
}
if (nextQueue != null) {
nextQueue.postEventPrivate(theEvent);
return;
}
postEvent(theEvent, getPriority(theEvent));
}
}
private static int getPriority(AWTEvent theEvent) {
if (theEvent instanceof PeerEvent &&
(((PeerEvent)theEvent).getFlags() &
PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0)
{
return ULTIMATE_PRIORITY;
}
if (theEvent instanceof PeerEvent &&
(((PeerEvent)theEvent).getFlags() &
PeerEvent.PRIORITY_EVENT) != 0)
{
return HIGH_PRIORITY;
}
if (theEvent instanceof PeerEvent &&
(((PeerEvent)theEvent).getFlags() &
PeerEvent.LOW_PRIORITY_EVENT) != 0)
{
return LOW_PRIORITY;
}
int id = theEvent.getID();
if (id == PaintEvent.PAINT || id == PaintEvent.UPDATE) {
return LOW_PRIORITY;
}
return NORM_PRIORITY;
}
private void postEvent(AWTEvent theEvent, int priority) {
Object source = theEvent.getSource();
if (coalesceEvent(theEvent, priority)) {
return;
}
EventQueueItem newItem = new EventQueueItem(theEvent);
cacheEQItem(newItem);
boolean notifyID = (theEvent.getID() == this.waitForID);
if (queues[priority].head == null) {
boolean shouldNotify = noEvents();
queues[priority].head = queues[priority].tail = newItem;
if (shouldNotify) {
if (theEvent.getSource() != AWTAutoShutdown.getInstance()) {
AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
}
notifyAll();
} else if (notifyID) {
notifyAll();
}
} else {
queues[priority].tail.next = newItem;
queues[priority].tail = newItem;
if (notifyID) {
notifyAll();
}
}
}
private boolean coalescePaintEvent(PaintEvent e) {
ComponentPeer sourcePeer = ((Component)e.getSource()).peer;
if (sourcePeer != null) {
sourcePeer.coalescePaintEvent(e);
}
EventQueueItem[] cache = ((Component)e.getSource()).eventCache;
if (cache == null) {
return false;
}
int index = eventToCacheIndex(e);
if (index != -1 && cache[index] != null) {
PaintEvent merged = mergePaintEvents(e, (PaintEvent)cache[index].event);
if (merged != null) {
cache[index].event = merged;
return true;
}
}
return false;
}
private PaintEvent mergePaintEvents(PaintEvent a, PaintEvent b) {
Rectangle aRect = a.getUpdateRect();
Rectangle bRect = b.getUpdateRect();
if (bRect.contains(aRect)) {
return b;
}
if (aRect.contains(bRect)) {
return a;
}
return null;
}
private boolean coalesceMouseEvent(MouseEvent e) {
EventQueueItem[] cache = ((Component)e.getSource()).eventCache;
if (cache == null) {
return false;
}
int index = eventToCacheIndex(e);
if (index != -1 && cache[index] != null) {
cache[index].event = e;
return true;
}
return false;
}
private boolean coalescePeerEvent(PeerEvent e) {
EventQueueItem[] cache = ((Component)e.getSource()).eventCache;
if (cache == null) {
return false;
}
int index = eventToCacheIndex(e);
if (index != -1 && cache[index] != null) {
e = e.coalesceEvents((PeerEvent)cache[index].event);
if (e != null) {
cache[index].event = e;
return true;
} else {
cache[index] = null;
}
}
return false;
}
private boolean coalesceOtherEvent(AWTEvent e, int priority) {
int id = e.getID();
Component source = (Component)e.getSource();
for (EventQueueItem entry = queues[priority].head;
entry != null; entry = entry.next)
{
if (entry.event.getSource() == source && entry.id == id) {
AWTEvent coalescedEvent = source.coalesceEvents(
entry.event, e);
if (coalescedEvent != null) {
entry.event = coalescedEvent;
return true;
}
}
}
return false;
}
private boolean coalesceEvent(AWTEvent e, int priority) {
if (!(e.getSource() instanceof Component)) {
return false;
}
if (e instanceof PeerEvent) {
return coalescePeerEvent((PeerEvent)e);
}
if (((Component)e.getSource()).isCoalescingEnabled()
&& coalesceOtherEvent(e, priority))
{
return true;
}
if (e instanceof PaintEvent) {
return coalescePaintEvent((PaintEvent)e);
}
if (e instanceof MouseEvent) {
return coalesceMouseEvent((MouseEvent)e);
}
return false;
}
private void cacheEQItem(EventQueueItem entry) {
int index = eventToCacheIndex(entry.event);
if (index != -1 && entry.event.getSource() instanceof Component) {
Component source = (Component)entry.event.getSource();
if (source.eventCache == null) {
source.eventCache = new EventQueueItem[CACHE_LENGTH];
}
source.eventCache[index] = entry;
}
}
private void uncacheEQItem(EventQueueItem entry) {
int index = eventToCacheIndex(entry.event);
if (index != -1 && entry.event.getSource() instanceof Component) {
Component source = (Component)entry.event.getSource();
if (source.eventCache == null) {
return;
}
source.eventCache[index] = null;
}
}
private static final int PAINT = 0;
private static final int UPDATE = 1;
private static final int MOVE = 2;
private static final int DRAG = 3;
private static final int PEER = 4;
private static final int CACHE_LENGTH = 5;
private static int eventToCacheIndex(AWTEvent e) {
switch(e.getID()) {
case PaintEvent.PAINT:
return PAINT;
case PaintEvent.UPDATE:
return UPDATE;
case MouseEvent.MOUSE_MOVED:
return MOVE;
case MouseEvent.MOUSE_DRAGGED:
return DRAG;
default:
return e instanceof PeerEvent ? PEER : -1;
}
}
private boolean noEvents() {
for (int i = 0; i < NUM_PRIORITIES; i++) {
if (queues[i].head != null) {
return false;
}
}
return true;
}
public AWTEvent getNextEvent() throws InterruptedException {
do {
SunToolkit.flushPendingEvents();
synchronized (this) {
for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
if (queues[i].head != null) {
EventQueueItem entry = queues[i].head;
queues[i].head = entry.next;
if (entry.next == null) {
queues[i].tail = null;
}
uncacheEQItem(entry);
return entry.event;
}
}
AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
wait();
}
} while(true);
}
AWTEvent getNextEvent(int id) throws InterruptedException {
do {
SunToolkit.flushPendingEvents();
synchronized (this) {
for (int i = 0; i < NUM_PRIORITIES; i++) {
for (EventQueueItem entry = queues[i].head, prev = null;
entry != null; prev = entry, entry = entry.next)
{
if (entry.id == id) {
if (prev == null) {
queues[i].head = entry.next;
} else {
prev.next = entry.next;
}
if (queues[i].tail == entry) {
queues[i].tail = prev;
}
uncacheEQItem(entry);
return entry.event;
}
}
}
this.waitForID = id;
wait();
this.waitForID = 0;
}
} while(true);
}
public synchronized AWTEvent peekEvent() {
for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
if (queues[i].head != null) {
return queues[i].head.event;
}
}
return null;
}
public synchronized AWTEvent peekEvent(int id) {
for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
EventQueueItem q = queues[i].head;
for (; q != null; q = q.next) {
if (q.id == id) {
return q.event;
}
}
}
return null;
}
protected void dispatchEvent(AWTEvent event) {
event.isPosted = true;
Object src = event.getSource();
if (event instanceof ActiveEvent) {
setCurrentEventAndMostRecentTimeImpl(event);
((ActiveEvent)event).dispatch();
} else if (src instanceof Component) {
((Component)src).dispatchEvent(event);
event.dispatched();
} else if (src instanceof MenuComponent) {
((MenuComponent)src).dispatchEvent(event);
} else if (src instanceof TrayIcon) {
((TrayIcon)src).dispatchEvent(event);
} else if (src instanceof AWTAutoShutdown) {
if (noEvents()) {
dispatchThread.stopDispatching();
}
} else {
System.err.println("unable to dispatch event: " + event);
}
}
public static long getMostRecentEventTime() {
return Toolkit.getEventQueue().getMostRecentEventTimeImpl();
}
private synchronized long getMostRecentEventTimeImpl() {
return (Thread.currentThread() == dispatchThread)
? mostRecentEventTime
: System.currentTimeMillis();
}
synchronized long getMostRecentEventTimeEx() {
return mostRecentEventTime;
}
public static AWTEvent getCurrentEvent() {
return Toolkit.getEventQueue().getCurrentEventImpl();
}
private synchronized AWTEvent getCurrentEventImpl() {
return (Thread.currentThread() == dispatchThread)
? ((AWTEvent)currentEvent.get())
: null;
}
public synchronized void push(EventQueue newEventQueue) {
if (debug) {
System.out.println("EventQueue.push(" + newEventQueue + ")");
}
if (nextQueue != null) {
nextQueue.push(newEventQueue);
return;
}
synchronized (newEventQueue) {
while (peekEvent() != null) {
try {
newEventQueue.postEventPrivate(getNextEvent());
} catch (InterruptedException ie) {
if (debug) {
System.err.println("interrupted push:");
ie.printStackTrace(System.err);
}
}
}
newEventQueue.previousQueue = this;
}
if (dispatchThread != null) {
dispatchThread.stopDispatchingLater();
}
nextQueue = newEventQueue;
AppContext appContext = AppContext.getAppContext();
if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
}
}
protected void pop() throws EmptyStackException {
if (debug) {
System.out.println("EventQueue.pop(" + this + ")");
}
EventQueue prev = previousQueue;
synchronized ((prev != null) ? prev : this) {
synchronized(this) {
if (nextQueue != null) {
nextQueue.pop();
return;
}
if (previousQueue == null) {
throw new EmptyStackException();
}
previousQueue.nextQueue = null;
while (peekEvent() != null) {
try {
previousQueue.postEventPrivate(getNextEvent());
} catch (InterruptedException ie) {
if (debug) {
System.err.println("interrupted pop:");
ie.printStackTrace(System.err);
}
}
}
AppContext appContext = AppContext.getAppContext();
if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
appContext.put(AppContext.EVENT_QUEUE_KEY, previousQueue);
}
previousQueue = null;
}
}
EventDispatchThread dt = this.dispatchThread;
if (dt != null) {
dt.stopDispatching(); }
}
public static boolean isDispatchThread() {
EventQueue eq = Toolkit.getEventQueue();
EventQueue next = eq.nextQueue;
while (next != null) {
eq = next;
next = eq.nextQueue;
}
return (Thread.currentThread() == eq.dispatchThread);
}
final void initDispatchThread() {
synchronized (this) {
AppContext appContext = AppContext.getAppContext();
if (dispatchThread == null && !threadGroup.isDestroyed() && !appContext.isDisposed()) {
dispatchThread = (EventDispatchThread)
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
EventDispatchThread t =
new EventDispatchThread(threadGroup,
name,
EventQueue.this);
t.setContextClassLoader(classLoader);
t.setPriority(Thread.NORM_PRIORITY + 1);
t.setDaemon(false);
return t;
}
});
AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
dispatchThread.start();
}
}
}
final void detachDispatchThread() {
dispatchThread = null;
}
final EventDispatchThread getDispatchThread() {
return dispatchThread;
}
final void removeSourceEvents(Object source, boolean removeAllEvents) {
SunToolkit.flushPendingEvents();
synchronized (this) {
for (int i = 0; i < NUM_PRIORITIES; i++) {
EventQueueItem entry = queues[i].head;
EventQueueItem prev = null;
while (entry != null) {
if ((entry.event.getSource() == source)
&& (removeAllEvents
|| ! (entry.event instanceof SequencedEvent
|| entry.event instanceof SentEvent
|| entry.event instanceof FocusEvent
|| entry.event instanceof WindowEvent
|| entry.event instanceof KeyEvent
|| entry.event instanceof InputMethodEvent)))
{
if (entry.event instanceof SequencedEvent) {
((SequencedEvent)entry.event).dispose();
}
if (entry.event instanceof SentEvent) {
((SentEvent)entry.event).dispose();
}
if (prev == null) {
queues[i].head = entry.next;
} else {
prev.next = entry.next;
}
uncacheEQItem(entry);
} else {
prev = entry;
}
entry = entry.next;
}
queues[i].tail = prev;
}
}
}
static void setCurrentEventAndMostRecentTime(AWTEvent e) {
Toolkit.getEventQueue().setCurrentEventAndMostRecentTimeImpl(e);
}
private synchronized void setCurrentEventAndMostRecentTimeImpl(AWTEvent e)
{
if (Thread.currentThread() != dispatchThread) {
return;
}
currentEvent = new WeakReference(e);
long mostRecentEventTime2 = Long.MIN_VALUE;
if (e instanceof InputEvent) {
InputEvent ie = (InputEvent)e;
mostRecentEventTime2 = ie.getWhen();
} else if (e instanceof InputMethodEvent) {
InputMethodEvent ime = (InputMethodEvent)e;
mostRecentEventTime2 = ime.getWhen();
} else if (e instanceof ActionEvent) {
ActionEvent ae = (ActionEvent)e;
mostRecentEventTime2 = ae.getWhen();
} else if (e instanceof InvocationEvent) {
InvocationEvent ie = (InvocationEvent)e;
mostRecentEventTime2 = ie.getWhen();
}
mostRecentEventTime = Math.max(mostRecentEventTime, mostRecentEventTime2);
}
public static void invokeLater(Runnable runnable) {
Toolkit.getEventQueue().postEvent(
new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
}
public static void invokeAndWait(Runnable runnable)
throws InterruptedException, InvocationTargetException {
if (EventQueue.isDispatchThread()) {
throw new Error("Cannot call invokeAndWait from the event dispatcher thread");
}
class AWTInvocationLock {}
Object lock = new AWTInvocationLock();
InvocationEvent event =
new InvocationEvent(Toolkit.getDefaultToolkit(), runnable, lock,
true);
synchronized (lock) {
Toolkit.getEventQueue().postEvent(event);
lock.wait();
}
Throwable eventThrowable = event.getThrowable();
if (eventThrowable != null) {
throw new InvocationTargetException(eventThrowable);
}
}
private void wakeup(boolean isShutdown) {
synchronized(this) {
if (nextQueue != null) {
nextQueue.wakeup(isShutdown);
} else if (dispatchThread != null) {
notifyAll();
} else if (!isShutdown) {
initDispatchThread();
}
}
}
}
class Queue {
EventQueueItem head;
EventQueueItem tail;
}
class EventQueueItem {
AWTEvent event;
int id;
EventQueueItem next;
EventQueueItem(AWTEvent evt) {
event = evt;
id = evt.getID();
}
}