| /* Copyright (C) 2000 Free Software Foundation |
| |
| This file is part of libgcj. |
| |
| This software is copyrighted work licensed under the terms of the |
| Libgcj License. Please consult the file "LIBGCJ_LICENSE" for |
| details. */ |
| |
| package java.awt; |
| |
| import java.awt.event.*; |
| import java.util.EmptyStackException; |
| import java.lang.reflect.InvocationTargetException; |
| |
| /* Written using on-line Java 2 Platform Standard Edition v1.3 API |
| * Specification, as well as "The Java Class Libraries", 2nd edition |
| * (Addison-Wesley, 1998). |
| * Status: Believed complete, but untested. Check FIXME's. |
| */ |
| |
| /** @author Bryce McKinlay */ |
| |
| public class EventQueue |
| { |
| private static final int INITIAL_QUEUE_DEPTH = 8; |
| private AWTEvent[] queue = new AWTEvent[INITIAL_QUEUE_DEPTH]; |
| |
| private int next_in = 0; // Index where next event will be added to queue |
| private int next_out = 0; // Index of next event to be removed from queue |
| |
| private EventQueue next; |
| private EventQueue prev; |
| |
| private EventDispatchThread dispatchThread = new EventDispatchThread(this); |
| |
| public EventQueue() |
| { |
| } |
| |
| public synchronized AWTEvent getNextEvent() |
| throws InterruptedException |
| { |
| if (next != null) |
| return next.getNextEvent(); |
| |
| while (next_in == next_out) |
| wait(); |
| |
| AWTEvent res = queue[next_out]; |
| |
| if (++next_out == queue.length) |
| next_out = 0; |
| return res; |
| } |
| |
| /** @specnote Does not block. Returns null if there are no events on the |
| * queue. |
| */ |
| public synchronized AWTEvent peekEvent() |
| { |
| if (next != null) |
| return next.peekEvent(); |
| |
| if (next_in != next_out) |
| return queue[next_out]; |
| else return null; |
| } |
| |
| /** @specnote Does not block. Returns null if there are no matching events |
| * on the queue. |
| */ |
| public synchronized AWTEvent peekEvent(int id) |
| { |
| if (next != null) |
| return next.peekEvent(id); |
| |
| int i = next_out; |
| while (i != next_in) |
| { |
| AWTEvent qevt = queue[i]; |
| if (qevt.id == id) |
| return qevt; |
| } |
| return null; |
| } |
| |
| public synchronized void postEvent(AWTEvent evt) |
| { |
| if (next != null) |
| { |
| next.postEvent(evt); |
| return; |
| } |
| // FIXME: Security checks? |
| |
| /* Check for any events already on the queue with the same source |
| and ID. */ |
| int i = next_out; |
| while (i != next_in) |
| { |
| AWTEvent qevt = queue[i]; |
| Object src; |
| if (qevt.id == evt.id |
| && (src = qevt.getSource()) == evt.getSource() |
| && src instanceof Component) |
| { |
| /* If there are, call coalesceEvents on the source component |
| to see if they can be combined. */ |
| Component srccmp = (Component) src; |
| AWTEvent coalesced_evt = srccmp.coalesceEvents(qevt, evt); |
| if (coalesced_evt != null) |
| { |
| /* Yes. Replace the existing event with the combined event. */ |
| queue[i] = coalesced_evt; |
| return; |
| } |
| break; |
| } |
| if (++i == queue.length) |
| i = 0; |
| } |
| |
| queue[next_in] = evt; |
| if (++next_in == queue.length) |
| next_in = 0; |
| |
| if (next_in == next_out) |
| { |
| /* Queue is full. Extend it. */ |
| AWTEvent[] oldQueue = queue; |
| queue = new AWTEvent[queue.length * 2]; |
| |
| int len = oldQueue.length - next_out; |
| System.arraycopy(oldQueue, next_out, queue, 0, len); |
| if (next_out != 0) |
| System.arraycopy(oldQueue, 0, queue, len, next_out); |
| |
| next_out = 0; |
| next_in = oldQueue.length; |
| } |
| notify(); |
| } |
| |
| /** @since JDK1.2 */ |
| public static void invokeAndWait(Runnable runnable) |
| throws InterruptedException, InvocationTargetException |
| { |
| EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); |
| Thread current = Thread.currentThread(); |
| if (current == eq.dispatchThread) |
| throw new Error("Can't call invokeAndWait from event dispatch thread"); |
| |
| InvocationEvent ie = |
| new InvocationEvent(eq, runnable, current, true); |
| |
| synchronized (current) |
| { |
| eq.postEvent(ie); |
| current.wait(); |
| } |
| |
| Exception exception; |
| |
| if ((exception = ie.getException()) != null) |
| throw new InvocationTargetException(exception); |
| } |
| |
| /** @since JDK1.2 */ |
| static void invokeLater(Runnable runnable) |
| { |
| EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); |
| |
| InvocationEvent ie = |
| new InvocationEvent(eq, runnable, null, false); |
| |
| eq.postEvent(ie); |
| } |
| |
| static boolean isDispatchThread() |
| { |
| EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); |
| return (Thread.currentThread() == eq.dispatchThread); |
| } |
| |
| /** Allows a custom EventQueue implementation to replace this one. |
| * All pending events are transferred to the new queue. Calls to postEvent, |
| * getNextEvent, and peekEvent are forwarded to the pushed queue until it |
| * is removed with a pop(). |
| */ |
| public synchronized void push(EventQueue newEventQueue) |
| { |
| int i = next_out; |
| while (i != next_in) |
| { |
| newEventQueue.postEvent(queue[i]); |
| next_out = i; |
| if (++i == queue.length) |
| i = 0; |
| } |
| |
| next = newEventQueue; |
| newEventQueue.prev = this; |
| } |
| |
| /** Transfer any pending events from this queue back to the parent queue that |
| * was previously push()ed. Event dispatch from this queue is suspended. */ |
| protected void pop() throws EmptyStackException |
| { |
| if (prev == null) |
| throw new EmptyStackException(); |
| |
| // Don't synchronize both this and prev at the same time, or deadlock could |
| // occur. |
| synchronized (prev) |
| { |
| prev.next = null; |
| } |
| |
| synchronized (this) |
| { |
| int i = next_out; |
| while (i != next_in) |
| { |
| prev.postEvent(queue[i]); |
| next_out = i; |
| if (++i == queue.length) |
| i = 0; |
| } |
| } |
| } |
| |
| protected void dispatchEvent(AWTEvent evt) |
| { |
| if (evt instanceof ActiveEvent) |
| { |
| ActiveEvent active_evt = (ActiveEvent) evt; |
| active_evt.dispatch(); |
| } |
| else |
| { |
| Object source = evt.getSource(); |
| |
| if (source instanceof Component) |
| { |
| Component srccmp = (Component) source; |
| srccmp.dispatchEvent(evt); |
| } |
| else if (source instanceof MenuComponent) |
| { |
| MenuComponent srccmp = (MenuComponent) source; |
| srccmp.dispatchEvent(evt); |
| } |
| } |
| } |
| } |