Milán Major

netscape-revival

1 branch
Code

sun-java/classsrc/sun/awt/ScreenUpdater.java

/*
 * @(#)ScreenUpdater.java	1.10 95/08/30  
 *
 * Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Permission to use, copy, modify, and distribute this software
 * and its documentation for NON-COMMERCIAL purposes and without
 * fee is hereby granted provided that this copyright notice
 * appears in all copies. Please refer to the file "copyright.html"
 * for further important copyright and licensing information.
 *
 * 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.
 */

package sun.awt;

import java.lang.SecurityManager;

class ScreenUpdaterEntry {
    UpdateClient client;
    long when;
    ScreenUpdaterEntry next;
    Object arg;

    ScreenUpdaterEntry(UpdateClient client, long when, Object arg, ScreenUpdaterEntry next) {
	this.client = client;
	this.when = when;
	this.arg = arg;
	this.next = next;
    }
}

/**
 * A seperate low priority thread that warns clients
 * when they need to update the screen. Clients that
 * need a wakeup call need to call Notify().
 *
 * @version 	1.10, 30 Aug 1995
 * @author 	Arthur van Hoff
 */
public
class ScreenUpdater extends Thread {
    private final int PRIORITY = Thread.NORM_PRIORITY - 1;
    private ScreenUpdaterEntry first;

    static ThreadGroup findSystemThreadGroup() {
	// This hack was put in so that the ScreenUpdater didn't get put in some
	// applet's thread group, and would consequently get killed when the applet
	// was killed. Take it out when Sun delivers a fix. -Warren
	Thread thread = Thread.currentThread();
	ThreadGroup group = thread.getThreadGroup();
	while (group != null && !group.getName().equals("main")) {
	    group = group.getParent();
	}
	return group;
    }

    static ScreenUpdater newScreenUpdater() {
	SecurityManager.setScopePermission();
        return new ScreenUpdater(findSystemThreadGroup(), "ScreenUpdater");
    }

    /**
     * The screen updater. 
     */
    public final static ScreenUpdater updater = newScreenUpdater();

    /**
     * Constructor. Starts the thread.
     */
    private ScreenUpdater(ThreadGroup group, String name) {
	super(group, name);
	start();
    }

    /**
     * Constructor. Starts the thread.
     */
    private ScreenUpdater() {
	start();
    }

    /**
     * Update the next client
     */
    private synchronized ScreenUpdaterEntry nextEntry() throws InterruptedException {
	while (true) {
	    ScreenUpdaterEntry entry;
	    if (first == null) {
		entry = null;
		wait();
		continue;
	    }

	    long delay = first.when - System.currentTimeMillis();
	    if (delay <= 0) {
		entry = first;
		first = first.next;
		return entry;
	    }

	    entry = null;
	    wait(delay);
	}
    }

    /**
     * The main body of the screen updater.
     */
    public void run() {
	SecurityManager.setScopePermission();
	setName("ScreenUpdater");

	try {
	    while (true) {
		setPriority(PRIORITY);
		ScreenUpdaterEntry entry = nextEntry();
		setPriority(entry.client.updatePriority());

		try {
		    entry.client.updateClient(entry.arg);
		} catch (Throwable e) {
		    e.printStackTrace();
		}

		// Because this thread is permanent, we don't want to defeat
		// the garbage collector by having dangling references to
		// objects we no longer care about. Clear out entry so that
		// when we go back to sleep in nextEntry we won't hold a
		// dangling reference to the previous entry we processed.
		entry = null;
	    }
	} catch (InterruptedException e) {
	}
    }

    /**
     * Notify the screen updater that a client needs
     * updating. As soon as the screen updater is
     * scheduled to run it will ask all of clients that
     * need updating to update the screen.
     */
    public void notify(UpdateClient client) {
	notify(client, 100, null);
    }
    public synchronized void notify(UpdateClient client, long delay) {
	notify(client, delay, null);
    }
    public synchronized void notify(UpdateClient client, long delay, Object arg) {
	long when = System.currentTimeMillis() + delay;
	long nextwhen = (first != null) ? first.when : -1L;

	if (first != null) {
	    if (first.client == client) {
		when = Math.min(first.when, when);
		first = first.next;
	    } else {
		for (ScreenUpdaterEntry e = first ; e.next != null ; e = e.next) {
		    if ((e.next.client == client) && (e.next.arg == arg)) {
			when = Math.min(e.next.when, when);
			e.next = e.next.next;
			break;
		    }
		}
	    }
	}

	if ((first == null) || (first.when > when)) {
	    first = new ScreenUpdaterEntry(client, when, arg, first);
	} else {
	    for (ScreenUpdaterEntry e = first ; ; e = e.next) {
		if ((e.next == null) || (e.next.when > when)) {
		    e.next = new ScreenUpdaterEntry(client, when, arg, e.next);
		    break;
		}
	    }
	}
	if (nextwhen != first.when) {
	    super.notify();
	}
    }
}