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

// Give ZafMSWindowsApp access to protected data.
#define OSWindow ZafMSWindowsApp
#include <w_app.hpp>
#include <z_button.hpp>
#include <z_ctype.hpp>
#include <z_htips.hpp>
#include <z_icon1.hpp>
#include <z_keymap.hpp>
#include <z_scrll2.hpp>
#include <z_win.hpp>
#include <z_notebk.hpp>

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

ZafWindowObject *ZafWindow::Add(ZafWindowObject *object, ZafWindowObject *position)
{
	// Make sure add is allowed.
	if (!object || object->parent)
		return (object);

	// Add the object to the list.
	if (object->SupportObject())
	{
		if (position)
			support.Add(object, position);	// position insert.
		else
			support.Add(object);			// compareFunction insert.
	}
	else
	{
		if (position)
			ZafList::Add(object, position);	// position insert.
		else
			ZafList::Add(object);			// compareFunction insert.
	}

	// 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 flag. (The object can't really have focus until it
	// is displayed in the window.)
	object->SetFocus(false);
	object->SetSelected(false);

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

	// See if the window (this) is already on the screen.
	if (screenID)
	{
		if (object->SupportObject())
		{
			if (object->SystemObject())
			{
				bool saveVisible = object->Visible(false);
				object->SetVisible(false);
				object->Event(S_CREATE);

				RECT rect;
				WINDOWPOS windowPos;
				OSWindowID frameID = OSScreenID(ZAF_FRAMEID);
				GetWindowRect(frameID, &rect);
				if (parent)
					MapWindowPoints(NULL, parent->screenID, (POINT *)&rect, 2);
				windowPos.hwnd = frameID;
				windowPos.x = rect.left;
				windowPos.y = rect.top;
				windowPos.cx = rect.right - rect.left;
				windowPos.cy = rect.bottom - rect.top;
				windowPos.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER |
					SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_NOZORDER;

				SendMessage(frameID, WM_WINDOWPOSCHANGED, (WPARAM)0, (LPARAM)&windowPos);
				object->SetVisible(saveVisible);
			}
			else
			{
				//???
				Event(S_DESTROY);
				Event(S_CREATE);
			}
		}
		else
			// Create the object (make it appear in the window).
			object->Event(S_CREATE);
	}

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

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

	return (object);
}

ZafRegionStruct ZafWindow::BeginDraw(void)
{
	// Prepare the display for drawing.
	if (editMode && parent)
	{
//???
//		HDC hDC = GetDCEx(OSScreenID(ZAF_FRAMEID), NULL, DCX_PARENTCLIP);
		HRGN hRegion = CreateRectRgn(0, 0, 10000, 10000);
		HDC hDC = GetDCEx(OSScreenID(ZAF_FRAMEID), hRegion, DCX_PARENTCLIP);
		DeleteObject(hRegion);

		display->BeginDraw(hDC, 0, zafRegion, zafRegion);

	}
	else
		display->BeginDraw(0, screenID, zafRegion, zafRegion);

	if (systemObject)
	{
		if (editMode)
		{
			ZafRegionStruct drawRegion = zafRegion;
			drawRegion.right -= drawRegion.left;
			drawRegion.bottom -= drawRegion.top;
			drawRegion.left = drawRegion.top = 0;
			return (drawRegion);
		}
		else
		{
			RECT clientRect;
			GetClientRect(screenID, &clientRect);
			ZafRegionStruct drawRegion;
			drawRegion.ImportPoint(clientRect);
			return (drawRegion);
		}
	}
	else
		return (ConvertToDrawRegion(this));
}

bool ZafWindow::ConvertToZafEvent(ZafEventStruct &event)
{
	if (EditMode() && !support.First())
		return (ZafWindowObject::ConvertToZafEvent(event));

	if (event.InputType() == E_MOUSE)
	{
		if (event.osEvent.message >= WM_MOUSEFIRST && event.osEvent.message <= WM_MOUSELAST)
		{
			// Convert event.position to window relative coordinates.
			ZafWindowObject::ConvertToZafEvent(event);

			if (systemObject && screenID)
			{
				// Convert event.position to client relative coordinates.
				RECT rect;
				GetWindowRect(OSScreenID(ZAF_FRAMEID), &rect);
				ScreenToClient(screenID, (POINT *)&rect);
				event.position.column += rect.left;
				event.position.line += rect.top;
			}

			return (true);
		}
		else
			// Don't convert non-client mouse messages.
			return (false);
	}
	else
		return (ZafWindowObject::ConvertToZafEvent(event));
};

#if defined(ZAF_DEFAULT_DRAW)
ZafEventType ZafWindow::Draw(const ZafEventStruct &event, ZafEventType ccode)
{
	// 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)
	{
		backgroundImage->SetRegion(clientRegion);
		ccode = backgroundImage->Draw(event, ccode);
	}
	else
	{
		// Fill the background.
		ZafRegionStruct drawRegion = BeginDraw();
		DrawBackground(drawRegion, ccode);
		EndDraw();
	}

	return (ccode);
}
#endif

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

	if (ccode == E_OSEVENT)
		return ZafWindow::OSEvent(event);

	// Process ZAF Events.
	switch (ccode)
	{
	case S_ADD_OBJECT:
		Add(event.windowObject);
		break;

	case S_CREATE:
		{
		// If the window was previously added to the windowManager and was 
		// maximized or minimized when it was subtracted, need to restore its
		// proper region so it can be registered with Windows properly.
		if ((Maximized() || Minimized()) && restoreRegion.left < restoreRegion.right &&
			restoreRegion.top < restoreRegion.bottom)
			zafRegion = restoreRegion;

		bool saveVisible = visible; visible = false;		
		bool saveMaximized = maximized; maximized = false;
		bool saveMinimized = minimized; minimized = false;
		ccode = ZafWindowObject::Event(event);
		SetMaximized(saveMaximized);
		SetMinimized(saveMinimized);
		SetVisible(saveVisible);
		}
		break;

	case S_CLOSE:
		{
		ZafEventStruct closeEvent = event;
		closeEvent.windowObject = RootObject();
		eventManager->Put(closeEvent);
		}
		break;

	case S_DESTROY:
		if (!SystemObject())
		{
			ZafWindowObject::Event(ZafEventStruct(S_REDISPLAY));
			BroadcastEvent(event);
			ZafWindowObject::Event(ZafEventStruct(S_DEINITIALIZE));
		}
		else
			ccode = ZafWindowObject::Event(event);
		break;

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

		// Broadcast to all of the children.
		BroadcastEvent(event);

		frameID = 0;

		// Default to the base class.
		ccode = ZafWindowObject::Event(event);
		break;

	case S_HOT_KEY:
		{
			ZafWindowObject *object;
			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 S_INITIALIZE:
		// Default to the base class.
		ccode = ZafWindowObject::Event(event);

		//??? This should be handled in ConvertCoordinates.
		ConvertRegion(clientRegion, ZAF_PIXEL);

		// Broadcast to all of the children.
		BroadcastEvent(event);

		// Disable other windows if modal.
		if (Modal())
		{
			for (ZafWindowObject *object = windowManager->First(); object; object = object->Next())
				if (object != this)
					EnableWindow(object->OSScreenID(ZAF_FRAMEID), (BOOL)false);
		}
		break;

	case S_MAXIMIZE:
		SetMaximized(true);
		break;

	case S_MINIMIZE:
		SetMinimized(true);
		break;

	case S_REDISPLAY_DATA:
		BroadcastEvent(event);
		break;

	case S_REGISTER_OBJECT:
		{
		// Register the object.
		ccode = ZafWindowObject::Event(event);

		// Register all of the children.
		BroadcastEvent(event);
		}
		break;

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

	case S_SIZE:
		if (screenID && SupportObject())
		{
			zafRegion = event.region;
			ConvertCoordinates(ZAF_PIXEL);

			//??? Duplicate code;
			RECT rect;
			WINDOWPOS windowPos;
			OSWindowID frameID = parent->OSScreenID(ZAF_FRAMEID);
			GetWindowRect(frameID, &rect);
//			if (parent)
//				MapWindowPoints(NULL, parent->screenID, (POINT *)&rect, 2);
			windowPos.hwnd = frameID;
			windowPos.x = rect.left;
			windowPos.y = rect.top;
			windowPos.cx = rect.right - rect.left;
			windowPos.cy = rect.bottom - rect.top;
			windowPos.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER |
				SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_NOZORDER;
			SendMessage(frameID, WM_WINDOWPOSCHANGED, (WPARAM)0, (LPARAM)&windowPos);
		}
		else
			ccode = ZafWindowObject::Event(event);
		break;

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

	// ----- Notification Events -----

	case N_MOVE:
		if (!systemObject)
		{
			// System object children must be manually moved.
			for (ZafWindowObject *object = First(); object; object = object->Next())
				if (object->SystemObject())
				{
					// Convert zafRegion to OS coordinates.
					ZafRegionStruct osRegion = ConvertToOSRegion(object);

					// Size/move the object with the OS.
					MoveWindow(object->OSScreenID(ZAF_FRAMEID), osRegion.left, osRegion.top, osRegion.Width(),
						osRegion.Height(), TRUE);
					UpdateWindow(object->OSScreenID(ZAF_FRAMEID));
				}
				else
					// Trickle the N_MOVE in case there are system objects at
					// a lower level.
					object->Event(N_MOVE);
		}
		break;

	case N_SIZE:
		{
		// Let children adjust their size based on the new window size.
		ZafWindowObject *object;
		for (object = First(); object; object = object->Next())
			object->Event(ZafEventStruct(S_COMPUTE_SIZE));

		// Perform geometry management based on the new window size.
		ZafWindowObject *geometryManager = (ZafWindowObject *)GeometryManager();
		if (geometryManager)
//??? S_COMPUTE_GEOMETRY.
			geometryManager->Event(ZafEventStruct(S_COMPUTE_SIZE));

		// "Ripple" sizing operation to the next level.
		for (object = First(); object; object = object->Next())
			object->OSSize();
		}
		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;

	// ----- Scroll messages -----
	case S_HSCROLL:
	case N_HSCROLL:
	case S_HSCROLL_CHECK:
	case S_HSCROLL_COMPUTE:
	case S_VSCROLL:
	case N_VSCROLL:
	case S_VSCROLL_CHECK:
	case S_VSCROLL_COMPUTE:
		ccode = ScrollEvent(event);
		break;

	default:
		ccode = ZafWindowObject::Event(event);
		if (ccode == S_UNKNOWN && current)
			ccode = Current()->Event(event);
		break;
	}

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

//??? Why both horizontal and vertical weights?
ZafRegionStruct ZafWindow::MaxRegion(ZafWindowObject *object, ZafVtJustify vtJustify, ZafHzJustify)
{
	// If "object" is equal to "this," then the region to be occupied
	// by the client window is returned.
	if (object == this)
		object = ZAF_NULLP(ZafWindowObject);

	ZafRegionStruct region;
	region.coordinateType = ZAF_PIXEL;
	ZafWindowObject *firstObject;
	if (!object || object->SupportObject())
	{
		// Object is inside the frame window.
		RECT clientRect;
		GetClientRect(OSScreenID(ZAF_FRAMEID), &clientRect);
		region.ImportPoint(clientRect);
		firstObject = SupportFirst();
	}
	else
	{
		// Object is inside the client window.
		region = clientRegion;
		if (object->RegionType() != ZAF_AVAILABLE_REGION)
			return (region);
		firstObject = First();
	}

	// Reserve all regions occupied by objects prior to "object" in
	// the window's list.
	ZafRegionList regionList;
	regionList.Allocate(screenID, region);
	for (ZafWindowObject *element = firstObject; element && element != object;
		element = element->Next())
	{
		if (element->RegionType() == ZAF_AVAILABLE_REGION &&
			(element->SystemObject() || !element->SupportObject()))
				regionList.Split(screenID, element->zafRegion, true);
	}

	// If the available region in the window is non-rectangular, then 
	// the vertical justification determines whethor the top-most or the
	// bottom-most rectangular portion of the available region is returned.
	if (vtJustify == ZAF_VT_BOTTOM)
		region = regionList.First()->region;
	else
		region = regionList.Last()->region;

	return (region);
}

ZafWindowObject *ZafWindow::Subtract(ZafWindowObject *object)
{
	if (!object)
		return object;

	// Remove the object from the window's list.
	if (object->SupportObject())
	{
		support.Subtract(object);
		if (screenID)
		{
			if (object->SystemObject())
			{
				RECT rect;
				WINDOWPOS windowPos;
				OSWindowID frameID = OSScreenID(ZAF_FRAMEID);
				GetWindowRect(frameID, &rect);
				if (parent)
					MapWindowPoints(NULL, parent->screenID, (POINT *)&rect, 2);
				windowPos.hwnd = frameID;
				windowPos.x = rect.left;
				windowPos.y = rect.top;
				windowPos.cx = rect.right - rect.left;
				windowPos.cy = rect.bottom - rect.top;
				windowPos.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER |
					SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_NOZORDER;

				SendMessage(frameID, WM_WINDOWPOSCHANGED, (WPARAM)0, (LPARAM)&windowPos);
			}
			else
			{
				Event(S_DESTROY);
				Event(S_CREATE);
			}
		}
	}
	else
		ZafList::Subtract(object);

	// Destroy the object.
	if (object->screenID)		   
		object->Event(ZafEventStruct(S_DESTROY));

//??? This should probably be handled by NotifyFocus but it isn't.
	if (object == current)
		current = ZAF_NULLP(ZafElement);

	object->parent = ZAF_NULLP(ZafWindowObject);

	return (object);
}

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

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

bool ZafWindow::SetDisabled(bool setDisabled)
{
	if (setDisabled != disabled)
	{
		ZafWindowObject::SetDisabled(setDisabled);

		if (screenID && !editMode)
		{
			// Reflect the change to all the children.
			ZafWindowObject *object = SupportFirst() ? SupportFirst() : First();
			while (object)
			{
				if (object->SystemObject() && object->OSDraw() && !object->EditMode())
					EnableWindow(object->OSScreenID(ZAF_FRAMEID), (BOOL)!object->Disabled());
				else
					object->SetDisabled(disabled);
				object = (!object->Next() && object->SupportObject()) ? First() : object->Next();
			}
		}
	}

	return disabled;
}

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

	if (screenID)
	{
		if (!current)
		{
			for (ZafWindowObject *object = First(); object; object = object->Next())
				if (!object->Disabled() && !object->Noncurrent())
				{
					SetCurrent(object);
					break;
				}
		}

		// Set the focus with the OS.
//		if (setFocus && current && Current()->SystemObject())
		if (IsA(ID_ZAF_MDI_WINDOW) && parent && setFocus)
			SendMessage(parent->screenID, WM_MDIACTIVATE, (WPARAM)frameID, (LPARAM)0);
		if (setFocus && current)
			Current()->SetFocus(setFocus);
		else if (!setFocus && !parent)
			SetActiveWindow(GetDesktopWindow());
		else
			ZafWindowObject::SetFocus(setFocus);
	}
	else
		ZafWindowObject::SetFocus(setFocus);

	return (focus);
}

bool ZafWindow::SetMaximized(bool setMaximized)
{
	if (setMaximized != maximized)
	{
		// Maximize or restore the window.
		maximized = setMaximized;

		if (maximized)
			minimized = false;

		// Perform the operation with the OS.
		if (screenID)
			ShowWindow(OSScreenID(ZAF_FRAMEID), maximized ? SW_SHOWMAXIMIZED : SW_RESTORE);
	}

	return maximized;
}

bool ZafWindow::SetMinimized(bool setMinimized)
{
	if (setMinimized != minimized)
	{
		// Minimize or restore the window.
		minimized = setMinimized;

		if (minimized)
			maximized = false;

		// Perform the operation with the OS.
		if (screenID)
			ShowWindow(OSScreenID(ZAF_FRAMEID), minimized ? SW_SHOWMINIMIZED : SW_RESTORE);
	}

	return minimized;
}

void ZafWindow::SetRegion(const ZafRegionStruct &setRegion)
{
	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;
}

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

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

ZafEventType ZafWindow::OSEvent(const ZafEventStruct &event)
{
	if (editMode && event.InputType() == E_MOUSE)
		return (ZafWindowObject::Event(event));

	// "top-down" processing.
	ZafWindowObject *routeObject = event.route;
	if (routeObject && routeObject != this)
	{
		// Find correct path to "event.route."
		while (routeObject && routeObject->parent != this)
			routeObject = routeObject->parent;
	}
	else
		routeObject = ZAF_NULLP(ZafWindowObject);

	ZafEventType ccode = routeObject ? routeObject->Event(event) : S_UNKNOWN;

	// Process default button selection.
	if (defaultButton  && !defaultButton->Disabled() &&
		event.osEvent.message == WM_KEYDOWN &&
		event.osEvent.wParam == VK_RETURN &&
		(ccode == S_UNKNOWN || ccode == 0))
	{
		// Allow the enter key to be processed by a ZafText object.
		if (Current() && !Current()->IsA(ID_ZAF_TEXT))
			defaultButton->Event(L_SELECT);
	}

	if (ccode == S_UNKNOWN)
	{
		// Process hot keys.
		if (event.osEvent.message == WM_SYSKEYDOWN ||
			(normalHotKeys && event.osEvent.message == WM_KEYDOWN))
		{
			ZafWindowObject *hotKeyObject = ZAF_NULLP(ZafWindowObject);
			if (event.osEvent.wParam != VK_MENU)
			{
				// Generate a hot-key event.
				ZafEventStruct hotKeyEvent = event;
				ConvertToZafEvent(hotKeyEvent);
				hotKeyEvent.type = S_HOT_KEY;
				hotKeyEvent.key.value = ToUpper(hotKeyEvent.key.value);

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

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


			// Return if a hot-key was processed.
			if (hotKeyObject)
				return (ccode);
			else if (ccode == S_UNKNOWN && event.osEvent.message == WM_SYSKEYDOWN &&
				!parent)
			{
				TranslateMessage(&event.osEvent);
				return (DefaultCallback(event));
			}
		}
		else if (event.osEvent.message == WM_SYSKEYUP && RootObject() == this)
		{
			TranslateMessage(&event.osEvent);
			return (DefaultCallback(event));
		}

		// Handle movement keys (tab / arrows).
		if (event.osEvent.message == WM_KEYDOWN)
		{
			int keyCode = (int)event.osEvent.wParam;
			switch (keyCode)
			{
			case VK_DOWN:
			case VK_LEFT:
			case VK_RIGHT:
			case VK_UP:
				if (Current())
				{
					// 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 (keyCode == VK_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 (keyCode == VK_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 (keyCode == VK_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 (keyCode == VK_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;

			case VK_TAB:
				if (GetKeyState(VK_SHIFT) & 0x8000)
				{
					// Don't allow tabbing from support object to support object.
					if (current && Current()->SupportObject())
						break;

					// Change the focus to the previous object.
					ZafWindowObject *prevObject = Current() ? Current()->Previous() : Last();
					while (prevObject != Current())
					{
						// Skip fields that can't become current.
						if (prevObject && !prevObject->Disabled() &&
							!prevObject->Noncurrent())
						{
							prevObject->SetFocus(true);
							ccode = 0;
							break;
						}

						if (prevObject)
							prevObject = prevObject->Previous();
						else
							prevObject = Last();
					}
				}
				else
				{
					// Don't allow tabbing from support object to support object.
					if (current && Current()->SupportObject())
						break;

					// Change the focus to the next object.
					ZafWindowObject *nextObject = Current() ? Current()->Next() : First();
					while (nextObject != Current())
					{
						// Skip fields that can't become current.
						if (nextObject && !nextObject->Disabled() &&
							!nextObject->Noncurrent())
						{
							nextObject->SetFocus(true);
							ccode = 0;
							break;
						}

						if (nextObject)
							nextObject = nextObject->Next();
						else
							nextObject = First();
					}
				}
				break;

			case VK_F1:
				ccode = ZafWindowObject::OSEvent(event);
				break;
			}
		}
	}

	// Don't process OS events not directed to this object.
	if (routeObject)
		return ccode;

	// Handle OS events meant for this object.
	switch (event.osEvent.message)
	{
	case WM_COMMAND:
		{
#if defined(ZAF_WIN32)
		WORD wID = LOWORD(event.osEvent.wParam);
		HWND hwndCtrl = (HWND)event.osEvent.lParam;
		DWORD lParam = 0;
#else
		WORD wID = event.osEvent.wParam;
		HWND hwndCtrl = (HWND)LOWORD(event.osEvent.lParam);
		DWORD lParam = MAKELONG(0, HIWORD(event.osEvent.lParam));
#endif
		// Send the message to its originator for processing.
		// Sometimes the WM_COMMAND goes to the child first and it needs to
		// both process it and pass it to the DefWindProc. Passing it to
		// DefWindProc usually results in it coming to the parent window
		// (here), which sends it back, resulting in the child processing the
		// message twice, or worse, an infinite loop. Thus, on messages we
		// send back, we zero out the hwnd in lParam so the child knows it
		// can process the message.
		if (hwndCtrl)
		{
			// Message came from a control.
			ccode = SendMessage(hwndCtrl, event.osEvent.message, event.osEvent.wParam, lParam);
		}
		else
		{
			if (windowManager->First() == this)
			{
				// Message came from child menu item.
				ZafWindowObject *object = GetObject(wID);
				if (object)
					ccode = object->Event(event);
			}
			else if (!parent)
				// Message came from stand alone pop-up menu.
				windowManager->First()->Event(event);
		}
		}
		break;

#if defined(ZAF_WIN32)
	case WM_CTLCOLORMSGBOX:
	case WM_CTLCOLOREDIT:
	case WM_CTLCOLORLISTBOX:
	case WM_CTLCOLORBTN:
	case WM_CTLCOLORDLG:
	case WM_CTLCOLORSCROLLBAR:
	case WM_CTLCOLORSTATIC:
		{
		HWND hwndChild = (HWND)event.osEvent.lParam;
#else
	case WM_CTLCOLOR:
		{
		HWND hwndChild = (HWND)LOWORD(event.osEvent.lParam);
#endif
		// Send the WM_CTLCOLOR message to the child object.
		// (ZAF objects handle their own WM_CTLCOLOR messages instead
		// of having their owners control the colors.)
		if (hwndChild == screenID)
			ccode = ZafWindowObject::OSEvent(event);
		else
			ccode = SendMessage(hwndChild, event.osEvent.message,
				event.osEvent.wParam, event.osEvent.lParam);
#if defined(ZAF_WIN32)
		}
#else
		}
#endif
		break;

 	case WM_DRAWITEM:
		{
		DRAWITEMSTRUCT *draw = (DRAWITEMSTRUCT *)event.osEvent.lParam;

		// Send the WM_DRAWITEM message to the object to be drawn.
		// (ZAF "items" draw themselves instead of having their
		// owners draw them.)
		ccode = SendMessage(draw->hwndItem, event.osEvent.message,
			event.osEvent.wParam, event.osEvent.lParam);
		}
		break;

	case WM_ERASEBKGND:
		if (OSDraw())
		{
			ZafWindowObject *backgroundImage;
			for (backgroundImage = SupportFirst(); backgroundImage; backgroundImage = backgroundImage->Next())
				if (backgroundImage->IsA(ID_ZAF_IMAGE))
					break;

			if (backgroundImage)
			{
				HDC hDC = (HDC)event.osEvent.wParam;
				display->BeginDraw(hDC, 0, zafRegion, zafRegion);
				backgroundImage->Draw(event, S_REDISPLAY);
				display->EndDraw();
				ccode = 0;
			}
			else
			{
				// Get the device context.
				HDC hDC = (HDC)event.osEvent.wParam;

				// Get the background palette.
				ZafPaletteStruct palette = LogicalPalette(ZAF_PM_BACKGROUND, PaletteState());

				// Get the OS colors from the background palette.
				COLORREF colorForeground = (palette.colorForeground == ZAF_CLR_DEFAULT) ?
					palette.osPalette.colorForeground :
					((ZafScreenDisplay *)display)->colorTable[palette.colorForeground];
				COLORREF colorBackground = (palette.colorBackground == ZAF_CLR_DEFAULT) ?
					palette.osPalette.colorBackground :
					((ZafScreenDisplay *)display)->colorTable[palette.colorBackground];

				// Set the OS colors.
				SelectPalette(hDC, ((ZafScreenDisplay *)display)->logicalPalette, FALSE);
				::SetTextColor(hDC, colorForeground);
				SetBkColor(hDC, colorBackground);

				// Get the background region.
				RECT rect;
				GetClientRect(screenID, &rect);

				// Draw the background.
				HBRUSH hBrush = ((ZafScreenDisplay *)display)->GetGdiCacheBrush(palette);
				HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, hBrush);
				PatBlt(hDC, rect.left, rect.top, rect.right - rect.left,
					rect.bottom - rect.top, PATCOPY);
				SelectObject(hDC, hOldBrush);
				((ZafScreenDisplay *)display)->ReleaseGdiCacheObject(hBrush);
				ccode = 1;
			}
		}
		else
			ccode = ZafWindowObject::Event(event);
		break;

	case WM_HSCROLL:
	case WM_VSCROLL:
		{
#if defined (ZAF_WIN32)
		HWND hwndScrollBar = (HWND)event.osEvent.lParam;
#else
		HWND hwndScrollBar = (HWND)HIWORD(event.osEvent.lParam);
#endif

		// Send the messages to the scroll bar for handling.
		if (hwndScrollBar)
			// Scroll bar is a child control.
			ccode = SendMessage(hwndScrollBar, event.osEvent.message,
				event.osEvent.wParam, event.osEvent.lParam);
		else
		{
			// Scroll bar is a support object.
			ZafWindowObject *hScroll = HorizontalScrollBar();
			ZafWindowObject *vScroll = VerticalScrollBar();
			if (event.osEvent.message == WM_HSCROLL && hScroll)
				ccode = hScroll->Event(event);
			else if (event.osEvent.message == WM_VSCROLL && vScroll)
				ccode = vScroll->Event(event);
			else
				ccode = DefaultCallback(event);
		}
		}
		break;

	case WM_MEASUREITEM:
		ccode = GetObject((ZafNumberID)((MEASUREITEMSTRUCT *)event.osEvent.lParam)->CtlID)->Event(event);
		break;

#if defined(ZAF_WIN32)
	case WM_NOTIFY:
		{
		NMHDR *notificationHeader = (NMHDR *)event.osEvent.lParam;

		// Send the notification to the child object.
		ccode = SendMessage(notificationHeader->hwndFrom, event.osEvent.message,
			event.osEvent.wParam, event.osEvent.lParam);

//??? Is this call needed?
//???		ccode = DefaultCallback(event);
		}
		break;
#endif

	case WM_PAINT:
		if (OSDraw())
			ccode = DefaultCallback(event);
		else
			ccode = ZafWindowObject::OSEvent(event);
		break;

	case WM_PALETTECHANGED:
		{
		// Allow children to update/realize palettes.
		BroadcastEvent(event);

		HWND hwnd = OSScreenID(ZAF_FRAMEID);
		if ((HWND)event.osEvent.wParam != hwnd)
		{
			// Realize the display's logical palette.
			HDC hDC = GetDC(hwnd);
			SelectPalette(hDC, ((ZafScreenDisplay *)display)->logicalPalette, TRUE);
			int i = RealizePalette(hDC);
			ReleaseDC(hwnd, hDC);
			if (i)
				InvalidateRect(screenID, NULL, TRUE);
			ccode = i;
		}
		}
		break;

	case WM_QUERYNEWPALETTE:
		{
		ZafEventStruct paletteEvent = event;

		// Give the current object the first chance to realize a palette.
		if (Current())
			paletteEvent.rawCode = (ZafRawCode)Current()->Event(paletteEvent);

		// Give all other children a chance to realize palettes.
		ZafWindowObject *object;
		for (object = First(); object; object = object->Next())
			if (object != current)
				paletteEvent.rawCode = (ZafRawCode)object->Event(paletteEvent);
		for (object = SupportFirst(); object; object = object->Next())
			if (object != current)
				paletteEvent.rawCode = (ZafRawCode)object->Event(paletteEvent);

		if (!parent)
		{
			// Realize the display's logical palette.
			HWND hwnd = OSScreenID(ZAF_FRAMEID);
			HDC hDC = GetDC(hwnd);
			SelectPalette(hDC, ((ZafScreenDisplay *)display)->logicalPalette, FALSE);
			int i = RealizePalette(hDC);
			ReleaseDC(hwnd, hDC);
			if (i)
				InvalidateRect(screenID, NULL, TRUE);
			else
				SendMessage(hwnd, WM_PALETTECHANGED, (WPARAM)hwnd, (LPARAM)NULL);
			ccode = i;
		}
		else 
			ccode = (ZafEventType)paletteEvent.rawCode;
		}
		break;

	case WM_WINDOWPOSCHANGED:
		{
		ccode = DefaultCallback(event);

		WINDOWPOS *windowPos = (WINDOWPOS *)event.osEvent.lParam;
		HWND frameID = OSScreenID(ZAF_FRAMEID);

		// Update zafRegion.
		if (event.osEvent.hwnd == frameID &&
			(windowPos->flags & (SWP_NOSIZE | SWP_NOMOVE)) !=
			(SWP_NOSIZE | SWP_NOMOVE))
		{
			// Get the OS region.
			ZafRegionStruct osRegion;
			osRegion.coordinateType = ZAF_PIXEL;
			osRegion.left = windowPos->x;
			osRegion.right = osRegion.left + windowPos->cx - 1;
			osRegion.top = windowPos->y;
			osRegion.bottom = osRegion.top + windowPos->cy - 1;

			// Update zafRegion by converting the OS region.
			zafRegion = parent ? parent->ConvertToZafRegion(this, &osRegion) :
				windowManager->ConvertToZafRegion(this, &osRegion);
		}

		// Update clientRegion.
		ZafRegionStruct oldClientRegion = clientRegion;
		RECT clientRect;
		GetClientRect(screenID, &clientRect);
		if (clientRect.right - clientRect.left > 0 &&
			clientRect.bottom - clientRect.top > 0)
			clientRegion.ImportPoint(clientRect);

		// Send Notifications.
		bool updateOldRegion = false;
		if (event.osEvent.hwnd == frameID && !(windowPos->flags & SWP_NOMOVE))
		{
			ZafEventStruct notifyEvent(N_MOVE);
			notifyEvent.region = oldRegion;
			Event(notifyEvent);
			updateOldRegion = true;
		}

		if (!(windowPos->flags & SWP_NOSIZE) ||
			clientRegion.Width() != oldClientRegion.Width() ||
			clientRegion.Height() != oldClientRegion.Height())
		{
			ZafEventStruct notifyEvent(N_SIZE);
			notifyEvent.region = oldRegion;
			Event(notifyEvent);
			updateOldRegion = true;
		}

		if (updateOldRegion)
			oldRegion = zafRegion;
		}
		break;

	default:
		ccode = ZafWindowObject::OSEvent(event);
		if (ccode == S_UNKNOWN && current)
			ccode = Current()->Event(event);
		break;
	}

	return (ccode);
}

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

void ZafWindow::OSRegisterObject(void)
{
	// Find decorations and set style bits accordingly.
	bool hasFrame = parent ? false : true;
	DWORD dwFrameStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
	DWORD dwFrameExStyle = 0;
	DWORD dwClientStyle = WS_CHILD;
	for (ZafWindowObject *object = SupportFirst(); object; object = object->Next())
	{
		if (object->SystemObject())
			hasFrame = true;
		else if (object->NumberID() == ZAF_NUMID_BORDER)
		{
			if (Sizeable())
				dwFrameStyle |= WS_SIZEBOX;
			else if (ZafMSWindowsApp::windowsPlatform != ZAF_WIN16 &&
				ZafMSWindowsApp::windowsPlatform != ZAF_WIN32S)
				dwFrameExStyle |= WS_EX_DLGMODALFRAME;
			else
				dwFrameStyle |= WS_BORDER;
		}
		else if (object->NumberID() == ZAF_NUMID_MAXIMIZE && sizeable)
			dwFrameStyle |= WS_MAXIMIZEBOX;
		else if (object->NumberID() == ZAF_NUMID_MINIMIZE)
			dwFrameStyle |= WS_MINIMIZEBOX;
		else if (object->NumberID() == ZAF_NUMID_TITLE)
			dwFrameStyle |= WS_CAPTION;
		else if (object->NumberID() == ZAF_NUMID_HZ_SCROLL)
			dwClientStyle |= WS_HSCROLL;
		else if (object->NumberID() == ZAF_NUMID_VT_SCROLL)
			dwClientStyle |= WS_VSCROLL;
		else if (object->NumberID() == ZAF_NUMID_SYSTEM)
			dwFrameStyle |= WS_SYSMENU;
	}

//	if (Bordered() && !(dwFrameStyle & (WS_SIZEBOX | WS_BORDER)) &&
	if (Bordered() && !(dwFrameStyle & WS_SIZEBOX) && !(dwFrameExStyle & WS_EX_DLGMODALFRAME) &&
		(SupportFirst() || OSDraw()))
	{
#if defined(ZAF_MSWINDOWS_3D)
		if (parent && ZafMSWindowsApp::native3D)
			dwFrameExStyle |= WS_EX_CLIENTEDGE;
		else
			dwFrameStyle |= WS_BORDER;
#else
		dwFrameStyle |= WS_BORDER;
#endif
	}

	if (!parent && !(dwFrameStyle & WS_CAPTION))
		dwFrameStyle |= WS_POPUP;

	if (visible)
		dwFrameStyle |= WS_VISIBLE;
	if (hasFrame)
		dwClientStyle |= WS_VISIBLE;

	if (parent)
		dwFrameStyle |= WS_CHILD;

	if (maximized)
		dwFrameStyle |= WS_MAXIMIZE;
	if (minimized)
		dwFrameStyle |= WS_MINIMIZE;

	if (Disabled() && !editMode)
	{
		if (hasFrame)
			dwFrameStyle |= WS_DISABLED;
		else
			dwClientStyle |= WS_DISABLED;
	}

	if (hasFrame)
	{
		// Create the frame window.
		HWND hwndOwner = ZAF_NULLH(HWND);
		if (!parent && owner && owner->screenID)
			hwndOwner = owner->OSScreenID(ZAF_FRAMEID);
		frameID = ZafMSWindowsApp::CreateSubclassedWindow(this, NULL, dwFrameStyle, ZAF_NULLP(ZafIChar), hwndOwner, dwFrameExStyle);

		// Re-direct the frame window's "window procedure."
		SetWindowLong(frameID, GWL_WNDPROC, (LONG)ZafMSWindowsApp::FrameJumpProc);

		// Create the client window.
		screenID = ZafMSWindowsApp::CreateSubclassedWindow(this, NULL, dwClientStyle, ZAF_NULLP(ZafIChar), frameID);
	}
	else
		// Create the client window.
		screenID = ZafMSWindowsApp::CreateSubclassedWindow(this, NULL, dwFrameStyle | dwClientStyle, ZAF_NULLP(ZafIChar), NULL, dwFrameExStyle);
}

OSWindowID ZafWindow::OSScreenID(ZafScreenIDType type) const
{
	if (type == ZAF_FRAMEID && frameID && systemObject)
		return (frameID);
	return (screenID);
}

// ----- Frame Window -------------------------------------------------------

LRESULT CallDefWindowProc(HWND hwnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
	return CallWindowProc((WINDOWSPROC)DefWindowProc, hwnd, wMsg, wParam, lParam);
}

LRESULT CALLBACK ZafMSWindowsApp::FrameJumpProc(HWND hwnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
	return FrameProc(CallDefWindowProc, hwnd, wMsg, wParam, lParam);
}

LRESULT ZafMSWindowsApp::FrameProc(LRESULT (DefaultProc)(HWND hwnd, UINT, WPARAM, LPARAM),
	HWND hwnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
	// Get a pointer to the Zinc window.
	ZafWindow *window = DynamicPtrCast(ObjectFromHandle(hwnd), ZafWindow);

	// Create a ZAF event.
  	ZafEventStruct event(E_MSWINDOWS);
	event.osEvent.hwnd = hwnd;
	event.osEvent.message = wMsg;
	event.osEvent.wParam = wParam;
	event.osEvent.lParam = lParam;

	// Process the windows message.
	switch (wMsg)
	{
	case WM_QUERYENDSESSION:
		if (zafWindowManager->First() == window)
			return (zafWindowManager->Event(event));

	case WM_KEYDOWN:
	case WM_KEYUP:
	case WM_SYSKEYDOWN:
	case WM_SYSKEYUP:
		TranslateMessage(&event.osEvent);
		break;

	case WM_MOUSEACTIVATE:
		if (!window->RootObject()->Focus())
		{
			if (!window->Disabled() && !window->Noncurrent())
				window->Event(S_SET_FOCUS);
			else
				window->RootObject()->Event(S_SET_FOCUS);
			return (MA_ACTIVATE);
		}
		return (DefaultProc(hwnd, wMsg, wParam, lParam));

	case WM_ACTIVATE:
#if defined(ZAF_WIN32)
		if (LOWORD(wParam) == WA_ACTIVE)
#else
		if (wParam == WA_ACTIVE)
#endif
			window->SetFocus(true);
		return 0;

	case WM_ACTIVATEAPP:
		if (!(BOOL)wParam)
		{
			// Application is losing focus.
			if (window->Focus())
				window->windowManager->NotifyFocus(ZAF_NULLP(ZafWindowObject), false);
		}
		break;

	case WM_CLOSE:
		{
		// Prevent the Windows close operation and post an S_CLOSE event.
		ZafEventStruct closeEvent(S_CLOSE);
		closeEvent.windowObject = window;
		window->eventManager->Put(closeEvent);
		}
		return (0);
 
	case WM_COMMAND:
		return (SendMessage(window->screenID, wMsg, wParam, lParam));

	case WM_MENUSELECT:
		{
#if defined(ZAF_WIN32)
		UINT flags = (UINT)HIWORD(wParam);
#else
		WORD flags = LOWORD(lParam);
#endif
		ZafWindowObject *pullDownMenu = (ZafWindowObject *)window->PullDownMenu();
		ZafWindowObject *systemButton = (ZafWindowObject *)window->SystemButton();

		if (flags == 0xFFFF)
		{
			if (pullDownMenu && pullDownMenu->Focus())
				pullDownMenu->Event(ZafEventStruct(S_NON_CURRENT));
			else if (systemButton && systemButton->Focus())
				systemButton->Event(ZafEventStruct(S_NON_CURRENT));
		}
		else if (flags & MF_HILITE)
		{
			if (flags & MF_SYSMENU)
				systemButton->Event(event);
			else if (pullDownMenu)
				pullDownMenu->Event(event);
		}
		}
		return 0;

	case WM_NCDESTROY:
		// Reset the original window procedure.
//		SetWindowLong(hwnd, GWL_WNDPROC, (LONG)DefWindowProc);
		SetWindowLong(hwnd, GWL_WNDPROC, (LONG)DefaultProc);

#if !defined(ZAF_WIN32)
		// Remove the window properties.
		RemoveProp(hwnd, (LPCSTR)ZafMSWindowsApp::objectLowWord);
		RemoveProp(hwnd, (LPCSTR)ZafMSWindowsApp::objectHighWord);
#endif
		break;

//??? should this be handled by system button.
	case WM_INITMENUPOPUP:
		{
		HMENU nmenu = (HMENU)wParam;
		if (nmenu && HIWORD(lParam))
		{
			EnableMenuItem(nmenu, SC_CLOSE, MF_BYCOMMAND | (window->Locked() ? MF_GRAYED : MF_ENABLED));
			EnableMenuItem(nmenu, SC_MAXIMIZE, MF_BYCOMMAND | (window->Sizeable() ? MF_ENABLED : MF_GRAYED));
			EnableMenuItem(nmenu, SC_MOVE, MF_BYCOMMAND | (window->Moveable() ? MF_ENABLED : MF_GRAYED));
			EnableMenuItem(nmenu, SC_SIZE, MF_BYCOMMAND | (window->Sizeable() ? MF_ENABLED : MF_GRAYED));
		}
		}
		break;


#if !defined(ZAF_WIN32)
	case WM_PAINT:
		if (window->Minimized())
		{
			// Begin the draw operation.
			PAINTSTRUCT paintStruct;
			BeginPaint(hwnd, &paintStruct);

			DefWindowProc(hwnd, WM_ICONERASEBKGND, (WORD)paintStruct.hdc, 0L);

			HICON hIcon;
			ZafIcon *minIcon = window->MinimizeIcon();
			if (minIcon)
				hIcon = window->MinimizeIcon()->IconData()->handle;
			else
				hIcon = LoadIcon(NULL, IDI_APPLICATION);

			DrawIcon(paintStruct.hdc, 0, 0, hIcon);

			EndPaint(hwnd, &paintStruct);

			return (0);
		}
		break;

	case WM_ERASEBKGND:
		if (window->Minimized())
			return (TRUE);
#endif

	case WM_QUERYDRAGICON:
		{
		HICON hIcon;
		ZafIcon *minIcon = window->MinimizeIcon();
		if (minIcon)
			hIcon = window->MinimizeIcon()->IconData()->handle;
		else
			hIcon = LoadIcon(NULL, IDI_APPLICATION);

		return ((LONG)(DWORD)hIcon);
		}

	case WM_PALETTECHANGED:
	case WM_QUERYNEWPALETTE:
		{
		event.rawCode = (ZafRawCode)(wMsg == WM_PALETTECHANGED) ? TRUE : FALSE;
		return window->Event(event);
		}

	case WM_SYSCOMMAND:
		if (wParam < 0xF000)
		{
			ZafWindowObject *object = window->GetObject((ZafNumberID)wParam);
			if (object)
				return (object->Event(event));
		}
		else
		{
			WORD command = (WORD)(wParam & 0xFFF0);

			switch (command)
			{
			case SC_MOVE:
				if (!window->Moveable())
					return (FALSE);
				break;

			case SC_SIZE:
				if (!window->Sizeable())
					return (FALSE);
				break;

			case SC_MAXIMIZE:
			case SC_MINIMIZE:
			case SC_RESTORE:
				{
				window->minimized = window->maximized = false;
				if (command == SC_MAXIMIZE)
				{
					window->maximized = true;
					window->restoreRegion = window->zafRegion;
				}
				else if (command == SC_MINIMIZE)
				{
					window->minimized = true;
					window->restoreRegion = window->zafRegion;
				}
				LRESULT result = DefaultProc(hwnd, wMsg, wParam, lParam);
				if (command == SC_MAXIMIZE)
					window->Event(ZafEventStruct(N_MAXIMIZE));
				else if (command == SC_MINIMIZE)
					window->Event(ZafEventStruct(N_MINIMIZE));
				else
					window->Event(ZafEventStruct(N_RESTORE));
				return (result);
				}
			}
		}
		break;

	case WM_WINDOWPOSCHANGED:
		{
		WINDOWPOS *windowPos = (WINDOWPOS *)event.osEvent.lParam;

		// See if the object has been moved or sized.
		if ((windowPos->flags & (SWP_NOSIZE | SWP_NOMOVE)) != (SWP_NOSIZE | SWP_NOMOVE))
		{
			if (!window->minimized)
			{
				// Get the OS region.
				ZafRegionStruct osRegion;
				osRegion.coordinateType = ZAF_PIXEL;
				osRegion.left = windowPos->x;
				osRegion.right = osRegion.left + windowPos->cx - 1;
				osRegion.top = windowPos->y;
				osRegion.bottom = osRegion.top + windowPos->cy - 1;

				// Update zafRegion by converting the OS region.
				window->zafRegion = window->parent ? window->parent->ConvertToZafRegion(window, &osRegion) :
					window->windowManager->ConvertToZafRegion(window, &osRegion);
			}

			// Send move notification.
			if (!(windowPos->flags & SWP_NOMOVE))
			{
				ZafEventStruct notifyEvent(N_MOVE);
				notifyEvent.region = window->oldRegion;
				window->Event(notifyEvent);
			}

			// See if the window's size has changed.
			if (!(windowPos->flags & SWP_NOSIZE))
			{
				// Resize the support objects.
				for (ZafWindowObject *object = window->SupportFirst(); object; object = object->Next())
					if (object->SystemObject())
					{
						object->Event(ZafEventStruct(S_COMPUTE_SIZE));
						object->OSSize();
					}

				// Resize the client window.
				ZafRegionStruct client = window->MaxRegion(window);
  				MoveWindow(window->screenID, client.left, client.top,
  					client.Width(), client.Height(), TRUE);
				UpdateWindow(window->screenID);
			}
		}
		}
	default:
		if (wMsg >= WM_USER)
			return (SendMessage(window->screenID, wMsg, wParam, lParam));
	}

	return (DefaultProc(hwnd, wMsg, wParam, lParam));
}

// ----- Stubs --------------------------------------------------------------

ZafPositionStruct ZafWindow::ConvertToOSPosition(const ZafWindowObject *object,
	const ZafPositionStruct *position) const
{
	return (ZafWindowObject::ConvertToOSPosition(object, position));
}

ZafPositionStruct ZafWindow::ConvertToZafPosition(const ZafWindowObject *object,
	const ZafPositionStruct *position) const
{
	return (ZafWindowObject::ConvertToZafPosition(object, position));
}

ZafEventType ZafWindow::DragDropEvent(const ZafEventStruct &event)
{
//??? How does window handle drag-drop...ZafText must work also.
	return (ZafWindowObject::DragDropEvent(event));
}

#if defined(ZAF_DEFAULT_DRAW)
ZafEventType ZafWindow::DrawFocus(ZafRegionStruct &region, ZafEventType ccode)
{
	return (ZafWindowObject::DrawFocus(region, ccode));
}
#endif

void ZafWindow::GetClip(ZafWindowObject *, ZafRegionStruct &, ZafRegionStruct &)
{
	// Handled automatically by Windows.
}

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

void ZafWindow::OSSize(void)
{
	if (systemObject)
	{
		if (parent || !sizeToClient)
			ZafWindowObject::OSSize();
		else
		{
			int targetClientWidth = clientRegion.Width();
			int targetClientHeight = clientRegion.Height();

			// If zafRegion is smaller than the minimum size imposed by the
			// OS then the iterative sizing process will fail.
			zafRegion.bottom = zafRegion.top + 1000;

			ZafWindowObject::OSSize();

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

			// Set the client region size.
			while (clientWidth != targetClientWidth || clientHeight != targetClientHeight)
			{
				zafRegion.right += targetClientWidth - clientWidth;
				zafRegion.bottom += targetClientHeight - clientHeight;

				ZafWindowObject::OSSize();

				sizeToClient = false;

				if (clientRegion.Width() == clientWidth && clientRegion.Height() == clientHeight)
				{
					RECT rect;
					GetWindowRect(screenID, &rect);
					zafRegion.ImportPoint(rect);
					return;
				}
				else
				{
					clientWidth = clientRegion.Width();
					clientHeight = clientRegion.Height();
				}
			}
		}
	}
	else
	{
		clientRegion.coordinateType = ZAF_PIXEL;
		clientRegion.left = clientRegion.top = 0;
		clientRegion.right = zafRegion.Width() - 1;
		clientRegion.bottom = zafRegion.Height() - 1;
		ZafWindowObject::OSSize();
	}
}

ZafError ZafWindow::OSUpdatePalettes(ZafPaletteType zafTypes, ZafPaletteType osTypes)
{
	if (screenID)
	{
		if (SystemObject() && OSDraw())
		{
			SendMessage(screenID, WM_SETREDRAW, (WPARAM)FALSE, 0);
			ZafWindowObject *object;
			for (object = SupportFirst(); object; object = object->Next())
				if (object->SystemObject())
					object->OSUpdatePalettes(zafTypes, osTypes);
			for (object = First(); object; object = object->Next())
				if (object->SystemObject())
					object->OSUpdatePalettes(zafTypes, osTypes);
//			if (automaticUpdate && visible)
//				SendMessage(screenID, WM_SETREDRAW, (WPARAM)TRUE, 0);
			ZafWindowObject::OSUpdatePalettes(zafTypes, osTypes);
		}
		Redisplay();
	}

	return (ZAF_ERROR_NONE);
}

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

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

bool ZafWindow::SetVisible(bool tVisible)
{
	return (ZafWindowObject::SetVisible(tVisible));
}
