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