GNU Classpath (0.20) | |
Frames | No Frames |
1: /* EventQueue.java -- 2: Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005 Free Software Foundation 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package java.awt; 40: 41: import java.awt.event.ActionEvent; 42: import java.awt.event.InputEvent; 43: import java.awt.event.InputMethodEvent; 44: import java.awt.event.InvocationEvent; 45: import java.lang.reflect.InvocationTargetException; 46: import java.util.EmptyStackException; 47: 48: /* Written using on-line Java 2 Platform Standard Edition v1.3 API 49: * Specification, as well as "The Java Class Libraries", 2nd edition 50: * (Addison-Wesley, 1998). 51: * Status: Believed complete, but untested. 52: */ 53: 54: /** 55: * This class manages a queue of <code>AWTEvent</code> objects that 56: * are posted to it. The AWT system uses only one event queue for all 57: * events. 58: * 59: * @author Bryce McKinlay 60: * @author Aaron M. Renn (arenn@urbanophile.com) 61: */ 62: public class EventQueue 63: { 64: private static final int INITIAL_QUEUE_DEPTH = 8; 65: private AWTEvent[] queue = new AWTEvent[INITIAL_QUEUE_DEPTH]; 66: 67: private int next_in = 0; // Index where next event will be added to queue 68: private int next_out = 0; // Index of next event to be removed from queue 69: 70: private EventQueue next; 71: private EventQueue prev; 72: private AWTEvent currentEvent; 73: private long lastWhen = System.currentTimeMillis(); 74: 75: private EventDispatchThread dispatchThread = new EventDispatchThread(this); 76: private boolean shutdown = false; 77: 78: synchronized private void setShutdown (boolean b) 79: { 80: shutdown = b; 81: } 82: 83: synchronized boolean isShutdown () 84: { 85: if (shutdown) 86: return true; 87: 88: // This is the exact self-shutdown condition specified in J2SE: 89: // http://java.sun.com/j2se/1.4.2/docs/api/java/awt/doc-files/AWTThreadIssues.html 90: 91: // FIXME: check somewhere that the native queue is empty 92: if (peekEvent() == null) 93: { 94: Frame[] frames = Frame.getFrames(); 95: for (int i = 0; i < frames.length; ++i) 96: if (frames[i].isDisplayable()) 97: return false; 98: return true; 99: } 100: return false; 101: } 102: 103: /** 104: * Initializes a new instance of <code>EventQueue</code>. 105: */ 106: public EventQueue() 107: { 108: } 109: 110: /** 111: * Returns the next event in the queue. This method will block until 112: * an event is available or until the thread is interrupted. 113: * 114: * @return The next event in the queue. 115: * 116: * @exception InterruptedException If this thread is interrupted while 117: * waiting for an event to be posted to the queue. 118: */ 119: public synchronized AWTEvent getNextEvent() 120: throws InterruptedException 121: { 122: if (next != null) 123: return next.getNextEvent(); 124: 125: while (next_in == next_out) 126: { 127: // We are not allowed to return null from this method, yet it 128: // is possible that we actually have run out of native events 129: // in the enclosing while() loop, and none of the native events 130: // happened to cause AWT events. We therefore ought to check 131: // the isShutdown() condition here, before risking a "native 132: // wait". If we check it before entering this function we may 133: // wait forever for events after the shutdown condition has 134: // arisen. 135: 136: if (isShutdown()) 137: throw new InterruptedException(); 138: 139: wait(); 140: } 141: 142: AWTEvent res = queue[next_out]; 143: 144: if (++next_out == queue.length) 145: next_out = 0; 146: return res; 147: } 148: 149: /** 150: * Returns the next event in the queue without removing it from the queue. 151: * This method will block until an event is available or until the thread 152: * is interrupted. 153: * 154: * @return The next event in the queue. 155: * @specnote Does not block. Returns null if there are no events on the 156: * queue. 157: */ 158: public synchronized AWTEvent peekEvent() 159: { 160: if (next != null) 161: return next.peekEvent(); 162: 163: if (next_in != next_out) 164: return queue[next_out]; 165: else 166: return null; 167: } 168: 169: /** 170: * Returns the next event in the queue that has the specified id 171: * without removing it from the queue. 172: * This method will block until an event is available or until the thread 173: * is interrupted. 174: * 175: * @param id The event id to return. 176: * 177: * @return The next event in the queue. 178: * 179: * @specnote Does not block. Returns null if there are no matching events 180: * on the queue. 181: */ 182: public synchronized AWTEvent peekEvent(int id) 183: { 184: if (next != null) 185: return next.peekEvent(id); 186: 187: int i = next_out; 188: while (i != next_in) 189: { 190: AWTEvent qevt = queue[i]; 191: if (qevt.id == id) 192: return qevt; 193: } 194: return null; 195: } 196: 197: /** 198: * Posts a new event to the queue. 199: * 200: * @param evt The event to post to the queue. 201: * 202: * @exception NullPointerException If event is null. 203: */ 204: public synchronized void postEvent(AWTEvent evt) 205: { 206: if (evt == null) 207: throw new NullPointerException(); 208: 209: if (next != null) 210: { 211: next.postEvent(evt); 212: return; 213: } 214: 215: /* Check for any events already on the queue with the same source 216: and ID. */ 217: int i = next_out; 218: while (i != next_in) 219: { 220: AWTEvent qevt = queue[i]; 221: Object src; 222: if (qevt.id == evt.id 223: && (src = qevt.getSource()) == evt.getSource() 224: && src instanceof Component) 225: { 226: /* If there are, call coalesceEvents on the source component 227: to see if they can be combined. */ 228: Component srccmp = (Component) src; 229: AWTEvent coalesced_evt = srccmp.coalesceEvents(qevt, evt); 230: if (coalesced_evt != null) 231: { 232: /* Yes. Replace the existing event with the combined event. */ 233: queue[i] = coalesced_evt; 234: return; 235: } 236: break; 237: } 238: if (++i == queue.length) 239: i = 0; 240: } 241: 242: queue[next_in] = evt; 243: if (++next_in == queue.length) 244: next_in = 0; 245: 246: if (next_in == next_out) 247: { 248: /* Queue is full. Extend it. */ 249: AWTEvent[] oldQueue = queue; 250: queue = new AWTEvent[queue.length * 2]; 251: 252: int len = oldQueue.length - next_out; 253: System.arraycopy(oldQueue, next_out, queue, 0, len); 254: if (next_out != 0) 255: System.arraycopy(oldQueue, 0, queue, len, next_out); 256: 257: next_out = 0; 258: next_in = oldQueue.length; 259: } 260: 261: if (dispatchThread == null || !dispatchThread.isAlive()) 262: { 263: dispatchThread = new EventDispatchThread(this); 264: dispatchThread.start(); 265: } 266: 267: notify(); 268: } 269: 270: /** 271: * Causes runnable to have its run method called in the dispatch thread of the 272: * EventQueue. This will happen after all pending events are processed. The 273: * call blocks until this has happened. This method will throw an Error if 274: * called from the event dispatcher thread. 275: * 276: * @exception InterruptedException If another thread has interrupted 277: * this thread. 278: * @exception InvocationTargetException If an exception is thrown when running 279: * runnable. 280: * 281: * @since 1.2 282: */ 283: public static void invokeAndWait(Runnable runnable) 284: throws InterruptedException, InvocationTargetException 285: { 286: if (isDispatchThread ()) 287: throw new Error("Can't call invokeAndWait from event dispatch thread"); 288: 289: EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); 290: Thread current = Thread.currentThread(); 291: 292: InvocationEvent ie = 293: new InvocationEvent(eq, runnable, current, true); 294: 295: synchronized (current) 296: { 297: eq.postEvent(ie); 298: current.wait(); 299: } 300: 301: Exception exception; 302: 303: if ((exception = ie.getException()) != null) 304: throw new InvocationTargetException(exception); 305: } 306: 307: /** 308: * This arranges for runnable to have its run method called in the 309: * dispatch thread of the EventQueue. This will happen after all 310: * pending events are processed. 311: * 312: * @since 1.2 313: */ 314: public static void invokeLater(Runnable runnable) 315: { 316: EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); 317: 318: InvocationEvent ie = 319: new InvocationEvent(eq, runnable, null, false); 320: 321: eq.postEvent(ie); 322: } 323: 324: /** 325: * Return true if the current thread is the current AWT event dispatch 326: * thread. 327: */ 328: public static boolean isDispatchThread() 329: { 330: EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); 331: 332: /* Find last EventQueue in chain */ 333: while (eq.next != null) 334: eq = eq.next; 335: 336: return (Thread.currentThread() == eq.dispatchThread); 337: } 338: 339: /** 340: * Return the event currently being dispatched by the event 341: * dispatch thread. If the current thread is not the event 342: * dispatch thread, this method returns null. 343: * 344: * @since 1.4 345: */ 346: public static AWTEvent getCurrentEvent() 347: { 348: EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); 349: Thread ct = Thread.currentThread(); 350: 351: /* Find out if this thread is the dispatch thread for any of the 352: EventQueues in the chain */ 353: while (ct != eq.dispatchThread) 354: { 355: // Try next EventQueue, if any 356: if (eq.next == null) 357: return null; // Not an event dispatch thread 358: eq = eq.next; 359: } 360: 361: return eq.currentEvent; 362: } 363: 364: /** 365: * Allows a custom EventQueue implementation to replace this one. 366: * All pending events are transferred to the new queue. Calls to postEvent, 367: * getNextEvent, and peekEvent and others are forwarded to the pushed queue 368: * until it is removed with a pop(). 369: * 370: * @exception NullPointerException if newEventQueue is null. 371: */ 372: public synchronized void push(EventQueue newEventQueue) 373: { 374: if (newEventQueue == null) 375: throw new NullPointerException (); 376: 377: /* Make sure we are at the top of the stack because callers can 378: only get a reference to the one at the bottom using 379: Toolkit.getDefaultToolkit().getSystemEventQueue() */ 380: if (next != null) 381: { 382: next.push (newEventQueue); 383: return; 384: } 385: 386: /* Make sure we have a live dispatch thread to drive the queue */ 387: if (dispatchThread == null) 388: dispatchThread = new EventDispatchThread(this); 389: 390: int i = next_out; 391: while (i != next_in) 392: { 393: newEventQueue.postEvent(queue[i]); 394: next_out = i; 395: if (++i == queue.length) 396: i = 0; 397: } 398: 399: next = newEventQueue; 400: newEventQueue.prev = this; 401: } 402: 403: /** Transfer any pending events from this queue back to the parent queue that 404: * was previously push()ed. Event dispatch from this queue is suspended. 405: * 406: * @exception EmptyStackException If no previous push was made on this 407: * EventQueue. 408: */ 409: protected void pop() throws EmptyStackException 410: { 411: if (prev == null) 412: throw new EmptyStackException(); 413: 414: /* The order is important here, we must get the prev lock first, 415: or deadlock could occur as callers usually get here following 416: prev's next pointer, and thus obtain prev's lock before trying 417: to get this lock. */ 418: synchronized (prev) 419: { 420: prev.next = next; 421: if (next != null) 422: next.prev = prev; 423: 424: synchronized (this) 425: { 426: int i = next_out; 427: while (i != next_in) 428: { 429: prev.postEvent(queue[i]); 430: next_out = i; 431: if (++i == queue.length) 432: i = 0; 433: } 434: // Empty the queue so it can be reused 435: next_in = 0; 436: next_out = 0; 437: 438: setShutdown(true); 439: dispatchThread = null; 440: this.notifyAll(); 441: } 442: } 443: } 444: 445: /** 446: * Dispatches an event. The manner in which the event is dispatched depends 447: * upon the type of the event and the type of the event's source object. 448: * 449: * @exception NullPointerException If event is null. 450: */ 451: protected void dispatchEvent(AWTEvent evt) 452: { 453: currentEvent = evt; 454: 455: if (evt instanceof InputEvent) 456: lastWhen = ((InputEvent) evt).getWhen(); 457: else if (evt instanceof ActionEvent) 458: lastWhen = ((ActionEvent) evt).getWhen(); 459: else if (evt instanceof InvocationEvent) 460: lastWhen = ((InvocationEvent) evt).getWhen(); 461: 462: if (evt instanceof ActiveEvent) 463: { 464: ActiveEvent active_evt = (ActiveEvent) evt; 465: active_evt.dispatch(); 466: } 467: else 468: { 469: Object source = evt.getSource(); 470: 471: if (source instanceof Component) 472: { 473: Component srccmp = (Component) source; 474: srccmp.dispatchEvent(evt); 475: } 476: else if (source instanceof MenuComponent) 477: { 478: MenuComponent srccmp = (MenuComponent) source; 479: srccmp.dispatchEvent(evt); 480: } 481: } 482: } 483: 484: /** 485: * Returns the timestamp of the most recent event that had a timestamp, or 486: * the initialization time of the event queue if no events have been fired. 487: * At present, only <code>InputEvent</code>s, <code>ActionEvent</code>s, 488: * <code>InputMethodEvent</code>s, and <code>InvocationEvent</code>s have 489: * timestamps, but this may be added to other events in future versions. 490: * If this is called by the event dispatching thread, it can be any 491: * (sequential) value, but to other threads, the safest bet is to return 492: * System.currentTimeMillis(). 493: * 494: * @return the most recent timestamp 495: * @see InputEvent#getWhen() 496: * @see ActionEvent#getWhen() 497: * @see InvocationEvent#getWhen() 498: * @see InputMethodEvent#getWhen() 499: * @since 1.4 500: */ 501: public static long getMostRecentEventTime() 502: { 503: EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); 504: if (Thread.currentThread() != eq.dispatchThread) 505: return System.currentTimeMillis(); 506: return eq.lastWhen; 507: } 508: }
GNU Classpath (0.20) |