Files
gzz-mirror/Java/ZZUpdateManager.java
2026-09-14 20:19:29 -04:00

254 lines
7.1 KiB
Java

/*
ZZUpdateManager.java
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.util.*;
/** A single global instance to manage the updating of views.
* The views are set in a priority order so that even if the user is
* moving fast, he will get an immediate response through the less important
* views not being updated at each step.
*/
public class ZZUpdateManager implements Runnable {
public static final String rcsid = "$Id: ZZUpdateManager.java,v 1.29 2001/02/27 08:36:15 raulir Exp $";
public static boolean dbg = false;
private static void p(String s) { if(dbg) ZZLogger.log(s); }
private static void pa(String s) { ZZLogger.log(s); }
/** The order of views, from the most important to the least.
*/
private static Vector ordering = new Vector();
/** Whether an update is currently in progress, through
* a view being painted.
*/
private static boolean updating;
private static int disabled;
private static boolean noanimation;
/** Whether the currently ongoing update should stop immediately
* and restart from the beginning
*/
private static boolean restartUpd = false;
public static void addView(ZZView v) { ordering.addElement(v); }
public static void rmView(ZZView v) { ordering.removeElement(v); }
/** Set the view that has the privilege of animating the next
* update.
* Setting this to null will make all views update fast.
*/
public static void setFast(ZZView v) {
p("Setfast: "+v + " cur: "+ordering.elementAt(0));
if(v == null) {
noanimation = true;
return;
}
if(ordering.elementAt(0)!=v) {
ordering.removeElement(v);
ordering.insertElementAt(v, 0);
}
}
/* Called by a space to inform that some cells have been
* changed
*/
public static void chg() {
p("UPDMANAGER CHG");
if(restartUpd) return;
synchronized(ordering) {
restartUpd = true;
ordering.notifyAll();
}
p("UPDMANAGER CHGOUT");
}
/** Disable all updating of views.
* XXX While frozen, might consider updating e.g. once every
* second...
*/
public static void freeze() {
p("ZZUpdatemanager freeze");
synchronized(ordering) { disabled++; }
p("ZZUpdatemanager frozen "+disabled);
}
/** Enable again the updating of views. */
public static void thaw() {
p("ZZUpdatemanager thaw");
synchronized(ordering) {
if(disabled<=0)
throw new ZZError("thaw() without matching freeze()!");
if(--disabled==0) ordering.notifyAll();
}
p("ZZUpdatemanager thawed "+disabled);
}
static ZZUpdateManager m = new ZZUpdateManager();
static Thread t= new Thread(m);
static {
p("STARTORDTHREAD");
t.start();
}
public void run() {
try {
int ind = -1;
boolean reras = true;
boolean anim = false;
Vector curUpdVec = new Vector();
while(true) {
p("STARTORD");
synchronized(ordering) {
p("STARTORD SYNCHED");
if(!anim) ind++;
updating = false;
try {
while(disabled>0 || (ind>=curUpdVec.size() && !restartUpd)) {
p("STARTORD "+disabled+" "+ind+" "+restartUpd);
ordering.wait();
}
} catch(Exception e) {
ZZLogger.exc(e);
}
p("STARTORD WAITED");
updating = true;
if(restartUpd) {
restartUpd = false;
curUpdVec = (Vector)ordering.clone();
ind = 0;
reras = true;
// Try to make the system stop less at
// inconvenient, unequal times.
// System.gc(); // doesn't seem to work.
}
if(curUpdVec.size()==0) continue;
}
try {
p("STARTORD DOING " + ind + " "+ curUpdVec+" "+reras);
ZZView v = (ZZView)curUpdVec.elementAt(ind);
if(ind==0) { // animate if need be
if(reras) {
timeNewCycle();
anim = v.reraster();
reras = false;
}
float fract = timeAnimFract();
if(fract >= 1 || !anim || noanimation) {
fract = 1;
anim = false;
noanimation = false;
}
p("PN 0: "+fract+" "+anim+" "+lastStart+" "+millis);
// XXX paintNow() is not really safe here, because ZZ code
// in general isn't thread-safe. If Kaffe someday provides
// EventQueue.invokeAndWait(), this could be fixed.
boolean care = ZZDrawing.instance.enableQuality(false);
v.paintNow((float)fract);
if (fract == 1 && care) {
ZZDrawing.instance.enableQuality(true);
v.paintNow(1.0f);
}
} else {
p("PN: "+ind);
v.reraster();
// XXX Ditto.
boolean care = ZZDrawing.instance.enableQuality(false);
v.paintNow(1.0f);
if (care) {
ZZDrawing.instance.enableQuality(true);
v.paintNow(1.0f);
}
}
((java.awt.Component)v).getToolkit().sync();
} catch(ZZError e) {
ZZLogger.exc(e);
System.out.println("EXCEPTION WHILE UPDATING!");
}
p("STARTORD DONE: anim "+anim);
}
} finally {
System.out.println("HELP! UPDATE LOOP STOPPED. XXX");
}
}
static final long defmillis = 800;
/** The time before the next user event
* to try to be ready.
*/
static final long trybefore = 150;
/** The time to increment the interval with.
*/
static final long inctime = 80;
private static long lastStart = 0;
/** The interval between start and end of animation.
*/
private static long millis = defmillis;
/** Called when we begin a new animation. */
private void timeNewCycle() {
long cur = System.currentTimeMillis();
// Interval between start of last animation and start of the new one.
long sinceLast = cur-lastStart;
// sinceLast - millis = interval between end of last animation and
// start of the new one. We try to end the last animation
// trybefore ticks before the start of the new one, so if
// sinceLast - millis < trybefore, the animation takes too long.
if(sinceLast - millis < trybefore)
millis = sinceLast-trybefore; // Shorten the animation time.
// If the animation didn't take too long, and if it's at least a unit
// (inctime) shorter than it was by default, gradually lengthen it.
else if(millis < defmillis - inctime)
millis += inctime;
lastStart = cur;
}
private float timeAnimFract() {
long cur = System.currentTimeMillis();
double fract = 1.0;
// If we are animating at all (20 milliseconds is
// minimum time we try to use animation with),
// calculate the fraction of the animation we are at.
if(millis > 20)
fract = (cur-lastStart) / (double)millis;
// Test for a really weird JVM problem.
if(cur - lastStart >= millis && fract < 1) {
System.out.println("AAAARRRRRGGGHHH!!! Division problem "+ cur + " "+lastStart+" "+millis);
}
return (float)fract;
}
}