/*********************************************************/
/* This source code copyright (c) 1991-2001, Aaron Giles */
/* See the Read Me file for licensing information.       */
/* Contact email: mac@aarongiles.com                     */
/*********************************************************/

//=====================================================================================
// Generic includes for Macintosh headers
//=====================================================================================

#if THINK_C
#include "THINK.Header"
#elif applec
#pragma load ":Headers:MPW.Header"
#elif __MWERKS__
//#include "MW.Header"
#else
#include "JPEGView.h"
#endif

//===================================================================================
// Includes specific to this module
//===================================================================================

#include "FloatingWindows.h"

//===================================================================================
// Local constants and macros
//===================================================================================

enum {
	kWindowType = 'WIND',
	kFloatingWindowID = 128
};

#define isFloating(win) (WindowKind(win) == floatingWindowKind)

//=====================================================================================
// Global variables local to this module
//=====================================================================================

static WindowPtr gOldTop, gDummyWindow = nil;
static RgnHandle gSaveRgn = nil;

//===================================================================================
// Local functions
//===================================================================================

static void FWRemoveFloats(void);
static void FWRestoreFloats(Boolean redraw);
static void FWInsertDummyWindow(WindowPtr behindWindow);
static void FWRemoveDummyWindow(void);
static Boolean isDialog(WindowPtr win);

//===================================================================================
// void FWActivate(void)
//===================================================================================
// Activates all floating windows and the frontmost document window.
//===================================================================================

extern void FWActivate(void)
{
	WindowPtr fwindow = FWTopFloatingWindow(), window = FWTopWindow();
	
	while (fwindow) {
		if (isFloating(fwindow)) HiliteWindow(fwindow, true);
		fwindow = NextWindow(fwindow);
	}
	while (window && !WindowVisible(window)) window = NextWindow(window);
	if (window) {
		EventRecord theEvent;
		HiliteWindow(window, true);
		theEvent.what = activateEvt;
		theEvent.message = (long)window;
		theEvent.modifiers = 1;
		HandleActivateEvent(&theEvent);
	}
}

//===================================================================================
// void FWDeactivate(void)
//===================================================================================
// Deactivates all floating windows and the frontmost document window.
//===================================================================================

extern void FWDeactivate(void)
{
	WindowPtr fwindow = FWTopFloatingWindow(), window = FWTopWindow();
	
	while (fwindow) {
		if (isFloating(fwindow)) HiliteWindow(fwindow, false);
		fwindow = NextWindow(fwindow);
	}
	while (window && !WindowVisible(window)) window = NextWindow(window);
	if (window) {
		EventRecord theEvent;
		HiliteWindow(window, false);
		theEvent.what = activateEvt;
		theEvent.message = (long)window;
		theEvent.modifiers = 0;
		HandleActivateEvent(&theEvent);
	}
}

//===================================================================================
// void FWHideFloatingWindows(void)
//===================================================================================
// Hides all floating windows.
//===================================================================================

extern void FWHideFloatingWindows(void)
{
	WindowPtr theWindow = FWTopFloatingWindow();

	while (theWindow) {
		if (isFloating(theWindow) && WindowVisible(theWindow)) 
			ShowHide(theWindow, false);
		else if (!isFloating(theWindow) && WindowHilited(theWindow))
			HiliteWindow(theWindow, false);
		theWindow = NextWindow(theWindow);
	}
}

//===================================================================================
// void FWShowFloatingWindows(void)
//===================================================================================
// Shows all floating windows.
//===================================================================================

extern void FWShowFloatingWindows(void)
{
	WindowPtr theWindow = FWBottomFloatingWindow();
	WindowPtr frontWindow = FWFrontWindow();
	WindowPtr lastFloating = nil;
	Boolean frontDialog = isDialog(frontWindow);
	Boolean hilited = false;
	
	if (theWindow) {
		FWInsertDummyWindow(theWindow);
		theWindow = FWTopFloatingWindow();
		while (theWindow) {
			if (isFloating(theWindow)) {
				if (!WindowVisible(theWindow)) {
					ShowHide(theWindow, true);
					HiliteWindow(theWindow, !gInBackground && !frontDialog);
				}
				lastFloating = theWindow;
			}
			if (!isFloating(theWindow) && !hilited) {
				HiliteWindow(theWindow, !gInBackground && !frontDialog);
				hilited = true;
			}
			theWindow = NextWindow(theWindow);
		}
		FWRemoveDummyWindow();
	}
	if (!frontDialog) {
		theWindow = FrontWindow();
		if (theWindow && !isFloating(theWindow) && lastFloating)
			SendBehind(theWindow, lastFloating);
	}
}

//===================================================================================
// WindowPtr FWGetNewFloatingWindow(short resID, Ptr wStorage, WindowPtr behind)
//===================================================================================
// Creates a new floating window, based on a given resource definition.
//===================================================================================

extern WindowPtr FWGetNewFloatingWindow(short resID, Ptr wStorage, WindowPtr behind)
{
	WindowPtr theWindow;

	if (behind != (WindowPtr)-1 && (!behind || !isFloating(behind))) {
		behind = FWBottomFloatingWindow();
		if (!behind) behind = (WindowPtr)-1;
	}
	FWInsertDummyWindow(behind);
	theWindow = GetNewCWindow(resID, wStorage, behind);
	if (theWindow) SetWindowKind(theWindow, floatingWindowKind);
	FWRemoveDummyWindow();
	return theWindow;
}

//===================================================================================
// WindowPtr FWNewFloatingWindow(Ptr wStorage, Rect *rBounds, Str255 title, 
//			Boolean visFlag, short wDefProcID, WindowPtr behind, Boolean goAwayFlag, 
//			long refCon)
//===================================================================================
// Creates a new floating window.
//===================================================================================

extern WindowPtr FWNewFloatingWindow(Ptr wStorage, Rect *rBounds, Str255 title, 
			Boolean visFlag, short wDefProcID, WindowPtr behind, Boolean goAwayFlag, 
			long refCon)
{
	WindowPtr theWindow;
	
	if (behind != (WindowPtr)-1 && (!behind || !isFloating(behind))) {
		behind = FWBottomFloatingWindow();
		if (!behind) behind = (WindowPtr)-1;
	}
	FWInsertDummyWindow(behind);
	theWindow = NewCWindow(wStorage, rBounds, title, visFlag, wDefProcID, behind, 
				goAwayFlag, refCon);
	if (theWindow) SetWindowKind(theWindow, floatingWindowKind);
	FWRemoveDummyWindow();
	return theWindow;
}

//===================================================================================
// short FWAlert(short alertID, ModalFilterProcPtr filterProc)
//===================================================================================
// Displays a generic alert in the floating window environment.
//===================================================================================

extern short FWAlert(short alertID, ModalFilterUPP filterProc)
{
	short theItem;
	
	FWDeactivate();
	theItem = Alert(alertID, filterProc);
	FWActivate();
	return theItem;
}

//===================================================================================
// short FWCautionAlert(short alertID, ModalFilterProcPtr filterProc)
//===================================================================================
// Displays a caution alert in the floating window environment.
//===================================================================================

extern short FWCautionAlert(short alertID, ModalFilterUPP filterProc)
{
	short theItem;
	
	FWDeactivate();
	theItem = CautionAlert(alertID, filterProc);
	FWActivate();
	return theItem;
}

//===================================================================================
// short FWNoteAlert(short alertID, ModalFilterProcPtr filterProc)
//===================================================================================
// Displays a note alert in the floating window environment.
//===================================================================================

extern short FWNoteAlert(short alertID, ModalFilterUPP filterProc)
{
	short theItem;
	
	FWDeactivate();
	theItem = NoteAlert(alertID, filterProc);
	FWActivate();
	return theItem;
}

//===================================================================================
// short FWStopAlert(short alertID, ModalFilterProcPtr filterProc)
//===================================================================================
// Displays a stop alert in the floating window environment.
//===================================================================================

extern short FWStopAlert(short alertID, ModalFilterUPP filterProc)
{
	short theItem;
	
	FWDeactivate();
	theItem = StopAlert(alertID, filterProc);
	FWActivate();
	return theItem;
}

//===================================================================================
// void FWCloseDialog(DialogPtr theDialog)
//===================================================================================
// Closes a dialog in the floating window environment.
//===================================================================================

extern void FWCloseDialog(DialogPtr theDialog)
{
	CloseDialog(theDialog);
	if (!FWTopDialog()) FWActivate();
}

//===================================================================================
// void FWDisposeDialog(DialogPtr theDialog)
//===================================================================================
// Disposes of a dialog in the floating window environment.
//===================================================================================

extern void FWDisposeDialog(DialogPtr theDialog)
{
	DisposeDialog(theDialog);
	if (!FWTopDialog()) FWActivate();
}

//===================================================================================
// Boolean FWDialogSelect(EventRecord *theEvent, DialogPtr *whichDlog, short *itemHit)
//===================================================================================
// Handles events in dialog within a floating window environment.
//===================================================================================

extern Boolean FWDialogSelect(EventRecord *theEvent, DialogPtr *whichDlog, short *itemHit)
{
	Boolean theAnswer;
	
	FWRemoveFloats();
	theAnswer = DialogSelect(theEvent, whichDlog, itemHit);
	FWRestoreFloats(false);
	return theAnswer;
}

//===================================================================================
// Boolean FWIsDialogEvent(EventRecord *theEvent)
//===================================================================================
// Returns true if the given event was associated with a dialog.
//===================================================================================

extern Boolean FWIsDialogEvent(EventRecord *theEvent)
{
	WindowPtr theWindow;
	Boolean theAnswer;
	short thePart;

	thePart = FindWindow(theEvent->where, &theWindow);
	if (!isFloating(theWindow)) FWRemoveFloats();
	theAnswer = IsDialogEvent(theEvent);
	if (!isFloating(theWindow)) FWRestoreFloats(false);
	return theAnswer;
}

//===================================================================================
// DialogPtr FWGetNewDialog(short dlgRsrcID, Ptr dStorage, WindowPtr behind)
//===================================================================================
// Creates a new dialog from a resource in the floating window environment.
//===================================================================================

extern DialogPtr FWGetNewDialog(short dlgRsrcID, Ptr dStorage, WindowPtr behind)
{
	Boolean floatingTop = (GetFirstWindow() && isFloating(GetFirstWindow()));
	DialogTHndl theTemplate = (DialogTHndl)GetResource('DLOG', dlgRsrcID);
	Boolean modalDialog = false;
	DialogPtr theDialog;
	
	if (theTemplate) {
		modalDialog = ((*theTemplate)->procID >= dBoxProc && 
					(*theTemplate)->procID <= altDBoxProc) ||
					(*theTemplate)->procID == movableDBoxProc;
		if (modalDialog) FWDeactivate();
		ReleaseResource((Handle)theTemplate);
	}
	if (!modalDialog && floatingTop) FWRemoveFloats();
	theDialog = GetNewDialog(dlgRsrcID, dStorage, behind);
	if (!modalDialog && floatingTop) FWRestoreFloats(true);
	return theDialog;
}

//===================================================================================
// DialogPtr FWNewCDialog(Ptr dStorage, Rect *wRect, Str255 title, Boolean visFlag,
//			short wDefProcID, WindowPtr behind, Boolean goAwayFlag, long refCon, 
//			Handle itemList)
//===================================================================================
// Creates a new color dialog window in the floating window environment.
//===================================================================================

extern DialogPtr FWNewCDialog(Ptr dStorage, Rect *wRect, Str255 title, Boolean visFlag,
			short wDefProcID, WindowPtr behind, Boolean goAwayFlag, long refCon, 
			Handle itemList)
{
	FWDeactivate();
	return NewCDialog(dStorage, wRect, title, visFlag, wDefProcID, behind, goAwayFlag, 
				refCon, itemList);
}

//===================================================================================
// DialogPtr FWNewDialog(Ptr dStorage, Rect *wRect, Str255 title, Boolean visFlag,
//			short wDefProcID, WindowPtr behind, Boolean goAwayFlag, long refCon, 
//			Handle itemList)
//===================================================================================
// Creates a new B&W dialog window in the floating window environment.
//===================================================================================

extern DialogPtr FWNewDialog(Ptr dStorage, Rect *wRect, Str255 title, Boolean visFlag,
			short wDefProcID, WindowPtr behind, Boolean goAwayFlag, long refCon, 
			Handle itemList)
{
	FWDeactivate();
	return NewDialog(dStorage, wRect, title, visFlag, wDefProcID, behind, goAwayFlag, 
				refCon, itemList);
}

//===================================================================================
// void FWCloseWindow(WindowPtr theWindow)
//===================================================================================
// Closes a window in the floating window environment.
//===================================================================================

extern void FWCloseWindow(WindowPtr theWindow)
{
	Boolean visible = WindowVisible(theWindow);
	Boolean floating = isFloating(theWindow);

	if (!floating && visible) FWRemoveFloats();
	CloseWindow(theWindow);
	if (!floating && visible) FWRestoreFloats(true);
}

//===================================================================================
// void FWDisposeWindow(WindowPtr theWindow)
//===================================================================================
// Disposes of a window in the floating window environment.
//===================================================================================

extern void FWDisposeWindow(WindowPtr theWindow)
{
	Boolean visible = WindowVisible(theWindow);
	Boolean floating = isFloating(theWindow);

	if (!floating && visible) FWRemoveFloats();
	DisposeWindow(theWindow);
	if (!floating && visible) FWRestoreFloats(true);
}

//===================================================================================
// void FWDragWindow(WindowPtr theWindow, Point startPoint, Rect *limitRect)
//===================================================================================
// Handles dragging a window in the floating window environment.
//===================================================================================

extern void FWDragWindow(WindowPtr theWindow, Point startPoint, Rect *limitRect)
{
	GDHandle oldGDevice;
	uchar theKeys[16];
	GrafPort tempPort;
	WindowPtr window;
	CGrafPtr oldPort;
	RgnHandle theRgn;
	Point oldPos;
	long newPos;

	GetKeys((long *)theKeys);
	if ((theKeys[0x37 >> 3] >> (0x37 & 7)) & 1)
		DragWindow(theWindow, startPoint, limitRect);
	else {
		if (theWindow != FWFrontWindow() && theWindow != FrontWindow())
			FWSelectWindow(theWindow);
		if (!StillDown()) return;
		oldPos = TopLeft((*GetContRgn(theWindow))->rgnBBox);
		GetGWorld(&oldPort, &oldGDevice);
		theRgn = NewRgn();
		if (theRgn) {
			CopyRgn(GetStrucRgn(theWindow), theRgn);
			OpenPort(&tempPort);
			CopyRgn(GetGrayRgn(), tempPort.visRgn);
			if (!isFloating(theWindow) && !isDialog(theWindow)) {
				window = FWTopFloatingWindow();
				while (window && window != theWindow) {
					if (WindowVisible(window)) 
						DiffRgn(tempPort.visRgn, GetStrucRgn(window), tempPort.visRgn);
					window = NextWindow(window);
				}
			}
			tempPort.portRect = (*tempPort.visRgn)->rgnBBox;
			SetGWorld((CGrafPtr)&tempPort, nil);
			newPos = DragGrayRgn(theRgn, startPoint, limitRect, limitRect, 0, nil);
			ClosePort(&tempPort);
			SetGWorld(oldPort, oldGDevice);
			if (newPos != 0x80008000) {
				oldPos.h += newPos & 0xffff;
				oldPos.v += (newPos >> 16) & 0xffff;
				FWMoveWindow(theWindow, oldPos.h, oldPos.v, false);
			}
			DisposeRgn(theRgn);
		}
	}
}

//===================================================================================
// WindowPtr FWFrontWindow(void)
//===================================================================================
// Returns the frontmost non-floating window.
//===================================================================================

extern WindowPtr FWFrontWindow(void)
{
	WindowPtr theWindow;
	
	if (theWindow = FWTopDialog()) {
		while (theWindow && !WindowVisible(theWindow))
			theWindow = NextWindow(theWindow);
		if (theWindow && !isFloating(theWindow)) return theWindow;
	}
	if (theWindow = FWTopWindow()) {
		while (theWindow && !WindowVisible(theWindow))
			theWindow = NextWindow(theWindow);
	}
	return theWindow;
}

//===================================================================================
// WindowPtr FWGetNewCWindow(short resID, Ptr wStorage, WindowPtr behind)
//===================================================================================
// Gets a new color window from a resource.
//===================================================================================

extern WindowPtr FWGetNewCWindow(short resID, Ptr wStorage, WindowPtr behind)
{
	Boolean floatingTop = (GetFirstWindow() && isFloating(GetFirstWindow()));
	WindowPtr theWindow;

	if (floatingTop) FWRemoveFloats();
	theWindow = GetNewCWindow(resID, wStorage, behind);
	if (floatingTop) FWRestoreFloats(true);
	return theWindow;
}

//===================================================================================
// WindowPtr FWGetNewWindow(short resID, Ptr wStorage, WindowPtr behind)
//===================================================================================
// Gets a new B&W window from a resource.
//===================================================================================

extern WindowPtr FWGetNewWindow(short resID, Ptr wStorage, WindowPtr behind)
{
	Boolean floatingTop = (GetFirstWindow() && isFloating(GetFirstWindow()));
	WindowPtr theWindow;
	
	if (floatingTop) FWRemoveFloats();
	theWindow = GetNewWindow(resID, wStorage, behind);
	if (floatingTop) FWRestoreFloats(true);
	return theWindow;
}

//===================================================================================
// void FWHideWindow(WindowPtr theWindow)
//===================================================================================
// Hides the window.
//===================================================================================

extern void FWHideWindow(WindowPtr theWindow)
{
	Boolean visible = WindowVisible(theWindow);
	Boolean floating = isFloating(theWindow);

	if (!floating && visible) FWRemoveFloats();
	HideWindow(theWindow);
	if (!floating && visible) FWRestoreFloats(true);
}

//===================================================================================
// void FWMoveWindow(WindowPtr theWindow, short hGlobal, short vGlobal, Boolean front)
//===================================================================================
// Moves a window to the specified point on the screen.
//===================================================================================

extern void FWMoveWindow(WindowPtr theWindow, short hGlobal, short vGlobal, Boolean front)
{
	Boolean floating = isFloating(theWindow);
	
	if (!floating) FWRemoveFloats();
	else FWInsertDummyWindow(nil);
	MoveWindow(theWindow, hGlobal, vGlobal, front);
	if (!floating) FWRestoreFloats(true);
	else FWRemoveDummyWindow();
}

//===================================================================================
// WindowPtr FWNewCWindow(Ptr wStorage, Rect *rBounds, Str255 title, Boolean visFlag,
//			short wDefProcID, WindowPtr behind, Boolean goAwayFlag, long refCon)
//===================================================================================
// Creates a new color window from all the good information presented here.
//===================================================================================

extern WindowPtr FWNewCWindow(Ptr wStorage, Rect *rBounds, Str255 title, Boolean visFlag,
			short wDefProcID, WindowPtr behind, Boolean goAwayFlag, long refCon)
{
	Boolean floatingTop = (GetFirstWindow() && isFloating(GetFirstWindow()));
	WindowPtr theWindow;
	
	if (floatingTop) FWRemoveFloats();
	theWindow = NewCWindow(wStorage, rBounds, title, visFlag, wDefProcID, behind,
				goAwayFlag, refCon);
	if (floatingTop) FWRestoreFloats(true);
	return theWindow;
}

//===================================================================================
// WindowPtr FWNewWindow(Ptr wStorage, Rect *rBounds, Str255 title, Boolean visFlag,
//			short wDefProcID, WindowPtr behind, Boolean goAwayFlag, long refCon)
//===================================================================================
// Creates a new B&W window from all the good information presented here.
//===================================================================================

extern WindowPtr FWNewWindow(Ptr wStorage, Rect *rBounds, Str255 title, Boolean visFlag,
			short wDefProcID, WindowPtr behind, Boolean goAwayFlag, long refCon)
{
	Boolean floatingTop = (GetFirstWindow() && isFloating(GetFirstWindow()));
	WindowPtr theWindow;
	
	if (floatingTop) FWRemoveFloats();
	theWindow = NewWindow(wStorage, rBounds, title, visFlag, wDefProcID, behind,
				goAwayFlag, refCon);
	if (floatingTop) FWRestoreFloats(true);
	return theWindow;
}

//===================================================================================
// void FWSelectWindow(WindowPtr theWindow)
//===================================================================================
// Selects a window and brings it to the front of its layer.
//===================================================================================

extern void FWSelectWindow(WindowPtr theWindow)
{
	Boolean floating = isFloating(theWindow);
	
	if (floating && gInBackground) return;
	if (!floating) FWRemoveFloats();
	else FWInsertDummyWindow(nil);
	SelectWindow(theWindow);
	if (!floating) FWRestoreFloats(true);
	else FWRemoveDummyWindow();
}

//===================================================================================
// void FWShowWindow(WindowPtr theWindow)
//===================================================================================
// Makes a window visible again.
//===================================================================================

extern void FWShowWindow(WindowPtr theWindow)
{
	WindowPtr frontWindow = FWFrontWindow(), realFrontWindow = FrontWindow();
	Boolean floating = isFloating(theWindow);
	
	if (floating && gInBackground) return;
	if (!floating) FWRemoveFloats();
	else FWInsertDummyWindow(nil);
	ShowWindow(theWindow);
	if (!floating) FWRestoreFloats(true);
	else FWRemoveDummyWindow();
	if (floating && realFrontWindow && !isFloating(realFrontWindow))
		SendBehind(realFrontWindow, theWindow);
	if (isFloating(theWindow) && !gInBackground && 
				(!frontWindow || !isDialog(frontWindow)))
		HiliteWindow(theWindow, true);
}

//===================================================================================
// WindowPtr FWBottomDialog(void)
//===================================================================================
// Returns a pointer to the bottommost dialog, or nil if none exist.
//===================================================================================

extern WindowPtr FWBottomDialog(void)
{
	WindowPtr theWindow = GetFirstWindow(), lastWindow = nil;

	while (theWindow) {
		if (isDialog(theWindow)) lastWindow = theWindow;
		theWindow = NextWindow(theWindow);
	}
	return lastWindow;
}

//===================================================================================
// WindowPtr FWBottomFloatingWindow(void)
//===================================================================================
// Returns a pointer to the bottommost floating window, or nil if none exist.
//===================================================================================

extern WindowPtr FWBottomFloatingWindow(void)
{
	WindowPtr theWindow = GetFirstWindow(), lastWindow = nil;

	while (theWindow) {
		if (isFloating(theWindow)) lastWindow = theWindow;
		theWindow = NextWindow(theWindow);
	}
	return lastWindow;
}

//===================================================================================
// WindowPtr FWBottomWindow(void)
//===================================================================================
// Returns a pointer to the bottommost standard window, or nil if none exist.
//===================================================================================

extern WindowPtr FWBottomWindow(void)
{
	WindowPtr theWindow = GetFirstWindow(), lastWindow = nil;

	while (theWindow) {
		if (!isFloating(theWindow) && !isDialog(theWindow)) lastWindow = theWindow;
		theWindow = NextWindow(theWindow);
	}
	return lastWindow;
}

//===================================================================================
// WindowPtr FWTopDialog(void)
//===================================================================================
// Returns a pointer to the topmost dialog, or nil if none exist.
//===================================================================================

extern WindowPtr FWTopDialog(void)
{
	WindowPtr theWindow = GetFirstWindow();
	
	while (theWindow && !isDialog(theWindow)) theWindow = NextWindow(theWindow);
	return theWindow;
}

//===================================================================================
// WindowPtr FWTopFloatingWindow(void)
//===================================================================================
// Returns a pointer to the topmost floating window, or nil if none exist.
//===================================================================================

extern WindowPtr FWTopFloatingWindow(void)
{
	WindowPtr theWindow = GetFirstWindow();

	while (theWindow && !isFloating(theWindow)) theWindow = NextWindow(theWindow);
	return theWindow;
}

//===================================================================================
// WindowPtr FWTopWindow(void)
//===================================================================================
// Returns a pointer to the topmost standard window, or nil if none exist.
//===================================================================================

extern WindowPtr FWTopWindow(void)
{
	WindowPtr theWindow = GetFirstWindow();

	while (theWindow && (isFloating(theWindow) || isDialog(theWindow)))
		theWindow = NextWindow(theWindow);
	return theWindow;
}

//===================================================================================
// void FWRemoveFloats(void)
//===================================================================================
// This is the heart of our kludges to make floating windows work.  This function
// should be called before any operation manipulating standard windows.  It simply
// removes the floating windows from the window list, and subtracts their structure
// regions from the GrayRgn of the desktop.  Call FWRestoreFloats() to put 
// everything back to normal.
//===================================================================================

static void FWRemoveFloats(void)
{
	WindowPtr topFloat = FWTopFloatingWindow(), bottomDialog = FWBottomDialog();
	
	if (!topFloat || bottomDialog) {
		gOldTop = (WindowPtr)-1;
		return;
	}
	if (!gSaveRgn) gSaveRgn = NewRgn();
	gOldTop = GetFirstWindow();
	CopyRgn(GetGrayRgn(), gSaveRgn);
	while (GetFirstWindow() && isFloating(GetFirstWindow())) {
		if (WindowVisible(GetFirstWindow())) 
			DiffRgn(GetGrayRgn(), GetStrucRgn(GetFirstWindow()), GetGrayRgn());
		SetFirstWindow(NextWindow(GetFirstWindow()));
	}
}

//===================================================================================
// void FWRestoreFloats(void)
//===================================================================================
// This function should be called after FWRemoveFloats() and the appropriate window
// manager function has been called.  This function simply restores the GrayRgn of
// the desktop and re-inserts the floating windows into the window list.  Because a
// palette change may have occurred, we also call PaintOne() on the titlebars of all
// floating windows, to ensure that their colors are fixed up properly.
//===================================================================================

static void FWRestoreFloats(Boolean redraw)
{
	WindowPtr newTop, bottomFloat;
	RgnHandle theRgn;
	
	if (gOldTop == (WindowPtr)-1) return;
	XorRgn(gSaveRgn, GetGrayRgn(), gSaveRgn);
	UnionRgn(gSaveRgn, GetGrayRgn(), GetGrayRgn());
	newTop = GetFirstWindow();
	SetFirstWindow(gOldTop);
	if (bottomFloat = FWBottomFloatingWindow()) SetNextWindow(bottomFloat, newTop);
	newTop = GetFirstWindow();
	if (redraw && newTop && isFloating(newTop)) {
		if (theRgn = NewRgn()) {
			while (isFloating(newTop)) {
				DiffRgn(GetStrucRgn(newTop), GetContRgn(newTop), theRgn);
				PaintOne((WindowPeek)newTop, theRgn);
				newTop = NextWindow(newTop);
			}
			DisposeRgn(theRgn);
		}
	}
}

//===================================================================================
// void FWInsertDummyWindow(WindowPtr behindWindow)
//===================================================================================
// This function inserts a dummy window into the windowlist behind the specified
// window.  We use this function to prevent windows from unhiliting when we 
// manipulate the floating windows above them.
//===================================================================================

static void FWInsertDummyWindow(WindowPtr behindWindow)
{
	if (!gDummyWindow) {
		if (gDummyWindow = AllocateWindow()) {
			Rect theRect = { -32760, -32760, -32761, -32761 };
			gDummyWindow = NewWindow(gDummyWindow, &theRect, gNullString, true, 
						plainDBox, nil, false, 0);
			FWRemoveDummyWindow();
		}
	}
	if (gDummyWindow) {
		if (behindWindow && (behindWindow != (WindowPtr)-1)) {
			SetNextWindow(gDummyWindow, NextWindow(behindWindow));
			SetNextWindow(behindWindow, gDummyWindow);
		} else {
			SetNextWindow(gDummyWindow, GetFirstWindow());
			SetFirstWindow(gDummyWindow);
		}
	}
}

//===================================================================================
// void FWRemoveDummyWindow(void)
//===================================================================================
// This function removes the dummy window from the window list.
//===================================================================================

static void FWRemoveDummyWindow(void)
{
	WindowPtr theWindow, lastWindow = nil;

	if (GetFirstWindow() == gDummyWindow) SetFirstWindow(NextWindow(gDummyWindow));
	else {
		for (theWindow = GetFirstWindow(); theWindow && (theWindow != gDummyWindow);
			 theWindow = NextWindow(theWindow)) lastWindow = theWindow;
		if (lastWindow) SetNextWindow(lastWindow, NextWindow(gDummyWindow));
	}
}

//===================================================================================
// void FWRemoveDummyWindow(void)
//===================================================================================
// Returns true if the window is a modal dialog window.
//===================================================================================

static Boolean isDialog(WindowPtr win)
{
	if (WindowKind(win) == dialogKind) {
		short var = GetWVariant(win);
		if ((var >= dBoxProc && var <= altDBoxProc) || var == movableDBoxProc) return true;
	}
	return false;
}

//===================================================================================
// These functions serve as interfaces to Window Manager variables.
//===================================================================================

extern WindowPtr GetFirstWindow(void)
{
	return (WindowPtr)LMGetWindowList();
}

extern WindowPtr NextWindow(WindowPtr theWindow)
{
	return (WindowPtr)((WindowPeek)theWindow)->nextWindow;
}

extern short WindowKind(WindowPtr theWindow)
{
	return ((WindowPeek)theWindow)->windowKind;
}

extern Boolean WindowVisible(WindowPtr theWindow)
{
	return ((WindowPeek)theWindow)->visible;
}

extern Boolean WindowHilited(WindowPtr theWindow)
{
	return ((WindowPeek)theWindow)->hilited;
}

extern RgnHandle GetStrucRgn(WindowPtr theWindow)
{
	return ((WindowPeek)theWindow)->strucRgn;
}

extern RgnHandle GetContRgn(WindowPtr theWindow)
{
	return ((WindowPeek)theWindow)->contRgn;
}

extern Boolean HasGoAway(WindowPtr theWindow)
{
	return ((WindowPeek)theWindow)->goAwayFlag;
}

extern void SetWindowKind(WindowPtr theWindow, short theKind)
{
	((WindowPeek)theWindow)->windowKind = theKind;
}

extern void SetNextWindow(WindowPtr theWindow, WindowPtr nextWindow)
{
	((WindowPeek)theWindow)->nextWindow = (WindowPeek)nextWindow;
}

extern void SetFirstWindow(WindowPtr theWindow)
{
	LMSetWindowList((WindowPeek)theWindow);
}
