/************************************************************************** * Parts copyright (c) 2001, 2002, 2003 by Punch Telematix. All rights * * reserved. * * Parts copyright (c) 2004 by Chris Gray, /k/ Embedded Java Solutions. * * All rights reserved. * * * * Redistribution and use in source and binary forms, with or without * * modification, are permitted provided that the following conditions * * are met: * * 1. Redistributions of source code must retain the above copyright * * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * * notice, this list of conditions and the following disclaimer in the * * documentation and/or other materials provided with the distribution. * * 3. Neither the name of Punch Telematix or of /k/ Embedded Java Solutions* * nor the names of other contributors may be used to endorse or promote* * products derived from this software without specific prior written * * permission. * * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL PUNCH TELEMATIX, /K/ EMBEDDED JAVA SOLUTIONS OR OTHER * * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **************************************************************************/ package java.awt; import java.util.ArrayList; import java.util.EmptyStackException; import java.util.Stack; import java.awt.event.*; import com.acunia.wonka.rudolph.peers.*; import com.acunia.wonka.rudolph.*; /** ** A device-independent structure for queueing AWT events. ** Note that this implementation is really only intended for internal use ** by Rudolph, and may not behave as expected if used by other code. <= FIXME */ public class EventQueue { /** ** If wonka.rudolph.queue.events is true (the default), keyboard/pointer ** events are enqueued by the scanner thread (Haigha) and dequeued by the ** dispatching thread (Hatta). If wonka.rudolph.queue.events=false, ** the scanner thread dispatches events directly. */ protected static boolean queueing_enabled = !"false".equalsIgnoreCase(System.getProperty("wonka.rudolph.queue.events", "true").trim()); /** ** The logic for coalesceEvents() is executed iff both ** wonka.rudolph.queue.events and wonka.rudolph.coalesce.events are true. ** Defaults to true, can be turned off using system property ** wonka.rudolph.coalesce.events=false. ** (For historical reasons we also allow coalescing to be turned off using ** wonka.rudolph.coalesce.event=false). */ private static boolean coalescing_enabled = queueing_enabled && !"false".equalsIgnoreCase(System.getProperty("wonka.rudolph.coalesce.events", "true").trim()) && !"false".equalsIgnoreCase(System.getProperty("wonka.rudolph.coalesce.event", "true").trim()); /** ** A native AWTEvent which was detected by Event.c and which should be ** appended to the queue when postNativeEvent() is called. */ private AWTEvent nativeAWTEvent; /** ** The ArrayList used to hold the queue of events. */ private ArrayList queue; /** ** A stack used by the push() and pop() methods of this class. */ private static Stack queueStack = new Stack(); /** * Constructor * @status Complient with java specs * @remark Complient with java specs */ public EventQueue() { // We create the queue even if queueing isn't enabled; makes life so much easier ... queue = new ArrayList(); /* if (!queueing_enabled) { System.out.println(this + ": event queueing is disabled"); } if (!coalescing_enabled) { System.out.println(this + ": coalesceEvents() is disabled"); } */ } /** ** Calls the dispatchEvent method of the event's source, passing the ** event as parameter. Events whose source is not a subclass of ** Component are silently ignored. ** N.B. FIXME This method should be protected, but is made public so that ** it can be called by com.acunia.wonka.rudolph.Dispatcher. The clean ** solution is to move the dispatching code into the java.awt package ... */ public void dispatchEvent(AWTEvent event) { Object source = event.getSource(); if (source instanceof Component) { ((Component)source).dispatchEvent(event); } } /** * Get the next event from the queue. If the queue is empty, this method * blocks until an event is available. If event queueing is disabled, * this method just blocks forever. * * @status Complient with java specs * @remark Complient with java specs */ public synchronized AWTEvent getNextEvent() throws InterruptedException { while (queue.isEmpty()) { //try { wait(1000); //} //catch (InterruptedException ie) {} } AWTEvent event = (AWTEvent) queue.get(queue.size() - 1); queue.remove(queue.size() - 1); return event; } /** ** Returns the first event on the event queue, or null if there is none. */ public synchronized AWTEvent peekEvent() { if (queue.isEmpty()) { return null; } return (AWTEvent) queue.get(queue.size() - 1); } public synchronized AWTEvent peekEvent(int id) { System.out.println("EventQueue.peekEvent(id): TODO!"); return null; } /** * Post a native event. The event to be posted is in nativeAWTEvent. * @status Complient with java specs * @remark Complient with java specs */ public void postNativeEvent() { try { if (nativeAWTEvent != null) { postEvent(nativeAWTEvent); nativeAWTEvent = null; } } catch (Throwable t) { t.printStackTrace(); } } /** ** Post an event to the queue, or dispatch it directly if event queueing ** is disabled. ** If menu is open and the new event does not come from a MenuItemComponent ** or MenuWindow then the open menu is first closed. If event queueing is ** disabled the event is then dispatched immediately. Otherwise, if event ** coalescing is enabled the new event is compared with each item currently ** in the queue (most recent first) to see if there is another event with ** the same source and ID; if so then the source Component's coalesceEvents() ** method is called with the old and new events as parameters. If ** coalesceEvents() returns non-null, then the AWTEvent returned overwrites ** the event in the queue; otherwise the search continues. If no matching ** event is found, or all calls to coalesceEvents() return null, or event ** coalescing is disabled, the new event is appended to the queue. */ public void postEvent(AWTEvent newEvent) { int newEventID = newEvent.getID(); Component newEventSource = (Component)newEvent.getSource(); if(newEventID == MouseEvent.MOUSE_PRESSED) { if(DefaultMenu.menuOpened) { if(!((newEventSource instanceof MenuItemComponent) || (newEventSource instanceof MenuWindow)) && DefaultMenu.lastMenuOpened != null) { ((DefaultMenu)DefaultMenu.lastMenuOpened.getPeer()).closeChildren(); ((DefaultMenu)DefaultMenu.lastMenuOpened.getPeer()).closeParents(); ((DefaultMenu)DefaultMenu.lastMenuOpened.getPeer()).close(); DefaultMenu.menuOpened = false; } } } if (!queueing_enabled) { dispatchEvent(newEvent); return; } synchronized (this) { if (coalescing_enabled) { for (int i = queue.size() - 1; i >= 0; --i) { AWTEvent oldEvent = (AWTEvent)queue.get(i); if (oldEvent.getID() == newEventID && oldEvent.getSource() == newEventSource) { AWTEvent mergedEvent = newEventSource.coalesceEvents(oldEvent, newEvent); if (mergedEvent != null) { queue.set(i, mergedEvent); notifyAll(); return; } } } } queue.add(0, newEvent); notifyAll(); } } /** ** Returns true iff the current thread is an AWT event dispatch thread. ** Works for Rudolph, but may not work for user-created event handlers. */ public static boolean isDispatchThread() { return com.acunia.wonka.rudolph.Dispatcher.isDispatchThread(Thread.currentThread()); } /** ** Push an event queue onto the stack. The new queue inherits all ** existing events. Untested? */ public void push(EventQueue newEventQueue) { Dispatcher dispatcher = new com.acunia.wonka.rudolph.Dispatcher(null); dispatcher.start(); queueStack.push(dispatcher); } /** ** Pop an event queue onto the stack. The previous queue inherits all ** existing events. Untested? */ protected void pop() throws EmptyStackException { Dispatcher dispatcher = (Dispatcher)queueStack.pop(); dispatcher.stop(); } }