/*ScianWindows.c
  Eric Pepke
  March 8, 1990
  Window handling routines in Scian
*/

#include "Scian.h"
#include "ScianTypes.h"
#include "ScianWindows.h"
#include "ScianVisWindows.h"
#include "ScianLists.h"
#include "ScianEvents.h"
#include "ScianColors.h"
#include "ScianErrors.h"
#include "ScianIDs.h"
#include "ScianScripts.h"
#include "ScianTextBoxes.h"
#include "ScianFileSystem.h"
#include "ScianPreferences.h"
#include "ScianDatasets.h"
#include "ScianHelp.h"
#include "ScianDialogs.h"
#include "ScianArrays.h"
#include "ScianFiles.h"
#include "ScianFontSystem.h"
#include "ScianSockets.h"
#include "ScianDraw.h"
#include "ScianObjFunctions.h"
#include "ScianStyle.h"

int updateBatch = 0;			/*Current batch of updates*/
WinInfoPtr allWindows = 0;		/*Window info on all windows*/
static short firstTime = 1;		/*First time a new window is made*/
int curDisplayMode;			/*Current display mode*/
Bool rgbp;				/*True iff in rgb mode*/
extern Bool phsco;			/*Phscologram mode*/
WinInfoPtr selWinInfo;			/*Info for currently selected window*/
ObjPtr windowClass = 0;			/*Window class*/
short curCursor = 0;			/*Current cursor*/
int recScrWidth = VSCRWIDTH;		/*Video screen size*/
int recScrHeight = VSCRHEIGHT;
ObjPtr clipboard;			/*Clipboard*/
WinInfoPtr inputWindow = 0;		/*Current window for input or 0*/

#ifdef WINNOCLOSE
#define MAXCACHEDWINDOWS 100
long cachedWindows[MAXCACHEDWINDOWS];
int nCachedWindows = 0;
#endif

int drawingQuality = DQ_FULL;   	/*The current drawing quality*/

long fontSubMenu;
long *styleSubMenus = 0;
int nStyleSubMenus = 0;			/*Number of style submenus*/
long sizeSubMenu;
long alignSubMenu;

#define STAGX		100		/*Minimum x for window staggering*/
#define STAGY		800		/*Maximum y for window staggering*/
#define STAGSTEP	40		/*Step for staggering*/
#define STAGMAX		200		/*Maximum staggering*/

int stagger = 0;			/*Current staggering amount*/

int textSizes[] =
    {
	9,
	10,
	12,
	14,
	18,
	24,
	36,
	48,
	72
    };

/*Names of all the main level menus*/
char *menuName[NMENUS] =
    {
	"File",
	"Network",
	"Datasets",
	"Object",
	"Text",
	"Deus",
	"Window Location",
	"Window",
	"Arrange"
    };

WinInfoPtr WhichWindow(x, y)
int x, y;
/*Returns which window x, y is in.  Messes up selected window*/
{
    WinInfoPtr retVal = 0;
#ifdef INTERACTIVE
#ifdef WINDOWS4D
    long minDepth;
    Bool first = true;
    WinInfoPtr curWindow;

    curWindow = allWindows;
    while (curWindow)
    {
	if (curWindow -> id)
	{
	    long depth;

	    /*It's a valid candidate*/
	    depth = windepth(curWindow -> id);
	    if (first || (depth < minDepth))
	    {
		long ox, oy, sx, sy;

		SelWindow(curWindow);
		getorigin(&ox, &oy);
		getsize(&sx, &sy);

		if (x >= ox && x <= ox + sx &&
		    y >= oy && y <= oy + sy)
		{
		    /*Hey, it's in there!*/
		    retVal = curWindow;
		    minDepth = depth;
		    first = false;
		}
	    }
	}
	curWindow = curWindow -> next;
    }
#endif
#endif
    return retVal;
}

#ifndef SelWindow
#ifdef PROTO
void SelWindow(WinInfoPtr w)
#else
void SelWindow(w)
WinInfoPtr w;
#endif
/*Procedure version of SelectWindow, useful for debugging*/
{
selWinInfo = w; if (w && ((WinInfoPtr) w) -> id) {winset(((WinInfoPtr) w) -> id);
		curDisplayMode = getdisplaymode();
		rgbp = (curDisplayMode == DMSINGLE || curDisplayMode == DMDOUBLE) ? false : true;}
}
#endif

void GetWindowBounds(l, r, b, t)
int *l, *r, *b, *t;
/*Gets the viewport of the current window into l, r, b, t*/
{
#ifdef WINDOWS4D
    Screencoord left, right, bottom, top;
    getviewport(&left, &right, &bottom, &top);
    *l = left;
    *r = right;
    *b = bottom;
    *t = top;
#else
    *l = 0;
    *r = 10;
    *b = 0;
    *t = 10;
#endif
}

void GetWindowOrigin(x, y)
int *x, *y;
/*Gets the origin of the current window*/
{
#ifdef WINDOWS4D
    long lx, ly;
    getorigin(&lx, &ly);
    *x = lx;
    *y = ly;
#else
    *x = 0;
    *y = 0;
#endif
}

void PushWindow(winInfo)
WinInfoPtr winInfo;
/*Pushes winInfo*/
{
#ifdef GRAPHICS
#ifdef WINDOWS4D
    if (winInfo -> id)
    {
	SelWindow(winInfo);
	winpush();
	Log("pushwindow\n");
    }
#endif
#endif
}

void PopWindow(winInfo)
WinInfoPtr winInfo;
/*Pops winInfo*/
{
    if (winInfo -> id)
    {
#ifdef GRAPHICS
#ifdef WINDOWS4D
	SelWindow(winInfo);
	winpop();
#endif
#endif
    }
    else
    {
	winInfo -> id = NewOpenedWindow(winInfo -> winTitle,
					winInfo -> minWidth,
					winInfo -> minHeight,
					winInfo -> maxWidth,
					winInfo -> maxHeight,
					winInfo -> flags);
	ImInvalid((ObjPtr) winInfo);
    }
}

void DoShowFrame()
/*Shows the window frame*/
{
#ifdef GRAPHICS
#ifdef WINDOWS4D
#ifndef NOHIDEFRAME
    int l, r, b, t;
    long ox, oy;
    long sx, sy;
    long oldWindow;
    if (!(selWinInfo -> flags & WINNOFRAME))
    {
	return;
    }
    if (logging)
    {
	Log("show frame\n");
    }
    if (!(selWinInfo -> id))
    {
	return;
    }

    /*Create a new window in the same place*/
    GetWindowBounds(&l, &r, &b, &t);
    getorigin(&ox, &oy);
    getsize(&sx, &sy);
    prefposition(ox, ox + sx - 1, oy, oy + sy - 1);
    oldWindow = selWinInfo -> id;
    selWinInfo -> id = winopen(selWinInfo -> winTitle);
    wintitle(selWinInfo -> winTitle);
    winclose(oldWindow);
    winset(selWinInfo -> id);
    setcursor(curCursor, 1, 0);
    minsize(selWinInfo -> minWidth, selWinInfo -> minHeight);
    maxsize(selWinInfo -> maxWidth, selWinInfo -> maxHeight);
    /*Set to the current window and set the graphics state*/
    SetMode(selWinInfo);
    winconstraints();

    selWinInfo -> flags &= ~WINNOFRAME;
    ImInvalid((ObjPtr) selWinInfo);
    DeleteMenus(selWinInfo);
#endif
#endif
#endif
}

void DoHideFrame()
/*Hides the window frame*/
{
#ifdef WINDOWS4D
#ifdef GRAPHICS
#ifndef NOHIDEFRAME
    int l, r, b, t;
    long ox, oy;
    long sx, sy;
    long oldWindow;
    if (selWinInfo -> flags & WINNOFRAME)
    {
	return;
    }
    if (logging)
    {
	Log("hide frame\n");
    }
    if (!(selWinInfo -> id))
    {
	return;
    }
    /*Save the stuff for the old window*/
    GetWindowBounds(&l, &r, &b, &t);
    getorigin(&ox, &oy);
    getsize(&sx, &sy);
    oldWindow = selWinInfo -> id;

    /*Create the new window*/
    noborder();
    prefposition(ox, ox + sx - 1, oy, oy + sy - 1);
    selWinInfo -> id = winopen(selWinInfo -> winTitle);
    wintitle(selWinInfo -> winTitle);
    winset(selWinInfo -> id);
    setcursor(curCursor, 1, 0);
    minsize(selWinInfo -> minWidth, selWinInfo -> minHeight);
    maxsize(selWinInfo -> maxWidth, selWinInfo -> maxHeight);
    winclose(oldWindow);

    /*Set to the current window and set the graphics state*/
    SetMode(selWinInfo);
    winconstraints();

    selWinInfo -> flags |= WINNOFRAME;
    ImInvalid((ObjPtr) selWinInfo);
    DeleteMenus(selWinInfo);
#endif
#endif
#endif
}

void ScrSaveFailed(void)
/*Alerts the user that a screen save failed*/
{
    WinInfoPtr errWindow;
    errWindow = AlertUser(UISEVEREALERT, (WinInfoPtr) 0, "The attempt to save the screen failed.", 0, 0, ""); 
SetVar((ObjPtr) errWindow, HELPSTRING,
	NewString("The attempt to save the screen failed.  This is probably \
because the current directory is a directory to which you don't have write \
access.  It may also be that the disk is full."));
}

void DrawWindowInfo(theWindow)
WinInfoPtr theWindow;
/*Draws the window based on WinInfoPtr theWindow into the current set window.
  This is the fundamental window drawing routine.*/
{
    int l, r, b, t;
    SelWindow(theWindow);
    GetWindowBounds(&l, &r, &b, &t);
    SetWindowArea(l, r, b, t);
    DrawObject((ObjPtr) theWindow);
    RestoreWindowArea();
}

void SaveScreen(window, flags)
WinInfoPtr window;
int flags;
/*Saves a screen*/
{
#ifdef GRAPHICS
    long l, r, b, t;
    int k;

#ifndef RELEASE
    if (GetPrefInteger(PREF_SAVESCREEN))
    {
	for (k = 0; ; ++k)
	{
	    sprintf(tempStr, "screen%d.eps", k);
	    if (drawFile = fopen(tempStr, "r"))
	    {
		fclose(drawFile);
	    }
	    else
	    {
		int left, right, bottom, top;
		drawFile = fopen(tempStr, "w");
		drawingMode = DRAW_POSTSCRIPT;
		SelWindow(window);
		GetWindowBounds(&left, &right, &bottom, &top);
		BeginDrawing(window -> winTitle, left, right, bottom, top);
		DrawWindowInfo(window);
		EndDrawing();
		drawingMode = DRAW_SCREEN;
		fclose(drawFile);
		return;
	    }
	}
    }
    else
#endif
    {
	if (flags & F_OPTIONDOWN)
	{
	    l = b = 0;
	    r = SCRWIDTH;
	    t = SCRHEIGHT;
	}
	else
	{
	    long sx, sy;
	    getorigin(&l, &b);
	    getsize(&sx, &sy);
	    r = l + sx - 1;
	    t = b + sy - 1;

	    if (!(flags & F_SHIFTDOWN || ((WinInfoPtr) window) -> flags & WINNOFRAME))
	    {
		l -= WINBL;
		r += WINBR;
		b -= WINBB;
		t += WINBT;
	    }
	}
	for (k = 0; ; ++k)
	{
	    FILE *test;
	    sprintf(tempStr, "screen%d.rgb", k);
	    if (test = fopen(tempStr, "r"))
	    {
		fclose(test);
	    }
	    else
	    {

		sprintf(tempStr, "scrsave screen%d.rgb %d %d %d %d", k, l, r, b, t);
		if (system(tempStr))
		{
		    DoTask(ScrSaveFailed);
		}
		else
		{
		    printf("Screen saved in screen%d.rgb\n", k);
		}
		return;
	    }
	}
    }
#endif
}

void DeleteMenus(winInfo)
WinInfoPtr winInfo;
/*Deletes the menus in winInfo*/
{
#ifdef GRAPHICS
#ifdef MENUS4D
    int k;
    if (winInfo -> mainMenu)
    {
	freepup(winInfo -> mainMenu);
	winInfo -> mainMenu = 0;
    }
    for (k = 0; k < NMENUS; ++k)
    {
	if (winInfo -> subMenus[k])
	{
	    freepup(winInfo -> subMenus[k]);
	    winInfo -> subMenus[k] = 0;
	}
    }
#endif
#endif
}

void SetFont(object, f)
ObjPtr object;
char *f;
/*Sets object to have font f*/
{
    if (object)
    {
	if (logging)
	{
	    char cmd[256];
	    char *s;

	    sprintf(cmd, "set font ");
	    s = &(cmd[0]);
	    while (*s) ++s;
	    MakeObjectName(s, object);
	    while (*s) ++s;
	    *s++ = ' ';
	    strcpy(s, f);
	    while (*s) ++s;
	    *s++ = '\n';
	    *s = 0;
	    Log(cmd);
	}
	SetTextFont(object, f);
    }
}

static char *globalFont;

static ObjPtr SetGlobalFont(object)
ObjPtr object;
/*Sets the object's font to globalFont*/
{
#ifdef GRAPHICS
    SetFont(object, globalFont);
    return ObjTrue;
#endif
}

void MenuSetFont(n)
int n;
/*Sets font n*/
{
#ifdef GRAPHICS
    globalFont = fonts[n];
    ForAllSelectedObjects(SetGlobalFont);
#endif
}

void SetSize(object, size)
ObjPtr object;
int size;
/*Sets object to have font size size*/
{
    if (object)
    {
	if (logging)
	{
	    char cmd[256];
	    char *s;

	    sprintf(cmd, "set size ");
	    s = &(cmd[0]);
	    while (*s) ++s;
	    MakeObjectName(s, object);
	    while (*s) ++s;
	    *s++ = ' ';
	    sprintf(s, "%d", size);
	    while (*s) ++s;
	    *s++ = '\n';
	    *s = 0;
	    Log(cmd);
	}
	{
	    SetTextSize(object, size);
	}
    }
}

static int globalSize;

static ObjPtr SetGlobalSize(object)
ObjPtr object;
/*Sets the object's font to globalFont*/
{
    SetSize(object, globalSize);
    return ObjTrue;
}

void MenuSetSize(n)
int n;
/*Sets size n*/
{
    globalSize = n;
    ForAllSelectedObjects(SetGlobalSize);
}

void SetAlignment(object, alignment)
ObjPtr object;
int alignment;
/*Sets object to have alignment*/
{
    if (object)
    {
	if (logging)
	{
	    char cmd[256];
	    char *s;

	    sprintf(cmd, "set alignment ");
	    s = &(cmd[0]);
	    while (*s) ++s;
	    MakeObjectName(s, object);
	    while (*s) ++s;
	    *s++ = ' ';
	    sprintf(s, "%d", alignment);
	    while (*s) ++s;
	    *s++ = '\n';
	    *s = 0;
	    Log(cmd);
	}
	{
	    SetTextAlign(object, alignment);
	}
    }
}

static int globalAlignment;

static ObjPtr SetGlobalAlignment(object)
ObjPtr object;
/*Sets the object's font to globalFont*/
{
    SetAlignment(object, globalAlignment);
    return ObjTrue;
}

void MenuSetAlignment(n)
int n;
/*Sets alignment of text to n, n is ALIGNLEFT, ALIGNRIGHT, or ALIGNCENTER*/
{
    globalAlignment = n;
    ForAllSelectedObjects(SetGlobalAlignment);
}

void PopDatasetsWindow(void)
{
    Log("show datasets\n");
    InhibitLogging(true);
    PopWindow(DatasetsWindow());
    InhibitLogging(false);
}

void PopFileReadersWindow(void)
{
    Log("show filereaders\n");
    InhibitLogging(true);
    PopWindow(FileReadersWindow());
    InhibitLogging(false);
}

void CutText(void)
/*Cuts text*/
{
    if (selWinInfo)
    {
	ObjPtr current;
	current = GetVar((ObjPtr) selWinInfo, CURRENT);
	if (current)
	{
	    FuncTyp method;
	    method = GetMethod(current, CUT);
	    if (method)
	    {
		ObjPtr value;
		value = (*method)(current);
		if (value)
		{
		    ObjPtr *elements;
		    elements = ELEMENTS(clipboard);
		    elements[0] = value;
		}
	    }
	}
    }
}

void CopyText(void)
/*Cuts text*/
{
    if (selWinInfo)
    {
	ObjPtr current;
	current = GetVar((ObjPtr) selWinInfo, CURRENT);
	if (current)
	{
	    FuncTyp method;
	    method = GetMethod(current, COPY);
	    if (method)
	    {
		ObjPtr value;
		value = (*method)(current);
		if (value)
		{
		    ObjPtr *elements;
		    elements = ELEMENTS(clipboard);
		    elements[0] = value;
		}
	    }
	}
    }
}

void PasteText(void)
/*Cuts text*/
{
    if (selWinInfo)
    {
	ObjPtr current;
	current = GetVar((ObjPtr) selWinInfo, CURRENT);
	if (current)
	{
	    FuncTyp method;
	    method = GetMethod(current, PASTE);
	    if (method)
	    {
		ObjPtr value;
		ObjPtr *elements;
		elements = ELEMENTS(clipboard);
		value = elements[0];
		(*method)(current, value);
	    }
	}
    }
}

void DoUndoReshape()
/*Undoes a reshape of the window*/
{
#ifdef GRAPHICS
#ifdef WINDOWS4D
    if (selWinInfo)
    {
	winposition(selWinInfo -> ol, selWinInfo -> or, selWinInfo -> ob, selWinInfo -> ot);
    }
#endif
#endif
}

void DoClose()
/*Closes the current window*/
{
    if (selWinInfo && selWinInfo -> id)
    {
	DeferMessage((ObjPtr) selWinInfo, DISPOSE);
    }
}

void BuildMenu(winInfo)
WinInfoPtr winInfo;
/*Builds a menu in winInfo*/
{
#ifdef GRAPHICS
#ifdef MENUS4D
    long mainMenu;		/*Main menu*/
    int k;
    Bool textMenu = false;	/*Text menu has been added*/
    
    /*Make the initial menus null*/
    DeleteMenus(winInfo);
    for (k = 0; k < NMENUS; ++k)
    {
	winInfo -> subMenus[k] = 0;
    }


    /*Give the window a WINDOW menu*/
    if (!winInfo -> subMenus[WINDOWSMENU]);
    {
	winInfo -> subMenus[WINDOWSMENU] = newpup();
    }

    /*Do the function menus*/
    AddFunctionMenus(winInfo);

    /*Set up the prefix parts of the menus*/

    /*Size menu*/
    if ((winInfo -> flags & WINFIXEDSIZE) == 0)
    {
	/*It can move; give it moving items*/
	winInfo -> subMenus[WINSIZEMENU] = newpup();
	addtopup(winInfo -> subMenus[WINSIZEMENU], "Full Screen%f", DoMaxScreen);
	addtopup(winInfo -> subMenus[WINSIZEMENU], "Video Screen%f", DoVideoScreen);
	addtopup(winInfo -> subMenus[WINSIZEMENU], "Double Video Screen%f", Do2VideoScreen);
	addtopup(winInfo -> subMenus[WINSIZEMENU], "Previous Location%f", DoUndoReshape);
    }

    /*File menu*/
    if (!winInfo -> subMenus[FILEMENU])
    {
	winInfo -> subMenus[FILEMENU] = newpup();
    }
    addtopup(winInfo -> subMenus[FILEMENU], "New File Window%f", DoNewFileWindow);
#ifdef SOCKETS
#ifndef RELEASE
    if (!winInfo -> subMenus[NETWORKMENU])
    {
	winInfo -> subMenus[NETWORKMENU] = newpup();
    }
    addtopup(winInfo -> subMenus[NETWORKMENU], "Connect To Computer...%f", DoConnectToComputer);
#endif
#endif

    /*Go through the defined menu items*/
    for (k = 0; k < winInfo -> nMenuItems; ++k)
    {
	int whichMenu;
	whichMenu = winInfo -> menuItems[k] . menu;
	if (!winInfo -> subMenus[whichMenu])
	{
	    winInfo -> subMenus[whichMenu] = newpup();
	}
	if ((whichMenu == TEXTMENU) && !textMenu)
	{
	    textMenu = true;
	    addtopup(winInfo -> subMenus[TEXTMENU], "Cut Text%f", CutText);
	    addtopup(winInfo -> subMenus[TEXTMENU], "Copy Text%f", CopyText);
	    addtopup(winInfo -> subMenus[TEXTMENU], "Paste Text%f", PasteText);
	    if (fontSubMenu)
	    {
		addtopup(winInfo -> subMenus[TEXTMENU], "Text Font%m", fontSubMenu);
	    }
	    if (sizeSubMenu)
	    {
		addtopup(winInfo -> subMenus[TEXTMENU], "Text Size%m", sizeSubMenu);
	    }
	    if (alignSubMenu)
	    {
		addtopup(winInfo -> subMenus[TEXTMENU], "Text Alignment%m", alignSubMenu);
	    }
	    if (strlen(winInfo -> menuItems[k] . name))
	    {
		addtopup(winInfo -> subMenus[TEXTMENU], "-");
	    }
	}
	if (strlen(winInfo -> menuItems[k] . name))
	{
	    sprintf(tempStr, "%s%%f", winInfo -> menuItems[k] . name);
	    addtopup(winInfo -> subMenus[whichMenu], tempStr, winInfo -> menuItems[k] . action);
	}
    }

    /*Put arrange menu in window menu*/
    if ((winInfo -> flags & WINFIXEDSIZE) == 0)
    {
	sprintf(tempStr, "%s%%m", menuName[WINSIZEMENU]);
	addtopup(winInfo -> subMenus[WINDOWSMENU], tempStr, winInfo -> subMenus[WINSIZEMENU]);
    }

    /*Set up the postfix parts of the menus*/
    if (GetPredicate((ObjPtr) winInfo, HIDEPANEL))
    {
	if (GetPredicate((ObjPtr) winInfo, PANELHIDDEN))
	{
	    addtopup(winInfo -> subMenus[WINDOWSMENU], "Show Control Panel%f", DoShowPanel);
	}
	else
	{
	    addtopup(winInfo -> subMenus[WINDOWSMENU], "Hide Control Panel%f", DoHidePanel);
	}
    }
#ifndef NOHIDEFRAME
    if (winInfo -> flags & WINNOFRAME)
    {
	addtopup(winInfo -> subMenus[WINDOWSMENU], "Show Window Frame%f", DoShowFrame);
    }
    else
    {
	addtopup(winInfo -> subMenus[WINDOWSMENU], "Hide Window Frame%f", DoHideFrame);
    }
#endif
    addtopup(winInfo -> subMenus[WINDOWSMENU], "Close%f", DoClose);
    addtopup(winInfo -> subMenus[FILEMENU], "Show File Readers%f", PopFileReadersWindow);

    /*Now create the main menu*/
    sprintf(tempStr, "%s%%t", "SciAn");
    mainMenu = defpup(tempStr);

    addtopup(mainMenu, "Help%f", DoShowHelp);
    addtopup(mainMenu, "Preferences%f", DoShowPreferences);

    /*Add in the little menus*/
    for (k = 0; k < NMENUS; ++k)
    {
	if ((winInfo -> subMenus[k]) && (k != WINSIZEMENU) && (k != ARRANGEMENU))
	{
	    sprintf(tempStr, "%s%%m", menuName[k]);
	    addtopup(mainMenu, tempStr, winInfo -> subMenus[k]);
	}
    }

    /*Add the quit*/
    addtopup(mainMenu, "Quit SciAn%f", MaybeQuit);
    winInfo -> mainMenu = mainMenu;
#endif
#endif
}

void DefineMenuItem(window, menu, name, action)
ObjPtr window;
int menu;
char *name;
void (*action)();
/*Defines a menu item in window under menu with name and action*/
{
    int nMenuItems;

    /*Add it to the window's list of menu items*/
    nMenuItems = ((WinInfoPtr) window) -> nMenuItems;
    ((WinInfoPtr) window) -> menuItems[nMenuItems] . menu = menu;
    strcpy(((WinInfoPtr) window) -> menuItems[nMenuItems] . name, name);
    ((WinInfoPtr) window) -> menuItems[nMenuItems] . action = action;
    ((WinInfoPtr) window) -> nMenuItems = nMenuItems + 1;
}

void DropCursorInWindows()
/*Drops the cursor in all the windows*/
{
#ifdef GRAPHICS
#ifdef CURSORS4D
	WinInfoPtr curWindow;

	curWindow = allWindows;
	while (curWindow)
	{
	    if (curWindow -> id)
	    {
		winset(curWindow -> id);
		if (curCursor < 0)
		{
		    cursoff();
		}
		else
		{
		    curson();
		    setcursor(curCursor, (Colorindex) 1, (Colorindex) 0);
		}
	    }
	    curWindow = curWindow -> next;
	}
#endif
#endif
}

void MySetCursor(cursorNumber)
int cursorNumber;
/*Sets the cursor to cursorNumber*/
{
#ifdef GRAPHICS
    if (cursorNumber != curCursor)
    {
	curCursor = cursorNumber;

	DoTask(DropCursorInWindows);
    }
#endif
}

WindowID NewOpenedWindow(title, minWidth, minHeight, maxWidth, maxHeight, flags)
char *title;
int minWidth, minHeight, maxWidth, maxHeight;
long flags;
/*Creates a new opened window with title, and size determined by minWidth,
  minHeight, maxWidth, and maxHeight and returns a window ID which will
  differ from machine to machine.*/
{
    WindowID retVal = 0;
    long ox, oy;
    int stagX, stagY;

    /*Edit flags*/
    if (!hasRGB && (flags & WINRGB)) flags &= ~WINRGB;
    if (!hasCmap && !(flags & WINRGB)) flags |= WINRGB;
    if (!hasDouble && (flags & WINDBUF)) flags &= ~WINDBUF;

#ifdef GRAPHICS
#ifdef WINDOWS4D
#ifndef NOHIDEFRAME
    if (flags & WINNOFRAME)
    {
	noborder();
    }
#endif
#endif
#endif

    if (flags & WINCENTERED)
    {
	ox = SCRWIDTH / 2 - minWidth / 2;
	oy = SCRHEIGHT / 2 - minHeight / 2;
#ifdef GRAPHICS
#ifdef WINDOWS4D
	prefposition(ox, ox + minWidth,
		     oy, oy + minHeight);
#endif
#endif
    }
    else
#ifndef WINNOCLOSE
    if (runningScript || runningRemote || GetPrefTruth(PREF_NEWWINPLACE))
#endif
    {
#ifdef GRAPHICS
#ifdef WINDOWS4D
	prefposition(stagX = STAGX + stagger, STAGX + stagger + minWidth,
		     stagY = STAGY - stagger - minHeight, STAGY - stagger);
#endif
#endif
	stagger += STAGSTEP;
	if (stagger > STAGMAX) stagger = 0;
    }
    else
    {
#ifdef GRAPHICS
#ifdef WINDOWS4D
	minsize(minWidth, minHeight);
	maxsize(maxWidth, maxHeight);
#endif
#endif
    }

#ifdef GRAPHICS
#ifdef WINDOWS4D
#ifdef WINNOCLOSE
	if (nCachedWindows)
	{
	    --nCachedWindows;
	    retVal = cachedWindows[nCachedWindows];
	    winset(retVal);
	    if (flags & WINCENTERED)
	    {
		ox = SCRWIDTH / 2 - minWidth / 2;
		oy = SCRHEIGHT / 2 - minHeight / 2;
		winposition(ox, ox + minWidth,
		     oy, oy + minHeight);
	    }
	    else
	    {
		winposition(stagX, stagX + minWidth,
		     stagY, stagY + minHeight);
	    }
	}
	else
#endif
    retVal = winopen(title);

    wintitle(title);
    minsize(minWidth, minHeight);
    maxsize(maxWidth, maxHeight);
    winconstraints();

    winset(retVal);
    if (hasDouble && (flags & WINDBUF))
    {
	doublebuffer();
    }
    else
    {
	singlebuffer();
    }
    shademodel(FLAT);
    gconfig();
#endif
#endif
    InitStuff();

    return retVal;
}

void SetMinSize(winInfo, mw, mh)
WinInfoPtr winInfo;
int mw, mh;
/*Sets the minimum size of window winInfo to mw, mh*/
{
#ifdef WINDOWS4D
    SelWindow(winInfo);
    minsize(mw, mh);
    winconstraints();
#endif
}

void SetMode(curWinInfo)
WinInfoPtr curWinInfo;
/*Sets the mode of the current window according to the flags*/
{
	SelWindow(curWinInfo);
#ifdef WINDOWS4D
	if (curWinInfo -> flags & WINRGB)
	{
	    if (hasRGB)
	    {
		RGBmode();
	    }
	    else
	    {
		cmode();
	    }
	}
	else
	{
	    if (hasCmap)
	    {
		cmode();
	    }
	    else
	    {
		RGBmode();
	    }
	}
	if (hasDouble && (curWinInfo -> flags & WINDBUF))
	{
	    doublebuffer();
	}
	else
	{
	    singlebuffer();
	}
	gconfig();
#endif
}

void DoMaxScreen()
/*Makes the current window go to the max screen*/
{
#ifdef GRAPHICS
#ifdef WINDOWS4D
    winposition(0, SCRWIDTH, 0, SCRHEIGHT);
#endif
#endif
    phsco = false;
}


void DoVideoScreen()
/*Makes the current window go to the video screen*/
{
#ifdef GRAPHICS
#ifdef WINDOWS4D
    winposition(0, recScrWidth, 0, recScrHeight);
#endif
#endif
    phsco = false;
}

void Do2VideoScreen()
/*Makes the current window go to twice the video screen*/
{
#ifdef GRAPHICS
#ifdef WINDOWS4D
    winposition(0, 2 * recScrWidth, 0, 2 * recScrHeight);
#endif
#endif
    phsco = false;
}

void LocateWindow(l, r, b, t)
int l, r, b, t;
/*Locates current window at l, r, b, t*/
{
#ifdef GRAPHICS
#ifdef WINDOWS4D
    winposition(l, r, b, t);
#endif
#endif
    phsco = false;
}

void DoPhscoScreen()
/*Makes the current window go to the phscologram screen*/
{
#ifdef GRAPHICS
#ifdef WINDOWS4D
    winposition(0, 1100, 0, 615);
#endif
#endif
    phsco = true;
}

static void NullAndVoid()
/*Default do-nothing void routine*/
{
}

static Bool TrueBool()
/*Boolean routine that returns true*/
{
}

WinInfoPtr NewWinInfo(superClass, windowID, flags, title, 
		minWidth, minHeight, maxWidth, maxHeight)
ObjPtr superClass;
long windowID;
long flags;
char *title;
int minWidth, minHeight, maxWidth, maxHeight;
/*Creates a new window information record associated with windowID 
  and returns it, or NIL if it couldn't 
  allocate one.  Sets everything to the default.  Sets the superclass to
  superClass so that it can inherit*/
{
    WinInfoPtr newInfo;

#ifdef GRAPHICS
    if (windowID)
    {
	winset(windowID);
    }
#endif

    if (firstTime)
    {
#ifdef GRAPHICS
	/*Finish the initialization that we couldn't do until the 1st window*/
#if 0
	singlebuffer();
	cmode();
	zbuffer(FALSE);
	gconfig();
#endif
	firstTime = 0;
#endif
    }

    if (superClass == 0)
    {
	superClass = windowClass;
    }

    newInfo = (WinInfoPtr) NewObject(superClass, sizeof(WinInfo) - sizeof(Thing));
    if (newInfo)
    {
	int k;
	WinInfoPtr *runner;
	long ox, oy, sx, sy;

	/*Set up the new info to point to this window*/
	newInfo -> id = windowID;

	/*Link the new info into the list*/
	runner = &(allWindows);
	while (*runner)
	{
	    runner = &((*runner) -> next);
	}
	*runner = newInfo;
	newInfo -> next = 0;

	/*Initialize values to defaults*/
        SETOBJTYPE(newInfo -> thing . flags, WINDOW);
	AddToReferenceList((ObjPtr) newInfo);
        
	newInfo -> flags = flags;
	ImInvalid((ObjPtr) newInfo);
	newInfo -> mainMenu = 0;
	for (k = 0; k < NMENUS; ++k)
	{
	    newInfo -> subMenus[k] = 0;
	}
	newInfo -> nMenuItems = 0;

	newInfo -> minWidth = minWidth;
	newInfo -> maxWidth = maxWidth;
	newInfo -> minHeight = minHeight;
	newInfo -> maxHeight = maxHeight;

	if (windowID)
	{
	/*Set to the current window and set the graphics state*/
	SetMode(newInfo);
	}
	
	/*Save the title*/
	strcpy(newInfo -> winTitle, title);
	SetVar((ObjPtr) newInfo, NAME, NewString(title));

	/*Select the new window*/
	SelWindow(newInfo);

	/*Stuff ol, or, ob, ot*/
#ifdef WINDOWS4D
#ifdef GRAPHICS
	if (windowID)
	{
	    getorigin(&ox, &oy);
	    getsize(&sx, &sy);
	}
	else
	{
	    ox = SCRWIDTH / 2 - minWidth / 2;
	    oy = SCRHEIGHT / 2 - minHeight / 2;
	    sx = minWidth;
	    sy = minHeight;
	}
	newInfo -> nl = ox;
	newInfo -> nr = ox + sx - 1;
	newInfo -> nb = oy;
	newInfo -> nt = oy + sy - 1;
	newInfo -> ol = ox;
	newInfo -> or = ox + sx - 1;
	newInfo -> ob = oy;
	newInfo -> ot = oy + sy - 1;
#endif
#endif

	/*Return the new info*/
	return newInfo;
    }
    else
    {
	/*Failed to allocate info.  Return NIL*/
	OMErr();
	return (WinInfoPtr) 0;
    }
}

void SetWindowTitle(win, title)
ObjPtr win;
char *title;
/*Sets window title to title*/
{
    strcpy(((WinInfoPtr) win) -> winTitle, title);
    SetVar((ObjPtr) win, NAME, NewString(title));
#ifdef GRAPHICS
#ifdef WINDOWS4D
    if (!(win -> flags & WINNOFRAME))
    {
	wintitle(title);
    }
#endif
#endif
}

Bool IsValidWindow(window)
WinInfoPtr window;
/*Returns true iff window is a valid window*/
{
    register WinInfoPtr runner;

    runner = allWindows;
    while (runner)
    {
	if (runner == window)
	{
	    return true;
	}
	runner = runner -> next;
    }
    return false;
}

WinInfoPtr GetWinInfo(winID)
long winID;
/*Gets the winInfo record associated with winID or returns NIL*/
{
    register WinInfoPtr runner;
    if (winID == 0) return 0;

    runner = allWindows;
    while (runner)
    {
	if (runner -> id == winID)
	{
	    return runner;
	}
	runner = runner -> next;
    }
    return (WinInfoPtr) 0;
}

int strcmp2(s1, s2)
char s1[], s2[];
/*Compares s1 and s2 without regard to case*/
{
    int k;
    for (k = 0; s1[k]; ++k)
    {
	if (toupper(s1[k]) < toupper(s2[k])) return -k - 1;
	if (toupper(s1[k]) > toupper(s2[k])) return k + 1;
    }
    return s2[k] ? -k - 1 : 0;
}

WinInfoPtr GetWinFromTitle(title)
char *title;
/*Gets the winInfo record associated with title.  If there is none or there
  is more than one, returns nil*/
{
    register WinInfoPtr runner;
    runner = allWindows;
    while (runner)
    {
	if (!strcmp2(runner -> winTitle, title))
	{
	    return runner;
	}
	runner = runner -> next;
    }
    return (WinInfoPtr) 0;
}

ObjPtr DisposeWindow(window)
WinInfoPtr window;
/*Disposes of the given window and closes the window.*/
{
    WinInfoPtr *runner;
    runner = &allWindows;
    while (*runner)
    {
	if ((*runner) == window)
	{
	    WinInfoPtr next;
	    FuncTyp closeRoutine;
	    
	    /*Found it.  Close it.*/
	    if (logging)
	    {
		Log("close\n");
	    }

	    /*First check for hide routine*/
	    closeRoutine = GetMethod((ObjPtr) *runner, HIDE);
	    if (closeRoutine && IsTrue((*closeRoutine)(*runner)))
	    {
#ifdef GRAPHICS
#ifdef WINDOWS4D
#ifdef WINNOCLOSE
		cachedWindows[nCachedWindows] = (*runner) -> id;
		++nCachedWindows;
		SelWindow(*runner);
		minsize(100, 100);
		maxsize(1280, 1024);
		winconstraints();
		winposition(-200, -100, -200, -100);
#else
		winclose((*runner) -> id);
#endif
#endif
#endif
		if ((*runner) == inputWindow)
		{
		    inputWindow = 0;
		}
		(*runner) -> id = 0;
		SelWindow((WinInfoPtr) 0);

		/*Just advance*/
		runner = &((*runner) -> next);
	    }
	    else
	    {
		closeRoutine = GetMethod((ObjPtr) *runner, CLOSE);
		if (closeRoutine && !IsTrue((*closeRoutine)(*runner)))
		{
		    return ObjFalse;
		}
		SelWindow(*runner);

#ifdef GRAPHICS
#ifdef WINDOWS4D
#ifdef WINNOCLOSE
		cachedWindows[nCachedWindows] = (*runner) -> id;
		++nCachedWindows;
		minsize(100, 100);
		maxsize(1280, 1024);
		winconstraints();
		winposition(-200, -100, -200, -100);
#else
		winclose((*runner) -> id);
#endif
#endif
#endif
		if ((*runner) == inputWindow)
		{
		    inputWindow = 0;
		}
		SelWindow(0);
		next = (*runner) -> next;
		(*runner) -> id = 0;
		DeleteThing((ObjPtr) *runner);
		*runner = next;
	    }
	}
	else
	{
	    /*Not found.  Just advance.*/
	    runner = &((*runner) -> next);
	}
    }
    if (!allWindows)
    {
	DoQuit();
    }
    return ObjTrue;
}

Bool DisposeAllWindows()
/*Disposes of all the windows.  Returns true iff successful.*/
{
    while (allWindows)
    {
	WinInfoPtr next;
	FuncTyp closeRoutine;

	closeRoutine = GetMethod((ObjPtr) allWindows, CLOSE);
	if (closeRoutine && !IsTrue((*closeRoutine)(allWindows)))
	{
	    return false;
	}
#ifdef WINNOCLOSE
	cachedWindows[nCachedWindows] = allWindows -> id;
	++nCachedWindows;
	SelWindow(allWindows);

#ifdef GRAPHICS
#ifdef WINDOWS4D
	minsize(100, 100);
	maxsize(1280, 1024);
	winconstraints();
	winposition(-200, -100, -200, -100);
#else
	if (allWindows -> id)
	{
	    winclose(allWindows -> id);
	    allWindows -> id = 0;
	}
#endif
#endif
#endif
	next = allWindows -> next;
	DeleteThing((ObjPtr) allWindows);
	allWindows = next;
    }
    inputWindow = 0;
    return true;
}

int ReshapeWindow(window)
ObjPtr window;
/*Reshapes a window to a new viewport.*/
{
    if (selWinInfo)
    {
	FuncTyp reshapeMethod;
	reshapeMethod = GetMethod(window, RESHAPE);
	if (reshapeMethod)
	{
	    (*reshapeMethod)(window, 
		((WinInfoPtr) selWinInfo) -> ol,
		((WinInfoPtr) selWinInfo) -> or,
		((WinInfoPtr) selWinInfo) -> ob,
		((WinInfoPtr) selWinInfo) -> ot,
		((WinInfoPtr) selWinInfo) -> nl,
		((WinInfoPtr) selWinInfo) -> nr,
		((WinInfoPtr) selWinInfo) -> nb,
		((WinInfoPtr) selWinInfo) -> nt
		);
	}
    }
    return true;
}

void ForAllWindows(routine)
void (*routine)();
/*Performs (*routine)(window) on all windows*/
{
    WinInfoPtr curWindow;
    curWindow = allWindows;
    while (curWindow)
    {
	(*routine)(curWindow);
	curWindow = curWindow -> next;
    }
}

static ObjPtr MakeWindowDrawn(curWindow)
WinInfoPtr curWindow;
/*Method to make a window drawn.  Returns true iff drawing done*/
{
    ObjPtr retVal = ObjFalse;
#ifdef GRAPHICS
    int picState;
    ObjPtr picVar;

    picVar = GetVar((ObjPtr) curWindow, PICSTATE);
    if (picVar)
    {
	picState = GetInt(picVar);
    }
    else
    {
	picState = FBBB;
    }    

    if (hasDouble && (curWindow -> flags & WINDBUF))
    {
	/*Double buffer*/
	if (!(picState & BG))
	{
	    /*Back buffer is bad, have to redraw it*/
	    SetVar((ObjPtr) curWindow, PICSTATE, 
		   NewInt(picState & FG ? FGBG : FGBB));
	    SelWindow(curWindow);
	    DrawWindowInfo(curWindow);
	    retVal = ObjTrue;
	}
    }
    else
    {
	/*Single buffer*/
	if (!(picState & FG))
	{
	    SetVar((ObjPtr) curWindow, PICSTATE, NewInt(FGBG));
	    SelWindow(curWindow);
	    DrawWindowInfo(curWindow);
	    retVal = ObjTrue;
	}
    }
#endif
    return retVal;
}

Bool IdleAllWindows()
/*Idles all the windows, redrawing double-buffered ones.  Returns true
  iff any redrawing was done*/
{
    Bool retVal = false;
#ifdef GRAPHICS
    WinInfoPtr curWindow;
    WinInfoPtr oldWindow;
    int dummy;
    int prefDrawMoving;

    oldWindow = selWinInfo;
    ++updateBatch;

    prefDrawMoving = GetPrefInteger(PREF_DRAWMOVING);

    for (curWindow = allWindows; curWindow; curWindow = curWindow -> next)
    {
	FuncTyp method;

	if (curWindow -> id == 0) continue;

	if (AltDown() && (curWindow != inputWindow))
	{
	    continue;
	}

	method = GetMethod((ObjPtr) curWindow, MAKEDRAWN);
	if (method)
	{
	    struct tms buffer;
	    long beginDraw;

	    if (interactiveMoving)
	    {
		if (prefDrawMoving == DM_SKELETON)
		{
		    SetVar((ObjPtr) curWindow, MOVESKELETON, ObjTrue);
		    drawingQuality = DQ_SKELETON;
		}
		else if (prefDrawMoving == DM_FULL)
		{
		    SetVar((ObjPtr) curWindow, MOVESKELETON, ObjFalse);
		    drawingQuality = DQ_FULL;
		}
		else if (prefDrawMoving == DM_AUTO)
		{
		    beginDraw = times(&buffer);
		    drawingQuality = 
			GetPredicate((ObjPtr) curWindow, MOVESKELETON) ?
			    DQ_SKELETON : DQ_FULL;
		}
	    }
	    else
	    {
		SetVar((ObjPtr) curWindow, MOVESKELETON, ObjFalse);
		drawingQuality = DQ_FULL;
	    }

	    if (IsTrue((*method)(curWindow)))
	    {
		retVal = true;
#ifdef GL4D
		if (hasDouble && (curWindow -> flags & WINDBUF))
		{
		    swapbuffers();
		}
#endif
	    }
	    if (interactiveMoving)
	    {
		if (prefDrawMoving == DM_AUTO && drawingQuality == DQ_FULL)
		{
		    if (times(&buffer) > beginDraw + MAXMOVETIME)
		    {
			/*Back off on drawing quality*/
			SetVar((ObjPtr) curWindow, MOVESKELETON, ObjTrue);
		    }
		    else
		    {
			SetVar((ObjPtr) curWindow, MOVESKELETON, ObjFalse);
		    }
		}
	    }
	}
    }
#ifndef GL4D
    if (hasDouble)
    {
	swapbuffers();
    }!
#endif
    if (oldWindow && (oldWindow != selWinInfo))
    {
	SelWindow(oldWindow);
    }
#endif
    return retVal;
}


void DeferClose()
/*Does a close as a deferred task*/
{
    if (selWinInfo)
    {
	DeferMessage((ObjPtr) selWinInfo, DISPOSE);
    }
}

void InitWindows()
/*Initializes the window system*/
{
    long dim;
    windowClass = NewObject(NULLOBJ, 0);
    SetMethod(windowClass, MAKEDRAWN, MakeWindowDrawn);
    SetMethod(windowClass, DISPOSE, DisposeWindow);
    SetVar(windowClass, TYPESTRING, NewString("window"));
    AddToReferenceList(windowClass);

#ifdef GRAPHICS
    if (nFonts)
    {
	int k;
	Bool subMenuP;
	char mainFontName[300];
	char *s, *d, *f;

	/*Make the fonts submenu*/
	strcpy(mainFontName, "");
	subMenuP = false;

	fontSubMenu = newpup();
	for (k = 0; k < nFonts; ++k)
	{
	    Bool matches;
	    f = strrchr(fonts[k], '-');

	    /*See if this one matches what's in the old name*/
	    if (mainFontName[0])
	    {
		s = mainFontName;
		d = fonts[k];
		while (*s == *d)
		{
		    ++s;
		    ++d;
		}

		if (d == f || *d == 0)
		{
		    matches = true;
		}
		else
		{
		    matches = false;
		}
	    }
	    else
	    {
		matches = false;
	    }

	    /*See if we need to finish up old font*/
	    if (mainFontName[0] && !matches)
	    {
		if (subMenuP)
		{
		    sprintf(tempStr, "%s%%m", mainFontName);
		    addtopup(fontSubMenu, tempStr, styleSubMenus[nStyleSubMenus - 1]);
		}
		else
		{
		    /*Just alone*/
		    sprintf(tempStr, "%s%%f%%x%d", fonts[k - 1], k - 1);
		    addtopup(fontSubMenu, tempStr, MenuSetFont);
		}
		mainFontName[0] = 0;
		subMenuP = 0;
	    }

	    if (!mainFontName[0])
	    {
		/*It's a new main font name.  Copy it in*/
		s = fonts[k];
		d = mainFontName;
		if (f)
		{
		    while (s < f)
		    {
			*d++ = *s++;
		    }
		}
		else
		{
		    while (*s)
		    {
			*d++ = *s++;
		    }
		}
		*d = 0;

		matches = true;

		if (f)
		{
		    /*We know there are more than one; make a new submenu*/
		    if (nStyleSubMenus)
		    {
			++nStyleSubMenus;
			styleSubMenus = (long *) realloc(styleSubMenus, nStyleSubMenus * sizeof(long));
		    }
		    else
		    {
			nStyleSubMenus = 1;
			styleSubMenus = (long *) malloc(nStyleSubMenus * sizeof(long));
		    }
		    styleSubMenus[nStyleSubMenus - 1] = newpup();
		    subMenuP = true;
		    sprintf(tempStr, "%s%%f%%x%d", f + 1, k);
		    addtopup(styleSubMenus[nStyleSubMenus - 1], tempStr, MenuSetFont);
		}
		else
		{
		    /*This may be the only one.  Don't make a submenu*/
		}
	    }
	    else
	    {
		/*It matches a current main font.*/

		if (!subMenuP)
		{
		    /*Create a submenu if it's not there, with Plain*/
		    if (nStyleSubMenus)
		    {
			++nStyleSubMenus;
			styleSubMenus = (long *) realloc(styleSubMenus, nStyleSubMenus * sizeof(long));
		    }
		    else
		    {
			nStyleSubMenus = 1;
			styleSubMenus = (long *) malloc(nStyleSubMenus * sizeof(long));
		    }
		    styleSubMenus[nStyleSubMenus - 1] = newpup();
		    subMenuP = true;
		    sprintf(tempStr, "Plain%%f%%x%d", k - 1);
		    addtopup(styleSubMenus[nStyleSubMenus - 1], tempStr, MenuSetFont);
		}

		/*Now add us*/
		sprintf(tempStr, "%s%%f%%x%d", f ? (f + 1) : "Plain", k);
		addtopup(styleSubMenus[nStyleSubMenus - 1], tempStr, MenuSetFont);
	    }
	}
	/*See if we need to finish up old font*/
	if (mainFontName[0])
	{
	    if (subMenuP)
	    {
		sprintf(tempStr, "%s%%m", mainFontName);
		addtopup(fontSubMenu, tempStr, styleSubMenus[nStyleSubMenus - 1]);
	    }
	    else
	    {
		/*Just alone*/
		sprintf(tempStr, "%s%%f%%x%d", fonts[k - 1], k - 1);
		addtopup(fontSubMenu, tempStr, MenuSetFont);
	    }
	    mainFontName[0] = 0;
	}

	sizeSubMenu = newpup();
	for (k = 0; k < (sizeof(textSizes) / sizeof(int)); ++k)
	{
	    sprintf(tempStr, "%d%%f%%x%d", textSizes[k], textSizes[k]);
	    addtopup(sizeSubMenu, tempStr, MenuSetSize);
	}
    }

    alignSubMenu = newpup();
    sprintf(tempStr, "Align Left%%f%%x%d", LEFTALIGN);
    addtopup(alignSubMenu, tempStr, MenuSetAlignment);
    sprintf(tempStr, "Align Center%%f%%x%d", CENTERALIGN);
    addtopup(alignSubMenu, tempStr, MenuSetAlignment);
    sprintf(tempStr, "Align Right%%f%%x%d", RIGHTALIGN);
    addtopup(alignSubMenu, tempStr, MenuSetAlignment);
#endif

    /*Create the clipboard*/
    dim = 1;
    clipboard = NewArray(AT_OBJECT, 1, &dim);
    AddToReferenceList(clipboard);
}

void KillWindows()
/*Kills the window system*/
{
#ifdef GRAPHICS
    freepup(fontSubMenu);
    if (styleSubMenus)
    {
	free(styleSubMenus);
    }
#endif
    DeleteThing(clipboard);
    DeleteThing(windowClass);
}

