/*	XGWindow.cpp
 *
 *		This is the core window processing routines
 */

/*  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 <string.h>
#include <XDocument.h>
#include <XForm.h>
#include <XMessages.h>
#include <XApplication.h>
#include <XWindow.h>
#include <XDataUtil.h>
#include <XCursorUtil.h>
#include <XError.h>

#include <XDialog.h>

#if OPT_XWIN
#include <X11/Xutil.h>
#include "XGMenuView.h"
#endif

#if OPT_MACOS
#include "MacFloater.h"
#endif

#if OPT_WINOS || OPT_XWIN
#include <XButtons.h>
#endif

/************************************************************************/
/*																		*/
/*	Dialog Constants													*/
/*																		*/
/************************************************************************/

/*	GSaveDialog
 *
 *		The save alert; this asks if the window should be saved first
 */

static unsigned char GSaveDialog[] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, /* 00000000: .......d */
    0x00, 0x00, 0x00, 0x54, 0x64, 0x6C, 0x6F, 0x67, /* 00000008: ...Tdlog */
    0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, /* 00000010: ........ */
    0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00000018: ........ */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00000020: ........ */
    0x00, 0x00, 0x00, 0x00, 0x01, 0x5E, 0x00, 0x00, /* 00000028: .....^.. */
    0x00, 0x76, 0x00, 0x00, 0x01, 0x5E, 0x00, 0x00, /* 00000030: .v...^.. */
    0x00, 0x76, 0x00, 0x00, 0x01, 0x5E, 0x00, 0x00, /* 00000038: .v...^.. */
    0x00, 0x76, 0x00, 0x00, 0x01, 0x5E, 0x00, 0x00, /* 00000040: .v...^.. */
    0x00, 0x76, 0x0C, 0x53, 0x61, 0x76, 0x65, 0x20, /* 00000048: .v.Save. */
    0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x3F, 0x00, /* 00000050: Window?. */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, /* 00000058: .......d */
    0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x7A, /* 00000060: ...e...z */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6A, /* 00000068: .......j */
    0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, /* 00000070: text.... */
    0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, /* 00000078: ........ */
    0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, /* 00000080: ........ */
    0x00, 0x00, 0x00, 0x0E, 0xFF, 0xFF, 0xFF, 0xF2, /* 00000088: ........ */
    0x00, 0x00, 0x00, 0x50, 0xFF, 0xFF, 0xFF, 0xFF, /* 00000090: ...P.... */
    0x00, 0x00, 0x3F, 0x53, 0x68, 0x6F, 0x75, 0x6C, /* 00000098: ..?Shoul */
    0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, /* 000000A0: d.the.co */
    0x6E, 0x74, 0x65, 0x6E, 0x74, 0x73, 0x20, 0x6F, /* 000000A8: ntents.o */
    0x66, 0x20, 0x5E, 0x30, 0x20, 0x62, 0x65, 0x20, /* 000000B0: f.^0.be. */
    0x73, 0x61, 0x76, 0x65, 0x64, 0x20, 0x62, 0x65, /* 000000B8: saved.be */
    0x66, 0x6F, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, /* 000000C0: fore.the */
    0x20, 0x77, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x20, /* 000000C8: .window. */
    0x69, 0x73, 0x20, 0x63, 0x6C, 0x6F, 0x73, 0x65, /* 000000D0: is.close */
    0x64, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 000000D8: d?...... */
    0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 000000E0: .D...... */
    0x00, 0x34, 0x70, 0x62, 0x74, 0x6E, 0x00, 0x00, /* 000000E8: .4pbtn.. */
    0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, /* 000000F0: .d...... */
    0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 000000F8: ........ */
    0x01, 0x10, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, /* 00000100: .....V.. */
    0x01, 0x54, 0x00, 0x00, 0x00, 0x72, 0xFF, 0xFF, /* 00000108: .T...r.. */
    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, /* 00000110: ........ */
    0x00, 0x00, 0x00, 0x00, 0x04, 0x53, 0x61, 0x76, /* 00000118: .....Sav */
    0x65, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, /* 00000120: e....F.. */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x70, 0x62, /* 00000128: .....6pb */
    0x74, 0x6E, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, /* 00000130: tn...e.. */
    0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, /* 00000138: ........ */
    0x00, 0x00, 0x00, 0x00, 0x00, 0xC4, 0x00, 0x00, /* 00000140: ........ */
    0x00, 0x56, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, /* 00000148: .V...... */
    0x00, 0x72, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 00000150: .r...... */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00000158: ........ */
    0x06, 0x43, 0x61, 0x6E, 0x63, 0x65, 0x6C, 0x00, /* 00000160: .Cancel. */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00000168: ........ */
    0x00, 0x00, 0x00, 0x3A, 0x70, 0x62, 0x74, 0x6E, /* 00000170: ...:pbtn */
    0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, /* 00000178: ...f.... */
    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, /* 00000180: ........ */
    0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x56, /* 00000188: ...(...V */
    0x00, 0x00, 0x00, 0x8C, 0x00, 0x00, 0x00, 0x72, /* 00000190: .......r */
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, /* 00000198: ........ */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x44, /* 000001A0: .......D */
    0x6F, 0x6E, 0x27, 0x74, 0x20, 0x53, 0x61, 0x76, /* 000001A8: on't.Sav */
    0x65, 0x00                                      /* 000001B0: e.       */
}; /* _R56526573_0083 */


/************************************************************************/
/*																		*/
/*	Globals																*/
/*																		*/
/************************************************************************/

#if OPT_XWIN
extern Display *_GDisplay;
extern bool _GDialogFlag;
#endif

/*
 *	Module specific globals
 */

static short GDefaultPosition;

/*
 *	External globals
 */

XGWindow *XGWindow::gList;

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

// @G"Construction/Destruction"

#if 0
#pragma mark Construction/Destruction
#endif

/*	@F"XGWindow::XGWindow" @I
 *
 *		Three versions of me to create/destroy me
 */

XGWindow::XGWindow(XGArgStream &stream, XGDocument *doc, XGForm *form)
{
	XGSWindowInitRecord r;

	fView = NULL;	
	fDocument = doc;
	fForm = form;
	
	r.windowType = stream.ReadInteger();
	r.windowKind = stream.ReadInteger();
	r.windowID = stream.ReadInteger();
	r.fVisible = stream.ReadBoolean();
	r.screenLeft = stream.ReadInteger();
	r.screenTop = stream.ReadInteger();
	r.screenRight = stream.ReadInteger();
	r.screenBottom = stream.ReadInteger();
	r.minx = stream.ReadInteger();
	r.miny = stream.ReadInteger();
	r.maxx = stream.ReadInteger();
	r.maxy = stream.ReadInteger();
	r.initx = stream.ReadInteger();
	r.inity = stream.ReadInteger();
	r.zoomx = stream.ReadInteger();
	r.zoomy = stream.ReadInteger();
	stream.ReadString(r.windowName);
	r.menuID = stream.ReadInteger();
	IInitWindow(r);
	
	/*
	 *	Add to my linked list
	 */
	
#if (OPT_WINOS == 1) && (OPT_XWIN == 1)
	fWindow = NULL;
#endif

	fPrev = NULL;
	fNext = gList;
	gList = this;
	if (fNext) fNext->fPrev = this;
	
	/*
	 *	The window is now invisible. Kludge create message by sending
	 *	it to my parent's receive method
	 */
	
	XGSWindowEvent we;
	we.window = this;
	XGDispatch::DoDispatch(KXGEventWindowCreate,r.windowID,(void *)&we);

	/*
	 *	Show the window if it's hidden
	 */
	
	if (r.fVisible) {
		ShowWindow();
		SelectWindow();
	}
}

XGWindow::XGWindow(XGSWindowInitRecord &r, XGDocument *doc, XGForm *form)
{
	fView = NULL;
	fDocument = doc;
	fForm = form;
	
	IInitWindow(r);
	
	/*
	 *	Add to my linked list
	 */
	
#if (OPT_WINOS == 1) && (OPT_XWIN == 1)
	fWindow = NULL;
#endif

	fPrev = NULL;
	fNext = gList;
	gList = this;
	if (fNext) fNext->fPrev = this;
	
	/*
	 *	The window is now invisible. Kludge create message by sending
	 *	it to my parent's receive method
	 */
	
	XGSWindowEvent we;
	we.window = this;
	XGDispatch::DoDispatch(KXGEventWindowCreate,r.windowID,(void *)&we);

	/*
	 *	Show the window if it's hidden
	 */
	
	if (r.fVisible) {
		ShowWindow();
		SelectWindow();
	}
}

/*	@F"XGWindow::~XGWindow" @I
 *
 *		Close me
 */

XGWindow::~XGWindow()
{
	/*
	 *	Remove from double-linked list
	 */

	if (gList == this) {
		gList = fNext;
		if (fNext) fNext->fPrev = NULL;
	} else {
		fPrev->fNext = fNext;
		if (fNext) fNext->fPrev = fPrev;
	}

	/*
	 *  Tell my document I'm gone
	 */
	
	XGSWindowEvent we;
	we.window = this;
	XGDispatch::DoDispatch(KXGEventWindowDestroy,GetWindowID(),(void *)&we);
	
	/*
	 *	Remove the document and form
	 */
	
	if (fDocument) {
		fDocument->DetachWindow(this);
		fDocument = NULL;
	}
	if (fForm) {
		fForm->Detach();
		fForm = NULL;
	}
	
	/*
	 *	Wipe out the contained view
	 */
	
	if (fView) delete fView;
	
	/*
	 *  Close this window itself
	 */
	
#if OPT_MACOS == 1
	if (fWindow.tw != NULL) {
		::MCloseWindow((WindowPtr)&fWindow.w);
	}
#endif

#if OPT_WINOS == 1
	if (fWindow) {
		if (fDlogParent != NULL) {
			HWND w;
			XGWindow *xw;
			
			/*
			 *	This was a dialog window. Reactivate the window I was in
			 *	front of. Also go ahead and disable all the parents above
			 *	this one...
			 */
			
			::EnableWindow(fDlogParent,TRUE);
			::SetWindowPos(fDlogParent,HWND_TOP,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE);

			xw = XGWindow::GetXGWindow(fDlogParent);
			while (xw) {
				w = xw->fDlogParent;
				if (w) {
					::EnableWindow(w,FALSE);
					xw = XGWindow::GetXGWindow(w);
				} else break;
			}
		}

		SetProp(fWindow,_GWindowClass,NULL);
		if (_GMDIWindow) {
			::SendMessage(_GMDIWindow,WM_MDIDESTROY,(WPARAM)fWindow,NULL);
		} else {
			DestroyWindow(fWindow);
		}
		fWindow = NULL;							// and forget the window
	}
#endif

#if OPT_XWIN == 1
	if (fWindow) {
		/*
		 *	Destroy me.
		 */
		
		::XUnmapWindow(_GDisplay,fWindow);
		::XDestroyWindow(_GDisplay,fWindow);
		fWindow = NULL;
	}
#endif
}

/*	@F"XGWindow::SetWindowView" @I
 *
 *		Add this view to this window. This does all the approriate
 *	magical calls
 */

void XGWindow::SetWindowView(XGView *v)
{
	fView = v;
	fView->SetDispatchParent(this);
	DoSizeWindow();
}


/*	@F"XGWindow::CloseWindow" @I
 *
 *		Handle closing this window. This queries the contained document
 *	and processes the close after saving the file
 */

bool XGWindow::CloseWindow()
{
	XGSWindowEvent vr;
	char name[256];
	int result;
	XGDocument *doc;

	/*
	 *	If this is dirty, put up the save message
	 */
	
	if (IsDirty()) {
		/*
		 *	This window is dirty. Determine if the user wants to save
		 *	the window/document first.
		 */
		
		doc = GetDocument();
		if (doc == NULL) GetTitle(name);
		else {
			if (!doc->LastEditWindow(this)) {
				// Don't need to save this window, because the
				// same document is opened elsewhere.
				delete this;
				return 1;
			}
			doc->GetDocumentName(name);
		}
		
		SetCursorID(KNormalCursor);
		
		result = XGDialog::ModalAlert(GSaveDialog,name,NULL,NULL,NULL);
		if (result == 100) {
			if (!DoSave()) return 0;		// save button
		} else if (result == 101) {
			return 0;						// cancel button
		}
	}
	
	/*
	 *	Send the predestroy message. Sent after the attempts to save this
	 *	document are made, as there may be other reasons why a window
	 *	may not allowed to be destroyed
	 */
	
	vr.window = this;
	if (0 == DoDispatch(KXGEventWindowPreDestroy,GetWindowID(),(void *)&vr)) {
		return false;
	}
	
	/*
	 *	We got here. Kill the window and return success.
	 */
	 
	delete this;
	return 1;
}

/************************************************************************/
/*																		*/
/*	Dirty/Save Support													*/
/*																		*/
/************************************************************************/

// @G"Document Support"

#if 0
#pragma mark -
#pragma mark Document Support
#endif

/*	@F"XGWindow::IsDirty" @I
 *
 *		Is this dirty? This by default passes up to the document
 */

bool XGWindow::IsDirty()
{
	if (fDocument) return fDocument->IsDocumentDirty();
	else {
		long ret;
		XGSWindowEvent we;
		
		we.window = this;
		ret = DoDispatch(KXGEventWindowDirty,0,&we);
		if (ret == 1) return true;
		else return false;
	}
}

/*	@F"XGWindow::DoSave" @I
 *
 *		Do save. This by default passes up to the document
 */

bool XGWindow::DoSave()
{
	if (fDocument) return fDocument->DoDocumentSave();
	else {
		long ret;
		XGSWindowEvent we;
		
		we.window = this;
		ret = DoDispatch(KXGEventWindowSave,0,&we);
		if (ret == 1) return true;
		else return false;
	}
}


/************************************************************************/
/*																		*/
/*	Window Min/Max stuff												*/
/*																		*/
/************************************************************************/

// @G"Window Size Support"

#if 0
#pragma mark -
#pragma mark Window size support
#endif

/*	@F"XGWindow::MinWindowSize" @I
 *
 *		Default: return what I read in
 */

Point XGWindow::MinWindowSize()
{
	return fMin;
}

/*	@F"XGWindow::MaxWindowSize" @I
 *
 *		Default: return what I read in
 */

Point XGWindow::MaxWindowSize()
{
	return fMax;
}

/*	@F"XGWindow::ZoomWindowSize" @I
 *
 *		Default: return what I read in
 */

Point XGWindow::ZoomWindowSize()
{
	return fZoom;
}

/*	@F"XGWindow::LimitWindowSize" @I
 *
 *		This is a support routine used for limiting the window's size
 */

void XGWindow::LimitWindowSize(Point *pt)
{
	Point m;
	
	m = MinWindowSize();
	if (m.h > pt->h) pt->h = m.h;
	if (m.v > pt->v) pt->v = m.v;
	
	m = MaxWindowSize();
	if ((m.h != 0) && (m.h < pt->h)) pt->h = m.h;
	if ((m.v != 0) && (m.v < pt->v)) pt->v = m.v;
}

/************************************************************************/
/*																		*/
/*	Window Attributes													*/
/*																		*/
/************************************************************************/

// @G"Window Attributes"

#if 0
#pragma mark -
#pragma mark Window Attributes
#endif

/*	@F"XGWindow::GetTitle" @I
 *
 *		Get the name of this window
 */

void XGWindow::GetTitle(char *name)
{
#if OPT_MACOS == 1
	::GetWTitle((WindowPtr)&fWindow.w,(unsigned char *)name);
	p2cstr((unsigned char *)name);
#endif

#if OPT_WINOS == 1
	::GetWindowText(fWindow,name,256);
#endif

#if OPT_XWIN == 1
	char *n;
	
	::XFetchName(_GDisplay,fWindow,&n);
	strcpy(name,n);
#endif
}

/*	@F"XGWindow::SetTitle" @I
 *
 *		Set the window name
 */

void XGWindow::SetTitle(const char *name)
{
	XGSWindowEvent vr;
	
#if OPT_MACOS == 1
	unsigned char buffer[256];

	::SetWTitle((WindowPtr)&fWindow.w,cvtc2p(buffer,name));
#endif

#if OPT_WINOS == 1
	::SetWindowText(fWindow,name);
#endif

#if OPT_XWIN == 1
	::XStoreName(_GDisplay,fWindow,name);
#endif

	vr.window = this;
	XGDispatch::DoDispatch(KXGEventWindowName,GetWindowID(),(void *)&vr);
}

/*	@F"XGWindow::GetWindowAttributes" @I
 *
 *		Based on the type of window, this returns an attribute flag
 */

unsigned short XGWindow::GetWindowAttributes()
{
	unsigned short a;
	
	switch (fWindowKind & KMaskType) {
		case KWinDocument:
			a = 0;
			break;
		case KWinModal:
			a = KAttrNoClose | KAttrNoResize | KAttrNoMenu;
			break;
		case KWinMovableModal:
			a = KAttrNoClose | KAttrNoResize | KAttrNoMenu;
			break;
		case KWinFloating:
			a = KAttrNoClose | KAttrNoResize | KAttrHideOnSwitch | KAttrFloater;
			break;
		default:
			a = 0;
			break;
	}
	return a;
}

/*	@F"XGWindow::ShowWindow" @I
 *
 *		Show this window.
 */

void XGWindow::ShowWindow()
{
	if (!IsVisible()) {
	
#if OPT_MACOS == 1
		::MShowWindow((WindowPtr)&fWindow.w);
#endif /* OPT_MACOS */

#if OPT_WINOS == 1
		::ShowWindow(fWindow,SW_SHOW);
#endif

#if OPT_XWIN == 1
		::XMapWindow(_GDisplay,fWindow);
#endif
	}
}

/*	@F"XGWindow::HideWindow" @I
 *
 *		Show this window.
 */

void XGWindow::HideWindow()
{
	if (IsVisible()) {
	
#if OPT_MACOS == 1
		::MHideWindow((WindowPtr)&fWindow.w);
#endif /* OPT_MACOS */

#if OPT_WINOS == 1
		::ShowWindow(fWindow,SW_HIDE);
#endif

#if OPT_XWIN == 1
		::XUnmapWindow(_GDisplay,fWindow);
#endif
	}
}

/*	@F"XGWindow::IsVisible" @I
 *
 *		Is this window visible?
 */

bool XGWindow::IsVisible()
{
#if OPT_MACOS == 1
	return fWindow.w.visible;
#endif

#if OPT_WINOS == 1
	return (bool)IsWindowVisible(fWindow);
#endif

#if OPT_XWIN == 1
	XWindowAttributes wa;
	::XGetWindowAttributes(_GDisplay,fWindow,&wa);
	if (wa.map_state == IsUnmapped) return false;
	return true;
#endif
}

/*	@F"XGWindow::GetFrontWindow" @I
 *
 *		Get the front window
 */

XGWindow *XGWindow::GetFrontWindow()
{
#if OPT_MACOS == 1
	WindowPtr w;
	
	w = MFrontWindow();
	return GetXGWindow(w);
#endif

#if OPT_WINOS == 1
	HWND w;
	
	/* If this is an SDI app, we have only one window */
	if (_GMDIWindow == NULL) {
		if (_GMainWindow == NULL) {
			/*
			 *	We're a multi-window SDI app. Return the event
			 *	owner.
			 */
			
			return GetXGWindow(::GetActiveWindow());
		} else {
			/*
			 *	There is only one SDI window. Return it
			 */
			 
			return XGWindow::GetXGWindow(_GMainWindow);
		}
	}
	
	/* It's an MDI window. Find the frontmost child to the MDI pane */
	w = ::GetWindow(_GMDIWindow,GW_CHILD);
	while (w != NULL) {
		if (::GetProp(w,_GWindowClass)) {
			if (::IsWindowVisible(w)) break;
		}
		w = ::GetWindow(w,GW_HWNDNEXT);
	}
	if (w == NULL) return NULL;
	return XGWindow::GetXGWindow(w);
#endif

#if OPT_XWIN == 1
	/*
	 *	The "front window" is the current window used when I'm
	 *	dealing with processing what's going on. On X Windows, this
	 *	does not necessarly mean the physically frontmost window.
	 *
	 *	If there is an event pending when this is called, I return
	 *	the window that is the target of that event. If not, this
	 *	returns the frontmost window in the window list, an arbitrary
	 *	choice.
	 */

	XGWindow *w;
		
	for (w = gList; w != NULL; w = w->fNext) {
		if (w->fActive) return w;
	}
	return NULL;
#endif
}

/*	@F"XGWindow::SelectWindow" @I
 *
 *		Bring this window frontmost
 */

void XGWindow::SelectWindow()
{
#if OPT_MACOS == 1
	MSelectWindow((WindowPtr)&fWindow.w);
#endif

#if OPT_WINOS == 1
	/* WM_MDIACTIVATE arguments same for Win16 and Win32 in this mode */
	if (_GMDIWindow) {
		::SendMessage(_GMDIWindow,WM_MDIACTIVATE,(WPARAM)fWindow,NULL);
		if (::IsIconic(fWindow)) ::SendMessage(_GMDIWindow,WM_MDIRESTORE,(WPARAM)fWindow,NULL);
	} else {
		::SetWindowPos(fWindow,HWND_TOP,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE);
		::ShowWindow(fWindow,SW_RESTORE);
	}
#endif

#if OPT_XWIN == 1
	/*
	 *	Raise my container window
	 */
	
	::XRaiseWindow(_GDisplay,fWMWindow);
#endif
}

/*	@F"XGWindow::GetScreenSize" @I
 *
 *		Return the size of the main screen (minus the menu bar)
 */

void XGWindow::GetScreenSize(Rect *r)
{
#if OPT_MACOS == 1
	WindowPtr w;
		
	GetWMgrPort(&w);
	*r = w->portRect;
	r->top += LMGetMBarHeight();
#endif

#if OPT_WINOS == 1
	if (_GMDIWindow) {
		::GetClientRect(_GMDIWindow,r);
	} else {
		r->left   = 0;
		r->top    = 0;
		r->right  = ::GetSystemMetrics(SM_CXFULLSCREEN);
		r->bottom = ::GetSystemMetrics(SM_CYFULLSCREEN);
	}
#endif

#if OPT_XWIN == 1
	int i;
	
	i = DefaultScreen(_GDisplay);
	r->left = 0;
	r->top = 0;
	r->right = DisplayWidth(_GDisplay,i);
	r->bottom = DisplayHeight(_GDisplay,i);
#endif
}

/************************************************************************/
/*																		*/
/*	Window Size															*/
/*																		*/
/************************************************************************/

// @G"Window Size"

#if 0
#pragma mark -
#pragma mark Window Size
#endif

/*	@F"XGWindow::GetContentSize" @I
 *
 *		Return the size of the content area
 */

Point XGWindow::GetContentSize(void) const
{
#if OPT_MACOS == 1
	Point pt;
	
	pt.h = fWindow.w.port.portRect.right - fWindow.w.port.portRect.left;
	pt.v = fWindow.w.port.portRect.bottom - fWindow.w.port.portRect.top;
	
	return pt;
#endif

#if OPT_WINOS == 1
	Point pt;
	Rect r;
	
	GetClientRect(fWindow,&r);
	
	pt.h = r.right - r.left;
	pt.v = r.bottom - r.top;
	
	return pt;
#endif

#if OPT_XWIN == 1
	XWindowAttributes wa;
	Point pt;
	
	::XGetWindowAttributes(_GDisplay,fWindow,&wa);
	pt.h = wa.width;			/* ### Menu bar height */
	pt.v = wa.height - 20;
	return pt;
#endif
}

/*	@F"XGWindow::GetContentRect" @I
 *
 *		Get the content rectangle
 */

Rect XGWindow::GetContentRect() const
{
	Rect r;
	Point size;
	
	size = GetContentSize();
	r.left = 0;
	r.top = 0;
	r.right = size.h;
	r.bottom = size.v;
	
	return r;
}

/*	@F"XGWindow::SetWindowSize" @I
 *
 *		Resize this window
 */

void XGWindow::SetWindowSize(Point size)
{
	LimitWindowSize(&size);
	
#if OPT_MACOS == 1
	SizeWindow((WindowPtr)&fWindow.w,size.h,size.v,1);
	DoSizeWindow();
#endif

#if OPT_WINOS == 1
	ContentToSize(&size);
	/* This depends on the window resize event to resize the contents */
	::SetWindowPos(fWindow,NULL,0,0,size.h,size.v,SWP_NOMOVE | SWP_NOZORDER);
#endif

#if OPT_XWIN == 1
	/* This depends on the window resize event to resize the contents */
	::XResizeWindow(_GDisplay,fWindow,size.h,size.v);
#endif
}

/*	@F"XGWindow::SetWindowPos" @I
 *
 *		Set the window's location (by the window's outer border)
 */

void XGWindow::SetWindowPos(Point pos)
{
#if OPT_MACOS == 1
	pos.h += 1;
	pos.v += 21;
	MoveWindow((WindowPtr)&fWindow.w,pos.h,pos.v,0);
#endif

#if OPT_WINOS == 1
	::SetWindowPos(fWindow,NULL,pos.h,pos.v,0,0,SWP_NOSIZE | SWP_NOZORDER);
#endif

#if OPT_XWIN == 1
	::XMoveWindow(_GDisplay,fWindow,pos.h,pos.v);
#endif
}

/*	@F"XGWindow::SetWindowLocation" @I
 *
 *		Set the window's global location
 */

void XGWindow::SetWindowLocation(Rect r)
{
	Point pt;
	
	pt.h = r.right - r.left;
	pt.v = r.bottom - r.top;
	LimitWindowSize(&pt);
	r.right = r.left + pt.h;
	r.bottom = r.top + pt.v;
	
#if OPT_MACOS == 1
	bool vis;
	
	vis = fWindow.w.visible;
	if (vis) ShowHide((WindowPtr)&fWindow.w,0);		// Temporary hide
	SizeWindow((WindowPtr)&fWindow.w,r.right-r.left,r.bottom-r.top,0);
	MoveWindow((WindowPtr)&fWindow.w,r.left,r.top,0);
	if (vis) ShowHide((WindowPtr)&fWindow.w,1);		// show it again

	DoSizeWindow();
#endif

#if OPT_WINOS == 1
	ContentToSize(&r);
	/* This depends on the window resize event to resize the contents */
	::SetWindowPos(fWindow,NULL,r.left,r.top,r.right-r.left,r.bottom-r.top,SWP_NOZORDER);
#endif

#if OPT_XWIN == 1
	/* This depends on the window resize event to resize the contents */
	::XMoveResizeWindow(_GDisplay,fWindow,r.left,r.top,r.right-r.left,r.bottom-r.top);
#endif
}

/*	@F"XGWindow::GetWindowSize" @I
 *
 *		Get the window's current size
 */

Point XGWindow::GetWindowSize() const
{
	Point pt;

#if OPT_MACOS == 1
	Rect r;
	
	r = fWindow.w.port.portRect;
	pt.h = r.right - r.left;
	pt.v = r.bottom - r.top;
#endif

#if OPT_WINOS == 1
	Rect r;
	
	GetWindowRect(fWindow,&r);
	pt.h = r.right - r.left;
	pt.v = r.bottom - r.top;
	SizeToContent(&pt);
#endif

#if OPT_XWIN == 1
	pt = GetContentSize();
#endif

	return pt;
}

/*	@F"XGWindow::GetWindowPos" @I
 *
 *		Get the window's current location
 */

Point XGWindow::GetWindowPos() const
{
	Point pt;
	
#if OPT_MACOS == 1
	const Rect *r;
	CGrafPtr port;
#endif

#if OPT_WINOS == 1
	Rect r;
#endif

#if OPT_MACOS == 1
	if (fWindow.w.port.portBits.rowBytes & 0x8000) {	// Color version
		port = (CGrafPtr)&fWindow.w.port;
		r = &(**(port->portPixMap)).bounds;
	} else {
		r = &fWindow.w.port.portBits.bounds;
	}
	pt.h = fWindow.w.port.portRect.left - r->left;
	pt.v = fWindow.w.port.portRect.top- r->top;
#endif

#if OPT_WINOS == 1
	GetWindowRect(fWindow,&r);
	SizeToContent(&r);
	pt.h = r.left;
	pt.v = r.top;
#endif

#if OPT_XWIN == 1
	XWindowAttributes wa;
	
	::XGetWindowAttributes(_GDisplay,fWindow,&wa);
	pt.h = wa.x;
	pt.v = wa.y;
#endif
	
	return pt;
}

/*	@F"XGWindow::GetWindowLocation" @I
 *
 *		Get the location of this thing. This is basically the screen
 *	location of the content region.
 */

Rect XGWindow::GetWindowLocation() const
{
	Rect r;
	Point pt;
	
	pt = GetWindowPos();
	r.left = pt.h;
	r.top = pt.v;
	pt = GetWindowSize();
	r.right = r.left + pt.h;
	r.bottom = r.top + pt.v;
	return r;
}

/*	@F"XGWindow::ContentToSize" @I
 *
 *		Convert from content to outer size of window. We don't care as
 *	much about the outer size of the window because that's used to
 *	approximate the location of a bunch of tiled windows on the screen.
 *		We *do* care about the interior, however.
 */

void XGWindow::ContentToSize(Point *size)
{
#if OPT_MACOS || OPT_XWIN
	/* X: What the hell. This varies from window manager to window manger */
	if (size->h > 0) size->h += 2;
	if (size->v > 0) size->v += 22;
#endif

#if OPT_WINOS
	/* This must be precise. */
	if (size->h > 0) size->h += 2 * ::GetSystemMetrics(SM_CXSIZEFRAME);
	if (size->v > 0) size->v += 2 * ::GetSystemMetrics(SM_CYSIZEFRAME) +
							    ::GetSystemMetrics(SM_CYCAPTION) +
							    ::GetSystemMetrics(SM_CYMENU);
#endif
}

void XGWindow::ContentToSize(Rect *size)
{
	if (EmptyRect(size)) return;
	
#if OPT_MACOS || OPT_XWIN
	/* X: What the hell. This varies from window manager to window manger */
	size->left -= 1;
	size->right += 1;
	size->top -= 21;
	size->bottom += 1;
#endif

#if OPT_WINOS
	/* This must be precise. */
	size->left -= ::GetSystemMetrics(SM_CXSIZEFRAME);
	size->right += ::GetSystemMetrics(SM_CXSIZEFRAME);
	size->bottom += ::GetSystemMetrics(SM_CYSIZEFRAME);
	size->top -= ::GetSystemMetrics(SM_CYSIZEFRAME) +
				 ::GetSystemMetrics(SM_CYCAPTION) +
				 ::GetSystemMetrics(SM_CYMENU);
#endif
}

/*	@F"XGWindow::SizeToContent" @I
 *
 *		Inverse of the above conversions.
 */

void XGWindow::SizeToContent(Point *size)
{
#if OPT_MACOS || OPT_XWIN
	/* X: What the hell. This varies from window manager to window manger */
	if (size->h > 0) size->h -= 2;
	if (size->v > 0) size->v -= 22;
#endif

#if OPT_WINOS
	/* This must be precise. */
	if (size->h > 0) size->h -= 2 * ::GetSystemMetrics(SM_CXSIZEFRAME);
	if (size->v > 0) size->v -= 2 * ::GetSystemMetrics(SM_CYSIZEFRAME) +
			   					::GetSystemMetrics(SM_CYCAPTION) +
							    ::GetSystemMetrics(SM_CYMENU);
#endif
}

void XGWindow::SizeToContent(Rect *size)
{
	if (EmptyRect(size)) return;

#if OPT_MACOS || OPT_XWIN
	/* X: What the hell. This varies from window manager to window manger */
	size->left += 1;
	size->right -= 1;
	size->top += 21;
	size->bottom -= 1;
#endif

#if OPT_WINOS
	/* This must be precise. */
	size->left += ::GetSystemMetrics(SM_CXSIZEFRAME);
	size->right -= ::GetSystemMetrics(SM_CXSIZEFRAME);
	size->bottom -= ::GetSystemMetrics(SM_CYSIZEFRAME);
	size->top += ::GetSystemMetrics(SM_CYSIZEFRAME) +
				 ::GetSystemMetrics(SM_CYCAPTION) +
				 ::GetSystemMetrics(SM_CYMENU);
#endif
}


/************************************************************************/
/*																		*/
/*	Event Support														*/
/*																		*/
/************************************************************************/

// @G"Window Events (internal)"

#if 0
#pragma mark -
#pragma mark Window Events
#endif

BEGINDISPATCHPROC(XGWindow,XGDispatch,XGWindow::Dispatch)
	DISPATCHTABLE(KXGKeyEvent,XGWindow::DoKey)
	DISPATCHTABLE(KXGCurMenuBar,XGWindow::DoCurMenuBar)
	DISPATCHTABLE(KXGMenuKey,XGDialog::DoMenuKey)
ENDDISPATCH

/*	@F"XGWindow::Dispatch" @I
 *
 *		Send message to the form if present
 */
 
long XGWindow::Dispatch(long msg, long arg, void *parg)
{
	if (fForm) {
		return fForm->DoDispatch(this,msg,arg,parg);
	} else {
		if (XGAppCore::GetApplication()->fModalWindow) {
			/* Modal window processing kludge: bump out menus */
			if (msg == KXGGetMenuStatus) return 0;
			if (msg == KXGDoMenuCommand) return 0;
		}
		return -1;
	}
}

/*	XGWindow::DoCurMenuBar
 *
 *		Get the current menu bar for me
 */

long XGWindow::DoCurMenuBar(long,void *)
{
	return fMenuBar;
}

/*	XGWindow::DoKey
 *
 *		Handle keyboard event.
 */

long XGWindow::DoKey(long k, void *)
{
	short key,code;
	
	key = GETLOWORD(k);
	code = GETHIWORD(k);
	
	if ((0 == (code & KSpecialKey)) && (key == '\t')) {
		/*
		 *	Tab key processing
		 */
		
		if (code & KKeyShift) PrevTabStop();
		else NextTabStop();
		return 0;
	}
	
	return -1;
}


/*	XGWindow::DoMenuKey
 *
 *		Handle menu key; find the accelerator and move to the
 *	appropriate tab stop. This is only done on windows and X 
 *	programs to allow keyboard navigation
 */

long XGWindow::DoMenuKey(long k, void *)
{
#if OPT_MACOS
	#pragma unused (k)
#endif

#if OPT_WINOS || OPT_XWIN
	short key;
	XGView *view;
	XGView *ptr;
	XGButton *btn;
	
	key = GETLOWORD(k);
	
	/*
	 *	Step 1: Find if there is a view with this accelerator
	 */
	
	view = FindViewByAccel(key);
	if (view == NULL) return -1;
	
	/*
	 *	Step 2: Find the view with the tab stop that is either
	 *	me or right after me. If it is me, simulate the push of
	 *	the button
	 */
	
	if (view->IsTabStop()) {
		view->SetFocus();
		
		/* And simulate push if this is the control I selected */
		btn = dynamic_cast<XGButton *>(view);
		if (btn) btn->PushButton();
		return 0;
	}
	ptr = view;
	for (;;) {
		ptr = ptr->FindNextView();
		if (ptr == NULL) ptr = GetView();
		if (ptr == view) break;				// no tab stop controls???
		
		if (ptr->IsTabStop()) {
			ptr->SetFocus();
			return 0;
		}
	}
#endif
	
	return -1;
}

/*	@F"XGWindow::FirstTabStop" @I
 *
 *		Find the first non-zero ID'ed view with the tab stop,
 *	visible, and enabled views
 */

void XGWindow::FirstTabStop(void)
{
	XGView *v = fView->FindFirstView();
	if (v) v->SetFocus();
}

/*	@F"XGWindow::NextTabStop" @I
 *
 *		Find the next non-zero ID'ed view with the tab stop,
 *	visible, and enabled views
 */

void XGWindow::NextTabStop(void)
{
	XGView *v;
	
	v = dynamic_cast<XGView *>(GetFocus());
	if (v == NULL) v = fView->FindFirstView();
	else if (v == dynamic_cast<XGView *>(this)) v = fView->FindFirstView();
	else {
		v = fView->FindAfterView(v->GetViewID());
		if (v == NULL) v = fView->FindFirstView();
	}
	
	if (v) v->SetFocus();
}

/*	@F"XGWindow::PrevTabStop" @I
 *
 *		Find the previous non-zero ID'ed view with the tab stop,
 *	visible, and enabled views
 */

void XGWindow::PrevTabStop(void)
{
	XGView *v;
	
	v = dynamic_cast<XGView *>(GetFocus());
	if (v == NULL) v = fView->FindLastView();
	else if (v == dynamic_cast<XGView *>(this)) v = fView->FindLastView();
	else {
		v = fView->FindBeforeView(v->GetViewID());
		if (v == NULL) v = fView->FindLastView();
	}
	
	if (v) v->SetFocus();
}

/************************************************************************/
/*																		*/
/*	Event Dispatch														*/
/*																		*/
/************************************************************************/

#if 0
#pragma mark -
#pragma mark Event Dispatch
#endif

/*	@F"XGWindow::DoDraw" @I
 *
 *		Handle drawing inside of this window. This draws the grow icon,
 *	the view, and redoes the grow icon again.
 */

void XGWindow::DoDraw(Rect r)
{
	if (fView == NULL) return;
	fView->ProcessDraw(r);
	
#if OPT_XWIN == 1
	if (fMenuBarView) fMenuBarView->ProcessDraw(r);
#endif
}

/*	@F"XGWindow::DoActivate" @I
 *
 *		Handle activate event
 */

void XGWindow::DoActivate(bool active)
{
	if (fView) fView->ProcessActivate(active);
}

/*	@F"XGWindow::DoSizeWindow" @I
 *
 *		Resize the view to fit within this window. This can also
 *	be called when the window is first opened
 */

void XGWindow::DoSizeWindow()
{
	Rect r;
	
#if OPT_MACOS == 1
	r = fWindow.w.port.portRect;
	r.bottom -= r.top;
	r.right -= r.left;
	r.top = 0;
	r.left = 0;
#endif

#if OPT_WINOS == 1
	::GetClientRect(fWindow,&r);
	r.bottom -= r.top;
	r.right -= r.left;
	r.top = 0;
	r.left = 0;
#endif

#if OPT_XWIN == 1
	XWindowAttributes wa;
	
	::XGetWindowAttributes(_GDisplay,fWindow,&wa);
	if (fMenuBarView) {
		r.left = 0;
		r.top = 0;
		r.right = wa.width;
		r.bottom = 20;
		fMenuBarView->SetLocation(r);
	}
	r.left = 0;
	r.top = 0;
	r.right = wa.width;
	r.bottom = wa.height;
	if (fMenuBarView) {
		r.top += 20;
	}
#endif

	if (fView) {
		fView->SetLocation(r);
	}
}

/*	@F"XGWindow::DoMouseDown" @I
 *
 *		Handle the mouse down
 */

XGView *XGWindow::DoMouseDown(Point pt, short flags)
{
	XGView *v;
	
#if OPT_XWIN == 1
	if ((pt.v < 20) && (fMenuBarView)) {
		v = fMenuBarView->FindClick(pt);
		if (!v) return NULL;
		if (!v->DoMouseDown(pt,flags)) return NULL;
		return v;
	}
#endif
	
	if (!fView) return NULL;
	v = fView->FindClick(pt);
	if (!v) return NULL;
	
	v->GlobalToView(&pt);
	if (!v->DoMouseDown(pt,flags)) return NULL;
	return v;
}

/*	@F"XGWindow::DoMouseMove" @I
 *
 *		Handle mouse move
 */

void XGWindow::DoMouseMove(Point pt, short flags, XGView *v)
{
	if (!fView) return;
	if (v == NULL) {
#if OPT_XWIN == 1
		if ((pt.v < 20) && (fMenuBarView)) {
			v = fMenuBarView->FindClick(pt);
		} else {
			v = fView->FindClick(pt);
		}
		if (v == NULL) return;
#else
		if (NULL == (v = fView->FindClick(pt))) return;
#endif
	}

	v->GlobalToView(&pt);
	v->DoMouseMove(pt,flags);
}

/*	@F"XGWindow::DoMouseUp" @I
 *
 *		Handle mouse up
 */

void XGWindow::DoMouseUp(Point pt, short flags, XGView *v)
{
	if (!fView) return;
	if (v == NULL) {
#if OPT_XWIN == 1
		if ((pt.v < 20) && (fMenuBarView)) {
			v = fMenuBarView->FindClick(pt);
		} else {
			v = fView->FindClick(pt);
		}
		if (v == NULL) return;
#else
		if (NULL == (v = fView->FindClick(pt))) return;
#endif
	}

	v->GlobalToView(&pt);
	v->DoMouseUp(pt,flags);
}


/************************************************************************/
/*																		*/
/*	Event Dispatch														*/
/*																		*/
/************************************************************************/

#if 0
#pragma mark -
#pragma mark Internal Support
#endif

/*	XGWindow::GetXGWindow
 *
 *		OS dependant routines go from the OS window to my window class
 */

#if OPT_MACOS == 1

XGWindow *XGWindow::GetXGWindow(GrafPtr p)
{
	XGSWindowRecord *r;
	
	if ((((WindowPeek)p)->windowKind != KFloatingWindow) &&
			(((WindowPeek)p)->windowKind != KNormalWindow) &&
			(((WindowPeek)p)->windowKind != KDialogWindow))
		return NULL;
	r = (XGSWindowRecord *)p;
	return r->tw;
}

#endif

#if OPT_WINOS == 1

XGWindow *XGWindow::GetXGWindow(HWND w)
{
	XGWindow *tw;
	
	for (tw = gList; tw != NULL; tw = tw->fNext) {
		if (tw->fWindow == w) return tw;
	}
	return NULL;
}

#endif

#if OPT_XWIN == 1

XGWindow *XGWindow::GetXGWindow(Window w)
{
	XGWindow *tw;
	
	for (tw = gList; tw != NULL; tw = tw->fNext) {
		if (tw->fWindow == w) return tw;
	}
	return NULL;
}

/*	XGWindow::GetXGWindowByParent
 *
 *		For X, this scans for the XGWindow object by the 
 *	parent window (the window that is the immediate child of the
 *	X root window
 */

XGWindow *XGWindow::GetXGWindowByParent(Window w)
{
	XGWindow *tw;
	
	for (tw = gList; tw != NULL; tw = tw->fNext) {
		if (tw->fWMWindow == w) return tw;
	}
	return NULL;
}

/*	XGWindow::SetMenuBar
 *
 *		Set the menu bar
 */

void XGWindow::SetMenuBar(XGMenuBar *bar)
{
	fMenuBarView = new XGMenuView(this,bar);

	fMenuBarView->SetDispatchParent(this);
	fMenuBarView->SetRootWindow(fWindow);
	DoSizeWindow();
}

/*	XGWindow::RedrawMenuBar
 *
 *		If I have a menu bar view, redraw it
 */

void XGWindow::RedrawMenuBar(void)
{
	if (fMenuBarView) {
		Rect r;
		
		r = fMenuBarView->GetContentRect();
		fMenuBarView->DoDrawView(r);
	}
}

#endif

/************************************************************************/
/*																		*/
/*	Initialization Support												*/
/*																		*/
/************************************************************************/

#if 0
#pragma mark -
#pragma mark Initialization Support
#endif

/*	XGWindow::IInitWindow
 *
 *		Initialize the window
 */

void XGWindow::IInitWindow(XGSWindowInitRecord &w)
{
	long autopos;
	Rect r;
	char buffer[256];
	short width,height;
	Rect s;
	
	/*
	 *	Copy data structures
	 */
	 
	fMin.h = w.minx;
	fMin.v = w.miny;
	fMax.h = w.maxx;
	fMax.v = w.maxy;
	fZoom.h = w.zoomx;
	fZoom.v = w.zoomy;
	
	fMenuBar = w.menuID;
	
	fWindowKind = w.windowKind;
	fWindowType = w.windowType;	
	fWindowID = w.windowID;
	
	/*
	 *	Figure out my name
	 */
	 
	strcpy(buffer,w.windowName);			// use default
	
#if OPT_XWIN == 1
	fMenuBarView = NULL;
	fCursorID = -1;
	fActive = false;
#endif
	
	/*
	 *	Figure out the window width/height.
	 */
		
	if (w.screenRight == 0) {
		if (w.initx <= 0) {
			width = 320;
			
			if ((width < w.minx) && (w.minx != 0)) width = w.minx;
			if ((width > w.maxx) && (w.maxx != 0)) width = w.maxx;
		} else {
			width = w.initx;
		}
	}
	if (w.screenBottom == 0) {
		if (w.inity <= 0) {
			height = 320;
			
			if ((height < w.miny) && (w.miny != 0)) height = w.miny;
			if ((height > w.maxy) && (w.maxy != 0)) height = w.maxy;
		} else {
			height = w.inity;
		}
	}
	
	/*
	 *	Figure out where to put my window.
	 */
	
	if ((w.screenLeft == 0) && (w.screenTop == 0)) {
		/*
		 *	Is the left, top zero? Then use the auto location
		 *	parameter specified
		 */
		
		autopos = fWindowKind & KMaskPos;
		if (autopos == KWinPosStagger) {
		
#if OPT_MACOS || OPT_XWIN
			r.top = GDefaultPosition * 15 + 44;
			r.left = GDefaultPosition * 15 + 6;
#endif

#if OPT_WINOS
			r.top = (1+GDefaultPosition) * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION));
			r.left = GDefaultPosition * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION));
			
			r.top += ::GetSystemMetrics(SM_CYMENU);
			r.left += GetSystemMetrics(SM_CXFRAME);
#endif

			GDefaultPosition++;
			if (GDefaultPosition >= 5) GDefaultPosition = 0;
		} else {
			/*
			 *	Center on frontmost window or in screen...
			 */
					
			if (autopos == KWinPosAlert) {
				XGWindow *w;
				
				w = GetFrontWindow();
				if (w == NULL) GetScreenSize(&r);
				else {
					r = w->GetWindowLocation();
					ContentToSize(&r);
				}
			} else {
				GetScreenSize(&r);
			}

			r.left = (r.left + r.right - width)/2;
			r.top = (r.top + r.bottom - height)/2;

#if OPT_MACOS
			if (r.top < 44) r.top = 44;
#endif

#if OPT_XWIN || OPT_WINOS
			if (r.top < 0) r.top = 0;
#endif
		}
	} else {
		r.top = w.screenTop;
		r.left = w.screenLeft;
	}
	
	r.bottom = r.top + height;
	r.right = r.left + width;
	
	/*
	 *	Keep window on screen
	 */
	
	GetScreenSize(&s);
	SizeToContent(&s);
	if (r.right > s.right) {
		r.left += s.right - r.right;
		r.right = s.right;
	}
	if (r.bottom > s.bottom) {
		r.top += s.bottom - r.bottom;
		r.bottom = s.bottom;
	}
	if (r.left < s.left) {
		r.right += s.left - r.left;
		r.left = s.left;
	}
	if (r.top < s.top) {
		r.bottom += s.top - r.top;
		r.top = s.top;
	}
	
	/*
	 *	And open it.
	 */
	
	XGWindow::ICreateWindow(buffer,r);
	
#if OPT_MACOS == 1
	fRootWindow = &fWindow.w.port;
#endif

#if OPT_WINOS == 1
	fRootWindow = fWindow;
#endif

#if OPT_XWIN == 1
	fRootWindow = fWindow;
	fWMWindow = fWindow;					// until notified later...
#endif
}

#if OPT_MACOS == 1

/*	SetWindowColor
 *
 *		This sets the background color of the specified window to grey.
 *	This is used for my dialog boxes
 */

static void SetWindowColor(WindowPtr w)
{
	WCTabHandle ctab;
	
	ctab = (WCTabHandle)::NewHandle(sizeof(WinCTab));
	if (ctab == NULL) return;
	
	(**ctab).wCSeed = 0;
	(**ctab).wCReserved = 0;
	(**ctab).ctSize = 0;					// one element
	(**ctab).ctTable[0].value = wContentColor;
	(**ctab).ctTable[0].rgb.red = 0xDDDD;
	(**ctab).ctTable[0].rgb.green = 0xDDDD;
	(**ctab).ctTable[0].rgb.blue = 0xDDDD;
	SetWinColor(w,ctab);
}

#endif

/*	XGWindow::ICreateWindow
 *
 *		This is the code to create the window based on the information
 *	just loaded
 */

void XGWindow::ICreateWindow(char *name, Rect s)
{
	long kind = fWindowKind & KMaskType;
	
#if OPT_MACOS == 1
	unsigned char buffer[256];
	short whichProc;
	long color;
#endif

#if OPT_WINOS == 1
	MDICREATESTRUCT mcs;
//	Rect sizerect;
#endif

#if OPT_XWIN == 1
	XGWindow *front;
	extern Atom _GDelWindowAtom;
#endif
	
#if OPT_MACOS == 1
	/*
	 *	Open the window itself [Macintosh version]
	 */
	
	Gestalt(gestaltQuickdrawVersion,&color);
	if (color >= 0x100) color = 1;		// Do I have color?
	else color = 0;
	
	fWindow.tw = this;					// Get the backpointer correct.	

	c2pstr(strcpy((char *)buffer,name));
	
	if (kind == KWinDocument) whichProc = 8;				// zoom proc
	else if (kind == KWinModal) whichProc = 1;			// modal
	else if (kind == KWinMovableModal) whichProc = 5;	// movemodal
	else if (kind == KWinFloating) whichProc = 1985;		// floater
	else whichProc = noGrowDocProc;

	if (color) {
		if (NULL == ::MNewCWindow((Ptr)&fWindow.w,&s,buffer,0,whichProc,(WindowPtr)-1,!(GetWindowAttributes() & KAttrNoClose),0L)) {
			fWindow.tw = NULL;			// Clear the backpointer
			throw XGPostError(KXGOutMemory);
		}
	} else {
		if (NULL == ::MNewWindow((Ptr)&fWindow.w,&s,buffer,0,whichProc,(WindowPtr)-1,!(GetWindowAttributes() & KAttrNoClose),0L)){
			fWindow.tw = NULL;			// Clear the backpointer
			throw XGPostError(KXGOutMemory);
		}
	}
	
	/*
	 *	Set the background content color to gray for dialogs
	 */
	
	if ((kind == KWinModal) || (kind == KWinMovableModal)) {
		SetWindowColor((WindowPtr)&fWindow.w);
	}
 
    /*
     *  Initialize drawing port
     */
	
	::SetPort((WindowPtr)&fWindow.w);
	::TextSize(9);						// Set a reasonable default font size
	fWindow.w.windowKind = (GetWindowAttributes() & KAttrFloater) ? KFloatingWindow : KNormalWindow;
#endif /* OPT_MACOS */

	/*
	 *	Windows version of this
	 */
	
#if OPT_WINOS == 1
	ContentToSize(&s);
	
	fDlogParent = NULL;
	if ((_GMDIWindow) && (kind == KWinDocument)) {
	    mcs.szClass = _GWindowClass;
	    mcs.szTitle = name;
	    mcs.hOwner = _GInstance;
		mcs.x = s.left;
		mcs.y = s.top;
		mcs.cx = s.right - s.left;
		mcs.cy = s.bottom - s.top;
	
	    mcs.style = 0;
	    mcs.lParam = NULL;						// Pass this on
		_GWindow = this;
		fWindow = (HWND)::SendMessage(_GMDIWindow,
										WM_MDICREATE,
										0,
										(LPARAM)(MDICREATESTRUCT FAR *)&mcs);
		_GWindow = NULL;
		if (fWindow == NULL) {
			throw XGPostError(KXGOutMemory);
		}
	} else {
		_GWindow = this;
		
		if (kind == KWinDocument) {
			// Window
			fWindow = CreateWindow(_GWindowClass,
									name,
									WS_OVERLAPPEDWINDOW | // WS_CLIPCHILDREN | 
								   		WS_MAXIMIZEBOX | WS_MINIMIZEBOX,
									s.left,
									s.top,
									s.right-s.left,
									s.bottom-s.top,
									NULL,
									NULL,
									_GInstance,
									NULL);
		} else if ((kind == KWinModal) || 
					(kind == KWinMovableModal)) {
			fDlogParent = _GMainWindow;
			if (XGAppCore::GetApplication()->fModalWindow) {
				fDlogParent = XGAppCore::GetApplication()->fModalWindow->GetHWND();
			}
			
			// Dialog
			
			/*
			 *	Kludge: the ContentToSize/SizeToContent routines only
			 *	work with windows containing a menu bar. Otherwise, they
			 *	give a result that's a hair too tall. Change this to
			 *	fix the problem
			 */
			
			s.bottom -= ::GetSystemMetrics(SM_CYMENU);
			fWindow = CreateWindowEx(WS_EX_DLGMODALFRAME,
									 _GDlogClass,
									 name,
									 WS_CLIPCHILDREN | 
								   		WS_POPUP | WS_CAPTION | WS_SYSMENU,
									 s.left,
									 s.top,
									 s.right-s.left,
									 s.bottom-s.top,
									 fDlogParent,
									 NULL,
									 _GInstance,
									 NULL);
									 
			/*
			 *	We've created the dialog box. Now disable the owner
			 */
			
			::EnableWindow(fDlogParent,FALSE);
		}
		_GWindow = NULL;
		
		if (fWindow == NULL) {
			throw XGPostError(KXGOutMemory);
		}
	}
#endif

#if OPT_XWIN == 1
	bool dialog;
	
	/*
	 *	Sanity check--we can only open modal or movable modal windows
	 *	if there is a document window available.
	 */

	dialog = false;
	front = XGWindow::GetFrontWindow();
	if ((kind == KWinModal) || (kind == KWinMovableModal)) {
		if (front) dialog = true;
	}
	
	/*
	 *	Windows version of this thing
	 */
	
	XSetWindowAttributes attrib;
	int gx,gy;
	
	if (kind == KWinDocument) {
		gx = 0;
		gy = 0;
	} else {
		gx = s.left;
		gy = s.top;
	}
							
	attrib.event_mask = KeyPressMask |
						ButtonPressMask |
						ButtonReleaseMask |
						EnterWindowMask |
						LeaveWindowMask |
						PointerMotionMask |
						ExposureMask |
						StructureNotifyMask |
						FocusChangeMask |
						ColormapChangeMask;

	fWindow = XCreateWindow(_GDisplay,
							DefaultRootWindow(_GDisplay),
							gx,
							gy,
							s.right - s.left,
							s.bottom - s.top,
							0,
							CopyFromParent,
							InputOutput,
							CopyFromParent,
							CWEventMask,&attrib);
	XStoreName(_GDisplay,fWindow,name);
	XSetWindowBackgroundPixmap(_GDisplay,fWindow,None);
	
	/*
     *	Set some attributes
     */
    
    XSetWMProtocols(_GDisplay,fWindow,&_GDelWindowAtom,1);
    if (dialog) {   
//	    if (_GDialogFlag) {
//  		/*
//    		 *	We're a modal dialog box.
//	    	 */
//    
//    		::XSetTransientForHint(_GDisplay,fWindow,front->GetWindow());
//    	} else {
    		/*
    		 *	We're a modeless dialog box
    		 */
    		
    		XWMHints h;
    		
    		h.flags = WindowGroupHint;
    		h.window_group = front->GetWindow();
    		XSetWMHints(_GDisplay,fWindow,&h);
//    	}
    } else {
    	XWMHints h;
    	
    	h.flags = WindowGroupHint;
    	h.window_group = fWindow;
    	XSetWMHints(_GDisplay,fWindow,&h);
    }
#endif
}

