CCL Home Page
Up Directory CCL ScianEvents
/*ScianEvents.c
  Eric Pepke
  March 8, 1990
  Event stuff for scian
*/

#include "Scian.h"
#include "ScianTypes.h"
#include "ScianWindows.h"
#include "ScianEvents.h"
#include "ScianGarbageMan.h"
#include "ScianSockets.h"
#include "ScianScripts.h"
#include "ScianColors.h"
#include "ScianIDs.h"
#include "ScianTimers.h"
#include "ScianMainWindow.h"
#include "ScianObjWindows.h"
#include "ScianVisWindows.h"
#include "ScianPreferences.h"
#include "ScianObjFunctions.h"
#include "ScianDialogs.h"
#include "ScianDraw.h"
#include "ScianStyle.h"
#include "ScianLists.h"
#include "ScianObjWindows.h"
#include "ScianFontMappings.h"
#include "ScianMenus.h"

Bool inhibitOtherWindows = false;	/*Inhibits other windows*/
long lastAwake = MAXINT;
int settleEvents = 0;			/*Events to settle*/
ObjPtr dropObject = NULLOBJ;		/*Object to drop in window*/
int dropX, dropY;			/*Global coordinates of place to drop*/
#ifdef INTERACTIVE
int curMouse = LEFTMOUSE;		/*Current mouse button down*/
Bool interactiveMoving = false;		/*True iff moving interactively*/
Bool contextHelp = false;		/*Context sensitive help*/
#endif
#ifdef IRISNTSC
Bool NTSCOn = 0;				/*True iff NTSC is on*/
#endif
Bool stereoOn = 0;
long lastGC = 0;			/*Time of last garbage collection*/
#define GCEVERY	((HEARTBEAT) * 10)	/*One garbage collection per ten seconds*/
#define NAPEVERY ((HEARTBEAT) * 5)	/*Nap after 5 seconds*/
long defaultMonitor;			/*Default monitor*/
Event events[MAXNEVENTS];
int curEvent = 0;			/*Current and last events for queue*/
int lastEvent = 0;			/*Queue empty when they're the same*/
Bool knownUserEvent;			/*There is a user event known*/
ObjPtr drawLaterList;			/*List of things to draw later*/
long interactBegin;			/*Begin time of interaction*/
#define INTERACTDELAY	HEARTBEAT	/*Interaction end after a second*/

int lastDialValues[8] =			/*Last values for each dial*/
	{0, 0, 0, 0, 0, 0, 0, 0};

#define MAXNTASKS	100		/*Maximum # of tasks*/

TaskType doTasks[MAXNTASKS];		/*Tasks to do*/
int tasksLeft = 0;			/*Number of tasks left*/

#define MAXNDEFMES	100		/*Maximum # of deferred messages*/

int curDef = 0;				/*Current deferred message set*/
WinInfoPtr lastCursorWindow = 0;	/*Last cursor window*/

struct
    {
	ObjPtr object;			/*The object to send the message*/
	NameTyp message;		/*The message to send*/
    } defMessages[2][MAXNDEFMES];
int defMesLeft = 0;

#ifdef INTERACTIVE
long lastClickTime = 0;			/*The time the last click was done*/
long lastKeyTime = 0;			/*The last time of a keypress*/
int lastClickX, lastClickY;		/*The last click X and Y*/ 
int sentKey = 0;			/*Last key that has been sent*/
WinInfoPtr keyWindow = 0;		/*Window the last key was sent to*/
#endif

int running = 1;			/*True iff running*/

#ifdef INTERACTIVE
/*Values for mouse switchboard*/
#define MOUSEPRESS	1		/*Select, drag, etc. with mouse*/
#define MOUSEMENU	2		/*Bring up mouse menu*/
#define MOUSEROTATE	3		/*Rotate with the mouse*/

/*Mouse switchboard*/
int mouseSwitchboard[3] =
    {
	MOUSEMENU,
	MOUSEROTATE,
	MOUSEPRESS
    };
#endif

char *functionKeyNames[FK_N];		/*Names of extra function keys*/

#ifdef HAVE_PROTOTYPES
void NeedToDrawFullQuality(ObjPtr object)
#else
void NeedToDrawFullQuality(object)
ObjPtr object;
#endif
/*Requests that an object needs to be drawn in full quality later*/
{
    if (interactiveMoving)
    {
	if (WhichListIndex(drawLaterList, object) < 0)
	{
	    PrefixList(drawLaterList, object);
	}
    }
    else
    {
	ImInvalid(object);
    }
}

#ifdef HAVE_PROTOTYPES
void DrawInteractive(Bool whether)
#else
void DrawInteractive(whether)
Bool whether;
#endif
/*Sets interactive drawing to whether*/
{
    if (whether)
    {
	/*Mark this point in time as beginning of interaction*/
	struct tms buffer;

	interactBegin = times(&buffer);
    }
    else if (whether != interactiveMoving)
    {
	/*Inval everything on drawLaterList before making transition*/
	ThingListPtr runner;

	runner = LISTOF(drawLaterList);
	while(runner)
	{
	    ImInvalid(runner -> thing);
	    runner = runner -> next;
	}
	EmptyList(drawLaterList);
    }
    interactiveMoving = whether;
}

void DoTask(task)
TaskType task;
/*Asks the system to do task at its earliest possible convenience*/
{
    doTasks[tasksLeft++] = task;
}

#ifdef HAVE_PROTOTYPES
void DeferMessage(ObjPtr object, NameTyp message)
#else
void DeferMessage(object, message)
ObjPtr object;
NameTyp message;
#endif
/*Asks the system to do task at its earliest possible convenience*/
{
    defMessages[curDef][defMesLeft] . object = object;
    defMessages[curDef][defMesLeft] . message = message;
    ++defMesLeft;
}

void DeferUniqueMessage(object, message)
ObjPtr object;
int message;
/*Asks the system to do task at its earliest possible convenience*/
{
    int k;
    for (k = 0; k < defMesLeft; ++k)
    {
	if ((defMessages[curDef][k] . object == object) &&
	    (defMessages[curDef][k] . message == message))
	{
	    return;
	}
    }

    defMessages[curDef][defMesLeft] . object = object;
    defMessages[curDef][defMesLeft] . message = message;
    ++defMesLeft;
}

void DoUniqueTask(task)
TaskType task;
/*Asks the system to do task at its earliest possible convenience,
  but only if it hasn't already been requested*/
{
    int k;
    for (k = 0; k < tasksLeft; ++k)
    {
	if (doTasks[k] == task)
	{
	    return;
	}
    }
    doTasks[tasksLeft++] = task;
}

void DoQuit()
/*Asks to quit on the next loop*/
{
    running = 0;
}

ObjPtr QuitReply(window, button)
WinInfoPtr window;
int button;
{
    if (button == 0)
    {
	DoQuit();
    }
}

void MaybeQuit()
/*Maybe quits on the next loop*/
{
    if (OptionDown())
    {
	DoQuit();
    }
    else
    {
	WinInfoPtr alertWindow;
	alertWindow = AlertUser(UIERRORALERT, (WinInfoPtr) 0, "Do you really want to quit SciAn?",
		QuitReply, 2, "Quit", "Cancel");
	SetVar((ObjPtr) alertWindow, INHIBITLOGGING, ObjTrue);
    }
}

void LongOperation()
/*Signals the user that a long operation is about to occur
  This version sets to the watchcursor*/
{
    MySetCursor(WATCHCURSOR);
}

void EndLongOperation()
/*Ends a long operation*/
{
    if (curCursor == WATCHCURSOR)
    {
	MySetCursor(0);
    }
}

#ifdef INTERACTIVE
void SetContextSensitiveHelp()
/*Sets up the system so that the next press click is a help*/
{
    MySetCursor(QUESTIONCURSOR);
    contextHelp = true;
}
#endif

#ifdef INTERACTIVE
#ifdef HAVE_PROTOTYPES
void KeyDown(int theKey, long flags)
#else
void KeyDown(theKey, flags)
int theKey;
long flags;
#endif
/*Does a keyDown for theKey with flags.*/
{
    WinInfoPtr window;

    window = inputWindow;
    if (!inputWindow)
    {
	/*No focus; return*/
	return;
    }
    SelWindow(inputWindow);

    if (!selWinInfo)
    {
	/*Pathological case.  Return.*/
	return;
    }

    if (DoFunctionKey(theKey, flags))
    {
    }
    else
    {
	FuncTyp actionMethod;		/*The method to call for the action*/

    /*See if it's one of the funny characters*/
    switch (theKey)
    {
	case CONTROL('C'):
#ifdef CH_COPYRIGHT
	    theKey = CH_COPYRIGHT;
#endif
	    break;
	case CONTROL('X'):
#ifdef CH_CROSS
	    theKey = CH_CROSS;
#endif
	    break;
	case CONTROL('D'):
#ifdef CH_DOT
	    theKey = CH_DOT;
#endif
	    break;
	case CONTROL('R'):
#ifdef CH_REGISTERED
	    theKey = CH_REGISTERED;
#endif
	    break;
   }

	actionMethod = GetMethod((ObjPtr) selWinInfo, KEYDOWN);
	if (actionMethod)
	{
	    /*There's a key down routine.  Call it.*/
	    DrawInteractive(true);
	    if (theKey == '\r')
	    {
		/*Kludge to get it to flush stuff before enter key*/
		FlushKeystrokes();
	    }
	    (*actionMethod)(selWinInfo, theKey, flags);
	}
    }
}
#endif

void FlushKeystrokes()
/*Flushes the keystrokes to an object that takes keystrokes*/
{
#ifdef INTERACTIVE
    if (sentKey && IsValidWindow(keyWindow))
    {
	WinInfoPtr tempInput;
	Screencoord l, r, b, t; 
	WinInfoPtr oldWindow;

	oldWindow = selWinInfo;

	tempInput = inputWindow;
	inputWindow = keyWindow;
	sentKey = 0;
	KeyDown(0, 0);
	inputWindow = tempInput;

	if (oldWindow)
	{
	    SelWindow(oldWindow);
	}
    }
#endif
}
static int ms = 0;

Bool Mouse(x, y)
int *x, *y;
/*Returns in x and y the current mouse position in local coordinates*/
{
#ifdef INTERACTIVE
    int ox, oy;

    UD();

    CurOffset(&ox, &oy);

    *x = getvaluator(MOUSEX) - ox;
    *y = getvaluator(MOUSEY) - oy;

    switch (curMouse)
    {
	case MB_LEFT:
	    return getbutton(MOUSE1);
	case MB_MIDDLE:
	    return getbutton(MOUSE2);
	case MB_RIGHT:
	    return getbutton(MOUSE3);
    }
#else
    return false;
#endif
}

#ifdef INTERACTIVE
static ObjPtr AbortScript(owner, button)
ObjPtr owner;
int button;
/*Callback routine to abort a script*/
{
    if (button)
    {
	/*Continue*/
	runningScript = true;
    }
    else
    {
	/*Real abort*/
	EndScript();
    }
}

void AbortScriptAlert()
/*Puts up an alert to abort the script*/
{
    WinInfoPtr errWindow;
    MySetCursor(0);
    runningScript = false;
    errWindow = AlertUser(UICAUTIONALERT, (WinInfoPtr) 0,
	"SciAn is currently running a script.  Would you like to abort the \
script or continue running it?",
        AbortScript, 2, "Abort", "Continue");
    SetVar((ObjPtr) errWindow, HELPSTRING,
        NewString("SciAn expects no user interaction while running a script.  \
This is because changing the state of the windows of SciAn while running a \
script can cause the script to generate an error.  It is best either to \
abort the script or continue and not interfere with it.  However, if you are really \
sure you know what you are doing, you can interact with SciAn now and press the \
Continue button later.  This is not recommended for the inexperienced."));
    SetVar((ObjPtr) errWindow, INHIBITLOGGING, ObjTrue);
}

#ifdef HAVE_PROTOTYPES
void MouseDown(int whichButton, int x, int y, long flags)
#else
void MouseDown(whichButton, x, y, flags)
int whichButton;
int x, y;
long flags;
#endif
/*Does a mouseDown.
  whichButton should be MB_LEFT, MB_MIDDLE, or MB_RIGHT.
  x and y are in global coordinates.*/
{
    int action;				/*The action to do*/
    FuncTyp actionMethod;		/*The method to call for the action*/
    int ox, oy;
    WinInfoPtr mouseWindow;

    curMouse = whichButton;

    mouseWindow = WhichWindow(x, y);
    if (!mouseWindow && !(IsValidWindow(mouseWindow)))
    {
	/*No focus; return*/
	return;
    }

    if (Equal(mouseWindow, GetVar(objClass, MOUSEWINDOW)))
    {
    }
    else
    {
	SetVar(objClass, MOUSEWINDOW, (ObjPtr) mouseWindow);
    }
    SelWindow(mouseWindow);
   
    if (!selWinInfo)
    {
	/*Pathological case.  Return.*/
	return;
    }

    /*Determine the action based on the mouse switchboard*/
    switch(whichButton)
    {
	case MB_LEFT:
	    action = mouseSwitchboard[0];
	    break;
	case MB_MIDDLE:
	    action = mouseSwitchboard[1];
	    break;
	case MB_RIGHT:
	    action = mouseSwitchboard[2];
	    break;
    }

    /*Do the action*/
    switch(action)
    {
	case MOUSEROTATE:
	    GetWindowOrigin(&ox, &oy);
	    x -= ox;
	    y -= oy;

	    actionMethod = GetMethod((ObjPtr) selWinInfo, PRESS);
	    if (actionMethod)
	    {
		DrawInteractive(true);
		inhibitOtherWindows = true;

		/*There's a press routine.  Call it.*/
		if (contextHelp)
		{
		    (*actionMethod)(selWinInfo, x, y, T_HELP | flags);
		    contextHelp = false;
		    MySetCursor(0);
		}	
		else
		{
		    (*actionMethod)(selWinInfo, x, y, T_ROTATE | flags);
		}

		inhibitOtherWindows = false;
		DrawInteractive(false);
	    }
	    break;
	case MOUSEPRESS:
	    GetWindowOrigin(&ox, &oy);
	    x -= ox;
	    y -= oy;

	    if (dragBuffer)
	    {
		dropX = getvaluator(MOUSEX);
		dropY = getvaluator(MOUSEY);
		MySetCursor(0);
	    }
	    actionMethod = GetMethod((ObjPtr) selWinInfo, PRESS);
	    if (actionMethod)
	    {
		DrawInteractive(true);
		inhibitOtherWindows = true;

		/*There's a press routine.  Call it.*/
		if (contextHelp)
		{
		    (*actionMethod)(selWinInfo, x, y, T_HELP | flags);
		    contextHelp = false;
		    MySetCursor(0);
		}	
		else
		{
		    (*actionMethod)(selWinInfo, x, y, T_PRESS | flags);
		}
		inhibitOtherWindows = false;
		DrawInteractive(false);
	    }
	    if (dragBuffer)
	    {
		DeleteThing(dragBuffer);
		dragBuffer = 0;
	    }

	    break;
	case MOUSEMENU:
	    /*Do the main menu*/
	    DoMenu(mainMenu, x, y);
	    break;
    }
}
#endif

#ifdef IRISNTSC
void SetNTSC()
/*Sets to NTSC mode*/
{
    NTSCOn = true;
#ifdef GRAPHICS
    setmonitor(NTSC);
#ifdef GL4D
    setvideo(CG_MODE, CG2_M_MODE2);
    setvideo(DE_R1, DER1_G_170);
#endif
#endif
}

void SetStereo()
/*Sets to stereo*/
{
    stereoOn = true;

#ifdef STR_RECT
    setmonitor(STR_RECT);
#endif
}

void Set60()
/*Sets to 60 Hz mode*/
{
    NTSCOn = false;
    stereoOn = false;
#ifdef GRAPHICS
    setmonitor(defaultMonitor);
#endif
}

void ToggleNTSC()
/*Toggles in and out of NTSC mode*/
{
    NTSCOn = NTSCOn ? false : true;
#ifdef GRAPHICS
    setmonitor(NTSCOn ? NTSC : defaultMonitor);
#ifdef GL4D
    if (NTSCOn)
    {
	setvideo(CG_MODE, CG2_M_MODE2);
	setvideo(DE_R1, DER1_G_170);
    }
#endif
#endif
}

void ToggleStereo()
/*Toggles in and out of stereo mode*/
{
    stereoOn = stereoOn ? false : true;
#ifdef GRAPHICS
#ifdef STR_RECT
    setmonitor(stereoOn ? STR_RECT : defaultMonitor);
#endif
#endif
}

#endif

Bool AltDown()
/*Returns true iff the alt key is down*/
{
#ifdef INTERACTIVE
    return (getbutton(LEFTALTKEY) || getbutton(RIGHTALTKEY)) ? true : false;
#else
    return false;
#endif
}

Bool ShiftDown()
/*Returns true iff the shift key is down*/
{
#ifdef INTERACTIVE
    return (getbutton(LEFTSHIFTKEY) || getbutton(RIGHTSHIFTKEY)) ? true : false;
#else
    return false;
#endif
}

Bool OptionDown()
/*Returns true iff the option key is down*/
{
#ifdef INTERACTIVE
    return (getbutton(LEFTCTRLKEY) || getbutton(RIGHTCTRLKEY) ||
		getbutton(CAPSLOCKKEY)) ? true : false;
#else
    return false;
#endif
}

Bool UserEvent()
/*Determine if there is a user event (mouse down or key down or close
  window) in the queue*/
{
    int k;

    if (knownUserEvent)
    {
	return true;
    }

#ifndef SIGNALS
    NewEvents();
#endif

    k = curEvent;
    while (k != lastEvent)
    {
	k = (k + 1) % MAXNEVENTS;
	if (ISUSEREVENT(events[k] . type))
	{
	    knownUserEvent = true;
	    return true;
	}
    }
    return false;
}

#ifdef HAVE_PROTOTYPES
void PostEvent(Event *event)
#else
void PostEvent(event)
Event *event;
#endif
/*Posts an event just like event, except for time*/
{
    int k;
    char *a, *b;
    struct tms buffer;

    lastEvent = (lastEvent + 1) % MAXNEVENTS;

    a = (char *) event;
    b = (char *) &(events[lastEvent]);

    for (k = 0; k < sizeof(Event); ++k)
    {
	b[k] = a[k];
    }
    events[lastEvent] . time = times(&buffer);
    if (ISUSEREVENT(event -> type))
    {
	knownUserEvent = true;
    }
}

void NewEvents()
/*Get all new events and deposit them in the event queue.  Do this every once
  in a while.*/
{
#ifdef INTERACTIVE
    /*Look for an event*/

    while (qtest())
    {
        long whichDevice;
        short theData;
	WinInfoPtr window;
	struct tms buffer;

        whichDevice = qread(&theData);
	lastEvent = (lastEvent + 1) % MAXNEVENTS;

	events[lastEvent] . type = ET_UNKNOWN;
	events[lastEvent] . time = times(&buffer);
	events[lastEvent] . flags = 0;
	/*Determine if the modifier keys are held down*/
	if (getbutton(LEFTSHIFTKEY) || getbutton(RIGHTSHIFTKEY))
	{
	    events[lastEvent] . flags |= F_SHIFTDOWN;
	}
	if (getbutton(LEFTCTRLKEY) || getbutton(RIGHTCTRLKEY) || getbutton(CAPSLOCKKEY))
	{
	    events[lastEvent] . flags |= F_OPTIONDOWN;
	}
	if (getbutton(LEFTALTKEY) || getbutton(RIGHTALTKEY))
	{
	    events[lastEvent] . flags |= F_OPTIONDOWN;
	}

        switch (whichDevice)
        {
	    case INPUTCHANGE:
		if (theData && (window = GetWinInfo(theData)))
		{
		    events[lastEvent] . type = ET_SET_WINDOW;
		    events[lastEvent] . data . window = window;
		}
		break;
#ifdef DEPTHCHANGE
	    case DEPTHCHANGE:
		if (theData && (window = GetWinInfo(theData)))
		{
		    events[lastEvent] . type = ET_DEPTHCHANGE_WINDOW;
		    events[lastEvent] . data . window = window;
		}
		break;
#endif
	    case WINFREEZE:
		if (theData && (window = GetWinInfo(theData)))
		{
		    events[lastEvent] . type = ET_ICONIFY_WINDOW;
		    events[lastEvent] . data . window = window;
		}
		break;
	    case WINTHAW:
		if (theData && (window = GetWinInfo(theData)))
		{
		    events[lastEvent] . type = ET_DEICONIFY_WINDOW;
		    events[lastEvent] . data . window = window;
		}
		break;
             case KEYBD:
		if (events[lastEvent] . time - lastKeyTime < CLICK2TIME)
		{ 
		    events[lastEvent] . flags |= F_DOUBLECLICK; 
		    lastKeyTime = events[lastEvent] . time;
		}
		events[lastEvent] . type = ET_KEY_DOWN;
		events[lastEvent] . data . key = theData;
		break;
	    case MOUSE1:
		if (theData)
		{
		    int newX, newY;

		    /*Determine if this is potentially a double click*/
		    newX = getvaluator(MOUSEX);
		    newY = getvaluator(MOUSEY);
		    if (events[lastEvent] . time - lastClickTime < CLICK2TIME &&
			ABS(newX - lastClickX) < CLICK2DIST &&
			ABS(newY - lastClickY) < CLICK2DIST)
		    {
			events[lastEvent] . flags |= F_DOUBLECLICK;
		    }

		    lastClickX = newX;
		    lastClickY = newY;

		    events[lastEvent] . type = ET_MOUSE_DOWN;
		}
		else
		{
		    events[lastEvent] . type = ET_MOUSE_UP;
		    lastClickTime = events[lastEvent] . time;
		}
		events[lastEvent] . data . mouse . x = getvaluator(MOUSEX);
		events[lastEvent] . data . mouse . y = getvaluator(MOUSEY);
 		events[lastEvent] . data . mouse . mouseButton = MB_LEFT;
		break;
	    case MOUSE2:
		if (theData)
		{
		    int newX, newY;

		    /*Determine if this is potentially a double click*/
		    newX = getvaluator(MOUSEX);
		    newY = getvaluator(MOUSEY);
		    if (events[lastEvent] . time - lastClickTime < CLICK2TIME &&
			ABS(newX - lastClickX) < CLICK2DIST &&
			ABS(newY - lastClickY) < CLICK2DIST)
		    {
			events[lastEvent] . flags |= F_DOUBLECLICK;
		    }

		    lastClickX = newX;
		    lastClickY = newY;

		    events[lastEvent] . type = ET_MOUSE_DOWN;
		}
		else
		{
		    events[lastEvent] . type = ET_MOUSE_UP;
		    lastClickTime = events[lastEvent] . time;
		}
		events[lastEvent] . data . mouse . x = getvaluator(MOUSEX);
		events[lastEvent] . data . mouse . y = getvaluator(MOUSEY);
 		events[lastEvent] . data . mouse . mouseButton = MB_MIDDLE;
		break;
	    case MOUSE3:
		if (theData)
		{
		    int newX, newY;

		    /*Determine if this is potentially a double click*/
		    newX = getvaluator(MOUSEX);
		    newY = getvaluator(MOUSEY);
		    if (events[lastEvent] . time - lastClickTime < CLICK2TIME &&
			ABS(newX - lastClickX) < CLICK2DIST &&
			ABS(newY - lastClickY) < CLICK2DIST)
		    {
			events[lastEvent] . flags |= F_DOUBLECLICK;
		    }

		    lastClickX = newX;
		    lastClickY = newY;

		    events[lastEvent] . type = ET_MOUSE_DOWN;
		}
		else
		{
		    events[lastEvent] . type = ET_MOUSE_UP;
		    lastClickTime = events[lastEvent] . time;
		}
		events[lastEvent] . data . mouse . x = getvaluator(MOUSEX);
		events[lastEvent] . data . mouse . y = getvaluator(MOUSEY);
 		events[lastEvent] . data . mouse . mouseButton = MB_RIGHT;
		break;
	    case REDRAW:
		if (theData && (window = GetWinInfo(theData)))
		{
		    events[lastEvent] . type = ET_RESHAPE_WINDOW;
		    events[lastEvent] . data . window = window;
		}
		break;
	    case PIECECHANGE:
		if (theData && (window = GetWinInfo(theData)))
		{
		    events[lastEvent] . type = ET_RESHAPE_WINDOW;
		    events[lastEvent] . data . window = window;
		}
		break;
	    case UPARROWKEY:
		if (theData)
		{
		    events[lastEvent] . type = ET_KEY_DOWN;
		events[lastEvent] . data . key = FK_UP_ARROW;
		}
		break;
	    case DOWNARROWKEY:
		if (theData)
		{
		    events[lastEvent] . type = ET_KEY_DOWN;
		events[lastEvent] . data . key = FK_DOWN_ARROW;
		}
		break;
	    case LEFTARROWKEY:
		if (theData)
		{
		    events[lastEvent] . type = ET_KEY_DOWN;
		events[lastEvent] . data . key = FK_LEFT_ARROW;
		}
		break;
	    case RIGHTARROWKEY:
		if (theData)
		{
		    events[lastEvent] . type = ET_KEY_DOWN;
		events[lastEvent] . data . key = FK_RIGHT_ARROW;
		}
		break;
	    case BUT157:
		if (theData)
		{
		    events[lastEvent] . type = ET_KEY_DOWN;
		    events[lastEvent] . data . key = FK_PRINT_SCREEN;
		}
		break;
	    case PADPF1:
	    case F1KEY:
		if (theData)
		{
		    events[lastEvent] . type = ET_KEY_DOWN;
		events[lastEvent] . data . key = FK_1;
		}
		break;
	    case PADPF2:
	    case F2KEY:
		if (theData)
		{
		    events[lastEvent] . type = ET_KEY_DOWN;
		events[lastEvent] . data . key = FK_2;
		}
		break;
	    case PADPF3:
	    case F3KEY:
		if (theData)
		{
		    events[lastEvent] . type = ET_KEY_DOWN;
		events[lastEvent] . data . key = FK_3;
		}
		break;
	    case PADPF4:
	    case F4KEY:
		if (theData)
		{
		    events[lastEvent] . type = ET_KEY_DOWN;
		events[lastEvent] . data . key = FK_4;
		}
		break;
	    case F5KEY:
		if (theData)
		{
		    events[lastEvent] . type = ET_KEY_DOWN;
		    events[lastEvent] . data . key = FK_5;
		}
		break;
	    case F6KEY:
		if (theData)
		{
		    events[lastEvent] . type = ET_KEY_DOWN;
		    events[lastEvent] . data . key = FK_6;
		}
		break;
	    case F7KEY:
		if (theData)
		{
		    events[lastEvent] . type = ET_KEY_DOWN;
		    events[lastEvent] . data . key = FK_7;
		}
		break;
	    case F8KEY:
		if (theData)
		{
		    events[lastEvent] . type = ET_KEY_DOWN;
		    events[lastEvent] . data . key = FK_8;
		}
		break;
	    case F9KEY:
		if (theData)
		{
		    events[lastEvent] . type = ET_KEY_DOWN;
		    events[lastEvent] . data . key = FK_9;
		}
		break;
	    case F10KEY:
		if (theData)
		{
		    events[lastEvent] . type = ET_KEY_DOWN;
		    events[lastEvent] . data . key = FK_10;
		}
		break;
	    case F11KEY:
		if (theData)
		{
		    events[lastEvent] . type = ET_KEY_DOWN;
		    events[lastEvent] . data . key = FK_11;
		}
		break;
	    case F12KEY:
		if (theData)
		{
		    events[lastEvent] . type = ET_KEY_DOWN;
		    events[lastEvent] . data . key = FK_12;
		}
		break;
#ifdef IRIS
	    case WINSHUT:
		if (theData && (window = GetWinInfo(theData)))
		{
		    events[lastEvent] . type = ET_CLOSE_WINDOW;
		    events[lastEvent] . data . window = window;
		}
		break;
#ifdef WINQUIT
	    case WINQUIT:
		if (theData)
		{
		    events[lastEvent] . type = ET_QUIT;
		    events[lastEvent] . data . window = 0;
		}
		break;
#endif
#ifdef DIALBOX
	    case DIAL0:
		if (theData)
		{
		    events[lastEvent] . type = ET_ROTATE_DIAL;
		    events[lastEvent] . data . dial . whichDial = 0;
		    events[lastEvent] . data . dial . delta = theData - lastDialValues[0];
		    if (theData > 20000 || theData < -20000)
		    {
			setvaluator(DIAL0, 0, -32767, 32767);
			lastDialValues[0] = 0;
		    }
		    else
		    {
			lastDialValues[0] = theData;
		    }
		}
		break;
	    case DIAL1:
		if (theData)
		{
		    events[lastEvent] . type = ET_ROTATE_DIAL;
		    events[lastEvent] . data . dial . whichDial = 1;
		    events[lastEvent] . data . dial . delta = theData - lastDialValues[1];
		    if (theData > 20000 || theData < -20000)
		    {
			setvaluator(DIAL1, 0, -32767, 32767);
			lastDialValues[1] = 0;
		    }
		    else
		    {
			lastDialValues[1] = theData;
		    }
		}
		break;
	    case DIAL2:
		if (theData)
		{
		    events[lastEvent] . type = ET_ROTATE_DIAL;
		    events[lastEvent] . data . dial . whichDial = 2;
		    events[lastEvent] . data . dial . delta = theData - lastDialValues[2];
		    if (theData > 20000 || theData < -20000)
		    {
			setvaluator(DIAL2, 0, -32767, 32767);
			lastDialValues[2] = 0;
		    }
		    else
		    {
			lastDialValues[2] = theData;
		    }
		}
		break;
	    case DIAL3:
		if (theData)
		{
		    events[lastEvent] . type = ET_ROTATE_DIAL;
		    events[lastEvent] . data . dial . whichDial = 3;
		    events[lastEvent] . data . dial . delta = theData - lastDialValues[3];
		    if (theData > 20000 || theData < -20000)
		    {
			setvaluator(DIAL3, 0, -32767, 32767);
			lastDialValues[3] = 0;
		    }
		    else
		    {
			lastDialValues[3] = theData;
		    }
		}
		break;
	    case DIAL4:
		if (theData)
		{
		    events[lastEvent] . type = ET_ROTATE_DIAL;
		    events[lastEvent] . data . dial . whichDial = 4;
		    events[lastEvent] . data . dial . delta = theData - lastDialValues[4];
		    if (theData > 20000 || theData < -20000)
		    {
			setvaluator(DIAL4, 0, -32767, 32767);
			lastDialValues[4] = 0;
		    }
		    else
		    {
			lastDialValues[4] = theData;
		    }
		}
		break;
	    case DIAL5:
		if (theData)
		{
		    events[lastEvent] . type = ET_ROTATE_DIAL;
		    events[lastEvent] . data . dial . whichDial = 5;
		    events[lastEvent] . data . dial . delta = theData - lastDialValues[5];
		    if (theData > 20000 || theData < -20000)
		    {
			setvaluator(DIAL5, 0, -32767, 32767);
			lastDialValues[5] = 0;
		    }
		    else
		    {
			lastDialValues[5] = theData;
		    }
		}
		break;
	    case DIAL6:
		if (theData)
		{
		    events[lastEvent] . type = ET_ROTATE_DIAL;
		    events[lastEvent] . data . dial . whichDial = 6;
		    events[lastEvent] . data . dial . delta = theData - lastDialValues[6];
		    if (theData > 20000 || theData < -20000)
		    {
			setvaluator(DIAL6, 0, -32767, 32767);
			lastDialValues[6] = 0;
		    }
		    else
		    {
			lastDialValues[6] = theData;
		    }
		}
		break;
	    case DIAL7:
		if (theData)
		{
		    events[lastEvent] . type = ET_ROTATE_DIAL;
		    events[lastEvent] . data . dial . whichDial = 7;
		    events[lastEvent] . data . dial . delta = theData - lastDialValues[7];
		    if (theData > 20000 || theData < -20000)
		    {
			setvaluator(DIAL7, 0, -32767, 32767);
			lastDialValues[7] = 0;
		    }
		    else
		    {
			lastDialValues[7] = theData;
		    }
		}
		break;
#endif

#endif
	}
    }
#endif
}

#ifdef HAVE_PROTOTYPES
void RotateDial(WinInfoPtr win, int whichDial, int iDelta, long flags)
#else
void RotateDial(win, whichDial, iDelta, flags)
WinInfoPtr win;
int whichDial;
int iDelta;
long flags;
#endif
/*Rotates dial whichDial by an amount iDelta within win*/
{
    real delta;
    FuncTyp method;

    delta = (flags & F_CONSTRAIN) ? iDelta * 0.1 : iDelta;

    method = GetMethod((ObjPtr) win, TURNDIAL);
    if (method)
    {
	DrawInteractive(true);
	(*method)((ObjPtr) win, whichDial, delta, T_ROTATE | flags);
    }
}

#ifdef HAVE_PROTOTYPES
Bool OneEvent(Bool processInput)
#else
Bool OneEvent(processInput)
Bool processInput;
#endif
/*Gets and processes one event.  if processInput is true, process input*/
{
    Bool readFromScript = true;
    Bool doNap;
    int k;

    if (tempStrFeeler)
    {
	ReportError("OneEvent", "Internal error: tempStr overrun");
    }

    if (logging)
    {
	InhibitLogging(true);
    }
    /*Do the messages remaining*/
    if (defMesLeft)
    {
	int which, defLeft;
	defLeft = defMesLeft;
	which = curDef;
	curDef = curDef ? 0 : 1;
	defMesLeft = 0;
	for (k = 0; k < defLeft; ++k)
	{
	    FuncTyp method;
	    method = GetMethod(defMessages[which][k] . object, defMessages[which][k] . message);
	    if (method)
	    {
		(*method)(defMessages[which][k] . object);
	    }
	}
    }
    if (logging)
    {
	InhibitLogging(false);
    }
    
    /*Do tasks that are waiting*/
    if (tasksLeft)
    {
	for (k = 0; k < tasksLeft; ++k)
	{
	    (*(doTasks[k]))();
	}
	tasksLeft = 0;
    }

#ifdef INTERACTIVE
#ifndef SIGNALS
    NewEvents();
#endif
    /*Look for an event*/
    if (curEvent != lastEvent)
    {
	/*There is an event*/
	curEvent = (curEvent + 1) % MAXNEVENTS;
	readFromScript = false;

	knownUserEvent = false;
        switch (events[curEvent] . type)
        {
	    case ET_SET_WINDOW:
		/*Changed windows, reset the moving quality to highest*/
		if (IsValidWindow(events[curEvent] . data . window))
		{
		    inputWindow = events[curEvent] . data . window;
		}
		else
		{
		    inputWindow = 0;
		}
		break;
	    case ET_ICONIFY_WINDOW:
		/*Window has been iconified*/
		if (IsValidWindow(events[curEvent] . data . window))
		{
		    events[curEvent] . data . window -> flags |= WINICONIFIED;
		}
		break;
	    case ET_DEICONIFY_WINDOW:
		/*Window has been iconified*/
		if (IsValidWindow(events[curEvent] . data . window))
		{
		    events[curEvent] . data . window -> flags &= ~WINICONIFIED;
		}
		break;
	    case ET_DEPTHCHANGE_WINDOW:
		/*Window's depth has changed.  See if we need to 
		  change any subwindow*/
		if (IsValidWindow(events[curEvent] . data . window))
		{
		    WinInfoPtr superWindow;
		    ObjPtr subWindows;

		    /*See if it has subwindows and needs to be popped*/
		    superWindow = (WinInfoPtr) GetVar((ObjPtr) events[curEvent] . data . window, SUPERWINDOW);
		    subWindows = GetVar((ObjPtr) superWindow, SUBWINDOWS);

		    if (subWindows && !superWindow)
		    {
			/*Window has sub windows*/
			if (TopWindow() == events[curEvent] . data . window)
			{
			    /*Pop the subwindows*/
			    ThingListPtr runner;
			    runner = LISTOF(subWindows);
			    while (runner)
			    {
				PopWindow((WinInfoPtr) runner -> thing);
				runner = runner -> next;
			    }
			}
			else if (BottomWindow() == events[curEvent] . data . window)
			{
			    ThingListPtr runner;
			    /*This window has just been pushed*/
	
			    /*This may be a superwindow which has been pushed.
			      Check to see if all the subwindows are OK*/
			    superWindow = events[curEvent] . data . window;
			    subWindows = GetVar((ObjPtr) superWindow, SUBWINDOWS);
			    runner = LISTOF(subWindows);
			    while (runner)
			    {
				if (!BelowAllBut((WinInfoPtr) runner -> thing, superWindow))
				{
				    /*Window out of place*/
				    break;
				}
				runner = runner -> next;
			    }

			    if (runner)
			    {
				/*One window is out of place.  Push subwindows*/
				runner = LISTOF(subWindows);
				while (runner)
				{
				    PushWindow((WinInfoPtr) runner -> thing);
				    runner = runner -> next;
				}

				/*Push super window*/
				PushWindow(superWindow);
			    }
			}
		    }
		}
		break;
	    case ET_ROTATE_DIAL:
		if (runningScript)
		{
		    return;
		}
		if (inputWindow && IsValidWindow(inputWindow))
		{
		    RotateDial(inputWindow,
			events[curEvent] . data . dial . whichDial,
			events[curEvent] . data . dial . delta,
			events[curEvent] . flags);
		}
		break;
	    case ET_KEY_DOWN:
		if (runningScript)
		{
		    AbortScriptAlert();
		    return;
		}

		sentKey = events[curEvent] . data . key;
		keyWindow = inputWindow;
		KeyDown(events[curEvent] . data . key,
			events[curEvent] . flags);

		break;
	    case ET_MOUSE_DOWN:
		if (runningScript)
		{
		    AbortScriptAlert();
		    return;
		}
		MouseDown(events[curEvent] . data . mouse . mouseButton,
			events[curEvent] . data . mouse . x,
			events[curEvent] . data . mouse . y,
			events[curEvent] . flags);
		break;
	    case ET_RESHAPE_WINDOW:
		if (IsValidWindow(events[curEvent] . data . window))
		{
		    ObjPtr subWindows;
		    long ol, or, ob, ot, nl, nr, nb, nt;
		    long sx, sy, ox, oy;
		    SelWindow(events[curEvent] . data . window);
		    
		    if (!selWinInfo)
		    {
			break;
		    }

		    reshapeviewport();

		    /*Stuff ol, or, ob, ot*/
		    getorigin(&ox, &oy);
		    getsize(&sx, &sy);

		    ol = ((WinInfoPtr) selWinInfo) -> nl;
		    or = ((WinInfoPtr) selWinInfo) -> nr;
		    ob = ((WinInfoPtr) selWinInfo) -> nb;
		    ot = ((WinInfoPtr) selWinInfo) -> nt;

		    nl = ox;
		    nr = ox + sx;
		    nb = oy;
		    nt = oy + sy;

		    if (nl != ol || nr != or || nb != ob || nt != ot)
		    {
			/*Change this window*/
			((WinInfoPtr) selWinInfo) -> ol = ol;
			((WinInfoPtr) selWinInfo) -> or = or;
			((WinInfoPtr) selWinInfo) -> ob = ob;
			((WinInfoPtr) selWinInfo) -> ot = ot;

			((WinInfoPtr) selWinInfo) -> nl = nl;
			((WinInfoPtr) selWinInfo) -> nr = nr;
			((WinInfoPtr) selWinInfo) -> nb = nb;
			((WinInfoPtr) selWinInfo) -> nt = nt;

			if (logging && !GetVar((ObjPtr) selWinInfo, SUPERWINDOW) &&
				!GetPredicate((ObjPtr) selWinInfo, INHIBITLOGGING))
			{
			    char cmd[400];
			    sprintf(cmd, "locate %d %d %d %d\n",
				nl, nr, nb, nt);
			    Log(cmd);
			}
			ReshapeWindow((ObjPtr) selWinInfo);
		    }
		    /*The window has been moved.  Both buffers are bad*/
		    ImInvalid((ObjPtr) selWinInfo);

		    /*Now, see if any of the subwindows need moving*/
		    subWindows = GetVar((ObjPtr) selWinInfo, SUBWINDOWS);
		    if (subWindows)
		    {
			long sox, soy, ssx, ssy;
			long l, r, b, t;
			ObjPtr var;
			real margin[4];

			ThingListPtr runner;
			runner = LISTOF(subWindows);
			while (runner)
			{
			    SelWindow((WinInfoPtr) runner -> thing);

			    /*Get the window position within superwindow*/
			    getorigin(&sox, &soy);
			    getsize(&ssx, &ssy);
			    var = GetVar(runner -> thing, SUBWINDOWMARGIN);
			    if (var)
			    {
				Array2CArray(margin, var);
			    }
			    else
			    {
				margin[0] = 0.0;
				margin[1] = 0.0;
				margin[2] = 0.0;
				margin[3] = 0.0;
			    }

			    /*Adjust*/
			    l = nl + (int) margin[0];
			    r = nr - (int) margin[1];
			    b = nb + (int) margin[2];
			    t = nt - (int) margin[3];

			    if (l != sox || b != soy ||
				r != sox + ssx - 1 || t != soy + ssy - 1)
			    {
				winposition(l, r, b, t);
				ImInvalid(runner -> thing);
			    }

			    runner = runner -> next;
			}
		    }
		}
		break;
	    case ET_DRAW_WINDOW:
		if (IsValidWindow(events[curEvent] . data . window))
		{
		    SelWindow(events[curEvent] . data . window);

		    reshapeviewport();
		    if (selWinInfo)
		    {
			/*Both buffers are bad*/
			ImInvalid((ObjPtr) selWinInfo);
		    }
		}
		break;
	    case ET_CLOSE_WINDOW:
		if (IsValidWindow(events[curEvent] . data . window))
		{
		    CloseWindow(events[curEvent] . data . window);
		}
		break;
	    case ET_QUIT:
		MaybeQuit();
		break;
	}
    }
    else
#endif
    if (settleEvents > 0)
    {
	--settleEvents;
    }
    else
    {
	struct tms buffer;

	if (interactiveMoving)
	{
	    /*See if we've delayed long enough*/
	    if (times(&buffer) - interactBegin > INTERACTDELAY)
	    {
		DrawInteractive(false);
	    }
	}

	/*If there's an object to drop, drop it.*/
	if (dropObject)
	{
	    WinInfoPtr dropWindow;

	    dropWindow = WhichWindow(dropX, dropY);

	    if (dropWindow)
	    {
		int left, right, bottom, top;
		int ox, oy;

		SelWindow(dropWindow);
		GetWindowBounds(&left, &right, &bottom, &top);
		GetWindowOrigin(&ox, &oy);
		dropX -= ox;
		dropY -= oy;

		if (dropX >= left && dropX <= right &&
		    dropY >= bottom && dropY <= top)
		{
		    FuncTyp method;
		    /*Drop*/
		    method = GetMethod((ObjPtr) selWinInfo, DROPOBJECTS);
		    if (method)
		    {
			if (logging)
			{
			    char cmd[256];
			    sprintf(cmd, "drop %d %d\n", dropX, dropY);
			    Log(cmd);
			    InhibitLogging(true);
			}
			
			(*method)(selWinInfo, dropObject, dropX, dropY);
			if (logging)
			{
			    InhibitLogging(false);
			}
		    }
		}
	    }
	    DeleteThing(dropObject);
	    dropObject = NULLOBJ;
	}

#ifdef CHANGECURSOR
#ifdef INTERACTIVE
#ifdef GRAPHICS
	{
	    WinInfoPtr cursorWindow;
	    FuncTyp method;
	    int x, y;

	    x = getvaluator(MOUSEX);
	    y = getvaluator(MOUSEY);
	    cursorWindow = WhichWindow(x, y);
	    if (cursorWindow != lastCursorWindow)
	    {
		/*Enter and leave messages*/
		if (lastCursorWindow)
		{
		    method = GetMethod((ObjPtr) lastCursorWindow, LEAVECURSOR);
		    if (method)
		    {
			(*method)(lastCursorWindow);
		    }
		}
		if (cursorWindow)
		{
		    method = GetMethod((ObjPtr) cursorWindow, ENTERCURSOR);
		    if (method)
		    {
			SelWindow(cursorWindow);
			(*method)(cursorWindow);
		    }
		}
		lastCursorWindow = cursorWindow;
	    }
	    if (cursorWindow)
	    {
		method = GetMethod((ObjPtr) cursorWindow, IDLECURSOR);
		if (method)
		{
		    SelWindow(cursorWindow);
		    (*method)((ObjPtr) cursorWindow, x, y);
		}
	    }
	}
#endif
#endif
#endif

	/*Idle the windows if appropriate*/
	if (settingUp && runningScript)
	{
	    readFromScript = true;
	    doNap = false;
	}
	else
	{
	    /*Do the drawing*/
	    switch(windowSystem)
	    {
		case WS_GLWINDOWS:
		    readFromScript = IdleAllWindows() ? false : true;
		    break;
		case WS_CAVESIM:
		    readFromScript = true;
#ifdef WINDOWSCAVESIM
		    cave_simulator_display(IdleCaveWindows, 0);
		    if (getbutton(ESCKEY)) DoQuit();
#endif
		    break;
		case WS_CAVE:
		    readFromScript = true;
#ifdef WINDOWSCAVE
		    cave_display(IdleCaveWindows, 0);
#endif
		    break;
	    }
	    doNap = readFromScript;
	}

        if (readFromScript)
	{
	    if (runningScript)
	    {
		ReadScriptLine();
	    }
	    else
	    {
#ifdef SOCKETS
		/*Idle all connections*/
		IdleAllConnections();
#endif
	    }
	}
	IdleTimers();

#ifdef RELEASE
	TrashDay();
#else
	if (GetPrefTruth(PREF_RECKLESSGC))
	{
	    struct tms buffer;
	    long curTime;
	    curTime = times(&buffer);
	    if (curTime - lastGC > GCEVERY)
	    {
		TrashDay();
		lastGC = curTime;
	    }
	}
	else
	{
	    TrashDay();
	}
#endif
	if (doNap && GetPrefTruth(PREF_NAPWHENIDLE))
	{
	    struct tms buffer;
	    long curTime;
	    curTime = times(&buffer);
	    if (curTime - lastAwake > NAPEVERY)
	    {
		sleep(1);
	    }
	}
	else
	{
	    struct tms buffer;
	    lastAwake = times(&buffer);
	}
    }
}

void MainLoop()
/*Main loop for scian*/
{
    SetSystemClock(0.0);
    while (running)
    {
	EndLongOperation();
	OneEvent(true);
    }
    EndScript();
    if (stereoOn)
    {
#ifdef IRISNTSC
	Set60();
#endif
    }
}

#ifdef HAVE_PROTOTYPES
void InitEvents(void)
#else
void InitEvents()
#endif
{
    int k;
#ifdef INTERACTIVE
    for (k = 0; k < FK_N; ++k) functionKeyNames[k] = 0;

    functionKeyNames[FK_1 - FK_BASE] = "F1";
    functionKeyNames[FK_2 - FK_BASE] = "F2";
    functionKeyNames[FK_3 - FK_BASE] = "F3";
    functionKeyNames[FK_4 - FK_BASE] = "F4";
    functionKeyNames[FK_5 - FK_BASE] = "F5";
    functionKeyNames[FK_6 - FK_BASE] = "F6";
    functionKeyNames[FK_7 - FK_BASE] = "F7";
    functionKeyNames[FK_8 - FK_BASE] = "F8";
    functionKeyNames[FK_9 - FK_BASE] = "F9";
    functionKeyNames[FK_10 - FK_BASE] = "F10";
    functionKeyNames[FK_11 - FK_BASE] = "F11";
    functionKeyNames[FK_12 - FK_BASE] = "F12";
    functionKeyNames[FK_PRINT_SCREEN - FK_BASE] = "Print";

#ifdef WINDOWS4D
    if (windowSystem == WS_GLWINDOWS)
    {
	qdevice(KEYBD);
	qdevice(PADPF1);
	qdevice(F1KEY);
	qdevice(PADPF2);
	qdevice(F2KEY);
	qdevice(PADPF3);
	qdevice(F3KEY);
	qdevice(PADPF4);
	qdevice(F4KEY);
	qdevice(F5KEY);
	qdevice(F6KEY);
	qdevice(F7KEY);
	qdevice(F8KEY);
	qdevice(F9KEY);
	qdevice(F10KEY);
	qdevice(F11KEY);
	qdevice(F12KEY);
	qdevice(MOUSE1);
	qdevice(MOUSE2);
	qdevice(MOUSE3);
	qdevice(UPARROWKEY);
	qdevice(DOWNARROWKEY);
	qdevice(LEFTARROWKEY);
	qdevice(RIGHTARROWKEY);
	qdevice(WINFREEZE);
	qdevice(WINTHAW);
#ifdef DIALBOX
	qdevice(DIAL0);
	qdevice(DIAL1);
	qdevice(DIAL2);
	qdevice(DIAL3);
	qdevice(DIAL4);
	qdevice(DIAL5);
	qdevice(DIAL6);
	qdevice(DIAL7);
#endif
#ifdef DEPTHCHANGE
	qdevice(DEPTHCHANGE);
#endif
#ifdef IRIS
#ifdef WINQUIT
	qdevice(WINQUIT);
#endif
	qdevice(WINSHUT);
	qdevice(BUT157);
#endif
    }
#endif

    drawLaterList = NewList();
    AddToReferenceList(drawLaterList);
#endif
}

#ifdef HAVE_PROTOTYPES
void KillEvents(void)
#else
void KillEvents()
#endif
{
    /*Unqueue all the devices*/
#ifdef WINDOWS4D
    if (windowSystem == WS_GLWINDOWS)
    {
#ifdef DIALBOX
	unqdevice(DIAL0);
	unqdevice(DIAL1);
	unqdevice(DIAL2);
	unqdevice(DIAL3);
	unqdevice(DIAL4);
	unqdevice(DIAL5);
	unqdevice(DIAL6);
	unqdevice(DIAL7);
#endif
#ifdef DEPTHCHANGE
	unqdevice(DEPTHCHANGE);
#endif
	unqdevice(WINFREEZE);
	unqdevice(WINTHAW);
	unqdevice(KEYBD);
	unqdevice(PADPF1);
	unqdevice(F1KEY);
	unqdevice(PADPF2);
	unqdevice(F2KEY);
	unqdevice(PADPF3);
	unqdevice(F3KEY);
	unqdevice(PADPF4);
	unqdevice(F4KEY);
	unqdevice(F5KEY);
	unqdevice(F6KEY);
	unqdevice(F7KEY);
	unqdevice(F8KEY);
	unqdevice(F9KEY);
	unqdevice(F10KEY);
	unqdevice(F11KEY);
	unqdevice(F12KEY);
	unqdevice(MOUSE1);
	unqdevice(MOUSE2);
	unqdevice(MOUSE3);
	unqdevice(UPARROWKEY);
	unqdevice(DOWNARROWKEY);
	unqdevice(LEFTARROWKEY);
	unqdevice(RIGHTARROWKEY);
#ifdef IRIS
#ifdef WINQUIT
	qdevice(WINQUIT);
#endif
	unqdevice(WINSHUT);
	unqdevice(BUT157);
#endif
    }
#endif

    RemoveFromReferenceList(drawLaterList);
}
Modified: Sun Nov 17 17:00:00 1996 GMT
Page accessed 2525 times since Sat Apr 17 21:55:05 1999 GMT