home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1998 November
/
Chip_1998-11_cd.bin
/
tema
/
Cafe
/
jfc.bin
/
TimerQueue.java
< prev
next >
Wrap
Text File
|
1998-02-26
|
11KB
|
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 com.sun.java.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();
}
}
}
}