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