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

#include <z_stdio.hpp>
#include <z_scrll2.hpp>
#include <z_string.hpp>
#include <z_ctype.hpp>
#include <z_help.hpp>
#include <z_icon1.hpp>
#include "m_win.hpp"

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

ZafWindowObject *ZafWindow::Add(ZafWindowObject *object, ZafWindowObject *position)
{
	// Make sure add is allowed.
	if (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 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;

	// Create the object (make it appear in the window).
	if (screenID && !Temporary())
	{
		object->Event(S_CREATE);

		// Resize the window.  If the object is a support object, then the 
		// frame widget must be called so the client area is resized.  
		// Otherwise, the client must be called so the children are resized.
		if (AutomaticUpdate() && Visible() && object->NumberID() > 0 && object->RegionType() != ZAF_INSIDE_REGION)
		{
			Widget widget = object->SupportObject() ? OSScreenID(ZAF_FRAMEID) : screenID;
			if (widget && widget->core.widget_class->core_class.resize)
				(widget->core.widget_class->core_class.resize)(widget);
		}
	}
	else if (screenID)
	{
		object->Event(S_INITIALIZE);
		object->Event(S_REGISTER_OBJECT);
	}

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

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

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

ZafRegionStruct ZafWindow::BeginDraw(void)
{
	// Defer to the base class.
	return (ZafWindowObject::BeginDraw());
}

ZafPositionStruct ZafWindow::ConvertToOSPosition(const ZafWindowObject *object,
	const ZafPositionStruct *position) const
{
	// Defer to the base class.
	return (ZafWindowObject::ConvertToOSPosition(object, position));
}

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

ZafPositionStruct ZafWindow::ConvertToZafPosition(const ZafWindowObject *object,
	const ZafPositionStruct *position) const
{
	// Defer to the base class.
	return (ZafWindowObject::ConvertToZafPosition(object, position));
}

ZafEventType ZafWindow::DragDropEvent(const ZafEventStruct &event)
{
	// Determine the drop message.
	ZafEventType ccode = event.type;
	ZafWindowObject *object = windowManager->dragObject;
	switch (ccode)
	{
	// --- Drop operations ---
	case S_DROP_COPY:
	case S_DROP_MOVE:
		if (Disabled())
			return (S_ERROR);
		else if (AcceptDrop() && object && object != this && object->parent != this)
		{
			ZafWindow *window = DynamicPtrCast(object, ZafWindow);
			if (window) // many-to-many
			{
				// Preserve the original automatic update.
				bool update = AutomaticUpdate();
				bool updateWindow = window->AutomaticUpdate();

				// Perform the specified drop operation.
				if (ccode == S_DROP_COPY)
				{
					// Duplicate the selected objects.
					for (object = window->First(); object; object = object->Next())
						if (object->Selected())
						{
							SetAutomaticUpdate(false); // turn off updating.
							ZafWindowObject *temp = object->Duplicate();
							temp->SetSelected(false);
							Add(temp);
						}
				}
				else
				{
					// Move the selected objects.
					object = window->First();
					while (object)
						if (object->Selected())
						{
							SetAutomaticUpdate(false); // turn off updating.
							window->SetAutomaticUpdate(false);

							ZafWindowObject *temp = object->Next();
							window->Subtract(object);
							object->SetSelected(false);
							Add(object);
							object = temp;
						}
						else
							object = object->Next();
				}

				// Restore automatic update, if changed.
				if (update != window->AutomaticUpdate())
					window->SetAutomaticUpdate(updateWindow);
				if (update != AutomaticUpdate())
					SetAutomaticUpdate(update);
			}
			else // one-to-many
				Add(object->Duplicate());
		}
		else
			ccode = S_ERROR;
		break;

	// ----- Base class messages -----
	default:
		ccode = ZafWindowObject::DragDropEvent(event);
		break;
	}

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

#if defined(ZAF_DEFAULT_DRAW)
ZafEventType ZafWindow::Draw(const ZafEventStruct &event, ZafEventType ccode)
{
	// Check for draw errors.
	if (!screenID)
		return (S_ERROR);

	// Draw the list items that appear on the screen.
	for (ZafWindowObject *object = First(); object; object = object->Next())
		if (!object->SystemObject())
			object->Draw(event, S_NON_CURRENT);

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

ZafEventType ZafWindow::DrawFocus(ZafRegionStruct &region, ZafEventType )
{
	// Window does not draw a focus rectangle, but must offset the value
	// based on a focus region.
	region -= ZAF_BORDER_SIZE;
	return (S_ERROR);
}
#endif

ZafEventType ZafWindow::Event(const ZafEventStruct &event)
{
	// Check for zinc events.
	ZafEventType ccode = event.type;
	ZafWindowObject *object = Current();
	switch (ccode)
	{
	// ----- Create messages -----
	case S_INITIALIZE:
		{
		ZafElement *object = ZAF_NULLP(ZafElement);
		for(ZafElement *currentElement = support.First(); currentElement;
		 currentElement = currentElement->Next())
		{
			if (currentElement->NumberID()== ZAF_NUMID_PULL_DOWN_MENU)
			{
				if (object)
				{
					support.Subtract(currentElement);
					support.Add(currentElement, object);
				}
				break;
			}
			else if (!object && currentElement->NumberID() >= 0)
				object = currentElement;
		}
		}
	case S_DEINITIALIZE:
		// Initialize the OS variables.
		decorations = 0;

		// Default to the base class.
		ZafWindowObject::Event(event);
		if (ccode == S_INITIALIZE)
			clientRegion.ConvertCoordinates(ZAF_PIXEL);

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

	case S_REGISTER_OBJECT:
		// Register the object.
		RegisterObject();

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

		// Check for a current object.
		if (SystemObject() && object && object->SystemObject())
			XtVaSetValues(screenID, XmNinitialFocus, object->screenID, 0);
		break;

	case S_DESTROY:
		// Check for special delete conditions.
		if (screenID && !SystemObject())
		{
			for (object = First(); object; object = object->Next())
				if (object->SystemObject())
					object->Event(event);
		}
		ccode = ZafWindowObject::Event(event);
		break;

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

	case S_REDISPLAY:
	case S_REDISPLAY_DATA:
	case S_REDISPLAY_REGION:
		// First, defer to the base class.
		ccode = ZafWindowObject::Event(event);

		// Next, broadcast to all of the children.
		if (ccode == S_REDISPLAY_REGION)
		{
			for (object = First(); object; object = object->Next())
				if (object->SystemObject() && object->zafRegion.Overlap(event.region))
					object->Event(S_REDISPLAY);
		}
		else
		{
			for (object = SupportFirst(); object; object = object->Next())
				if (object->SystemObject())
					object->Event(event);
			for (object = First(); object; object = object->Next())
				if (object->SystemObject())
					object->Event(event);
		}
		break;

	case N_CURRENT:
		ccode = ZafWindowObject::Event(event);
		if (Modal())
			XtAddGrab(OSScreenID(ZAF_FRAMEID), true, false);
		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 & Size messages -----
	case S_MINIMIZE:
		SetMinimized(true);
		break;

	case S_MAXIMIZE:
		break;

	case S_RESTORE:
		if (Minimized())
			SetMinimized(false);
		break;

	case S_SIZE:
		if (!parent)
		{
			// This code bypasses ZafWindow::OSSize() which forces a size
			// based on clientRegion.
			SetRegion(event.region);
			Event(S_COMPUTE_SIZE);
			OSSize();
		}
		else
			ccode = ZafWindowObject::Event(event);
		break;

	case N_SIZE:
		// Size the normal children.
		for (object = First(); object; object = object->Next())
			object->Event(S_COMPUTE_SIZE);

		// Apply geometry management to the children.
		for (object = SupportFirst(); object; object = object->Next())
			if (object->NumberID() == ZAF_NUMID_GEOMETRY)
			{
				object->Event(S_COMPUTE_SIZE);
				break;
			}

		// "Ripple" sizing operation to the next level (if necessary).
		for (object = First(); object; object = object->Next())
			object->OSSize();
		break;

	// ----- Movement messages -----
	case L_BOL:
	case L_EOL:
	case L_LEFT:
	case L_RIGHT:
	case L_UP:
	case L_DOWN:
	case L_FIRST:
	case L_LAST:
	case L_NEXT:
	case L_PREVIOUS:
	case L_PGDN:
	case L_PGUP:
		ccode = MoveEvent(event);
		break;

	// ----- Miscellaneous messages -----
	case L_SELECT:
		// Call the default button.
		if (defaultButton)
			defaultButton->Event(ccode);
		else
			object->Event(ccode);
		break;

	case S_CONTINUE:
	case L_ALT_KEY:
		ccode = object ? object->Event(event) : S_ERROR;
		break;

	// ----- Base class messages -----
	case E_MOTIF:
		// Check for hotkey matches.
		if (event.osEvent.type == KeyPress && 
		  (event.osEvent.xkey.state == Mod1Mask || NormalHotKeys()))
		{
			// Try to find a matching hotkey.
			ZafEventStruct hotKeyEvent = event;
			ConvertToZafEvent(hotKeyEvent);
			hotKeyEvent.type = S_HOT_KEY;
			hotKeyEvent.osEvent = event.osEvent;
			hotKeyEvent.key.value = ToUpper(hotKeyEvent.key.value);
			
			// Make sure current object/window has first chance to
			// handle hot keys.
			if (current && !Disabled())
				ccode = Current()->Event(hotKeyEvent);
			// If NormalHotKeys and an error is returned the object is an editable
			// object and the object should handle the hotkey.
			if (ccode == S_ERROR && NormalHotKeys() && 
			  event.osEvent.xkey.state != Mod1Mask)
				break;

			// 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(hotKeyEvent);
				object = (object == SupportLast()) ?
					First() : object->Next();
			}
			break;
		}

		// Determine the proper event route.
		if (object && event.InputType() != E_MOUSE)
			ccode = object->Event(event);
		else
			ccode = ZafWindowObject::Event(event);
		break;

	case S_HOT_KEY:
		// Give all objects a chance to process the hot key.
		ccode = S_UNKNOWN;
		// If the hotkey is a result of NormalHotKeys() and the current
		// object is an editable object we need to return and let the object
		// process the key an a non hotkey.
		if (current && !Disabled() && event.osEvent.xkey.state != Mod1Mask)
		{
			ccode = Current()->Event(event);
			if (ccode == S_ERROR)
				break;
		}
			
		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:
		ccode = 0;
		break;

	// ----- Miscellaneous -----
	case S_HELP:
	case L_HELP:
		// Display help based on the current object.
		ccode = object ? object->Event(event) : ZafWindowObject::Event(event);
		break;

	case L_VIEW:
	case L_BEGIN_SELECT:
	case L_CONTINUE_SELECT:
	case L_END_SELECT:
	case L_BEGIN_ESCAPE:
	case L_CONTINUE_ESCAPE:
	case L_END_ESCAPE:
		ccode = ZafWindowObject::Event(event);
		break;

	default:
		// First defer to the base class, then to the current object.
		ccode = ZafWindowObject::Event(event);
		if (object && (ccode == S_ERROR || ccode == S_UNKNOWN))
		{
			if (((event.type > L_BEGIN_SELECT && event.type < L_END_ESCAPE) ||
		 	 event.type == L_DOUBLE_CLICK) && !object->zafRegion.Overlap(event.position))
				break;
			ccode = object->Event(event);
		}
		break;
	}

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

void ZafWindow::GetClip(ZafWindowObject *object, ZafRegionStruct &clip, ZafRegionStruct &virtualRegion)
{
	// Defer to the base class.
	ZafWindowObject::GetClip(object, clip, virtualRegion);
}

ZafRegionStruct ZafWindow::MaxRegion(ZafWindowObject *object, ZafVtJustify vWeight, ZafHzJustify hWeight)
{
	// Check against null requests.
	if (object == this)
		object = ZAF_NULLP(ZafWindowObject);

	// Determine the initial available region.
	ZafWindowObject *element;
	ZafRegionStruct region;
	if (!object || object->SupportObject())
	{
		// Area is a frame region.
		region = ZafWindowObject::MaxRegion(object, vWeight, hWeight);
		element = SupportFirst();
	}
	else if (object->RegionType() == ZAF_AVAILABLE_REGION)
	{
		// Area is a client region.
		region.coordinateType = ZAF_PIXEL;
		region.left = region.top = 0;
		region.right = clientRegion.right - clientRegion.left;
		region.bottom = clientRegion.bottom - clientRegion.top;
		element = First();
	}
	else
		return (clientRegion);

	// Determine the final available region.
	ZafRegionList regionList;
	regionList.Add(new ZafRegionElement(screenID, region));
	for ( ; element && element != object; element = element->Next())
		if (!element->SystemObject())
			continue; // invalid region.
		else if (element->RegionType() == ZAF_AVAILABLE_REGION)
			regionList.Split(screenID, element->zafRegion, true);
		else if (element->RegionType() == ZAF_OUTSIDE_REGION)
		{
			region = element->zafRegion;
			regionList.Destroy();
			regionList.Add(new ZafRegionElement(screenID, --region));
		}

	// Return the region based on its justification.
	return ((vWeight == ZAF_VT_BOTTOM) ? regionList.First()->region : regionList.Last()->region);
}

ZafEventType ZafWindow::Modify(const ZafEventStruct &event)
{
	// Defer to the base class.
	return (ZafWindowObject::Modify(event));
}

ZafEventType ZafWindow::ScrollEvent(const ZafEventStruct &)
{
	// No scroll events are supported at the window level.
	return (S_ERROR);
}

ZafWindowObject *ZafWindow::Subtract(ZafWindowObject *object)
{
	// Make sure the object is part of this list.
	if (!object || object->parent != this)
		return (object);

	// Check for a current object and update the focus.
	if (object == Current())
	{
		// Try to find a new candidate.
		ZafWindowObject *newCurrent = object->Next();
		for ( ; newCurrent; newCurrent = newCurrent->Next())
			if (!newCurrent->Disabled(false) && !newCurrent->Noncurrent())
				break;
		if (!newCurrent)
			for (newCurrent = object->Previous(); newCurrent; newCurrent = newCurrent->Previous())
				if (!newCurrent->Disabled(false) && !newCurrent->Noncurrent())
					break;

		// Make the new object current.
		if (newCurrent && object->Focus())
			newCurrent->SetFocus(true);
		else if (newCurrent)
			ZafList::SetCurrent(newCurrent);
	}

	// Delete the object from the system.
	if (object->screenID)
		object->Event(S_DESTROY);

	// Remove the object from the window's list.
	ZafWindowObject *nextObject = object->Next();
	if (object->SupportObject())
		support.Subtract(object);
	else
		ZafList::Subtract(object);
	object->parent = ZAF_NULLP(ZafWindowObject);

	// Check for window re-formatting.
	if (screenID && AutomaticUpdate() && Visible() && object->RegionType() != ZAF_INSIDE_REGION)
	{
		Widget widget = object->SupportObject() ? OSScreenID(ZAF_FRAMEID) : screenID;
		if (widget->core.widget_class->core_class.resize)
			(widget->core.widget_class->core_class.resize)(widget);
	}

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

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

bool ZafWindow::SetAutomaticUpdate(bool setAutomaticUpdate)
{
	// Defer to the base class.
	if (automaticUpdate == setAutomaticUpdate)
		return (automaticUpdate);
	ZafWindowObject::SetAutomaticUpdate(setAutomaticUpdate);

	// Now, update the children.
	if (screenID && AutomaticUpdate() && SystemObject())
	{
		ZafWindowObject *object;
		for (object = First(); object; object = object->Next())
			if (object->screenID && object->SystemObject())
				XtManageChild(object->OSScreenID(ZAF_FRAMEID));
			else
				object->Redisplay();

		for (object = SupportFirst(); object; object = object->Next())
			if (object->screenID && object->SystemObject())
				XtManageChild(object->OSScreenID(ZAF_FRAMEID));
			else
				object->Redisplay();

	}
	return (automaticUpdate);
}

bool ZafWindow::SetDestroyable(bool setDestroyable)
{
	// Make sure the attribute has changed.
	if (destroyable != setDestroyable)
		destroyable = setDestroyable;

	// Return the current attribute.
	return (destroyable);
}

bool ZafWindow::SetDisabled(bool setDisabled)
{
	// Make sure the attribute has changed.
	if (setDisabled != disabled)
	{
		// Defer to the base class.
		ZafWindowObject::SetDisabled(setDisabled);

		// Reflect the change to all the children.
		ZafWindowObject *object = SupportFirst() ? SupportFirst() : First();
		while (object)
		{
			object->SetDisabled(setDisabled);
			object = (!object->Next() && object->SupportObject()) ? First() : object->Next();
		}
	}

	// Return the current attribute.
	return (disabled);
}

bool ZafWindow::SetFocus(bool setFocus)
{
	// If there is no screenID just make it the current object.
	if (!screenID && setFocus)
		NotifyFocus(this, true);
	// Push the focus down if there is a current object.
	else if (Current() && setFocus)
 		Current()->SetFocus(setFocus);
	else if (Current())
	{
 		Current()->SetFocus(setFocus);
		ZafWindowObject::SetFocus(setFocus);
	}
	else
		ZafWindowObject::SetFocus(setFocus);

	// Return the current attribute.
	return (focus);
}

bool ZafWindow::SetMaximized(bool tMaximized)
{
	// Make sure the attribute has changed.
	if (maximized != tMaximized)
	{
		maximized = tMaximized;
		if (tMaximized && !Minimized())
			restoreRegion = zafRegion;
	}

	if (maximized && Minimized())
		SetMinimized(false);

	// Return the current attribute.
	return maximized;
}

bool ZafWindow::SetMinimized(bool tMinimized)
{
	// Make sure the attribute has changed.
	if (minimized != tMinimized)
	{
		minimized = tMinimized;
		if (tMinimized && !Maximized())
			restoreRegion = zafRegion;
	}
	
	if (screenID)
		if (!minimized)
			XtMapWidget(OSScreenID(ZAF_SHELLID));
		else
			minimized = XIconifyWindow(((ZafScreenDisplay *)display)->xDisplay,
			 XtWindow(OSScreenID(ZAF_SHELLID)), 
			 ((ZafScreenDisplay *)display)->xScreenNumber);

	if (minimized && Maximized())
		SetMaximized(false);

	// Return the current attribute.
	return minimized;
}

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

ZafSelectionType ZafWindow::SetSelectionType(ZafSelectionType setSelectionType)
{
	// Make sure the attribute has changed.
	if (selectionType != setSelectionType && !screenID)
	{
		selectionType = setSelectionType;

		// Deselect non-current items if the window is marked as single-selection.
		if (selectionType == ZAF_SINGLE_SELECTION)
			NotifySelection(Current(), true);
	}

	// Return the current attribute.
	return (selectionType);
}

bool ZafWindow::SetVisible(bool setVisible)
{
	// Defer to the base class.
	return (ZafWindowObject::SetVisible(setVisible));
}

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

void ZafWindow::OSDestroy(void)
{
	if (!screenID)
		return;

	// Unmap the window.
	if (screenID && visible && systemObject)
		XtUnmapWidget(screenID);

	// Delete the children.
	for (ZafWindowObject *object = First(); object; object = object->Next())
		object->Event(S_DESTROY);

	// Remap the window.
	if (screenID && visible && systemObject)
		XtMapWidget(screenID);
}

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

void ZafWindow::OSMapPalette(ZafPaletteStruct &palette, ZafPaletteType type, ZafPaletteState state)
{
	// Check for a system object.
	if (!screenID)
		return;
	else if (!SystemObject())
	{
		parent->OSMapPalette(palette, type, state);
		return;
	}
	else if (!XmIsManager(screenID))
	{
		ZafWindowObject::OSMapPalette(palette, type, state);
		return;
	}

	// Determine the proper palette.
	XGCValues values;
	XtGCMask mask = GCForeground | GCBackground;
	XmManagerRec *widget = (XmManagerRec *)screenID;
	if (type == ZAF_PM_FOCUS || type == ZAF_PM_OUTLINE)
	{
		values.foreground = widget->manager.highlight_color;
		values.background = widget->core.background_pixel;
		if (widget->manager.highlight_pixmap != XmUNSPECIFIED_PIXMAP)
		{
   			mask |= GCFillStyle | GCTile;
   			values.fill_style = FillTiled;
   			values.tile = widget->manager.highlight_pixmap;
		}
	}
	else if (type == ZAF_PM_LIGHT_SHADOW)
	{
		if (palette.colorForeground < ZAF_MAXCOLORS && display->DisplayMode() == ZAF_DISPLAY_COLOR)
			values.foreground = ((ZafScreenDisplay *)display)->colorTable[palette.colorForeground].pixel;
		else if (palette.monoForeground < ZAF_MAXCOLORS && display->DisplayMode() == ZAF_DISPLAY_MONO)
			values.foreground = ((ZafScreenDisplay *)display)->monoTable[palette.monoForeground].pixel;
		else
			values.foreground = widget->manager.top_shadow_color;
		values.background = widget->manager.foreground;
		if (widget->manager.top_shadow_pixmap != XmUNSPECIFIED_PIXMAP)
		{
  			mask |= GCFillStyle | GCTile;
  			values.fill_style = FillTiled;
  			values.tile = widget->manager.top_shadow_pixmap;
		}
	}
	else if (type == ZAF_PM_DARK_SHADOW)
	{
		if (palette.colorForeground < ZAF_MAXCOLORS && display->DisplayMode() == ZAF_DISPLAY_COLOR)
			values.foreground = ((ZafScreenDisplay *)display)->colorTable[palette.colorForeground].pixel;
		else if (palette.monoForeground < ZAF_MAXCOLORS && display->DisplayMode() == ZAF_DISPLAY_MONO)
			values.foreground = ((ZafScreenDisplay *)display)->monoTable[palette.monoForeground].pixel;
		else
			values.foreground = widget->manager.bottom_shadow_color;
		values.background = widget->manager.foreground;
		if (widget->manager.bottom_shadow_pixmap != XmUNSPECIFIED_PIXMAP)
		{
			mask |= GCFillStyle | GCTile;
			values.fill_style = FillTiled;
			values.tile = widget->manager.bottom_shadow_pixmap;
		}
	}
	else if (type == ZAF_PM_TEXT || type == ZAF_PM_HOT_KEY)
	{
		mask |= GCFillStyle | GCFont;
		values.background = widget->core.background_pixel;
		values.foreground = widget->manager.foreground;
		// pattern
		if (state & ZAF_PM_DISABLED)
		{
			mask |= GCTile;
			values.fill_style = FillTiled;
			values.tile = XmGetPixmapByDepth(XtScreen(screenID), "50_foreground",
				values.foreground, values.background, widget->core.depth);
		}
		else
		{
			values.background = values.foreground;
			values.fill_style = FillSolid;
		}
		// font
		XmFontList mtfFont = 0;
		if (palette.font >= 0)
			mtfFont = ((ZafScreenDisplay *)display)->fontTable[palette.font];
		else
			XtVaGetValues(screenID, "fontList", &mtfFont, 0);
		if (!mtfFont)
			mtfFont = ((ZafScreenDisplay *)display)->fontTable[ZAF_FNT_DIALOG];
		values.font = ((ZafScreenDisplay *)display)->MtfGetFont(mtfFont)->fid;
	}
	else
	{
		values.background = widget->core.background_pixel;
		values.foreground = values.background;
		if (widget->core.background_pixmap != XmUNSPECIFIED_PIXMAP)
		{
   			mask |= GCFillStyle | GCTile;
   			values.fill_style = FillTiled;
   			values.tile = widget->core.background_pixmap;
		}
	}
	palette.osPalette = XtGetGC(screenID, mask, &values);
}

void ZafWindow::OSRegisterObject(void)
{
	// Create the Motif widget.
	char *name = zafCodeSet->ConvertToOSString(stringID, 0, false);
	if (!parent)
	{
		// If we don't have a minicon create one.
		if (!MinimizeIcon())
		{
			const ZafIChar *text = Text() ? Text() : ZAF_NULLP(ZafIChar);
			ZafIcon *minIcon = new ZafIcon(0, 0, text, ZAF_NULLP(ZafIconData), ZAF_MINIMIZE_ICON);
			minIcon->SetIconImage(ZAF_APPLICATION_ICON);
			Add(minIcon);
		}

		// Pre-Level 1 - Create the shell widget.
		OSDisplayContext xDisplay = XtDisplay(((ZafScreenDisplay *)display)->topLevelShell);
		screenID = XtVaAppCreateShell(0, name,
			(WidgetClass)&MtfWindowShell::classRecord, xDisplay, 0);

		// Update the shell attributes.
		if (Sizeable())
			SetDecoration(MWM_DECOR_RESIZEH);

		// The shell position is automatically calculated base on the frame's position.
		ZafRegionStruct osRegion = windowManager->ConvertToOSRegion(this);
		XtVaSetValues(screenID,
			// region
			XmNx, osRegion.left,
			XmNy, osRegion.top,
 			XmNwidth, 10,
			XmNheight, 10,
			// miscellaneous
			XmNdeleteResponse, XmDO_NOTHING, // wait for ExitShell.
			XmNsensitive, Disabled() ? false : true,
			XtNallowShellResize, false,
			XmNmwmDecorations, Decorations(),// | (Sizeable() ? MWM_DECOR_RESIZEH : 0),
			0);
		
		// Remove size option from sys menu if not sizeable this also removes min and max.
		if (!Sizeable())
		{
			long mwmFunctions;
			XtVaGetValues(screenID, XmNmwmFunctions, &mwmFunctions, NULL);
			mwmFunctions &= ~MWM_FUNC_RESIZE;
			XtVaSetValues(screenID, XmNmwmFunctions, &mwmFunctions, NULL);
		}
		if (Modal())
			XtVaSetValues(screenID, XmNmwmInputMode, MWM_INPUT_FULL_APPLICATION_MODAL, 0);
		if (Minimized())
			XtVaSetValues(screenID, XmNinitialState, IconicState, 0);
		else if (Maximized())
			maximized = false; // not allowed by default in Motif.

		// Tell Motif to call ExitShell when user tries to close the window.
		Atom deleteWindowAtom = XmInternAtom(((ZafScreenDisplay *)display)->xDisplay, "WM_DELETE_WINDOW", false);
		XmAddWMProtocolCallback(screenID, deleteWindowAtom,
			(XtCallbackProc)MtfWindowShell::delete_window, (XtPointer)this);

		// Add callbacks for shell size and position changes.
		XtAddEventHandler(screenID,
			PropertyChangeMask | VisibilityChangeMask | StructureNotifyMask | FocusChangeMask,
			false, (XtEventHandler)MtfWindowShell::callback,
			(XtPointer)this);

		// Initialize variables for determining title and border sizes.
		MtfWindowShell *shell = (MtfWindowShell *)screenID;
		BorderSizeInitialized((Widget)shell) = false;
		TitleSizeInitialized((Widget)shell) = false;
		BorderSize((Widget)shell) = 0;
		TitleSize((Widget)shell) = 0;

	}
	else if (SupportObject())
		screenID = parent->OSScreenID(ZAF_FRAMEID);
	else
		screenID = parent->OSScreenID(ZAF_CLIENTID);

	// Level 1 - Create the frame area.
	screenID = XtVaCreateWidget(name,
		(WidgetClass)&MtfWindowFrame::classRecord, screenID,
		// user information
		XmNuserData, this,
		// miscellaneous
		XmNresizePolicy, parent ? XmRESIZE_NONE : XmRESIZE_ANY,
		XmNshadowThickness, Bordered() ? ZAF_SHADOW_SIZE : 0,
		XmNtraversalOn, Noncurrent() ? false : true,
		XmNx, 0,
		XmNy, 0,
		XmNmarginWidth, 0,
		XmNmarginHeight, 0,
		0);

	// Set additional default values.
	MtfWindowFrame *mtfFrame = MtfWindowFrame::GetMotifWidget(screenID);
	mtfFrame->OverrideTranslations();
	Shadow_Type((Widget)mtfFrame) = XmSHADOW_IN;

	// Level 2 - Create the client area.
	screenID = XtVaCreateManagedWidget(name,
		(WidgetClass)&MtfWindowClient::classRecord, screenID,
		// user information
		XmNuserData, this,
		// miscellaneous
		XmNresizePolicy, XmRESIZE_NONE,
		XmNtraversalOn, Noncurrent() ? false : true,
		XmNmarginWidth, 0,
		XmNmarginHeight, 0,
		0);

	// Override translations.
	MtfWindowClient *mtfClient = MtfWindowClient::GetMotifWidget(screenID);
	mtfClient->OverrideTranslations();

	// Add edit mode overrides.
	ZafEditModeRegister(this);

	// Add drag/drop capabilities.
	ZafDropSiteRegister(this);
}

OSWindowID ZafWindow::OSScreenID(ZafScreenIDType type) const
{
	// Return the frame widget.
	if (!screenID)
		return (screenID);
	else if (type == ZAF_FRAMEID)
		return (XtParent(screenID));
	else if (type == ZAF_SHELLID)
	{
		if (parent)
			return (parent->OSScreenID(type));
		return (XtParent(XtParent(screenID)));
	}
	return (screenID);
}

void ZafWindow::OSSize(void)
{
	if (!screenID)
		return;
	// Default to the base window object class.
	if (!parent)
	{
		int clientWidth = clientRegion.Width();
		int clientHeight = clientRegion.Height();

		// Reset the window (convert zafRegion to shell region)
		ZafRegionStruct osRegion = windowManager->ConvertToOSRegion(this);

		// Get handles to native objects
		Widget shell = OSScreenID(ZAF_SHELLID);
		Widget frame = OSScreenID(ZAF_FRAMEID);
		Widget widget = screenID;

		// We only want to change the direct descendant of frame.  In the 
		// case of scrolled windows, this is not screenID.
		while (widget != frame && XtParent(widget) != frame)
			widget = XtParent(widget);

		// Set the SHELL position and size
		XtVaSetValues(shell,
			XmNx, osRegion.left,
			XmNy, osRegion.top,
			XmNwidth, osRegion.Width(),
			XmNheight, osRegion.Height(),
			0);

		// Set the FRAME if not automatically handled
# 			if !defined(__DECCXX) && !defined(__alpha__)
		XtVaSetValues(frame,
			XmNx, 0, XmNy, 0,
			XmNwidth, osRegion.Width(),
			XmNheight, osRegion.Height(),
			0);
# 			endif

		if (sizeToClient && (widget->core.width != clientWidth || widget->core.height != clientHeight))
		{
			zafRegion.right += clientWidth - widget->core.width;
			zafRegion.bottom += clientHeight - widget->core.height;
			osRegion = windowManager->ConvertToOSRegion(this);

			// Adjust the window position.
			int deltaX = clientWidth - widget->core.width;
			int deltaY = clientHeight - widget->core.height;

			// Set the SHELL position and size (returns after OS size message processed)
			XtVaSetValues(shell,
				XmNx, osRegion.left,
				XmNy, osRegion.top,
				XmNwidth, frame->core.width + deltaX,
				XmNheight, frame->core.height + deltaY,
				0);

			// Set the FRAME if not automatically handled
#if !defined(__DECCXX) && !defined(__alpha__)
 			XtVaSetValues(frame,
 				XmNx, 0, XmNy, 0,
 				XmNwidth, frame->core.width + deltaX,
 				XmNheight, frame->core.height + deltaY,
 				0);
#endif
 		}

 		sizeToClient = false;

		// Make sure the frame is visible.
		if (visible && !XtIsManaged(frame))
			XtManageChild(frame);
		oldRegion = zafRegion;
	}
	else 
		ZafWindowObject::OSSize();
}

ZafError ZafWindow::OSUpdatePalettes(ZafPaletteType zafTypes, ZafPaletteType osTypes)
{
	// First, defer to the base class.
	ZafError tError = ZafWindowObject::OSUpdatePalettes(zafTypes, osTypes);

	// Clear all the children.
	if (!tError)
	{
		for (ZafWindowObject *object = First(); object; object = object->Next())
			if (object->SystemObject() && object->Visible())
			{
				Widget frame = object->OSScreenID(ZAF_FRAMEID);
				if (frame && frame != screenID && XtIsRealized(frame) && XtWindow(frame))
					XClearArea(XtDisplay(frame), XtWindow(frame), 0, 0, 0, 0, true);
			}
	}

	// Return the error status.
	return (tError);
}

