//	Zinc Application Framework - I_WINDOW.CPP
//	COPYRIGHT (C) 1990-1999.  All Rights Reserved.
//	Zinc Software Incorporated.  Pleasant Grove, Utah  USA

#define ZAF_BLIT_MOVE
#define USE_RAW_KEYS
#include "i_close.hpp"
#include <z_border.hpp>
#include <z_ctype.hpp>
#include <z_error.hpp>
#include <z_help.hpp>
#include <z_htips.hpp>
#include <z_icon1.hpp>
#include <z_keymap.hpp>
#include <z_max.hpp>
#include <z_min.hpp>
#include <z_plldn.hpp>
#include <z_scrll2.hpp>
#include <z_stdio.hpp>
#include <z_string.hpp>
#include <z_sys.hpp>
#include <z_utils.hpp>
#include <z_win.hpp>

#define ZAF_ICON_INFO
#include "img_def.cpp"

// ----- ZafWindow ---------------------------------------------------------

ZafWindowObject *ZafWindow::Add(ZafWindowObject *object, ZafWindowObject *position)
{
	// NOTE: Child windows that are not ZafMDIWindow objects must not have decorations.
	// In other words, a child window with a title bar object or a border object that
	// is not a ZafMDIWindow object is not supported. Window decorations are only
	// supported by the ZafMDIWindow class, or if the window is on the window manager.

	// Check for a null object.
	if (!object)
		return (ZAF_NULLP(ZafWindowObject));

	// Add the object to the list.
	if (!object->SupportObject() && ZafList::Index(object) == -1)
	{
		if (position)
			ZafList::Add(object, position);		// Position insert.
		else
			ZafList::Add(object);				// CompareFunction insert.

		// Make the object current if there isn't a current object yet.
		if (!Current() && !object->Noncurrent() && !object->Disabled())
			SetCurrent(object);
	}
	else if (object->SupportObject() && support.Index(object) == -1)
	{
//??? "Hide" the icon for now.
		if (object->IsA(ID_ZAF_ICON))
		{
			object->zafRegion.left =
				object->zafRegion.top =
				object->zafRegion.right =
				object->zafRegion.bottom = -10000;
		}
		if (position)
			support.Add(object, position);		// Position insert.
		else
			support.Add(object);				// CompareFunction insert.
	}
	else if (object == Current())
		return (object);

	// See if object should be the "current" object (and selected).
	bool setSelected = object->Selected();
	bool setCurrent = (object->Focus() || (selectionType == ZAF_SINGLE_SELECTION &&
		setSelected))? true : false;

	// Clear the focus and selected attributes. (The object can't really have
	// focus until it is displayed in the window, and if it is to be selected,
	// the previously selected sibling must be deselected on a
	// ZAF_SINGLE_SELECTION window.)
	object->SetFocus(false);
	object->SetSelected(false);

	// Set parent after SetSelected(false) in case ZAF_SINGLE_SELECTION.
	object->parent = this;

	if (screenID && !object->screenID)
	{
		bool saveVisible = object->Visible(false);
		object->SetVisible(false);
		object->Event(S_CREATE);

		// Mark overlaps.
		for (ZafWindowObject *obj1 = First(); obj1; obj1 = obj1->Next())
		{
			obj1->overlapped = false;
			for (ZafWindowObject *obj2 = obj1->Next(); obj2; obj2 = obj2->Next())
			{
				if (obj1->zafRegion.Overlap(obj2->zafRegion))
				{
					obj1->overlapped = true;
					break;
				}
			}
		}

		if (object->SupportObject())
			OSSize();

		object->SetVisible(saveVisible);
	}

	// Update the focus.
	if (setCurrent)
	{
		if (Focus())
			object->SetFocus(true);
		else
			ZafList::SetCurrent(object);
	}

	// Update selection.
	if (setSelected)
		object->SetSelected(true);

	if (Title() == object && screenID)
	{
		bool canClose = false;

		// Determine if the window can be closed.
		ZafSystemButton *systemButton = SystemButton();
		if (systemButton)
		{
			// If it is a generic system menu, the window can be closed.
			if (DynamicPtrCast(systemButton, ZafSystemButton))
			{
				if (DynamicPtrCast(systemButton, ZafSystemButton)->SystemButtonType() == ZAF_NATIVE_SYSTEM_BUTTON)
						canClose = true;
				else // Look for the 'close' system menu option.
				{
					ZafPopUpMenu *sMenu = &systemButton->menu;
					if (sMenu)
					{
						ZafPopUpItem *pItem = DynamicPtrCast(sMenu->Last(), ZafPopUpItem);
						while (pItem && pItem->ItemType() != ZAF_CLOSE_OPTION)
							pItem = DynamicPtrCast(pItem->Previous(), ZafPopUpItem);
						if (pItem)
							canClose = true;
					}
				}
			}
		}
		else if (!Locked())
			canClose = true;

		// Create and add close button.
#if defined(ZAF_GRAPHICS_MODE)
		ZafCloseButton *closeButton = new ZafCloseButton(S_CLOSE);
//		closeButton->parent = this;
		// Insert the closeButton in front of an object.
		ZafWindowObject *object = GetObject(ZAF_NUMID_MAXIMIZE);
		if (!object)
		{
			object = GetObject(ZAF_NUMID_MINIMIZE);
			if (!object)
			{
				object = GetObject(ZAF_NUMID_SYSTEM);
				if (!object)
					object = GetObject(ZAF_NUMID_TITLE);
			}
		}

		// Set disabled if the window can't be closed.
		if (!canClose || Locked())
			closeButton->SetDisabled(true);

		Add(closeButton, object);
		OSInvalidateRegion(0, true);
//		support.Add(closeButton, object);
#endif
	}

	// Return a pointer to the object.
	return (object);
}

ZafRegionStruct ZafWindow::BeginDraw(void)
{
	// Start with screen region and pare it down.
	ZafRegionStruct clip, viewPort;
	clip.left = clip.top = 0;
	clip.right = display->columns - 1;
	clip.bottom = display->lines - 1;
#if defined(ZAF_GRAPHICS_MODE)
	clip.coordinateType = ZAF_PIXEL;
#elif defined(ZAF_TEXT_MODE)
	clip.coordinateType = ZAF_CELL;
#endif

	// Start with the object's region, based at (0, 0), and translate it
	// based on its parents' regions.
	viewPort = clientRegion;

	// Don't compensate for the fact that we are only to the clientRegion
	// until after we  have our viewPort and clip calculated.
	viewPort.left = viewPort.top = 0;

	// Get the clip and virtual regions.
	GetClip(this, clip, viewPort);

	// Compensate for the fact that we are only able to draw to our 
	// clientRegion.
	viewPort.left += clientRegion.left;
	viewPort.top += clientRegion.top;

	// Initialize the display class for drawing.
	ZafError dispError = display->BeginDraw(0, screenID, viewPort, clip);
	if (dispError != ZAF_ERROR_NONE)
	{
		display->EndDraw();
		ZafRegionList drawList;
		ZafRegionStruct tRegion = zafRegion;
		tRegion.VtShift(-tRegion.top);
		tRegion.HzShift(-tRegion.left);
		drawList.Allocate(screenID, tRegion);
		windowManager->GetDrawRegionList(this, drawList);
		
		ZafRegionStruct osRegion;
		if (parent)
		{
			if (regionType == ZAF_OUTSIDE_REGION)
			{
				osRegion = parent->zafRegion;
				osRegion.VtShift(-osRegion.top);
				osRegion.HzShift(-osRegion.left);
				osRegion = parent->ConvertToOSRegion(parent, &osRegion);
			}
			else
			{
				osRegion = zafRegion;
				osRegion.VtShift(-osRegion.top);
				osRegion.HzShift(-osRegion.left);
				osRegion = ConvertToOSRegion(this, &osRegion);
			}
		}
		else
			osRegion = zafRegion;

		ZafRegionElement *damageElement;
		for (damageElement = drawList.First(); damageElement;
			damageElement = damageElement->Next())
		{
			damageElement->region.VtShift(osRegion.top);
			damageElement->region.HzShift(osRegion.left);
		}
		if (!drawList.First())
		{
			tRegion.Assign(-1000, -1000, 0, 0, zafRegion.coordinateType);
			drawList.Allocate(screenID, tRegion);
		}


		display->SetDrawRegions(&drawList);
		display->BeginDraw(0, screenID, viewPort, clip);
	}

	// Shift the region to be (0, 0)-based.
	viewPort = ConvertToDrawRegion(this, &viewPort);
	return (viewPort);
}

ZafRegionStruct ZafWindow::BeginDrawFrame(void)
{
	return (ZafWindowObject::BeginDraw());
}

ZafPositionStruct ZafWindow::ConvertToOSPosition(const ZafWindowObject *object,
	const ZafPositionStruct *zafPosition) const
{
	ZafPositionStruct osPosition;
	if (zafPosition)
	{
		osPosition.column = zafPosition->column + zafRegion.left;
		osPosition.line = zafPosition->line + zafRegion.top;
		osPosition.coordinateType = zafPosition->coordinateType;
	}
	else
	{
		osPosition.column = osPosition.line = 0;
#if defined(ZAF_GRAPHICS_MODE)
		osPosition.coordinateType = ZAF_PIXEL;
#elif defined(ZAF_TEXT_MODE)
		osPosition.coordinateType = ZAF_CELL;
#endif
	}

	if (!object || (!object->SupportObject() && object != this))
	{
		osPosition.column += clientRegion.left;
		osPosition.line += clientRegion.top;
	}

	if (parent && windowManager->Index(this) == -1)
		osPosition = parent->ConvertToOSPosition(this, &osPosition);

	return (osPosition);
}

bool ZafWindow::ConvertToZafEvent(ZafEventStruct &event)
{
	// Defer to the base class.
	return (ZafWindowObject::ConvertToZafEvent(event));
}

ZafPositionStruct ZafWindow::ConvertToZafPosition(const ZafWindowObject *object,
	const ZafPositionStruct *osPosition) const
{
	ZafPositionStruct zafPosition;

	if (osPosition)
	{
		zafPosition.column = osPosition->column - zafRegion.left;
		zafPosition.line = osPosition->line - zafRegion.top;
		zafPosition.coordinateType = osPosition->coordinateType;
	}
	else
	{
		zafPosition.column = zafPosition.line = 0;
#if defined(ZAF_GRAPHICS_MODE)
		zafPosition.coordinateType = ZAF_PIXEL;
#elif defined(ZAF_TEXT_MODE)
		zafPosition.coordinateType = ZAF_CELL;
#endif
	}

	if (!object->SupportObject() && object != this)
	{
		zafPosition.column -= clientRegion.left;
		zafPosition.line -= clientRegion.top;
	}

	if (parent && windowManager->Index(this) == -1)
		zafPosition = parent->ConvertToZafPosition(this, &zafPosition);

	return (zafPosition);
}

ZafEventType ZafWindow::DispatchMouseEvent(const ZafEventStruct &event)
{
	// Dispatch all mouse events to the leaf-most object.

	// LogicalEvent() must be called first to map the logical events (L_*) and
	// to convert the event to the context of this object.
	ZafEventType ccode = LogicalEvent(event);

	if (modifyMode)
		return (Modify(event));

	if (windowManager->MouseEventRoute() == this)
	{
		ccode = Event(event);
		return (ccode);
	}

	// If minimized, pass the event to the minimize icon.
/* START BLOCK COMMENT
**		if (Minimized())
**			return (MinimizeIcon()->DispatchMouseEvent(event));
END BLOCK COMMENT */

	// Convert mouse position to the coordinates of this object.
	bool overClient = false;
	ZafPositionStruct mousePosition = event.position;
	ZafRegionStruct windowClient = ClientRegion();
	if (windowClient.Overlap(mousePosition))
	{
		// If the mouse is over the client region, convert to the client
		// region's coordinates.
		overClient = true;
		mousePosition.column -= windowClient.left;
		mousePosition.line -= windowClient.top;
		// Cast away the constness so we can have event.position relative
		// to the client region.
		((ZafEventStruct &)event).position = mousePosition;
	}

	// Process drag and drop events.
	ZafWindowObject *object;
	if (windowManager->dragObject)
	{
		if (overClient)
		{
			for (object = First(); object; object = object->Next())
				if (object->Visible() && object->zafRegion.Overlap(mousePosition))
				{
					ccode = object->DispatchMouseEvent(event);
					break;
				}
		}
		else
		{
			for (object = SupportLast(); object; object = object->Previous())
				if (!object->IsA(ID_ZAF_BORDER) &&
					object->Visible() && object->zafRegion.Overlap(mousePosition))
				{
					ccode = object->DispatchMouseEvent(event);
					break;
				}
		}

		// If the mouse is not over a child object, this is the
		// leaf-most object so it processes the event.
		if (!object)
			ccode = ZafWindowObject::DispatchMouseEvent(event);
		return (ccode);
	}

	if (overClient)
	{
		for (object = First(); object; object = object->Next())
			if (object->Visible() && object->zafRegion.Overlap(mousePosition))
			{
				if (object->systemObject)
				{
					ccode = object->DispatchMouseEvent(event);
					break;
				}
				else
				{
					ZafWindow *win = DynamicPtrCast(object, ZafWindow);
					ZafWindowObject *tObject = win ? win->Current() : ZAF_NULLP(ZafWindowObject);
					while (win && tObject)
					{
						if (tObject->systemObject)
							break;
						win = DynamicPtrCast(tObject, ZafWindow);
						tObject = win ? win->Current() : ZAF_NULLP(ZafWindowObject);
					}
					if (tObject)
					{
						ccode = object->DispatchMouseEvent(event);
						break;
					}
				}
			}
	}
	else
	{
		// Start with last object, since the border is the first object
		// and its region covers the entire window.
		for (object = SupportLast(); object; object = object->Previous())
			if (object->Visible() && object->zafRegion.Overlap(mousePosition))
			{
				ccode = object->DispatchMouseEvent(event);
				break;
			}

		if (!object && Border())
		{
//??? Check to see that mouse overlaps the border.
			// Allow the border object to process its mouse events.
			// Set the object variable so we know an object was found.
			object = Border();
			ccode = object->DispatchMouseEvent(event);
		}
	}

	// If the mouse is not over a child object, this is the
	// leaf-most object so it processes the event.
	if (!object)
		ccode = ZafWindowObject::DispatchMouseEvent(event);

	return (ccode);
}

ZafWindowObject *ZafWindow::FindMouseObject(const ZafEventStruct &event)
{
	// If the object is disabled return a null pointer.
	if (Disabled())
		return (ZAF_NULLP(ZafWindowObject));

	if (modifyMode)
		return (this);

	if (windowManager->MouseEventRoute() == this)
		return (this);

	ZafPositionStruct position;
	position.line = event.osEvent.position.line;
	position.column = event.osEvent.position.column;
#if defined(ZAF_GRAPHICS_MODE)
	position.coordinateType = ZAF_PIXEL;
#else
	position.coordinateType = ZAF_CELL;
#endif
	// Convert mouse position to the coordinates of this object.
	bool overClient = false;
	ZafPositionStruct mousePosition = ConvertToZafPosition(this, &position);

	ZafRegionStruct windowClient = ClientRegion();
	if (windowClient.Overlap(mousePosition))
	{
		// If the mouse is over the client region, convert to the client
		// region's coordinates.
		overClient = true;
		mousePosition.column -= windowClient.left;
		mousePosition.line -= windowClient.top;
	}

	ZafWindowObject *object;
	ZafWindowObject *mouseObject = 0;

/* START BLOCK COMMENT
**		if (windowManager->dragObject)
**		{
**			if (overClient)
**			{
**				for (object = First(); object; object = object->Next())
**					if (object->Visible() && object->zafRegion.Overlap(position))
**					{
**						mouseObject = object->FindMouseObject(event);
**						break;
**					}
**			}
**			else
**			{
**				for (object = SupportLast(); object; object = object->Previous())
**					if (!object->IsA(ID_ZAF_BORDER) &&
**						object->Visible() && object->zafRegion.Overlap(position))
**					{
**						mouseObject = object->FindMouseObject(event);
**						break;
**					}
**			}
**	
**			// If the mouse is not over a child object, this is the
**			// leaf-most object so it processes the event.
**			if (!mouseObject)
**				mouseObject = this;
**			return (mouseObject);
**		}
END BLOCK COMMENT */

	if (overClient)
	{
		for (object = First(); object; object = object->Next())
			if (object->Visible() && object->zafRegion.Overlap(mousePosition))
			{
				mouseObject = object->FindMouseObject(event);
				break;
			}
	}
	else
	{
		// Start with last object, since the border is the first object
		// and its region covers the entire window.
		for (object = SupportLast(); object; object = object->Previous())
			if (object->Visible() && object->zafRegion.Overlap(mousePosition))
			{

				mouseObject = object->FindMouseObject(event);
				break;
			}
	}


	if (!mouseObject)
		mouseObject = ZafWindowObject::FindMouseObject(event);
	return (mouseObject);
}

ZafEventType ZafWindow::DragDropEvent(const ZafEventStruct &event)
{
	return (ZafWindowObject::DragDropEvent(event));
}

#if defined(ZAF_DEFAULT_DRAW)
ZafEventType ZafWindow::Draw(const ZafEventStruct &event, ZafEventType ccode)
{
	// Compute the actual draw region.
	ZafRegionStruct drawRegion = BeginDraw();

	display->SetClipRegion(event.region);

/* START BLOCK COMMENT
**		if (minimized)
**		{
**			display->SetPalette(windowManager->LogicalPalette(ZAF_PM_BACKGROUND, ZAF_PM_ANY_STATE));
**			display->Rectangle(drawRegion, 0, true);
**	
**			ZafIcon *minIcon = MinimizeIcon();
**			ZafPaletteStruct textPalette = minIcon->LogicalPalette(ZAF_PM_TEXT, PaletteState());
**			display->SetPalette(textPalette);
**	
**			ZafIconData *iconData = minIcon->IconData();
**	
**			if (iconData)
**				display->Icon(drawRegion.left + (drawRegion.Width() - iconData->Width()) / 2,
**					drawRegion.top, *iconData);
**	
**			display->Text(drawRegion.left, drawRegion.top + iconData->Height() + 1, drawRegion.right, drawRegion.bottom, minIcon->Text(), -1, ZAF_HZ_CENTER, ZAF_VT_BOTTOM, -1, true);
**			EndDraw();
**			return (ccode);
**		}
END BLOCK COMMENT */

	// See if a background (wallpaper) image exists.
//??? Is there a better way to get the image?
	ZafWindowObject *backgroundImage;
	for (backgroundImage = SupportFirst(); backgroundImage; backgroundImage = backgroundImage->Next())
		if (backgroundImage->IsA(ID_ZAF_IMAGE))
			break;

	if (backgroundImage)
	{
		ZafRegionStruct imageRegion = clientRegion;
		imageRegion.HzShift(-imageRegion.left);
		imageRegion.VtShift(-imageRegion.top);
		if (backgroundImage->zafRegion != imageRegion)
		{
			bool tAuto = automaticUpdate;
			automaticUpdate = false;
			backgroundImage->SetRegion(clientRegion);
			backgroundImage->OSSize();
			automaticUpdate = tAuto;
		}

		ccode = backgroundImage->Draw(event, ccode);
	}
	else
		DrawBackground(drawRegion, ccode);

	EndDraw();

	return (ccode);
}

ZafEventType ZafWindow::DrawFocus(ZafRegionStruct &, ZafEventType)
{
	// Window does not draw a focus rectangle.
	return (S_ERROR);
}

ZafEventType ZafWindow::DrawFrame(const ZafEventStruct &, ZafEventType ccode)
{
	if (bordered)
	{
		ZafRegionStruct drawRegion = BeginDrawFrame();
		DrawBorder(drawRegion, ccode);
		EndDraw();
	}

	return (ccode);
}
#endif

ZafEventType ZafWindow::Event(const ZafEventStruct &event)
{
	ZafEventType ccode = LogicalEvent(event);

	if (modifyMode && event.InputType() == E_MOUSE)
		return (Modify(event));

	if (minimized)
	{
		if (ccode != L_BEGIN_SELECT &&
			ccode != L_CONTINUE_SELECT &&
			ccode != L_END_SELECT &&
			ccode != L_SELECT &&
			ccode != L_SYSTEM_MENU &&
			ccode != N_CLOSE &&
			ccode != N_CURRENT &&
			ccode != N_NON_CURRENT &&
			ccode != S_CREATE &&
			ccode != S_COMPUTE_SIZE &&
			ccode != S_CURRENT &&
			ccode != S_DEINITIALIZE &&
			ccode != S_DESTROY &&
			ccode != S_MAXIMIZE &&
			ccode != S_INITIALIZE &&
			ccode != S_MOVE_MODE &&
			ccode != S_NON_CURRENT &&
			ccode != S_REDISPLAY &&
			ccode != S_REDISPLAY_REGION &&
			ccode != S_RESTORE &&
			ccode != S_REGISTER_OBJECT &&
			ccode != S_SIZE)
			return (S_UNKNOWN);
	}

	ZafEventStruct tEvent;

	// Check for zinc events.
	ZafWindowObject *object = ZAF_NULLP(ZafWindowObject);

	switch (ccode)
	{
	// ----- Create messages -----
	case S_INITIALIZE:
		{
			// Validate the order of the support objects.
			bool validOrder = true;
			bool endOrderCheck = false;
			ZafElement *currentElement = support.First();
			ZafElement *nextElement = (currentElement) ? currentElement->Next() :
				ZAF_NULLP(ZafElement);

			for (; nextElement && validOrder;)
			{
				if (nextElement->NumberID() > currentElement->NumberID() &&
					currentElement->NumberID() != ZAF_NUMID_CLOSE)
				{
					if (nextElement->NumberID() <= ZAF_NUMID_BORDER &&
						nextElement->NumberID() >= ZAF_NUMID_TITLE)
						validOrder = false;
					else if (!endOrderCheck)
						endOrderCheck = true;

				}
				else if (endOrderCheck &&
					nextElement->NumberID() <= ZAF_NUMID_BORDER &&
					nextElement->NumberID() >= ZAF_NUMID_TITLE)
					validOrder = false;

				currentElement = nextElement;
				nextElement = currentElement->Next();
			}

			if (!validOrder) // Reorder support list.
			{
				ZafList tempList;

				for (ZafNumberID findID = ZAF_NUMID_BORDER;
					findID >= ZAF_NUMID_TITLE; findID--)
				{
					currentElement = support.Find(findID);
					if (currentElement)
					{
						support.Subtract(currentElement);
						tempList.Add(currentElement);
					}
				}

				for (currentElement = support.First(); currentElement;
					currentElement = support.First())
				{
					support.Subtract(currentElement);
					tempList.Add(currentElement);
				}

				for (currentElement = tempList.First(); currentElement;
					currentElement = tempList.First())
				{
					tempList.Subtract(currentElement);
					support.Add(currentElement);
				}
			}

			ZafWindowObject::Event(event);
#if defined(ZAF_GRAPHICS_MODE)
			ConvertRegion(clientRegion, ZAF_PIXEL);
#elif defined(ZAF_TEXT_MODE)
			ConvertRegion(clientRegion, ZAF_CELL);
#endif
			ZafSystemButton *systemButton = SystemButton();
			// Add a close button if appropriate.
			ZafWindowObject *close = GetObject(ZAF_ITEXT("ZAF_NUMID_CLOSE"));
			if (systemButton)
			{
#if defined(ZAF_GRAPHICS_MODE)
				bool canClose = false;

				// Determine if the window can be closed.
				// If it is a generic system menu, the window can be closed.
				ZafSystemButton *sysButton = DynamicPtrCast(systemButton, ZafSystemButton);
				if (sysButton)
				{
					if (sysButton->SystemButtonType() == ZAF_NATIVE_SYSTEM_BUTTON)
							canClose = true;
					else // Look for the 'close' system menu option.
					{
						ZafPopUpMenu *sMenu = &systemButton->menu;
						if (sMenu)
						{
							ZafPopUpItem *pItem = DynamicPtrCast(sMenu->Last(), ZafPopUpItem);
							while (pItem && pItem->ItemType() != ZAF_CLOSE_OPTION)
								pItem = DynamicPtrCast(pItem->Previous(), ZafPopUpItem);
							if (pItem)
								canClose = true;
						}
					}
				}
				else if (!Locked())
					canClose = true;

				// Create and add close button.
				ZafCloseButton *closeButton = 0;
				if (close)
				{
					support.Subtract(close);
					closeButton = DynamicPtrCast(close, ZafCloseButton);
                    if (!closeButton)
						delete close;
				}

				if (!closeButton)
					closeButton = new ZafCloseButton(S_CLOSE);

				closeButton->parent = this;
				// Insert the closeButton in front of an object.
				ZafWindowObject *object = GetObject(ZAF_NUMID_MAXIMIZE);
				if (!object)
				{
					object = GetObject(ZAF_NUMID_MINIMIZE);
					if (!object)
						object = systemButton;
				}
				support.Add(closeButton, object);

				// Set disabled if the window can't be closed.
				if (!canClose || Locked())
					closeButton->SetDisabled(true);
#endif
			}
			else if (close)
			{
				support.Subtract(close);
				delete close;
			}
			BroadcastEvent(event);
		}
		break;

	case S_DEINITIALIZE:
		// Check for a deleted help object.
		SetFocus(false);
		if (!parent && windowManager->helpObject && windowManager->helpObject->RootObject() == this)
		{
			windowManager->helpObject = ZAF_NULLP(ZafWindowManager);
			tEvent.type = DH_SET_HELP_OBJECT;
			tEvent.windowObject = ZAF_NULLP(ZafWindowObject);
			eventManager->Event(tEvent, E_HELPTIPS);
		}

		ZafWindowObject::Event(event);
		BroadcastEvent(event);
		break;

	case S_HOT_KEY:
		// Give all objects a chance to process the hot key.
		ccode = S_UNKNOWN;
		object = SupportFirst() ? SupportFirst() : First();
		while (object && (ccode == S_ERROR || ccode == S_UNKNOWN))
		{
			ccode = object->Event(event);
			object = (!object->Next() && object->SupportObject()) ? First() : object->Next();
		}
		break;

 	case N_CLOSE:
		if (Locked())
			// Prevent the window from being closed.
			ccode = S_ERROR;
		else
			// Allow the window to be closed.
			ccode = 0;
		break;

	case S_REGISTER_OBJECT:
		RegisterObject();
		BroadcastEvent(event);
		break;

	// ----- Activation messages -----
	case S_CLOSE:
		{
			tEvent = event;
			tEvent.windowObject = RootObject();
			eventManager->Put(tEvent);
		}
		break;

	case S_CURRENT:
	case S_NON_CURRENT:
		{
			if (ccode == S_NON_CURRENT)
			{
				ZafWindowObject *newCurrent;
				newCurrent = windowManager->windowFocusObject;

				ZafWindowObject *pullDownMenu = PullDownMenu();
				ZafWindowObject *systemButton = SystemButton();
				if (pullDownMenu && pullDownMenu == Current())
				{
					windowManager->windowFocusObject = ZAF_NULLP(ZafWindowObject);
					pullDownMenu->NotifyFocus(0, false);
					current = newCurrent;
				}
				else if(systemButton && systemButton == Current())
				{
					windowManager->windowFocusObject = ZAF_NULLP(ZafWindowObject);
					systemButton->NotifyFocus(0, false);
					current = newCurrent;
				}
			}

			ZafWindowObject::Event(event);
			if ((object = SystemButton()) != 0)
				object->OSInvalidateRegion(0, false);
			if ((object = MinimizeButton()) != 0)
				object->OSInvalidateRegion(0, false);
			if ((object = MaximizeButton()) != 0)
				object->OSInvalidateRegion(0, false);
#if defined(ZAF_GRAPHICS_MODE)
			ZafCloseButton *tClose = ZAF_NULLP(ZafCloseButton);
			for (object = SupportFirst(); object && ! tClose; object = object->Next())
				if ((tClose = DynamicPtrCast(object, ZafCloseButton)) != 0)
					tClose->OSInvalidateRegion(0, false);
#endif
			if ((object = Title()) != 0)
				object->OSInvalidateRegion(0, false);
		}
		break;

	case S_REDISPLAY_REGION:
		if (AutomaticUpdate() && Visible() && screenID)
		{
			ZafRegionStruct redrawRegion = event.region;
			OSInvalidateRegion(&redrawRegion, true, true);
		}
		break;

	case S_REDISPLAY_DATA:
		{
		for (ZafWindowObject *object = First(); object; object = object->Next())
			object->Event(event);
		}
		break;

	case L_SYSTEM_MENU:
		if (SystemButton())
			SystemButton()->Event(L_SELECT);
		break;

	// ----- MDI requests -----
	case S_MDI_CLOSE:
	case S_MDI_MAXIMIZE:
	case S_MDI_MINIMIZE:
	case S_MDI_RESTORE:
		break;

	// ----- Add & Subtract -----
	case S_ADD_OBJECT:
		Add(event.windowObject);
		break;

	case S_SUBTRACT_OBJECT:
		Subtract(event.windowObject);
		break;

	// ----- Position messages -----
	case S_MAXIMIZE:
		SetMaximized(true);
		break;

	case S_MINIMIZE:
		SetMinimized(true);
		break;

	case S_RESTORE:
		if (Maximized())
			SetMaximized(false);
		else if (Minimized())
			SetMinimized(false);
		break;

	case L_SIZE_MODE:
	case L_MOVE_MODE:
		ccode = (ccode == L_SIZE_MODE) ? S_SIZE_MODE : S_MOVE_MODE;
		// Continue to S_ messages.

	case S_SIZE_MODE:
	case S_MOVE_MODE:
		if ((ccode == S_MOVE_MODE && !Maximized() && Moveable()) ||
			(ccode == S_SIZE_MODE && !Maximized() && !Minimized() && Sizeable()))
		{
			tEvent = event;
			if (ccode != tEvent.type)
			{
				tEvent.type = ccode;
				tEvent.rawCode = 0;
			}
			Modify(tEvent);
		}
		break;

	case N_SIZE:
		{
			ZafWindowObject *object;

			// Adjust the non-support object sizes.
			for (object = First(); object; object = object->Next())
				object->Event(S_COMPUTE_SIZE);

			// Perform geometry management based on the new window size.
			ZafWindowObject *geometryManager = GetObject(ZAF_NUMID_GEOMETRY);
			if (geometryManager)
				geometryManager->Event(S_COMPUTE_SIZE);

			// Mark overlaps.
			for (object = First(); object; object = object->Next())
			{
				object->overlapped = false;
				for (ZafWindowObject *obj2 = object->Next(); obj2; obj2 = obj2->Next())
				{
					if (object->zafRegion.Overlap(obj2->zafRegion))
					{
						object->overlapped = true;
						break;
					}
				}
			}

			// Finalize the sizing operation.
			for (object = First(); object; object = object->Next())
				object->OSSize();

			ZafWindowObject *backgroundImage;
			for (backgroundImage = SupportFirst(); backgroundImage;
				backgroundImage = backgroundImage->Next())
				if (backgroundImage->IsA(ID_ZAF_IMAGE))
					break;

			if (backgroundImage)
				for (object = First(); object; object = object->Next())
				{
					if (object->zafRegion.Overlap(backgroundImage->zafRegion))
						object->Redisplay();
				}
			if (windowManager->cursorObject)
				windowManager->cursorObject->Event(S_REDISPLAY_CURSOR);
		}
		break;

	// ----- Miscellaneous messages -----
	case L_NEXT:
		{
			if (Minimized())
				return (S_UNKNOWN);
			ZafEventType tcode = ccode;
			ccode = S_UNKNOWN;

			// Make sure there is a current object.
			if (!current)
			{
				for (object = First(); object; object = object->Next())
					if (!object->Disabled() && !object->Noncurrent())
					{
						object->SetFocus(true);
						break;
					}
			}

			// See if the current object processes the message.
			else if (Current()->Event(event) != S_UNKNOWN)
				ccode = tcode;

			// Don't move if on a support object.
			else if (Current()->SupportObject())
				ZafErrorStub::Beep();

/* START BLOCK COMMENT
**				// Don't move if on the last field of a non-wrapping window.
**				else if (!Current()->Next() && !WrappedData())
**					;
**				else if (!parent && WindowType() == ZafMDIWindow)
**					ccode = tcode;
END BLOCK COMMENT */

			// Go to the next field in the window.
			else
			{
				object = Current()->Next() ? Current()->Next() : First();
				while (object && object != current && ccode == S_UNKNOWN)
					if (!object->Disabled() && !object->Noncurrent() && object->Visible())
					{
						object->SetFocus(true);
						ccode = tcode;
					}
					else if (object->Next())
						object = object->Next();
//					else if (!WrappedData())
//						break;
					else
						object = First();
				if (Current()->Disabled())
					current = ZAF_NULLP(ZafElement);
			}
		}
		break;

	case L_PREVIOUS:
		if (Minimized())
			return (S_UNKNOWN);
		{
			ZafEventType tcode = ccode;
			ccode = S_UNKNOWN;

			// Make sure there is a current object.
			if (!current)
				ZafWindow::Add(Last());
			// See if the current object processes the message.
			else if (Current()->Event(event) != S_UNKNOWN)
				ccode = tcode;
			// Don't move if on a support object.
			else if (Current()->SupportObject())
//				ZafErrorStub::Beep();
				;
/* START BLOCK COMMENT
**				// Don't move if on the first field of a non-wrapping window.
**				else if (!Current()->Previous() && !WrappedData())
**					break;
**				else if (!parent && WindowType() == ZafMDIWindow)
**					ccode = tcode;
END BLOCK COMMENT */
			// Go to the previous field in the window.
			else
			{
				object = Current()->Previous() ? Current()->Previous() : Last();
				while (object && object != current && ccode == S_UNKNOWN)
					if (!object->Disabled() && !object->Noncurrent() && object->Visible())
					{
						object->SetFocus(true);
						ccode = tcode;
					}
					else if (object->Previous())
						object = object->Previous();
//					else if (!WrappedData())
//						break;
					else
						object = Last();
				if (Current()->Disabled())
					current = ZAF_NULLP(ZafElement);
			}
		}
		break;

	case S_HELP:
	case L_HELP:
		if (Current())
		{
			// Pass the event to the current child for processing.
			if (Current()->Event(event) == S_UNKNOWN)
			{
				// The current child branch doesn't have an assigned help context,
				// so we'll display ours if we have one.
				if (helpContext && zafHelpSystem)
					zafHelpSystem->DisplayHelp(helpContext);
				else
				{
					// Allow the parent to display a help context if it has one.
					ccode = S_UNKNOWN;
				}
			}
		}
		else
			ccode = ZafWindowObject::Event(event);
		break;

	case L_CANCEL:
	case L_ALT_KEY:
		{
			// Bring up or take down the pull-down menu or
			// system button (if any).
			ZafWindowObject *pullDownMenu = PullDownMenu();
			ZafWindowObject *systemButton = SystemButton();
			if (pullDownMenu && pullDownMenu->Focus())
			{
				ZafWindowObject *newCurrent;

				newCurrent = windowManager->windowFocusObject;
				windowManager->windowFocusObject = ZAF_NULLP(ZafWindowObject);

				if (newCurrent)
					newCurrent->SetFocus(true);
				else
				{
					pullDownMenu->NotifyFocus(0, false);
					current = 0;
				}
				windowManager->RepairDamage();
			}
			else if (systemButton && systemButton->Focus())
			{
				ZafWindowObject *newCurrent;

				newCurrent = windowManager->windowFocusObject;
				windowManager->windowFocusObject = ZAF_NULLP(ZafWindowObject);

				if (newCurrent)
					newCurrent->SetFocus(true);
				else if (pullDownMenu)
					pullDownMenu->SetFocus(true);
				else
				{
					systemButton->NotifyFocus(0, false);
					current = 0;
				}
				windowManager->RepairDamage();
			}
			// Activate the pull-down menu.
			else if (pullDownMenu && ccode == L_ALT_KEY && !pullDownMenu->Disabled())
			{
				windowManager->windowFocusObject = Current();
				pullDownMenu->SetFocus(true);
			}
			else if (systemButton && ccode == L_ALT_KEY)
			{
				windowManager->windowFocusObject = Current();
				systemButton->SetFocus(true);
			}
			else
				ccode = S_UNKNOWN;
		}
		break;

	case L_SELECT:
		if (modifyMode)
		{
			Modify(L_END_SELECT);
			ZafWindowObject *border = Border();
			if (border)
				border->Redisplay();
/* START BLOCK COMMENT
**				else
**				{
**					modifyMode = 0;
**					windowManager->CaptureMouse(ZAF_NULLP(ZafWindowObject));
**				}
END BLOCK COMMENT */
			return (ccode);
		}
		if (minimized)
		{
			MinimizeButton()->Event(event);
			break;
		}
		if (defaultButton && !defaultButton->Disabled())
		{
			ccode = 0;
			if (Current())
			{
				for (ZafWindow *childWindow = this;
					childWindow && childWindow->Current();
					childWindow = DynamicPtrCast(childWindow->Current(), ZafWindow))
				{
					if (childWindow->Current()->IsA(ID_ZAF_TEXT))
						return (Current()->Event(event));
					else if (childWindow->Current()->IsA(ID_ZAF_COMBO_BOX))
					{
						ccode = 0;
						break;
					}
					else if (childWindow->Current()->IsA(ID_ZAF_BUTTON))
					{
						ccode = Current()->Event(event);
						break;
					}
				}
			}

			if ((!current || (ccode != L_SELECT && ccode != S_ERROR)))
				ccode = defaultButton->Event(L_SELECT);
		}
		else if (current)
			ccode = Current()->Event(event);
		break;

	case L_BEGIN_SELECT:
	case L_CONTINUE_SELECT:
	case L_END_SELECT:
	case N_MOUSE_ENTER:
	case N_MOUSE_LEAVE:
		// The mouse is over the window, but not any of its children.
		ccode = ZafWindowObject::Event(event);
		break;

	case L_DOWN:
	case L_LEFT:
	case L_RIGHT:
	case L_UP:
		if (modifyMode)
		{
			ccode = Modify(event);
			return (ccode);
		}
		if (Current() && Current()->Event(event) == S_UNKNOWN)
		{
			// Move focus to the nearest object in the specified direction.
			ZafWindowObject *nextObject = ZAF_NULLP(ZafWindowObject);
			ZafWindowObject *wrapObject = ZAF_NULLP(ZafWindowObject);
			for (ZafWindowObject *object = First(); object; object = object->Next())
			{
				// Is it an object that can get focus?
				if (object == Current() || object->Disabled() || object->Noncurrent())
					continue;

				// See if the object is the closest object in the specified direction.
				if (ccode == L_LEFT && !(object->zafRegion.top > Current()->zafRegion.bottom ||
					object->zafRegion.bottom < Current()->zafRegion.top))
				{
					if (object->zafRegion.right < Current()->zafRegion.right)
					{
						if (!nextObject || object->zafRegion.right > nextObject->zafRegion.right)
							nextObject = object;
					}
					else if (!wrapObject || object->zafRegion.right > wrapObject->zafRegion.right)
						wrapObject = object;
				}
				else if (ccode == L_RIGHT && !(object->zafRegion.top > Current()->zafRegion.bottom ||
					object->zafRegion.bottom < Current()->zafRegion.top))
				{
					if (object->zafRegion.left > Current()->zafRegion.left)
					{
						if (!nextObject || object->zafRegion.left < nextObject->zafRegion.left)
							nextObject = object;
					}
					else if (!wrapObject || object->zafRegion.left < wrapObject->zafRegion.left)
						wrapObject = object;
				}
				else if (ccode == L_UP && !(object->zafRegion.left > Current()->zafRegion.right ||
					object->zafRegion.right < Current()->zafRegion.left))
				{
					if (object->zafRegion.bottom < Current()->zafRegion.bottom)
					{
						if (!nextObject || object->zafRegion.bottom > nextObject->zafRegion.bottom)
							nextObject = object;
					}
					else if (!wrapObject || object->zafRegion.bottom > wrapObject->zafRegion.bottom)
						wrapObject = object;
				}
				else if (ccode == L_DOWN && !(object->zafRegion.left > Current()->zafRegion.right ||
					object->zafRegion.right < Current()->zafRegion.left))
				{
					if (object->zafRegion.top > Current()->zafRegion.top)
					{
						if (!nextObject || object->zafRegion.top < nextObject->zafRegion.top)
							nextObject = object;
					}
					else if (!wrapObject || object->zafRegion.top < wrapObject->zafRegion.top)
						wrapObject = object;
				}
			}

			if (nextObject || wrapObject)
			{
				(nextObject ? nextObject : wrapObject)->SetFocus(true);
				ccode = 0;
			}
			else
				ccode = S_UNKNOWN;
		}
		break;


	// ----- Unknown or error messages -----
	default:
		// Process hot key messages.
		if (event.InputType() == E_KEY && ((event.modifiers & S_ALT) || normalHotKeys))
		{
				tEvent = event;
				tEvent.type = S_HOT_KEY;
				tEvent.key.value = ToUpper(tEvent.key.value);

				// Make sure current object/window has first chance to
				// handle hot keys.
				if (current && !Disabled())
					ccode = Current()->Event(tEvent);

				// Give all objects a chance to process the hot key.
				object = SupportFirst() ? SupportFirst() : First();
				while (object && (ccode == S_UNKNOWN || ccode == S_ERROR))
				{
					if (object != current && !object->Disabled())
						ccode = object->Event(tEvent);
					object = (object == SupportLast()) ?
						First() : object->Next();
				}
				break;
		}

		// Let the base class try to process the event. If it can't,
		// the event should be routed to the current object on the window.
		ccode = ZafWindowObject::Event(event);
		if (ccode == S_UNKNOWN)
		{
			object = (IsA(ID_ZAF_MDI_WINDOW) && !parent && ccode >= U_USER_FIRST) ? Last() : Current();
			ccode = object ? object->Event(event) : S_UNKNOWN;
		}
		break;
	}

	// Return the control code.
	return (ccode);
}

void ZafWindow::GetClip(ZafWindowObject *object, ZafRegionStruct &clip,
	ZafRegionStruct &viewPort)
{
	// Let the parent adjust the regions first.
	if (parent)
		parent->GetClip(this, clip, viewPort);

	// Adjust the viewPort region.
	viewPort.HzShift(zafRegion.left);
	viewPort.VtShift(zafRegion.top);

	// Adjust the clip region.
	if (viewPort.left > clip.left)
		clip.left = viewPort.left;
	if (viewPort.top > clip.top)
		clip.top = viewPort.top;

	int minVal;
	if (viewPort.left < 0)
	{
		minVal = clip.left + zafRegion.Width() - 1 + viewPort.left;
		clip.right = ZafMin(clip.right, minVal);
	}
	else 
		clip.right = ZafMin(clip.right, clip.left + zafRegion.Width() - 1);
	if (viewPort.top < 0)
	{
		minVal = clip.top + zafRegion.Height() - 1 + viewPort.top;
		clip.bottom = ZafMin(clip.bottom, minVal);
	}
	else 
		clip.bottom = ZafMin(clip.bottom, clip.top + zafRegion.Height() - 1);

	// Adjust for the client region if the object is in the client area.
	if (object != this && !object->SupportObject())
	{
		viewPort.left += clientRegion.left;
		viewPort.top += clientRegion.top;
		viewPort.right += clientRegion.left;
		viewPort.bottom += clientRegion.top;

		if (viewPort.left > clip.left)
			clip.left = viewPort.left;
		if (viewPort.top > clip.top)
			clip.top = viewPort.top;

		if (viewPort.left < 0)
		{
			minVal = clip.left + clientRegion.Width() - 1 + viewPort.left;
			clip.right = ZafMin(clip.right, minVal);
		}
		else
			clip.right = ZafMin(clip.right, clip.left + clientRegion.Width() - 1);
		if (viewPort.top < 0)
		{
			minVal = clip.top + clientRegion.Height() - 1 + viewPort.top;
			clip.bottom = ZafMin(clip.bottom, minVal);
		}
		else
			clip.bottom = ZafMin(clip.bottom, clip.top + clientRegion.Height() - 1);
	}
	// If object is this, then we are really clipping to a region the size
	// of viewPort.  clip.left and clip.top are fine already, but right
	// and bottom could be too large since we have so far only limited clip
	// to our zafRegion width and height.  (viewPort could start life as
	// our client region.)
	else if (object == this)
	{
		clip.right = ZafMin(clip.right, clip.left + viewPort.Width() - 1);
		clip.bottom = ZafMin(clip.bottom, clip.top + viewPort.Height() - 1);
	}
}

ZafRegionStruct ZafWindow::MaxRegion(ZafWindowObject *object, ZafVtJustify vWeight, ZafHzJustify hWeight)
{
	bool getClient = false;
	if (!object || object == this)
		getClient = true;

	// Determine the available regions. This is done by first allocating all
	// the available space in the window, then by dividing up the available
	// space based on the space requirements of each sibling that will be
	// created before the specified object.
	ZafRegionList regionList;
	ZafRegionStruct region;
	if (getClient || object->SupportObject())
	{
		// Get the default region.
		region = ZafWindowObject::MaxRegion(this, vWeight, hWeight);
		if (Bordered())
			region -= ZAF_BORDER_SIZE;
		regionList.Allocate(screenID, region);

		ZafWindowObject *element = SupportFirst();
		while (element && element != object)
		{
			// Reallocate space for objects that either reserve their region
			// (ZAF_AVAILABLE_REGION) or that are defined as using the region
			// outside their area (ZAF_OUTSIDE_REGION).
			if (element->zafRegion.bottom < 0 || element->zafRegion.right < 0)
				; // invalid region.
			else if (element->RegionType() == ZAF_OUTSIDE_REGION)
			{
				region = element->zafRegion;
				regionList.Destroy();
				regionList.Allocate(screenID, region);
			}
			else if (element->RegionType() == ZAF_AVAILABLE_REGION &&
				element->Visible(false))
				regionList.Split(screenID, element->zafRegion, true);

			// Get the next element and return if done.
			element = element->Next();
			if (!element && getClient)
				return (regionList.First()->region);
		}
		region = regionList.First()->region;
	}
	else if (object->RegionType() == ZAF_AVAILABLE_REGION &&
		object->Visible(false))
	{
		// clientRegion is relative to the window's origin. Need to adjust region
		// so it is relative to the window's clientRegion.
		region.left = region.top = 0;
		region.right = clientRegion.right - clientRegion.left;
		region.bottom = clientRegion.bottom - clientRegion.top;
		region.coordinateType = clientRegion.coordinateType;

		regionList.Allocate(screenID, region);
		for (ZafWindowObject *element = First(); element && element != object;
			element = element->Next())
		{
			// Reallocate space for objects that either reserve their region
			// (ZAF_AVAILABLE_REGION) or that are defined as using the region
			// outside their area (ZAF_OUTSIDE_REGION).
			if (element->zafRegion.bottom < 0 || element->zafRegion.right < 0)
				; // invalid region.
			else if (element->RegionType() == ZAF_AVAILABLE_REGION)
				regionList.Split(screenID, element->zafRegion, true);
		}
		region = regionList.First()->region;
	}
	else
	{
		// clientRegion is relative to the window's origin. Need to adjust region
		// so it is relative to the window's clientRegion.
		region.left = region.top = 0;
		region.right = clientRegion.right - clientRegion.left;
		region.bottom = clientRegion.bottom - clientRegion.top;
		region.coordinateType = clientRegion.coordinateType;
	}

	// Compute the maximum region for the object. This is done by checking the
	// relative horizontal and vertical weighting for a given object.
	for (ZafRegionElement *element = regionList.First(); element;
		element = element->Next())
	{
		if (vWeight == ZAF_VT_TOP && region.top > element->region.top)
			region = element->region;
		else if (vWeight == ZAF_VT_BOTTOM && region.bottom < element->region.bottom)
			region = element->region;
		if (hWeight == ZAF_HZ_LEFT && region.left > element->region.left)
			region = element->region;
		else if (hWeight == ZAF_HZ_RIGHT && region.right < element->region.right)
			region = element->region;
	}

	return (region);
}

ZafEventType ZafWindow::Modify(const ZafEventStruct &event)
{
	if (!Maximized())
	{
		if (event.type == S_MOVE_MODE && !Moveable())
			return S_CONTINUE;

		if (LogicalEvent(event) == L_END_SELECT)
		{
			ZafWindowObject::Modify(event);
			if (minimized)
				MinimizeIcon()->zafRegion = zafRegion;
		}
		else
			ZafWindowObject::Modify(event);
	}

	return (S_CONTINUE);
}

ZafEventType ZafWindow::ScrollEvent(const ZafEventStruct &event)
{
	return (event.type);
}

ZafWindowObject *ZafWindow::Subtract(ZafWindowObject *object)
{
	// Make sure there is an object to subtract.
	if (!object)
		return (ZAF_NULLP(ZafWindowObject));

	// Keep track of region that gets damaged.
	bool redraw = false;

#if defined(ZAF_GRAPHICS_MODE)
	ZafWindowObject *title = Title();
	if (object == title)
	{
		ZafCloseButton *tClose = ZAF_NULLP(ZafCloseButton);
		ZafWindowObject *tObject = GetObject("ZAF_NUMID_CLOSE");
		if ((tClose = DynamicPtrCast(tObject, ZafCloseButton)) != 0)
		{
			Subtract(tClose);
			delete tClose;
		}
	}
#endif

	if (object->screenID)
	{
		// Object was visible, so get its region.
		redraw = true;
		object->Event(ZafEventStruct(S_DESTROY));
	}

	// Remove the object from the list and redraw the window if appropriate.
	ZafWindowObject *nextObject = object->Next();
	if (object->SupportObject() && support.Index(object) != -1)
	{
		support.Subtract(object);
/* START BLOCK COMMENT
**			if (redraw)
**				OSInvalidateRegion(&object->zafRegion);
END BLOCK COMMENT */
		if (screenID)
			OSSize();
	}
	else if (ZafList::Index(object) != -1)
	{
		ZafList::Subtract(object);
		if (redraw)
			OSInvalidateRegion(&object->zafRegion, false, true);
	}
	object->parent = ZAF_NULLP(ZafWindow);

	// Return a pointer to the next object.
	return (nextObject);
}

// ----- Attributes ---------------------------------------------------------

bool ZafWindow::SetAutomaticUpdate(bool automaticUpdate)
{
	return (ZafWindowObject::SetAutomaticUpdate(automaticUpdate));
}

bool ZafWindow::SetDestroyable(bool tDestroyable)
{
	destroyable = tDestroyable;
	return (destroyable);
}

bool ZafWindow::SetDisabled(bool setDisabled)
{
	return (ZafWindowObject::SetDisabled(setDisabled));
}

bool ZafWindow::SetFocus(bool tFocus)
{
	// If there is no screenID just make it the current object.
	if (!screenID && tFocus)
		NotifyFocus(this, true);

	if (tFocus && current && screenID &&
		!(Current()->Noncurrent() || Current()->Disabled()) &&
		!Current()->Focus())
	{
		Current()->SetFocus(tFocus);
	}
	else
		ZafWindowObject::SetFocus(tFocus);

	return (focus);
}

bool ZafWindow::SetMaximized(bool tMaximized)
{
	if (maximized != tMaximized && MaximizeButton())
	{
		maximized = tMaximized;

		if (maximized)
		{
			MaximizeButton()->SetValue(S_RESTORE);

			// Save restore region unless the window is minimized.
			if (minimized)
			{
				if (MinimizeButton())
					MinimizeButton()->SetValue(S_MINIMIZE);
				minimized = false;
			}
			else
				restoreRegion = zafRegion;

			ZafRegionStruct maxRegion;
			maxRegion.left = maxRegion.top = 0;
			maxRegion.right = display->columns - 1;
			maxRegion.bottom = display->lines - 1;
#if defined(ZAF_GRAPHICS_MODE)
			maxRegion.coordinateType = ZAF_PIXEL;
#else
			maxRegion.coordinateType = ZAF_CELL;
#endif
			SetRegion(maxRegion);
		}
		else
		{
			// Restore settings in case the window was minimized from a maximized
			// state or vice versa.
			minimized = false;
			if (MaximizeButton())
				MaximizeButton()->SetValue(S_MAXIMIZE);
			if (MinimizeButton())
				MinimizeButton()->SetValue(S_MINIMIZE);

			SetRegion(restoreRegion);
		}

		Event(S_COMPUTE_SIZE);
		bool saveAuto = automaticUpdate;
		SetAutomaticUpdate(false);
		OSSize();
		SetAutomaticUpdate(saveAuto);
	}

	return (maximized);
}

bool ZafWindow::SetMinimized(bool tMinimized)
{
	if (minimized != tMinimized && MinimizeButton())
	{
		minimized = tMinimized;

		ZafIcon *minIcon = MinimizeIcon();
		if (minimized)
		{
			MinimizeButton()->SetValue(S_RESTORE);

			if (!minIcon)
			{
				// Create blank icon.
				ZafIcon::ImageAllocate();
				minIcon = new ZafIcon(0, 0, Text(), ZafIcon::imageTable[ZAF_APPLICATION_ICON]);
				minIcon->SetIconType(ZAF_MINIMIZE_ICON);
				minIcon->SetSupportObject(true);
				Add(minIcon);

				// Make sure minIcon has regions initialized.
				minIcon->Event(S_CREATE);
			}

			ZafRegionStruct minRegion;
			if (!minIcon->Initialized())
			{
				minRegion.left = Display()->cellWidth;
#if defined(ZAF_GRAPHICS_MODE)
				minRegion.top = display->lines - 2 * display->cellHeight;
#elif defined(ZAF_TEXT_MODE)
				minRegion.top = display->lines - 3 * display->cellHeight;
#endif
				minRegion.right = Display()->cellWidth * 31;
				minRegion.bottom = Display()->lines - Display()->cellHeight;
				minRegion.coordinateType = Display()->CoordinateType();

				// Check for overlapping minimized windows.
				ZafRegionStruct boundRegion;
				ZafWindow *parentWindow = DynamicPtrCast(parent, ZafWindow);
				if (parentWindow)
					boundRegion = parentWindow->ClientRegion();
				else
				{
					boundRegion.left = boundRegion.top = 0;
					boundRegion.right = Display()->columns - 1;
					boundRegion.bottom = Display()->lines - 1;
				}
				int width = minRegion.Width();
				int height = minRegion.Height();
				int left = minRegion.left;
				int top = minRegion.top;
				ZafWindow *window = parentWindow ? DynamicPtrCast(parentWindow->Last(), ZafWindow) :
					DynamicPtrCast(windowManager->Last(), ZafWindow);

				while (window)
				{
					if (window->Minimized() && window != this && minRegion.Overlap(window->zafRegion))
					{
						left = window->zafRegion.right + 2 * Display()->cellWidth;
						if (left + width > boundRegion.right)
						{
							top -= (height + Display()->cellHeight);
							minRegion.top = top;
							minRegion.bottom = top + height;
							left = Display()->cellWidth;
						}
						minRegion.left = left;
						minRegion.right = left + width;
					}
					window = DynamicPtrCast(window->Previous(), ZafWindow);
				}

				minIcon->SetRegion(minRegion);
				minIcon->SetInitialized(true);
			}
			else
				minRegion = minIcon->zafRegion;

			// Save restore region unless the window is maximized.
			if (maximized)
			{
				if (MaximizeButton())
					MaximizeButton()->SetValue(S_MAXIMIZE);
				maximized = false;
			}
			else
				restoreRegion = zafRegion;

			SetRegion(minRegion);
		}
		else
		{
			// Restore settings in case the window was minimized from a maximized
			// state or vice versa.
			maximized = false;
			if (MaximizeButton())
				MaximizeButton()->SetValue(S_MAXIMIZE);
			if (MinimizeButton())
				MinimizeButton()->SetValue(S_MINIMIZE);

			SetRegion(restoreRegion);
		}

		Event(S_COMPUTE_SIZE);
		bool saveAutomaticUpdate = automaticUpdate;
		automaticUpdate = false;
		OSSize();
		automaticUpdate = saveAutomaticUpdate;
		if (automaticUpdate && windowManager->First() == this)
		{
			windowManager->OSInvalidateRegion(&minIcon->zafRegion);
			windowManager->OSInvalidateRegion(&zafRegion);
			windowManager->OSInvalidateRegion(&restoreRegion);
		}
		else
		{
			ZafRegionList damageList;
			damageList.Allocate(0, minIcon->zafRegion);
			damageList.Allocate(0, zafRegion);
			damageList.Allocate(0, restoreRegion);
			for (ZafWindowObject *win = windowManager->First(); win &&
				win != this; win = win->Next())
				damageList.Split(0, win->zafRegion, false);
			for (ZafRegionElement *regionElement = damageList.First();
				regionElement; regionElement = regionElement->Next())
					windowManager->OSInvalidateRegion(&regionElement->region);
			windowManager->RepairDamage();
		}
	}

	return (minimized);
}

void ZafWindow::SetRegion(const ZafRegionStruct &setRegion)
{
	if (setRegion != zafRegion)
	{
		zafRegion = setRegion;
		sizeToClient = false;
	}
}

ZafSelectionType ZafWindow::SetSelectionType(ZafSelectionType setSelectionType)
{
	if (selectionType != setSelectionType && !screenID)
	{
		selectionType = setSelectionType;

		if (selectionType == ZAF_SINGLE_SELECTION)
		{
			// If the current object is selected, let it remain selected.
			ZafWindowObject *selectedObject = (Current() && Current()->Selected()) ?
				Current() : ZAF_NULLP(ZafWindowObject);

			// Clear all selections except for one.
			for (ZafWindowObject *object = First(); object; object = object->Next())
				if (object->Selected())
				{
					if (!selectedObject)
						selectedObject = object;
					else if (object != selectedObject)
						object->SetSelected(false);
				}
		}
	}
	return (selectionType);
}

bool ZafWindow::SetVisible(bool tVisible)
{
	if (tVisible && !visible && windowManager->First() == this)
		SetFocus(true);
	return (ZafWindowObject::SetVisible(tVisible));
}

// ----- OS Specific Functions ----------------------------------------------

void ZafWindow::OSDestroy(void)
{
	for (ZafWindowObject *object = First(); object; object = object->Next())
		object->Event(S_DESTROY);
	OSInvalidateRegion(0, false, false);
}

ZafEventType ZafWindow::OSEvent(const ZafEventStruct &)
{
	return (S_ERROR);
}

void ZafWindow::OSInvalidateRegion(ZafRegionStruct *region, bool immediateRedraw, bool client)
{
	if (AutomaticUpdate() && Visible() && screenID)
	{
		ZafRegionStruct tRegion = region ? *region : zafRegion;
		if (!region)
		{
			tRegion.HzShift(-zafRegion.left);
			tRegion.VtShift(-zafRegion.top);
		}
		if (client)
		{
			tRegion.HzShift(clientRegion.left);
			tRegion.VtShift(clientRegion.top);
		}

		// Don't need to worry about whether this is an overlapped
		// child, since ZafWO::OSInvalidateReg() will.
		if (!systemObject)
			ZafWindowObject::OSInvalidateRegion(&tRegion, immediateRedraw, client);
		else
		{
			// If this is an overlapped child object, make sure we only
			// invalidate the exposed pieces of the object.
			if (parent && overlapped)
			{
				ZafWindowObject::OSInvalidateRegion(&tRegion, immediateRedraw, false);
				// The comparison with other regions is based on
				// zafRegion.  ie, with respect to all the siblings'
				// parent origin.  So, need to shift the region that 
				// got passed in, since it was relative to the object's
				// origin.
			}
			else
				windowManager->OSInvalidateObject(&tRegion, this);

			if (immediateRedraw)
				windowManager->RepairDamage();
		}
	}
}

void ZafWindow::OSDrawSupport(ZafRegionList *regionList)
{
	if (AutomaticUpdate() && Visible() && screenID)
	{
		ZafRegionList childList;
		ZafWindowObject *child;
		ZafRegionElement *damageElement;
		ZafRegionElement *nextElement;
		ZafRegionStruct childRegion;

		for (child = SupportFirst(); child; child = child->Next())
		{
			if (child->IsA(ID_ZAF_IMAGE))
				continue;
			else if (child->RegionType() == ZAF_OUTSIDE_REGION)
			{
				child->OSUpdateRegions(regionList);
			}
			else if (child->Visible(false))
			{
				childList.Destroy();
				for (damageElement = regionList->First();
					damageElement; damageElement = nextElement)
				{
					if (child->zafRegion.Overlap(damageElement->region, childRegion))
					{
						// Remove the region we are repairing from the damage list.
						nextElement = damageElement->Next();
//						regionList->Split(0, childRegion, false);
/* 						nextElement = regionList->First(); */

						childRegion.HzShift(-child->zafRegion.left);
						childRegion.VtShift(-child->zafRegion.top);

						if (child->SystemObject())
							child->OSInvalidateRegion(&childRegion, false, false);
						else
							childList.Allocate(0, childRegion);
					}
					else
						nextElement = damageElement->Next();
				}
				if (childList.First())
					child->OSUpdateRegions(&childList);
			}
		}
	}
}

void ZafWindow::OSDrawChildren(ZafRegionList *regionList)
{
	if (AutomaticUpdate() && Visible() && screenID)
	{
		ZafRegionList childList;
		ZafWindowObject *child;
		ZafRegionElement *damageElement;
		ZafRegionElement *nextElement;
		ZafRegionStruct childRegion;

		for (child = First(); child; child = child->Next())
		{
			if (child->Visible(false))// && child->SystemObject())
			{
				childList.Destroy();
				for (damageElement = regionList->First();
					damageElement; damageElement = nextElement)
				{
					nextElement = damageElement->Next();
					if (child->zafRegion.Overlap(damageElement->region, childRegion))
					{
						childRegion.HzShift(-child->zafRegion.left);
						childRegion.VtShift(-child->zafRegion.top);

						if (child->SystemObject())
							child->OSInvalidateRegion(&childRegion, false, false);
						else
							childList.Allocate(0, childRegion);
					}
				}
				if (childList.First())
					child->OSUpdateRegions(&childList);
			}
		}
	}
}

void ZafWindow::ModifyOSShift(ZafPositionStruct &osPosition)
{
	osPosition.line -= clientRegion.top;
	osPosition.column -= clientRegion.left;
}

void ZafWindow::OSUpdateRegions(ZafRegionList *regionList)
{
	if (AutomaticUpdate() && Visible() && screenID)
	{
		// Calculate the regions for non-transparent children && draw non-transparent
		// children.
		ZafRegionElement *damageElement;

		OSDrawSupport(regionList);

		// Don't try to draw children if the clientRegion region is "flat."
		if (Minimized() || clientRegion.right <= clientRegion.left || clientRegion.bottom <= clientRegion.top)
			return;

		if (!regionList->First())
			return;

		if (SystemObject())
		{
		// draw.
		ZafEventStruct event(S_REDISPLAY_REGION);
		event.region = regionList->First()->region;

		// Set the drawRegion list for the display.

		ZafPositionStruct osPosition;
		osPosition.Assign(zafRegion.left, zafRegion.top,
			zafRegion.coordinateType);
		if (parent && windowManager->Index(this) == -1)
			osPosition = parent->ConvertToOSPosition(this, &osPosition);

		// Globalize regionList
		for (damageElement = regionList->First(); damageElement;
			damageElement = damageElement->Next())
		{
			event.region.left = ZafMin(event.region.left, damageElement->region.left);
			event.region.top = ZafMin(event.region.top, damageElement->region.top);
			event.region.right = ZafMax(event.region.right, damageElement->region.right);
			event.region.bottom = ZafMax(event.region.bottom, damageElement->region.bottom);

			damageElement->region.VtShift(osPosition.line);
			damageElement->region.HzShift(osPosition.column);
		}

		display->SetDrawRegions(regionList, false);
		DrawFrame(event, S_REDISPLAY_REGION);
		event.region.HzShift(-clientRegion.left);
		if (event.region.left < 0)
			event.region.left = 0;
		event.region.VtShift(-clientRegion.top);
		if (event.region.top < 0)
			event.region.top = 0;
		Draw(event, S_REDISPLAY_REGION);
		display->SetDrawRegions(0);

		osPosition.line = -osPosition.line;
		osPosition.column = -osPosition.column;
		ModifyOSShift(osPosition);

		for (damageElement = regionList->First(); damageElement;
			damageElement = damageElement->Next())
		{
			damageElement->region.VtShift(osPosition.line);
			damageElement->region.HzShift(osPosition.column);
		}
		}

		OSDrawChildren(regionList);
	}
}

void ZafWindow::OSMapPalette(ZafPaletteStruct &palette, ZafPaletteType type, ZafPaletteState state)
{
	ZafWindowObject::OSMapPalette(palette, type, state);
}

void ZafWindow::OSRegisterObject(void)
{
	// Assign a screenID.
	if (!screenID)
		if (!parent || temporary) // || WindowType() == ZafMDIWindow)
			screenID = ++(windowManager->currentScreenID);

	ZafWindowObject::OSRegisterObject();
}

OSWindowID ZafWindow::OSScreenID(ZafScreenIDType) const
{
	return (screenID);
}

void ZafWindow::OSSize(void)
{
	ZafRegionStruct oldClient = clientRegion;
	ZafWindowObject *object;

	if (!screenID)
		return;

	// Calculate support object sizes so can determine clientRegion;
	for (object = SupportFirst(); object; object = object->Next())
		object->Event(S_COMPUTE_SIZE);

	// Determine new client region.
	ZafRegionStruct newClientRegion = MaxRegion(this, ZAF_VT_TOP, ZAF_HZ_LEFT);

	// If nothing changed, don't do anything.
	if (zafRegion == oldRegion && oldClient == newClientRegion)
		return;

	if (parent || !sizeToClient || Minimized())
	{
		// Assign the new client region.
		clientRegion = newClientRegion;
	}
	else
	{
		// Size the window based on the new clientRegion.
		int targetClientHeight = clientRegion.Height();
		int targetClientWidth = clientRegion.Width();

		// Assign the new client region.
		clientRegion = newClientRegion;

		int clientWidth = clientRegion.Width();
		int clientHeight = clientRegion.Height();

		// Set the client region size.
		while (clientHeight != targetClientHeight ||
			clientWidth != targetClientWidth)
		{
			// Adjust the zafRegion by the height and width the clientRegion was
			// off.
			zafRegion.bottom += targetClientHeight - clientHeight;
			zafRegion.right += targetClientWidth - clientWidth;

			// Recalculate support object sizes with the new zafRegion.
			for (object = SupportFirst(); object; object = object->Next())
				object->Event(S_COMPUTE_SIZE);

			// See if the new zafRegion produces the correct clientRegion.
			clientRegion = MaxRegion(this, ZAF_VT_TOP, ZAF_HZ_LEFT);

			if (clientRegion.Height() == clientHeight &&
				clientRegion.Width() == clientWidth)
				break;
			else
			{
				clientHeight = clientRegion.Height();
				clientWidth = clientRegion.Width();
			}
		}
		sizeToClient = false;
	}

	// Redraw the window.
	ZafRegionStruct updateRegion;
	updateRegion.coordinateType = zafRegion.coordinateType;

	// If oldRegion == -10000 it means the window is just getting initialized
	// so draw it.  No damage regions to fix up or children to draw yet (they
	// haven't been sized properly yet).
	if (oldRegion.left == -10000 && oldRegion.top == -10000 &&
		oldRegion.right == -10000 && oldRegion.bottom == -10000)
	{
		if (AutomaticUpdate() && Visible())
		{
			OSInvalidateRegion(0);
		}
	}
	// Otherwise, figure out what changed and fix damaged areas.
	else
	{
		// Support objects don't need to redraw where they were since either
		// another support object will draw in that space or the fact that
		// it moved means the parent's client region changed and the parent
		// will cause it to redraw.

		// Repair damage where window used to be.
		// Create damage list with original region.
		// Subtract new region and Invalidate.
		ZafRegionStruct clip;
		ZafRegionList damageList;

		damageList.Allocate(0, oldRegion);

		clip = zafRegion;
		damageList.Split(0, clip, false);

		if (parent)
			for (ZafRegionElement *regionElement = damageList.First();
				regionElement; regionElement = regionElement->Next())
			{
				parent->OSInvalidateRegion(&regionElement->region, false, !supportObject);
			}
		else
			for (ZafRegionElement *regionElement = damageList.First();
				regionElement; regionElement = regionElement->Next())
			{
				windowManager->OSInvalidateRegion(&regionElement->region);
			}


		// If we moved everything needs to be redrawn.
		if (oldRegion.left != zafRegion.left || oldRegion.top != zafRegion.top)
		{
			OSInvalidateRegion(0, false, false);
		}
		
		// Otherwise if the client region "moved" it needs to be redrawn.
		if ((oldClient.left != clientRegion.left && oldClient.Width()) ||
			(oldClient.top != clientRegion.top && oldClient.Height()))
		{
			OSInvalidateRegion(&clientRegion, false, false);
		}

		int width;
		int oldWidth;
		int height;
		int oldHeight;

		width = zafRegion.Width();
		oldWidth = oldRegion.Width();
		height = zafRegion.Height();
		oldHeight = oldRegion.Height();

		if (width != oldWidth || height != oldHeight)
		{
			if (!zafRegion.Encompassed(oldRegion)) // zafRegion grew.
			{
				clip = zafRegion;
				clip.HzShift(-clip.left);
				clip.VtShift(-clip.top);
				damageList.Allocate(0, clip);

				// The border may have to draw so invalidate outside of 
				// oldClient on the right and bottom.
				clip.Assign(0, 0, oldRegion.Width(), oldRegion.Height());

				if (width != oldWidth)
					clip.right = oldClient.right;
				if (height != oldHeight)
					clip.bottom = oldClient.bottom;

				damageList.Split(0, clip, false);

				for (ZafRegionElement *regionElement = damageList.First();
					regionElement; regionElement = regionElement->Next())
				{
					OSInvalidateRegion(&regionElement->region, false, false);
				}
				damageList.Destroy();

			}
		}

		width = clientRegion.Width();
		oldWidth = oldClient.Width();
		height = clientRegion.Height();
		oldHeight = oldClient.Height();

		if (width != oldWidth || height != oldHeight)
		{
			if (!clientRegion.Encompassed(oldClient)) // clientRegion grew.
			{
				damageList.Allocate(0, clientRegion);
				clip = oldClient;
			}
			else
			{
				damageList.Allocate(0, oldClient);
				clip = clientRegion;
			}

			damageList.Split(0, clip, false);

			for (ZafRegionElement *regionElement = damageList.First();
				regionElement; regionElement = regionElement->Next())
			{
				OSInvalidateRegion(&regionElement->region, false, false);
			}
			damageList.Destroy();
		}
	}

	// Finalize the sizing operation for support objects.
	for (object = SupportFirst(); object; object = object->Next())
  		object->OSSize();

	if (oldRegion.left != zafRegion.left || oldRegion.top != zafRegion.top)
		Event(N_MOVE);
	Event(N_SIZE);

	// Set new region.
	oldRegion = zafRegion;
}

ZafError ZafWindow::OSUpdatePalettes(ZafPaletteType zafTypes, ZafPaletteType osTypes)
{
	// Defer to the base class.
	ZafWindowObject::OSUpdatePalettes(zafTypes, osTypes);

	return (ZAF_ERROR_NONE);
}

