home *** CD-ROM | disk | FTP | other *** search
Java Source | 1998-03-20 | 11.5 KB | 373 lines |
- /*
- * @(#)TimerQueue.java 1.18 98/02/02
- *
- * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
- *
- * This software is the confidential and proprietary information of Sun
- * Microsystems, Inc. ("Confidential Information"). You shall not
- * disclose such Confidential Information and shall use it only in
- * accordance with the terms of the license agreement you entered into
- * with Sun.
- *
- * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
- * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
- * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
- * THIS SOFTWARE OR ITS DERIVATIVES.
- *
- */
-
-
- /**
- * Internal class to manage all Timers using one thread.
- *
- *
- * @version 1.18 02/02/98
- * @author Dave Moore
- */
-
- package java.awt.swing;
-
- import java.util.*;
- import java.awt.Toolkit;
- import java.awt.Panel;
- import java.awt.Graphics;
- import java.awt.Window;
- import java.applet.Applet;
- import java.awt.Color;
-
- /** Private class to manage a queue of Timers. The Timers are chained
- * together in a linked list sorted by the order in which they will expire.
- */
- class TimerQueue implements Runnable {
- Timer firstTimer;
- boolean running;
-
- private static final Object sharedInstanceKey =
- new StringBuffer("TimerQueue.sharedInstanceKey");
- private static final Object expiredTimersKey =
- new StringBuffer("TimerQueue.expiredTimersKey");
-
- // This static variable can be shared across AppContexts.
- private static Hashtable timerPanels = null;
-
- public TimerQueue() {
- super();
-
- // Force Toolkit to be initialized before any timers go off,
- // so the Toolkit threads won't inherit the timer threads'
- // daemon state. This is a workaround for a bug in pre-1.1.4
- // Sun VMs (#4066493).
- Toolkit t = Toolkit.getDefaultToolkit();
-
- // Now start the TimerQueue thread.
- start();
- }
-
- public static TimerQueue sharedInstance() {
- synchronized (TimerQueue.class) {
- TimerQueue sharedInst = (TimerQueue)
- SwingUtilities.appContextGet(sharedInstanceKey);
- if (sharedInst == null) {
- sharedInst = new TimerQueue();
- SwingUtilities.appContextPut(sharedInstanceKey,
- sharedInst);
- }
- return sharedInst;
- }
- }
-
- synchronized void start() {
- if (running) {
- throw new RuntimeException("Can't start a TimerQueue that is already running");
- } else {
- Thread timerThread = new Thread(this, "TimerQueue");
-
- try {
- if (timerThread.getPriority() > Thread.MIN_PRIORITY)
- timerThread.setPriority(timerThread.getPriority() - 1);
-
- timerThread.setDaemon(true);
- } catch (SecurityException e) {
- }
- timerThread.start();
- running = true;
- }
- }
-
- synchronized void stop() {
- running = false;
- notify();
- }
-
- synchronized void addTimer(Timer timer, long expirationTime) {
- Timer previousTimer, nextTimer;
-
- // If the Timer is already in the queue, then ignore the add.
- if (timer.running) {
- return;
- }
-
- previousTimer = null;
- nextTimer = firstTimer;
-
- // Insert the Timer into the linked list in the order they will
- // expire. If two timers expire at the same time, put the newer entry
- // later so they expire in the order they came in.
-
- while (nextTimer != null) {
- if (nextTimer.expirationTime > expirationTime)
- break;
-
- previousTimer = nextTimer;
- nextTimer = nextTimer.nextTimer;
- }
-
- if (previousTimer == null)
- firstTimer = timer;
- else
- previousTimer.nextTimer = timer;
-
- timer.expirationTime = expirationTime;
- timer.nextTimer = nextTimer;
- timer.running = true;
- notify();
- }
-
- synchronized void removeTimer(Timer timer) {
- boolean found;
- Timer previousTimer, nextTimer;
-
- if (!timer.running)
- return;
-
- previousTimer = null;
- nextTimer = firstTimer;
- found = false;
-
- while (nextTimer != null) {
- if (nextTimer == timer) {
- found = true;
- break;
- }
-
- previousTimer = nextTimer;
- nextTimer = nextTimer.nextTimer;
- }
-
- if (!found)
- return;
-
- if (previousTimer == null)
- firstTimer = timer.nextTimer;
- else
- previousTimer.nextTimer = timer.nextTimer;
-
- timer.expirationTime = 0;
- timer.nextTimer = null;
- timer.running = false;
- }
-
- synchronized boolean containsTimer(Timer timer) {
- return timer.running;
- }
-
- // If there are a ton of timers, this method may never return. It loops
- // checking to see if the head of the Timer list has expired. If it has,
- // it posts the Timer and reschedules it if necessary.
-
- synchronized long postExpiredTimers() {
- long currentTime, timeToWait;
- Timer timer;
-
- // The timeToWait we return should never be negative and only be zero
- // when we have no Timers to wait for.
-
- do {
- timer = firstTimer;
- if (timer == null)
- return 0;
-
- currentTime = System.currentTimeMillis();
- timeToWait = timer.expirationTime - currentTime;
-
- if (timeToWait <= 0) {
- if (timerPanels != null) {
- /* If an applet is running we assume that access to the event
- * queue isn't allowed (see initAppletTimer). So instead of
- * posting a TimerEvent directly we add the timer to the
- * expiredTimers vector and queue an expose event by calling
- * timerPanel.repaint(). See the TimerPanel class.
- */
- TimerPanel timerPanel = getActiveTimerPanel();
- if (timerPanel != null) {
- Vector expiredTimers = getExpiredTimers();
- synchronized(expiredTimers) {
- expiredTimers.addElement(timer);
- }
- timerPanel.repaint();
- } else {
- /* There are applets, but none are currently visible:
- * drop event.
- */
- }
- } else {
- try {
- timer.post(); // have timer post an event
- } catch (SecurityException e) {}
- }
- removeTimer(timer);
-
- // This tries to keep the interval uniform at the cost of
- // drift.
-
- if (timer.isRepeats())
- addTimer(timer, currentTime + timer.getDelay());
-
- // Allow other threads to call addTimer() and removeTimer()
- // even when we are posting Timers like mad. Since the wait()
- // releases the lock, be sure not to maintain any state
- // between iterations of the loop.
-
- try {
- wait(1);
- } catch (InterruptedException e) {
- }
- }
- } while (timeToWait <= 0);
-
- return timeToWait;
- }
-
- public synchronized void run() {
- long timeToWait;
-
- while (running) {
- timeToWait = postExpiredTimers();
- try {
- wait(timeToWait);
- } catch (InterruptedException e) {
- }
- }
- }
-
- public synchronized String toString() {
- StringBuffer buf;
- Timer nextTimer;
-
- buf = new StringBuffer();
- buf.append("TimerQueue (");
-
- nextTimer = firstTimer;
- while (nextTimer != null) {
- buf.append(nextTimer.toString());
-
- nextTimer = nextTimer.nextTimer;
- if (nextTimer != null)
- buf.append(", ");
- }
-
- buf.append(")");
- return buf.toString();
- }
-
- /**
- * Applets can't post events to the system event queue (JDK1.1.x)
- * however a timers ActionListener.actionPerformed() method must be
- * run on the event dispatching thread. To enable this we create
- * an off screen java.awt.Panel whose update() method dequeues
- * timers that are ready to run, see the TimerPanel class below.
- * The TimerQueue.postTimers() method applies repaint to the panel
- * which causes a "paint" event to be queued for the event dispatching
- * thread. The event dispatching thread handles paint events
- * by calling Component.update().
- */
- static synchronized void initAppletTimer(JApplet applet) {
- Hashtable timerPanels = getTimerPanels();
- TimerPanel timerPanel = (TimerPanel)timerPanels.get(applet);
- if(timerPanel == null) {
- timerPanel = new TimerPanel();
- applet.getLayeredPane().add(timerPanel);
- timerPanels.put(applet,timerPanel);
- }
- }
-
- static synchronized void removeAppletTimer(JApplet applet) {
- getTimerPanels().remove(applet);
- }
-
- /**
- * Return the first usable timer panel
- */
- static synchronized TimerPanel getActiveTimerPanel() {
- Enumeration e = getTimerPanels().elements();
- TimerPanel tp;
- while(e.hasMoreElements()) {
- tp = (TimerPanel) e.nextElement();
- if(tp.isShowing())
- return tp;
- }
- return null;
- }
-
- static Hashtable getTimerPanels() {
- if (timerPanels == null) {
- timerPanels = new Hashtable(2);
- }
- return timerPanels;
- }
-
- static Vector getExpiredTimers() {
- Vector v = (Vector)SwingUtilities.appContextGet(expiredTimersKey);
- if (v == null) {
- v = new Vector();
- SwingUtilities.appContextPut(expiredTimersKey, v);
- }
- return v;
- }
-
- /**
- * @see #initAppletTimer
- */
- private static class TimerPanel extends Panel
- {
- TimerPanel () {
- super();
- setBounds(0, 0, 1, 1);
- //setBackground(Color.red);
- }
-
- public void update(Graphics g)
- {
- Vector expiredTimers =
- TimerQueue.sharedInstance().getExpiredTimers();
- Vector shouldFire;
-
- /* Copy the expiredTimers vector so we don't have to
- * synchronize access to it while firing the timers.
- */
- synchronized (expiredTimers) {
- if (expiredTimers.size() == 0) {
- return;
- }
- Enumeration e = expiredTimers.elements();
- shouldFire = new Vector();
- while(e.hasMoreElements()) {
- shouldFire.addElement(e.nextElement());
- }
- expiredTimers = new Vector();
- SwingUtilities.appContextPut(expiredTimersKey, expiredTimers);
- }
-
- /* Fire the timers
- */
- int nTimers = shouldFire.size();
- for(int i = 0; i < nTimers; i++) {
- ((Timer)shouldFire.elementAt(i)).fire();
- }
- }
- }
-
- }
-