/*	XGAppMultiWindow.cpp
 *
 *		This creates a single-window application.
 */

/*  YAAF - Yet another application framework
 *  Copyright (C) 1997, 1998 William Edward Woody
 *  
 *  This library is free software; you can redistribute it
 *  and/or modify it under the terms of the GNU Library
 *  General Public License as published by the Free Software
 *  Foundation; either version 2 of the License, or any
 *  later version.
 *  
 *  This library is distributed in the hope that it will be
 *  useful, but WITHOUT ANY WARRANTY; without even the implied
 *  warranty of MERCHANTABIILITY or FITNESS FOR A PARTICULAR
 *  PURPOSE. See the GNU Library General Public License for
 *  more details.
 *  
 *  You should have received a copy of the GNU Library General
 *  Public License along with this library; if not, write to the
 *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 *  Boston, MA 02111-1307, USA.
 *  
 *  To contact the author, either e-mail me at woody@pandawave.com, 
 *	or write to
 *  
 *          William Edward Woody
 *          In Phase Consulting
 *          1545 Ard Eevin Avenue
 *          Glendale, CA 91202
 *
 *	Or visit us on the web at http://www.pandawave.com
 */

#include <XConfig.h>			// must be first to optimize compile on MSVC++
#include <XDataUtil.h>
#include <XCursorUtil.h>
#include <XWindow.h>
#include <XMenu.h>
#include <XMessages.h>
#include <XError.h>
#include <XApplication.h>
#include <XAppMenu.h>

/************************************************************************/
/*																		*/
/*	Support routines													*/
/*																		*/
/************************************************************************/

/*	ToUpper
 *
 *		My lower case to upper case routine
 */

static char ToUpper(char c)
{
	if ((c >= 'a') && (c <= 'z')) return c + ('A' - 'a');
	else return c;
}

/*	StringCompare
 *
 *		String compare: which is bigger and which is smaller
 */

static int StringCompare(char *a, char *b)
{
	while ((*a) && (ToUpper(*a) == ToUpper(*b))) a++, b++;
	
	if (*a == *b) return 0;
	if (ToUpper(*a) < ToUpper(*b)) return -1;
	return 1;
}

/*	WindowCompare
 *
 *		This compares these two windows
 */

static int WindowCompare(XGWindow *a, XGWindow *b)
{
	char bufa[256];
	char bufb[256];
	short la,lb;
	
	la = GETLOWORD(a->GetWindowAttributes());
	lb = GETLOWORD(b->GetWindowAttributes());
	if (la < lb) return -1;
	if (la > lb) return 1;

	a->GetTitle(bufa);
	b->GetTitle(bufb);
	return StringCompare(bufa,bufb);
}

/*	IsWindowMenuID
 *
 *		Is this in the range of my window menu identifiers?
 */

static bool IsWindowMenuID(long id)
{
	if (id == KXGWindowList) return 1;
	if ((id >= 0x7000) && (id < 0x8000)) return 1;
	return 0;
}

/************************************************************************/
/*																		*/
/*	Construction/Destruction											*/
/*																		*/
/************************************************************************/

// @G"Construction/Destruction"

/*	@F"XGAppMultiWindow::XGAppMultiWindow" @I
 *
 *		Create me
 */

XGAppMultiWindow::XGAppMultiWindow(char *appName)
{
#if OPT_MACOS == 1
	#pragma unused(appName)

	fMyMenuBar = new XGMenuBar();
	fMyMenuBar->LoadFromResource(KXGDefaultMenu);
#endif

#if OPT_WINOS == 1
	if (appName) {
		/* MDI Framework Initialization */
		if (_GPrevInstance == NULL) InitMDIApplication();
		InitMDIInstance(appName);
	
		fMyMenuBar = new XGMenuBar(_GMDIWindow,true);
		fMyMenuBar->LoadFromResource(KXGDefaultMenu);
	} else {
		/* SDI Framework Initialization */
		fMyMenuBar = NULL;
		if (_GPrevInstance == NULL) InitSDIApplication();
		InitSDIInstance();
	}
#endif

#if OPT_XWIN == 1
	#pragma unused(appName)
#endif
	
	XGBroadcast::AddBroadcast(this);
}

/*	@F"XGAppMultiWindow:::~XGAppMultiWindow" @I
 *
 *		Delete me
 */

XGAppMultiWindow::~XGAppMultiWindow()
{
#if OPT_MACOS || OPT_WINOS
	if (fMyMenuBar) delete fMyMenuBar;
#endif

#if OPT_XWIN || OPT_WINOS
	int i,len;
	
	len = fWindowList.Length();
	for (i = 0; i < len; i++) {
		if (fWindowList[i].fMenuBar) {
			delete fWindowList[i].fMenuBar;
		}
	}
#endif
}

/************************************************************************/
/*																		*/
/*	Construction/Destruction											*/
/*																		*/
/************************************************************************/


/*
 *	Dispatch table
 */

BEGINDISPATCH(XGAppMultiWindow,XGAppCore)
	DISPATCHTABLE(KXGEventWindowCreate,XGAppMultiWindow::DoWindowCreate)
	DISPATCHTABLE(KXGEventWindowDestroy,XGAppMultiWindow::DoWindowDestroy)
	DISPATCHTABLE(KXGEventWindowName,XGAppMultiWindow::DoWindowName)
	DISPATCHTABLE(KXGGetMenuStatus,XGAppMultiWindow::DoGetMenuStatus)
	DISPATCHTABLE(KXGDoMenuCommand,XGAppMultiWindow::DoMenuCommand)
	DISPATCHTABLE(KXGAppPostEvent,XGAppMultiWindow::DoPostPeriodic)
ENDDISPATCH

/*	XGAppMultiWindow::DoWindowCreate
 *
 *		Handle window creation
 */

long XGAppMultiWindow::DoWindowCreate(long, void *parg)
{
	DoCreateWindow(((XGSWindowEvent *)parg)->window);
	return -1;
}

/*	XGAppMultiWindow::DoWindowDestroy
 *
 *		Handle window destruction
 */

long XGAppMultiWindow::DoWindowDestroy(long, void *parg)
{
	DoDestroyWindow(((XGSWindowEvent *)parg)->window);
	return -1;
}

/*	XGAppMultiWindow::DoWindowName
 *
 *		Handle window rename
 */

long XGAppMultiWindow::DoWindowName(long, void *parg)
{
	DoRenameWindow(((XGSWindowEvent *)parg)->window);
	return -1;
}

/*	XGAppMultiWindow::DoGetMenuStatus
 *
 *		Handle menu status message
 */

long XGAppMultiWindow::DoGetMenuStatus(long arg, void *parg)
{
	XGSMenuStatus *gs;
	long len,off;
	XGWindow *w;
		
	if (IsModalWindow()) return -1;				// skip if modal up
	
	gs = (XGSMenuStatus *)parg;
	w = XGWindow::GetFrontWindow();
	if (IsWindowMenuID(arg) && (arg != KXGWindowList)) {
		gs->enable = true;
		
		len = fWindowList.Length();
		for (off = 0; off < len; off++) {
			if (fWindowList[off].fWindow == w) {
				if (fWindowList[off].menuID == arg) {
					gs->check = true;
				}
				break;
			}
		}
		return 1;
	}
	switch (arg) {
		/* Handle tile/cascade stuff */
		case KXGWindowTile:
		case KXGWindowCascade:
#if OPT_WINOS
		case KXGWindowArrange:
			if (!_GMDIWindow) return -1;
#endif

#if OPT_MACOS || OPT_WINOS
			if (fWindowList.Length() > 0) {
				gs->enable = true;
				return 1;
			}
#endif
			break;
	}
	return -1;
}

/*	XGAppMultiWindow::DoMenuCommand
 *
 *		Handle menu command
 */

long XGAppMultiWindow::DoMenuCommand(long arg, void *)
{
	long len,off;

	if (IsModalWindow()) return -1;				// skip if modal up
	
	if (IsWindowMenuID(arg) && (arg != KXGWindowList)) {
		/* Find the window to enable */
		len = fWindowList.Length();
		for (off = 0; off < len; off++) {
			if (fWindowList[off].menuID == arg) {
				fWindowList[off].fWindow->SelectWindow();
				return 1;
			}
		}
	}
	switch (arg) {
#if (OPT_MACOS == 1) || (OPT_WINOS == 1)
		case KXGWindowTile:
			TileWindows();
			return 1;
		case KXGWindowCascade:
			CascadeWindows();
			return 1;
#endif

#if OPT_WINOS == 1
		case KXGWindowArrange:
			ArrangeIcons();
			return 1;
#endif
	}
	return -1;
}

/*	XGAppMultiWindow::DoPostPeriodic
 *
 *		Process postperiodic event to update menu bar
 */

long XGAppMultiWindow::DoPostPeriodic(long, void *)
{
	XGWindow *tw;
	short menuID;

#if OPT_XWIN || OPT_WINOS
	bool f;
	int i;
	int len;
	XGMenuBar *m;
#endif
	
	/*
	 *	Update the menu bar. On the Macintosh and on
	 *	Windows, there is only one menu bar.
	 */
	
#if (OPT_MACOS == 1) || (OPT_WINOS == 1)
	tw = XGWindow::GetFrontWindow();
	if (fMyMenuBar != NULL) {
		if (tw) {
			menuID = GetCurFocus()->SendDispatch(KXGCurMenuBar,0,NULL);
			if (menuID == -1) return 0;
			if (menuID == 0) menuID = KXGDefaultMenu;
			fMyMenuBar->LoadFromResource(menuID);
		} else {
			fMyMenuBar->LoadFromResource(KXGDefaultMenu);
		}
		UpdateWindowMenu();			// update the window
		fMyMenuBar->UpdateMenuBar(GetCurFocus());

#if OPT_WINOS == 1					// we could be an SDI app...
	} else {
		/*
		 *	Run through all the SDI windows
		 */
		
		len = fWindowList.Length();
		for (i = 0; i < len; i++) {
			m = fWindowList[i].fMenuBar;
			tw = fWindowList[i].fWindow;

			menuID = tw->SendDispatch(KXGCurMenuBar,0,NULL);
			if (menuID == 0) menuID = KXGDefaultMenu;

			if (menuID != -1) {
				f = m->LoadFromResource(menuID);
				fEventOwner = tw;
				if (f) UpdateWindowMenu(m);
				m->UpdateMenuBar(tw);
				fEventOwner = NULL;
			}
		}

#endif

	}
#endif

	/*
	 *	Under X Windows, there are multiple menu bars,
	 *	one for each document window. This updates all of 'em
	 */
	
#if OPT_XWIN == 1
	len = fWindowList.Length();
	for (i = 0; i < len; i++) {
		m = fWindowList[i].fMenuBar;
		tw = fWindowList[i].fWindow;

		menuID = tw->SendDispatch(KXGCurMenuBar,0,NULL);
		if (menuID == 0) menuID = KXGDefaultMenu;

		f = m->LoadFromResource(menuID);
		fEventOwner = tw;
		if (f) UpdateWindowMenu(m);
		m->UpdateMenuBar(tw);
		if (f) tw->RedrawMenuBar();
		fEventOwner = NULL;
	}
#endif
	return 0;
}

/************************************************************************/
/*																		*/
/*	Construction/Destruction											*/
/*																		*/
/************************************************************************/

/*	XGAppMultiWindow::GetCurMenu
 *
 *		The current menu for this single window application
 */

XGMenuBar *XGAppMultiWindow::GetCurMenu()
{
#if OPT_MACOS == 1
	return fMyMenuBar;
#endif

#if OPT_WINOS == 1
	int i;
	int len;
	XGWindow *tw;
	
	if (fMyMenuBar) return fMyMenuBar;				// mdi
	else {
		if (fEventOwner) tw = fEventOwner;			// sdi
		else tw = XGWindow::GetFrontWindow();
		len = fWindowList.Length();
		for (i = 0; i < len; i++) {
			if (fWindowList[i].fWindow == tw) {
				return fWindowList[i].fMenuBar;
			}
		}
		return NULL;
	}
#endif
	
#if OPT_XWIN == 1
	int i;
	int len;
	XGWindow *tw;
	
	if (fEventOwner) tw = fEventOwner;
	else tw = XGWindow::GetFrontWindow();
	len = fWindowList.Length();
	for (i = 0; i < len; i++) {
		if (fWindowList[i].fWindow == tw) {
			return fWindowList[i].fMenuBar;
		}
	}
	return NULL;
#endif
}

/*	XGAppMultiWindow::GetCurFocus
 *
 *		The current menu for this single window application
 */

XGFocus *XGAppMultiWindow::GetCurFocus()
{
	XGWindow *tw;
	
	if (fModalWindow) return fModalWindow;

#if OPT_MACOS == 1
	tw = XGWindow::GetFrontWindow();
#endif

#if OPT_WINOS
	if (fEventOwner && !fMyMenuBar) tw = fEventOwner;	// sdi
	else tw = XGWindow::GetFrontWindow();				// mdi
#endif

#if OPT_XWIN
	if (fEventOwner) return fEventOwner;
	tw = XGWindow::GetFrontWindow();					// generic thing
#endif

	if (tw) {
		return tw;					/* Front window is focus */
	} else {
		return this;				/* I'm the focus */
	}
}

/************************************************************************/
/*																		*/
/*	Window Menu Management												*/
/*																		*/
/************************************************************************/

/*	XGAppMultiWindow::DoCreateWindow
 *
 *		Insert this window into the list of windows that are being
 *	managed
 */

void XGAppMultiWindow::DoCreateWindow(XGWindow *w)
{
	XGLstRecord wl;
	
	/*
	 *	Screen out non-document windows
	 */
	
	if (w->GetWindowKind() != KWinDocument) return;
	if (w->GetWindowAttributes() & KAttrNoMenu) return;
	
	/*
	 *	Insert this thing into my list of windows
	 */
	
	wl.menuAccel = -1;
	wl.menuID = -1;
	wl.fWindow = w;

#if OPT_XWIN == 1
	short menuID;
	menuID = w->SendDispatch(KXGCurMenuBar,0,NULL);
	if (menuID == 0) menuID = KXGDefaultMenu;

	if (menuID != -1) {
		wl.fMenuBar = new XGMenuBar(w->GetWindow());
		w->SetMenuBar(wl.fMenuBar);
		wl.fMenuBar->LoadFromResource(menuID);
	} else {
		wl.fMenuBar = NULL;
	}
#endif
	
#if OPT_WINOS == 1
	if (fMyMenuBar == NULL) {
		short menuID;
		menuID = w->SendDispatch(KXGCurMenuBar,0,NULL);
		if (menuID == 0) menuID = KXGDefaultMenu;

		if (menuID != -1) {
			wl.fMenuBar = new XGMenuBar(w->GetHWND(),false);
			wl.fMenuBar->LoadFromResource(menuID);
		} else {
			wl.fMenuBar = NULL;
		}
	} else {
		wl.fMenuBar = NULL;
	}
#endif

	fWindowList += wl;
	
	/*
	 *	Sort and update the window list
	 */
	
	SortWindowList();
	UpdateWindowMenu();
}

/*	XGAppMultiWindow::DoDestroyWindow
 *
 *		Scan the list of windows that are in me, and if this one is,
 *	delete it
 */

void XGAppMultiWindow::DoDestroyWindow(XGWindow *w)
{
	long len,off;
	
	/*
	 *	Screen out non-document windows
	 */
	
	if (w->GetWindowKind() != KWinDocument) return;
	if (w->GetWindowAttributes() & KAttrNoMenu) return;
	
	/*
	 *	Find window
	 */
	
	len = fWindowList.Length();
	for (off = 0; off < len; off++) {
		if (fWindowList[off].fWindow == w) break;
	}
	
	/*
	 *	Delete it
	 */
	
	if (off >= len) return;

#if OPT_XWIN || OPT_WINOS
	if (fWindowList[off].fMenuBar) delete fWindowList[off].fMenuBar;
#endif

	fWindowList.Delete(off);

#if OPT_XWIN == 1
	if (fWindowList.Length() == 0) {
		/*
		 *	All document windows closed. Force exit of application
		 */
		
		GetCurFocus()->SendDispatch(KXGQuitApplication,0,NULL);
	}
#endif

#if OPT_WINOS == 1
	if ((fWindowList.Length() == 0) && (!_GMDIWindow)) {
		/*
		 *	SDI App and all document windows closed. Force exit 
		 *  of application
		 */
		
		GetCurFocus()->SendDispatch(KXGQuitApplication,0,NULL);
	}
#endif
	
	/*
	 *	Update the window list
	 */
	
	UpdateWindowMenu();
}

/*	XGAppMultiWindow::DoRenameWindow
 *
 *		handle the fact that this window was renamed
 */

void XGAppMultiWindow::DoRenameWindow(XGWindow *w)
{
	long len,off;
	
	/*
	 *	Screen out non-document windows
	 */
	
	if (w->GetWindowKind() != KWinDocument) return;
	if (w->GetWindowAttributes() & KAttrNoMenu) return;
	
	/*
	 *	Find window
	 */
	
	len = fWindowList.Length();
	for (off = 0; off < len; off++) {
		if (fWindowList[off].fWindow == w) break;
	}
	
	/*
	 *	Sort and update if it was there
	 */
	
	if (off >= len) return;
	SortWindowList();
	UpdateWindowMenu();
}

/************************************************************************/
/*																		*/
/*	Window Menu Construction											*/
/*																		*/
/************************************************************************/

/*	XGAppMultiWindow::SortWindowList
 *
 *		Sort this window list.
 */

void XGAppMultiWindow::SortWindowList(void)
{
	long len,off;
	XGLstRecord wl;
	
	/*
	 *	Resort this list. This does a simple bubble sort because
	 *	I assume my window is no more than about 20 elements or so.
	 */
	
	len = fWindowList.Length();
	for (;;) {
		for (off = 1; off < len; off++) {			
			if (WindowCompare(fWindowList[off-1].fWindow,
							  fWindowList[off  ].fWindow) > 0) {
				/* Switch */
				wl = fWindowList[off-1];
				fWindowList[off-1] = fWindowList[off];
				fWindowList[off] = wl;
			}
		}
		if (off >= len) break;
	}
}

/*	XGAppMultiWindow::UpdateWindowMenu
 *
 *		This updates all of the menus, wherever they are.
 */

void XGAppMultiWindow::UpdateWindowMenu()
{
#if OPT_XWIN == 1
	int i;
	int len;
	
	len = fWindowList.Length();
	for (i = 0; i < len; i++) {
		fEventOwner = fWindowList[i].fWindow;
		UpdateWindowMenu(fWindowList[i].fMenuBar);
		fEventOwner = NULL;
	}
#endif

#if OPT_MACOS == 1
	UpdateWindowMenu(fMyMenuBar);
#endif

#if OPT_WINOS == 1
	if (fMyMenuBar) UpdateWindowMenu(fMyMenuBar);
	else {
		int i;
		int len;
		
		len = fWindowList.Length();
		for (i = 0; i < len; i++) {
			fEventOwner = fWindowList[i].fWindow;
			UpdateWindowMenu(fWindowList[i].fMenuBar);
			fEventOwner = NULL;
		}
	}
#endif
}

/*	XGAppMultiWindow::UpdateWindowMenu
 *
 *		This updates the menu window (if it exists) with the new
 *	window list.
 */

void XGAppMultiWindow::UpdateWindowMenu(XGMenuBar *menuBar)
{
	long len;
	long off;
	XGMenu *menu;
	long lmenu;
	long loff;
	long id;
	short accel;
	char buffer[256];
	
	/*
	 *	First, scan the menu bar until I find the menu which 
	 *	contains either my placeholder or one of my windows
	 */
	
	len = menuBar->GetLength();
	for (off = 0; off < len; off++) {
		menu = menuBar->GetMenu(off);

		lmenu = menu->GetLength();
		for (loff = 0; loff < lmenu; loff++) {
			id = menu->GetItemID(loff);
			if (IsWindowMenuID(id)) break;
		}
		if (loff < lmenu) break;
	}
	if (off >= len) return;			/* Couldn't find it. */
	
	/*
	 *	if we get here, then
	 *
	 *		menu			Is the reference to the menu containing my
	 *						window menu list
	 *		loff			Is the first item which refers to my menu
	 *
	 *	Next, we delete what was there before
	 */
	
	for (;;) {
		lmenu = menu->GetLength();
		if (loff >= lmenu) break;
		id = menu->GetItemID(loff);
		if (!IsWindowMenuID(id)) break;
		
		menu->DeleteItem(loff);
	}
	
	/*
	 *	Update the accelerators in my menu list to assign those
	 *	where I have a free accelerator. (We only assign accelerator
	 *	keys '1' through '9'; we expect '0' is reserved.)
	 */
	
	len = fWindowList.Length();
	for (off = 0; off < len; off++) {
		if (fWindowList[off].menuAccel == -1) {
			/* No accelerator; scan for one */
			for (accel = 1; accel <= 9; accel++) {
				for (id = 0; id < len; id++) {
					if (fWindowList[id].menuAccel == accel) break;
				}
				if (id >= len) break;
			}
			if (accel >= 10) break;
			
			fWindowList[off].menuAccel = accel;
		}
	}
	
	/*
	 *	Update the menu identifier to assign an empty identifier
	 */
	
	for (off = 0; off < len; off++) {
		if (fWindowList[off].menuID == -1) {
			/* No accelerator; scan for one */
			for (accel = 0x7000; accel < 0x8000; accel++) {
				for (id = 0; id < len; id++) {
					if (fWindowList[id].menuID == accel) break;
				}
				if (id >= len) break;
			}
			if (accel >= 0x8000) break;
			
			fWindowList[off].menuID = accel;
		}
	}
	
	/*
	 *	Now insert the list into the menu bar
	 */
	
	if (len == 0) {
		menu->InsertItem(loff);
		menu->SetItemID(loff,KXGWindowList);
		menu->SetText(loff,"Empty");
	} else {
		for (off = 0; off < len; off++, loff++) {
			menu->InsertItem(loff);
			menu->SetItemID(loff,fWindowList[off].menuID);
			
#if (OPT_MACOS == 1) || (OPT_XWIN == 1)
			fWindowList[off].fWindow->GetTitle(buffer);
			menu->SetText(loff,buffer);
			if (fWindowList[off].menuAccel != -1) {
				menuBar->SetAccelerator(fWindowList[off].menuID,'0' + fWindowList[off].menuAccel);
			}
#endif

#if OPT_WINOS == 1
			if (fWindowList[off].menuAccel == -1) {
				fWindowList[off].fWindow->GetTitle(buffer);
			} else {
				buffer[0] = '&';
				buffer[1] = '0' + fWindowList[off].menuAccel;
				buffer[2] = ' ';
				fWindowList[off].fWindow->GetTitle(buffer+3);
			}
			menu->SetText(loff,buffer);
#endif
		}
	}
}

/************************************************************************/
/*																		*/
/*	Tiling/Cascading Windows (Macintosh Version)						*/
/*																		*/
/************************************************************************/

#if OPT_MACOS == 1

/*	XGAppMultiWindow::TileWindows
 *
 *		Tile the windows across the screen
 */
 
void XGAppMultiWindow::TileWindows()
{
	Rect r,s,tmp;
	short count;
	short i,mid;
	Point nsize;
	XGWindow *foo;
	
	count = fWindowList.Length();
	if (count == 0) return;				// Huh?  Something didn't compute
	XGWindow::GetScreenSize(&r);		// Get bounding of the screen
	
	if (count == 1) {
		InsetRect(&r,2,2);
		
		foo = fWindowList[0].fWindow;
		nsize.h = r.right - r.left;
		nsize.v = r.bottom - r.top;
		foo->LimitWindowSize(&nsize);
		r.right = r.left + nsize.h;
		r.bottom = r.top + nsize.v;
		foo->SizeToContent(&r);
		foo->SetWindowLocation(r);
	} else if (count == 2) {
		s = r;
		s.bottom = (r.top + r.bottom)/2;
		InsetRect(&s,1,1);
		foo = fWindowList[0].fWindow;
		nsize.h = s.right - s.left;
		nsize.v = s.bottom - s.top;
		foo->LimitWindowSize(&nsize);
		s.right = s.left + nsize.h;
		s.bottom = s.top + nsize.v;
		foo->SizeToContent(&s);
		foo->SetWindowLocation(s);
		
		s = r;
		s.top = (r.top + r.bottom)/2;
		InsetRect(&s,1,1);
		foo = fWindowList[1].fWindow;
		nsize.h = s.right - s.left;
		nsize.v = s.bottom - s.top;
		foo->LimitWindowSize(&nsize);
		s.right = s.left + nsize.h;
		s.bottom = s.top + nsize.v;
		foo->SizeToContent(&s);
		foo->SetWindowLocation(s);
	} else {
		mid = count/2;
		s = r;
		s.right = (r.right+r.left)/2;
		for (i = 0; i < mid; i++) {
			WaitCursor();
			tmp = s;
			tmp.top = ((r.bottom-r.top)*i)/mid + s.top;
			tmp.bottom = ((r.bottom-r.top)*(i+1))/mid + s.top;
			InsetRect(&tmp,1,1);
			
			foo = fWindowList[i].fWindow;
			nsize.h = tmp.right - tmp.left;
			nsize.v = tmp.bottom - tmp.top;
			foo->LimitWindowSize(&nsize);
			tmp.right = tmp.left + nsize.h;
			tmp.bottom = tmp.top + nsize.v;
			foo->SizeToContent(&tmp);
			foo->SetWindowLocation(tmp);
		}
		s = r;
		s.left = (r.right+r.left)/2;
		for (i = mid; i < count; i++) {
			WaitCursor();
			tmp = s;
			tmp.top = ((r.bottom-r.top)*(i-mid))/(count-mid) + s.top;
			tmp.bottom = ((r.bottom-r.top)*(i-mid+1))/(count-mid) + s.top;
			InsetRect(&tmp,1,1);

			foo = fWindowList[i].fWindow;
			nsize.h = tmp.right - tmp.left;
			nsize.v = tmp.bottom - tmp.top;
			foo->LimitWindowSize(&nsize);
			tmp.right = tmp.left + nsize.h;
			tmp.bottom = tmp.top + nsize.v;
			foo->SizeToContent(&tmp);
			foo->SetWindowLocation(tmp);
		}
		NormalCursor();
	}
}

/*	XGAppMultiWindow::CascadeWindows
 *
 *		Cascade the windows on the screen
 */

void XGAppMultiWindow::CascadeWindows()
{
	Rect r,s;
	XGWindow *foo;
	int count;
	Point size;
	Point nsize;
	int i;
	
	count = fWindowList.Length();
	if (count == 0) return;
	XGWindow::GetScreenSize(&r);
	r.bottom -= 2;
	
	if (count > 15) count = 13;
	size.h = (r.right - r.left - 10) - 5 * (count - 1);
	if (count > 10) count = 10;
	size.v = (r.bottom - r.top) - 20 * (count - 1);
	
	count = fWindowList.Length();
	for (i = 0; i < count; i++) {
		WaitCursor();
		
		nsize = size;
		foo = fWindowList[i].fWindow;
		foo->LimitWindowSize(&nsize);

		s.left = (i % 13) * 5 + r.left + 5;
		s.right = s.left + nsize.h;
		s.top = (i % 10) * 20 + r.top;
		s.bottom = s.top + nsize.v;
		
		foo->SizeToContent(&s);
		foo->SetWindowLocation(s);
	}
	NormalCursor();
}

#endif

/************************************************************************/
/*																		*/
/*	Tiling/Cascading Windows (Microsoft Windows Version)				*/
/*																		*/
/************************************************************************/

#if OPT_WINOS == 1

/*	XGAppMultiWindow::TileWindows
 *
 *		Tile the windows across the screen
 */
 
void XGAppMultiWindow::TileWindows()
{
	::SendMessage(_GMDIWindow,WM_MDITILE,(WPARAM)MDITILE_VERTICAL,NULL);
}

/*	XGAppMultiWindow::_CascadeWindows
 *
 *		Cascade the windows on the screen
 */

void XGAppMultiWindow::CascadeWindows()
{
	::SendMessage(_GMDIWindow,WM_MDICASCADE,0,NULL);
}

/*	XGAppMultiWindow::ArrangeWindows
 *
 *		Arrange the window icons at the bottom of the MDI window
 */

void XGAppMultiWindow::ArrangeIcons()
{
	::SendMessage(_GMDIWindow,WM_MDIICONARRANGE,0,NULL);
}

#endif

/************************************************************************/
/*																		*/
/*	Windows initialization support										*/
/*																		*/
/************************************************************************/

#if OPT_WINOS == 1

/*	XGAppMultiWindow::InitMDIApplication
 *
 *		Register the classes which are in me
 */

void XGAppMultiWindow::InitMDIApplication(void)
{
	WNDCLASSEX wc;
	static bool gInit = false;
		
	if (gInit) return;					// run this only once.
	gInit = true;
	
	/*
	 *	Initialize four instances: the main window which encapsulates
	 *	the MDI window, the child window, the dialog window and the 
	 *	view window
	 */
	
	wc.cbSize = sizeof(wc);
	wc.style = 0;
	wc.lpfnWndProc = _GMainMDIWindowProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = _GInstance;
	wc.hIcon = (HICON)LoadImage(_GInstance,"AppIcon",IMAGE_ICON,32,32,LR_SHARED);;
	wc.hCursor = LoadCursor(NULL,IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE+1);
	wc.lpszMenuName = MAKEINTRESOURCE(KXGDefaultMenu);
	wc.lpszClassName = _GMainClass;
	wc.hIconSm = (HICON)LoadImage(_GInstance,"AppIconSmall",IMAGE_ICON,16,16,LR_SHARED);
	Assert(RegisterClassEx(&wc));
	
	wc.cbSize = sizeof(wc);
	wc.style = CS_DBLCLKS;
	wc.lpfnWndProc = _GChildWindowProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = _GInstance;
	wc.hIcon = NULL;
	wc.hCursor = NULL;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = _GWindowClass;
	wc.hIconSm = NULL;
	Assert(RegisterClassEx(&wc));
	
	wc.cbSize = sizeof(wc);
	wc.style = CS_DBLCLKS;
	wc.lpfnWndProc = _GSingleWindowProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = _GInstance;
	wc.hIcon = (HICON)LoadImage(_GInstance,"AppIcon",IMAGE_ICON,32,32,LR_SHARED);;
	wc.hCursor = NULL;
	wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = _GDlogClass;
	wc.hIconSm = (HICON)LoadImage(_GInstance,"AppIconSmall",IMAGE_ICON,16,16,LR_SHARED);
	Assert(RegisterClassEx(&wc));
}

/*	XGAppMultiWindow::InitMDIInstance
 *
 *		Initialize the instance of this thing. This builds the MDI frame
 *	of my window.
 */

void XGAppMultiWindow::InitMDIInstance(char *appName)
{
	if (appName == NULL) appName = "YAAF Application";
	
	_GMainWindow = CreateWindow(_GMainClass,appName,
					WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_MAXIMIZEBOX |
					WS_MINIMIZEBOX,
					CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
					NULL, NULL, _GInstance, NULL);
	Assert(_GMainWindow);
	
	ShowWindow(_GMainWindow,_GArgShow);
	UpdateWindow(_GMainWindow);
}

/*	XGAppMultiWindow::InitSDIApplication
 *
 *		Register the classes which are in me
 */

void XGAppMultiWindow::InitSDIApplication(void)
{
	WNDCLASSEX wc;
	static bool gInit = false;
		
	if (gInit) return;					// run this only once.
	gInit = true;
	
	/*
	 *	Initialize three instances: a class of class name "_XGWindow"
	 *	and a class of class name "_XGView", and "_XGDialog"
	 */
	
	wc.cbSize = sizeof(wc);
	wc.style = CS_DBLCLKS;
	wc.lpfnWndProc = _GSingleWindowProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = _GInstance;
	wc.hIcon = (HICON)LoadImage(_GInstance,"AppIcon",IMAGE_ICON,32,32,LR_SHARED);;
	wc.hCursor = NULL;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = _GWindowClass;
	wc.hIconSm = (HICON)LoadImage(_GInstance,"AppIconSmall",IMAGE_ICON,16,16,LR_SHARED);
	Assert(RegisterClassEx(&wc));
	
	wc.cbSize = sizeof(wc);
	wc.style = CS_DBLCLKS;
	wc.lpfnWndProc = _GSingleWindowProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = _GInstance;
	wc.hIcon = (HICON)LoadImage(_GInstance,"AppIcon",IMAGE_ICON,32,32,LR_SHARED);;
	wc.hCursor = NULL;
	wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = _GDlogClass;
	wc.hIconSm = (HICON)LoadImage(_GInstance,"AppIconSmall",IMAGE_ICON,16,16,LR_SHARED);
	Assert(RegisterClassEx(&wc));
}

/*	XGAppMultiWindow::InitSDIInstance
 *
 *		Initialize the instance of this thing. This does nothing; we assume
 *	the window that is initialized elsewhere will provide me the UI.
 */

void XGAppMultiWindow::InitSDIInstance(void)
{
}



#endif
