/* 
 * Motif
 *
 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
 *
 * These libraries and programs are free software; you can
 * redistribute them and/or modify them under the terms of the GNU
 * Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * These libraries and programs are distributed in the hope that
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with these librararies and programs; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301 USA
*/ 
/* 
 * Motif Release 1.2.3
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

 
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$TOG: WmWinInfo.c /main/18 1999/02/04 15:17:25 mgreess $"
#endif
#endif


/*
 * Included Files:
 */

#include "WmGlobal.h"
#include "WmICCC.h"
#include "WmResNames.h"

#define MWM_NEED_ICONBOX
#include "WmIBitmap.h"

#include <Xm/Xm.h>
#include <X11/Xlocale.h>
#ifdef PANELIST
#include "WmPanelP.h"
#endif /* PANELIST */

#define makemult(a, b) ((b==1) ? (a) : (((int)((a) / (b))) * (b)) )

/*
 * include extern functions
 */
#include "WmWinInfo.h"
#include "WmCDInfo.h"
#include "WmCDecor.h"
#include "WmCPlace.h"
#include "WmError.h"
#include "WmIDecor.h"
#include "WmIPlace.h"
#include "WmIconBox.h"
#include "WmImage.h"
#include "WmManage.h"
#include "WmMenu.h"
#include "WmProperty.h" 
#include "WmResource.h"
#ifdef WSM
#include "WmWrkspace.h"
#endif /* WSM */
#include "WmWinList.h"
#ifdef WSM
#include "WmPresence.h"
#endif /* WSM */
#include "WmXSMP.h"

#ifdef PANELIST
static void AdjustSlideOutGeometry (ClientData *pCD);
static void FixSubpanelEmbeddedClientGeometry (ClientData *pCD);
#endif /* PANELIST */

#ifndef NO_MESSAGE_CATALOG
# define LOCALE_MSG GETMESSAGE(70, 7, "[XmbTextPropertyToTextList]:\n     Locale (%.100s) not supported. (Check $LANG).")
#else
# define LOCALE_MSG "[XmbTextPropertyToTextList]:\n     Locale (%.100s) not supported. (Check $LANG)."
#endif

/*
 * Global Variables:
 */
#ifdef WSM
WmWorkspaceData *pIconBoxInitialWS;
#endif /* WSM */



/*************************************<->*************************************
 *
 *  GetClientInfo (pSD, clientWindow, manageFlags)
 *
 *
 *  Description:
 *  -----------
 *  This function is used to initialize client window data based on the
 *  contents of client window properties and the client window configuration.
 *
 *
 *  Inputs:
 *  ------
 *  pSD = pointer to screen data for screen that client lives in
 *
 *  clientWindow = window id for the client window that is to be managed
 *
 *  manageFlags = flags that indicate wm state info
 *
 * 
 *  Outputs:
 *  -------
 *  Return = pointer to an initialized client data structure for the
 *           specified client window
 *
 *************************************<->***********************************/

ClientData * 
GetClientInfo (WmScreenData *pSD, Window clientWindow, long manageFlags)

{
    ClientData *pCD;
    XSetWindowAttributes sAttributes;


    /*
     * Allocate and initialize a client data structure:
     */

    if (!(pCD = (ClientData *)XtMalloc (sizeof (ClientData))))
    {
	/* unable to allocate space */
	Warning (((char *)GETMESSAGE(70, 1, "Insufficient memory for client data")));
	return (NULL);
    }

    
    /*
     * Initialize the data structure:
     */

    pCD->client = clientWindow;
    pCD->clientID = ++(pSD->clientCounter);
    pCD->clientFlags = WM_INITIALIZATION;
    pCD->iconFlags = 0;
#ifndef WSM
    pCD->pIconBox = NULL;
#endif /* WSM */
    pCD->thisIconBox = NULL;
#ifdef PANELIST
    pCD->pECD = NULL;
    pCD->pPRCD = NULL;
    pCD->pSOR = NULL;
#endif /* PANELIST */
    pCD->wmUnmapCount = 0;
    pCD->transientFor = (Window)0L;
    pCD->transientLeader = NULL;
    pCD->transientChildren = NULL;
    pCD->transientSiblings = NULL;
#ifdef WSM
    pCD->primaryStackPosition = 0;
#endif /* WSM */
    pCD->fullModalCount = 0;
    pCD->primaryModalCount = 0;
    pCD->focusPriority = 0;
    pCD->focusAutoRaiseDisabled = False;
    pCD->focusAutoRaiseDisablePending = False;

    pCD->clientClass = NULL;
    pCD->clientName = NULL;
    pCD->clientFrameWin = (Window)0L;
#ifndef WSM
    pCD->iconFrameWin = (Window)0L;
#endif /* WSM */
    pCD->iconWindow = (Window)0L;
    pCD->iconPixmap = (Pixmap)0L;
#ifndef WSM
    pCD->iconPlace = NO_ICON_PLACE;
#endif /* WSM */
    pCD->clientProtocols = NULL;
    pCD->clientProtocolCount = 0;
    pCD->mwmMessages = NULL;
    pCD->mwmMessagesCount = 0;
    pCD->clientCmapCount = 0;
    pCD->clientCmapIndex = 0;
    pCD->clientCmapFlagsInitialized = FALSE;
    pCD->systemMenuSpec = NULL;
#ifdef WSM
    pCD->putInAll = False;
    pCD->pWorkspaceHints = NULL;
    pCD->numInhabited = 0;
    pCD->pWsList = NULL;
    pCD->dtwmFunctions = DtWM_FUNCTION_OCCUPY_WS;
    pCD->dtwmBehaviors = 0L;
    pCD->paInitialProperties = NULL;
    pCD->numInitialProperties = 0;
#endif /* WSM */

    pCD->decorFlags = 0L;
    pCD->pTitleGadgets = NULL;
    pCD->cTitleGadgets = 0;
    pCD->pResizeGadgets = NULL;
    pCD->clientTitleWin = (Window)0L;
    pCD->pclientTopShadows = NULL;
    pCD->pclientBottomShadows = NULL;
    pCD->pclientTitleTopShadows = NULL;
    pCD->pclientTitleBottomShadows = NULL;
    pCD->pclientMatteTopShadows = NULL;
    pCD->pclientMatteBottomShadows = NULL;
    pCD->piconTopShadows = NULL;
    pCD->piconBottomShadows = NULL;
    pCD->internalBevel = (wmGD.frameStyle == WmSLAB) ? 0 : 
						FRAME_INTERNAL_SHADOW_WIDTH;
#ifndef NO_OL_COMPAT
    pCD->bPseudoTransient = False;
#endif /* NO_OL_COMPAT */

    pCD->maxWidth = pCD->maxWidthLimit = BIGSIZE;
    pCD->maxHeight = pCD->maxHeightLimit = BIGSIZE;
    pCD->maxConfig = FALSE;
    pCD->pSD = pSD;
    pCD->dataType = CLIENT_DATA_TYPE;
    pCD->window_status = 0L;

    pCD->clientEntry.nextSibling = NULL;
    pCD->clientEntry.prevSibling = NULL;
    pCD->clientEntry.pCD = NULL;

    pCD->smClientID = (String)NULL;

     /*
     * Do special processing for client windows that are controlled by
     * the window manager.
     */

    if (manageFlags & MANAGEW_WM_CLIENTS)
    {
#ifdef WSM
        WmWorkspaceData *pWS;

	if (manageFlags & MANAGEW_ICON_BOX)
	{
	    pWS = pIconBoxInitialWS;
	}
	else 
	{
	    pWS = pSD->pActiveWS;
	}
	return (GetWmClientInfo (pWS, pCD, manageFlags));
#else /* WSM */
	return (GetWmClientInfo (pSD->pActiveWS, pCD, manageFlags));
#endif /* WSM */
    }


    /*
     * Register the client window to facilitate event handling:
     */

    XSaveContext (DISPLAY, clientWindow, wmGD.windowContextType, (caddr_t)pCD);


    /*
     * Listen for property change events on the window so that we keep 
     * in sync with the hints.
     */
    sAttributes.event_mask = (PropertyChangeMask | ColormapChangeMask);    
    XChangeWindowAttributes (DISPLAY, pCD->client, CWEventMask,
        &sAttributes);

    /*
     * Get window configuration attributes.  WmGetWindowAttributes sets
     * up the global window attributes cache with the client window 
     * attributes.
     */

    if (!WmGetWindowAttributes (clientWindow))
    {
	/*
	 * Cannot get window attributes. Do not manage window.
	 * (error message within WmGetWindowAttributes)
	 */

	UnManageWindow (pCD);
	return (NULL);
    }
    pCD->xBorderWidth = wmGD.windowAttributes.border_width;

#ifdef WSM
    /*
     * Get the initial list of properties on this window. 
     * Save it to optimize subsequent property fetching.
     */
    GetInitialPropertyList (pCD);
#endif /* WSM */

    /*
     * Retrieve and process WM_CLASS hints client window property info:
     */

    ProcessWmClass (pCD);


    /*
     * Retrieve and process WM_TRANSIENT_FOR client window property info:
     */

    ProcessWmTransientFor (pCD);

    /*
     * Get client window resource data (from resources, .mwmrc):
     *  Moved prior to GetClientWorkspaceInfo() because the
     *  ignoreWMSaveHints resource may affect that function.
     */

    ProcessClientResources (pCD);

    /*
     * Retreive and process SM_CLIENT_ID client window property info
     * and WMSAVE_HINT client window property info:
     * must be done prior to calling GetClientWorkspaceInfo().
     */
    ProcessSmClientID (pCD);
    ProcessWmSaveHint (pCD);

#ifdef WSM
    /*
     *  Set client's workspace information.  NOTE: this also may
     *  set the geometry, initial state, etc.  For Sm-aware clients,
     *  this info will be in private DB; for older clients, it will
     *  be contained in the screen's pDtSessionItems.
     */
    if (!GetClientWorkspaceInfo (pCD, manageFlags))
    {
	XtFree ((char *)pCD);
	return (NULL);
    }

    /*
     *  Restore client's per-workspace icon information.
     */
    LoadClientIconPositions(pCD);

    /*
     * Retrieve and process _DT_WM_HINTS client window property
     * (results are used in ProcessMwmHints)
     */
    ProcessDtWmHints (pCD);
#else

    /*
     * For Sm-aware clients, retrieve geometry and initial state
     * from private DB.
     */
    FindClientDBMatch(pCD, (char **)NULL);

#endif /* WSM */

    /*
     * Retrieve and process M_CLIENT_DECOR client window property info:
     */

    ProcessMwmHints (pCD);


    /*
     * Retrieve and process WM_HINTS client window property info:
     */

    ProcessWmHints (pCD, True /*first time*/);


    /*
     * Set offset from frame of client window
     */

    SetClientOffset (pCD);


    /*
     * Retrieve and process WM_NORMAL_HINTS client window property info:
     * 
     */

    ProcessWmNormalHints (pCD, True /*first time*/, manageFlags);


    /*
     * Retrieve and process WM_NAME client window property info (this
     * property contains the window title NOT the window resource name):
     */

    ProcessWmWindowTitle (pCD, TRUE);


    /*
     * Retrieve and process WM_ICON_NAME client window property info:
     */

    ProcessWmIconTitle (pCD, TRUE);


    /*
     * Retrieve and process the WM_PROTOCOLS property.
     */

    ProcessWmProtocols (pCD);


    /*
     * If necessary retrieve and process the _MWM_MESSAGES property.
     */

    if (pCD->protocolFlags & PROTOCOL_MWM_MESSAGES)
    {
	ProcessMwmMessages (pCD);
    }


    /*
     * Make or find a system menu for the client.
     */

    if (pCD->systemMenu)
    {
	MakeSystemMenu (pCD);
    }
    else
    {
	pCD->systemMenuSpec = NULL;
    }


    /*
     * Setup the colormap data for the client window.  This includes
     * retrieving and processing client window properties that deal with
     * subwindow colormaps.
     */

    InitCColormapData (pCD);


    /* successful return */

    return (pCD);


} /* END OF FUNCTION GetClientInfo */



/*************************************<->*************************************
 *
 *  GetWmClientInfo (pWS, pCD, manageFlags)
 *
 *
 *  Description:
 *  -----------
 *  This function is used to initialize client window data for a window
 *  that is controlled by the window manager (e.g., the icon box).  The 
 *  client window may get made in the process.
 *
 *
 *  Inputs:
 *  ------
 *  pWS = pointer to workspace data
 *
 *  pCD = pointer to client window data structure
 *
 *  manageFlags = flags that indicate wm state info
 *
 * 
 *  Outputs:
 *  -------
 *  Return = pointer to an initialized client data structure or NULL
 *           if the client data could not be initialized
 *
 *************************************<->***********************************/
ClientData * 
GetWmClientInfo (WmWorkspaceData *pWS,
			      ClientData * pCD,
			      long manageFlags)

{
    Pixmap 	iconBitmap;
#ifdef WSM
int i;
#endif /* WSM */

    /*
     * Set up the client class and name for resource retrieval.
     * Get client specific resource data (from resources, .mwmrc).
     */

    if (manageFlags & MANAGEW_ICON_BOX)
    {
	SetIconBoxInfo (pWS, pCD);
    }
    else if (manageFlags & MANAGEW_CONFIRM_BOX)
    {
	pCD->clientClass = WmCConfirmbox;
	pCD->clientName = WmNconfirmbox;
	pCD->iconImage = NULL;
	pCD->useClientIcon = False;
	pCD->focusAutoRaise = True;
	pCD->internalBevel = (wmGD.frameStyle == WmSLAB) ? 0 : 
						FRAME_INTERNAL_SHADOW_WIDTH;
	pCD->matteWidth = 0;
	pCD->maximumClientSize.width = 0;
	pCD->maximumClientSize.height = 0;
	pCD->systemMenu = NULL;
    }


    /*
     * Set up transient for data.
     */

    if (manageFlags & MANAGEW_ICON_BOX)
    {
    }


    /*
     * Set up WM_HINTS type information.
     */

    pCD->inputFocusModel = True;
    pCD->clientState = NORMAL_STATE;
    
    if (ICON_DECORATION(pCD) & ICON_IMAGE_PART)
    {
	if (manageFlags & MANAGEW_ICON_BOX)
	{
	    pCD->clientFlags |= ICON_BOX;
	}
        
	if (!pCD->useClientIcon && pCD->iconImage)
        {
	    /*
	     * Make a client supplied icon image.
	     * Do not use the default icon image if iconImage is not found.
	     */

	    pCD->iconPixmap = MakeNamedIconPixmap (pCD, pCD->iconImage);
        }

	if (!pCD->iconPixmap)
        {
	    /*
	     * Use a built-in icon image for the window manager client.
	     * The image may differ from the default icon image, depending on
	     * the particular client (eg the iconbox).
	     */

	    if (manageFlags & MANAGEW_ICON_BOX)
	    {
		/*
		 * Make a default iconBox icon image.
		 */

		iconBitmap = XCreateBitmapFromData (DISPLAY, 
				ROOT_FOR_CLIENT(pCD), (char *)iconBox_bits, 
				iconBox_width, iconBox_height);

		pCD->iconPixmap = MakeIconPixmap (pCD, 
				iconBitmap, (Pixmap)0L,
				iconBox_width, iconBox_height, 1);

	    }
        }
    }

#ifdef WSM
    /* 
     * Allocate initial workspace ID list 
     * fill with NULL IDs
     */
    if ((pCD->pWsList = (WsClientData *) 
	    XtMalloc(pCD->pSD->numWorkspaces * sizeof(WsClientData))) == NULL)
    {
	Warning (((char *)GETMESSAGE(70, 2, "Insufficient memory for client data")));
	return (NULL);
    }
    pCD->sizeWsList = pCD->pSD->numWorkspaces;
    for (i = 0; i < pCD->pSD->numWorkspaces; i++)
    {
	pCD->pWsList[i].wsID = NULL;
	pCD->pWsList[i].iconPlace = NO_ICON_PLACE;
	pCD->pWsList[i].iconX = 0;
	pCD->pWsList[i].iconY = 0;
	pCD->pWsList[i].iconFrameWin = (Window)0L;
	pCD->pWsList[i].pIconBox = NULL;
    }
    /* 
     * Internally managed clients must be specifically inserted
     * into workspaces the first time by calling
     * PutClientIntoWorkspace.
     */
    pCD->numInhabited = 0;
#else /* WSM */
    pCD->iconPlace = NO_ICON_PLACE;
    pCD->iconX = 0;
    pCD->iconY = 0;
#endif /* WSM */
    pCD->windowGroup = 0L;
#ifndef NO_OL_COMPAT
    pCD->bPseudoTransient = False;
#endif /* NO_OL_COMPAT */


    /*
     * Set up _MWM_HINTS data.
     */
    /*
     * Fix the client functions and decorations fields if they have
     * default resource values.
     */


    if (manageFlags & MANAGEW_CONFIRM_BOX)
    {
        pCD->clientFunctions = WM_FUNC_NONE;
        pCD->clientDecoration = WM_DECOR_BORDER;
    }
    else
    {
        if (pCD->clientFunctions & WM_FUNC_DEFAULT)
        {
	    pCD->clientFunctions = WM_FUNC_ALL;
        }

        if (pCD->clientDecoration & WM_DECOR_DEFAULT)
        {
	    pCD->clientDecoration = WM_DECOR_ALL;
        }

        if (manageFlags & MANAGEW_ICON_BOX)
        {
            pCD->clientFunctions &= ICON_BOX_FUNCTIONS;
#ifdef WSM
	    pCD->dtwmFunctions &= ~DtWM_FUNCTION_OCCUPY_WS;
#endif /* WSM */
#ifdef PANELIST
	    if (wmGD.useFrontPanel && pCD->pSD->iconBoxControl) 
	    { 
		/*
		 * If there's a front panel button for the icon
		 * box, then use it to "hide" the box on "close"
		 */
		pCD->clientFunctions &= ~MWM_FUNC_MINIMIZE;
		pCD->clientFunctions |= MWM_FUNC_CLOSE;
	    }
#else /* PANELIST */
#endif /* PANELIST */
        }


        if (!(pCD->clientFunctions & MWM_FUNC_RESIZE))
        {
	    pCD->clientDecoration &= ~MWM_DECOR_RESIZEH;
        }

        if (!(pCD->clientFunctions & MWM_FUNC_MINIMIZE))
        {
	    pCD->clientDecoration &= ~MWM_DECOR_MINIMIZE;
        }

        if (!(pCD->clientFunctions & MWM_FUNC_MAXIMIZE))
        {
	    pCD->clientDecoration &= ~MWM_DECOR_MAXIMIZE;
        }
    }

    pCD->decor = pCD->clientDecoration;

    if (manageFlags & MANAGEW_ICON_BOX)
    {
        pCD->inputMode = MWM_INPUT_MODELESS;
    }
    else if (manageFlags & MANAGEW_CONFIRM_BOX)
    {
        pCD->inputMode = MWM_INPUT_SYSTEM_MODAL;
    }

    /*
     * Set up WM_NORMAL_HINTS data.
     */

    pCD->icccVersion = ICCC_CURRENT;
    pCD->sizeFlags = US_POSITION | US_SIZE;

    /* 
     * Any calls to create Window Manager clients should
     * return with the values for the following fields set.
     *  If it fails, it should free any space allocated and
     *  set pCD = NULL
     * 
     *  pCD->clientX =
     *  pCD->clientY =
     *  pCD->clientWidth =
     *  pCD->clientHeight =
     *  pCD->minWidth =
     *  pCD->minHeight =
     *  pCD->widthInc =
     *  pCD->heightInc =
     *  pCD->baseWidth =
     *  pCD->baseHeight =
     *  pCD->maxWidth =
     *  pCD->maxHeight =
     *  pCD->oldMaxWidth =
     *  pCD->oldMaxHeight =
     *
     *        AND PROBABLY SHOULD SET
     *         pCD->client = THE_WINDOW_THE_FUNCTION_CREATES
     */

    pCD->windowGravity = NorthWestGravity;

    /* 
     * Create IconBox window 
     */
    
    if (manageFlags & MANAGEW_ICON_BOX)
    {
        if (!MakeIconBox (pWS, pCD))
        {
            /*
             *  May want a more verbose message here 
             */

            Warning (((char *)GETMESSAGE(70, 3, "Couldn't make icon box")));
	    return (NULL);
        }
#ifdef WSM
	PutClientIntoWorkspace (pWS, pCD);
#endif /* WSM */
    }
    else if (manageFlags & MANAGEW_CONFIRM_BOX)
    {
	Window       root;
	unsigned int cbWidth, cbHeight;
	unsigned int depth;

        XGetGeometry (DISPLAY, pCD->client, &root,
		      &(pCD->clientX), &(pCD->clientY),
		      &cbWidth, &cbHeight, 
		      (unsigned int*)&(pCD->xBorderWidth), &depth);

        pCD->clientWidth = cbWidth;
        pCD->clientHeight = cbHeight;
	pCD->minWidth = pCD->baseWidth = pCD->maxWidth = pCD->clientWidth;
	pCD->minHeight = pCD->baseHeight = pCD->maxHeight = pCD->clientHeight;
	pCD->oldMaxWidth = pCD->maxWidth;
	pCD->oldMaxHeight = pCD->maxHeight;
        pCD->widthInc = 1;
        pCD->heightInc = 1;
        pCD->clientFlags |= CONFIRM_BOX;
#ifdef WSM
	PutClientIntoWorkspace (ACTIVE_WS, pCD);
#endif /* WSM */
    }

    /*
     * Set offset from frame of client window (need client size information).
     */

    SetFrameInfo (pCD);


    /*
     * Register the client window to facilitate event handling.
     */

    XSaveContext (DISPLAY, pCD->client, wmGD.windowContextType, (caddr_t)pCD);


    /*
     * Set up WM_PROTOCOLS data.
     */

    pCD->clientProtocolCount = 0;
    pCD->protocolFlags = 0;


    /*
     * Make the system menu.
     */

    if (manageFlags & MANAGEW_ICON_BOX)
    {
#if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
	/** BEGIN FIX CR 6941 **/
	MenuItem *iconBoxMenuItems, *lastItem;

	/* This MenuSpec is not added to pSD->acceleratorMenuSpecs */
	pCD->systemMenuSpec = 
	    MAKE_MENU (PSD_FOR_CLIENT(pCD), pCD, pCD->systemMenu,
		      F_CONTEXT_WINDOW, F_CONTEXT_WINDOW|F_CONTEXT_ICON,
		      NULL, TRUE);
	if (pCD->systemMenuSpec != (MenuSpec *) NULL)
	{
	    pCD->systemMenuSpec = DuplicateMenuSpec(pCD->systemMenuSpec);
	    XtFree(pCD->systemMenuSpec->name);
	    pCD->systemMenuSpec->name = XtNewString("IconBoxMenu");
	    iconBoxMenuItems = GetIconBoxMenuItems (PSD_FOR_CLIENT(pCD));
	    
	    /* Find the last menu item in the menu spec's list. */
	    for (lastItem = pCD->systemMenuSpec->menuItems;
		 lastItem->nextMenuItem != (MenuItem *) NULL;
		 lastItem = lastItem->nextMenuItem)
	      /*EMPTY*/;
	    lastItem->nextMenuItem = iconBoxMenuItems;
	    
	    /* Now recreate the menu widgets since we've appended the
	       icon box menu items */
	    DestroyMenuSpecWidgets(pCD->systemMenuSpec);
	    pCD->systemMenuSpec->menuWidget =
	      CreateMenuWidget (PSD_FOR_CLIENT(pCD), pCD, "IconBoxMenu",
				PSD_FOR_CLIENT(pCD)->screenTopLevelW, TRUE,
				pCD->systemMenuSpec, NULL);
	}
	/** END FIX CR 6941 **/
#else
	pCD->systemMenuSpec = 
	    MAKE_MENU (PSD_FOR_CLIENT(pCD), pCD, pCD->systemMenu,
		       F_CONTEXT_WINDOW, F_CONTEXT_WINDOW|F_CONTEXT_ICON,
		       GetIconBoxMenuItems(PSD_FOR_CLIENT(pCD)),
		       TRUE);
#endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
    }



    /*
     * Setup the colormap data.
     */

    pCD->clientColormap = PSD_FOR_CLIENT(pCD)->workspaceColormap;


    /*
     * Return the pointer to the client data.
     */

    return (pCD);


} /* END OF FUNCTION GetWmClientInfo */



/*************************************<->*************************************
 *
 *  ProcessWmClass (pCD)
 *
 *
 *  Description:
 *  -----------
 *  This function retrieves the contents of the WM_CLASS property on the
 *  cient window.  The resource class and the resource name are saved in
 *  the ClientData structure (note that the space for the strings is
 *  allocated using Xmalloc).
 *
 *
 *  Inputs:
 *  ------
 *  pCD		- pointer to client data
 *
 * 
 *  Outputs:
 *  -------
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/

void 
ProcessWmClass (ClientData *pCD)
{
    XClassHint classHint;


#ifdef PORT_OLDXLIB
    classHint.res_class = "";
    classHint.res_name = "";
    XGetClassHint (DISPLAY, pCD->client, &classHint);
#else
#ifdef WSM
    if ((HasProperty (pCD, XA_WM_CLASS)) &&
	(XGetClassHint (DISPLAY, pCD->client, &classHint)))
#else /* WSM */
    if (XGetClassHint (DISPLAY, pCD->client, &classHint))
#endif /* WSM */
#endif
    {
	/* the WM_CLASS property exists for the client window */
	pCD->clientClass = classHint.res_class;
	pCD->clientName = classHint.res_name;
    }
    /* else no WM_CLASS property; assume clientClass, clientName are NULL */

} /* END OF FUNCTION ProcessWmClass */



/*************************************<->*************************************
 *
 *  ProcessSmClientID (pCD)
 *
 *
 *  Description:
 *  -----------
 *  This function retrieves the contents of the SM_CLIENT_ID property on the
 *  cient window.  The value is saved in the ClientData structure
 *  (note that the space for the strings is allocated using Xmalloc).
 *
 *
 *  Inputs:
 *  ------
 *  pCD		- pointer to client data
 *
 * 
 *  Outputs:
 *  -------
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/

void 
ProcessSmClientID (ClientData *pCD)
{
    Atom actualType;
    int actualFormat;
    unsigned long nitems, leftover;
    char *clientID;

    if (pCD->smClientID != (String)NULL)
    {
	XFree(pCD->smClientID);
	pCD->smClientID = (String)NULL;
    }

    if ((XGetWindowProperty(DISPLAY, pCD->client, wmGD.xa_SM_CLIENT_ID,
			    0L, (long)1000000, False, AnyPropertyType,
			    &actualType, &actualFormat, &nitems,
			    &leftover, (unsigned char **)&clientID)
	 == Success) &&
	(actualType != None) && (actualFormat == 8))
    {
	/* the SM_CLIENT_ID property exists for the client window */
	pCD->smClientID = clientID;
    }

} /* END OF FUNCTION ProcessSmClientID */



/*************************************<->*************************************
 *
 *  ProcessWmSaveHint (pCD)
 *
 *
 *  Description:
 *  -----------
 *  This function retrieves the contents of the WMSAVE_HINT property on the
 *  cient window.  The value is saved in the ClientData structure.
 *
 *
 *  Inputs:
 *  ------
 *  pCD		- pointer to client data
 *
 * 
 *  Outputs:
 *  -------
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/

void 
ProcessWmSaveHint (ClientData *pCD)
{
    Atom actualType;
    int actualFormat;
    unsigned long nitems, leftover;
    BITS32 *saveHintFlags = (BITS32 *)NULL;

    if ((XGetWindowProperty(DISPLAY, pCD->client, wmGD.xa_WMSAVE_HINT,
			    0L, (long)1000000, False, AnyPropertyType,
			    &actualType, &actualFormat, &nitems,
			    &leftover, (unsigned char **)&saveHintFlags)
	 == Success) &&
	(actualType != None) && (actualFormat == 32))
    {
	/* the WMSAVE_HINT property exists for the client window */
	pCD->wmSaveHintFlags = (int)*saveHintFlags;
    }
    else pCD->wmSaveHintFlags = 0;

    if (saveHintFlags)
	XFree(saveHintFlags);

} /* END OF FUNCTION ProcessWmSaveHint */


/*************************************<->*************************************
 *
 *  ProcessWmHints (pCD, firstTime)
 *
 *
 *  Description:
 *  -----------
 *  This function retrieves the contents of the WM_HINTS property on the
 *  cient window.
 *
 *
 *  Inputs:
 *  ------
 *  pCD = pointer to client data for the window with the property
 *
 *  firstTime = if True this is the first time the property has been processed
 *
 * 
 *  Outputs:
 *  -------
 *  pCD = initialize various WM_HINTS related fields
 *
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/

void 
ProcessWmHints (ClientData *pCD, Boolean firstTime)
{
    register XWMHints *pXWMHints;
    register long flags;
    Pixmap iconPixmap;
    Pixmap iconMask;
#ifdef WSM
    WmWorkspaceData *pWsTmp;
    WsClientData *pWsc;
    int iws;
#endif /* WSM */
    int tmpIconX, tmpIconY;


    /*
     * If the WM_HINTS property does not exist the flags field will be
     * set to 0.  If flags is 0 don't reference the WMHints structure
     * since they may be none.
     */

#ifdef WSM
    if (firstTime && !HasProperty (pCD, XA_WM_HINTS))
	pXWMHints = NULL;
    else
#endif /* WSM */
    pXWMHints = XGetWMHints (DISPLAY, pCD->client);

    if (pXWMHints)
    {
	flags = pXWMHints->flags;
    }
    else
    {
	flags = 0;
    }


    /*
     * Parse the WM_HINTS information.  If this is the first time the hints
     * have been processed then parse all fields and set defaults where hint
     * fields are not set.  If this is not the first time do selective
     * parsing.
     */

    if (firstTime)
    {
#ifndef NO_OL_COMPAT
        ClientData *leader;
	Atom *pIDs;
	unsigned int numIDs = 0;

        /*
         * Save the window group.
         */

        if (flags & WindowGroupHint)
	{
	    pCD->windowGroup = pXWMHints->window_group;
	    /*
	     * Pretend this is a transient window 
	     */
	    if ((pCD->bPseudoTransient) && 
		(pCD->transientFor == (Window)0L))
	    {
		pCD->clientFlags |= CLIENT_TRANSIENT;

		/*
		 * Treat this like a transient window. This is transient
		 * for the window group window.
		 */

		if ((pCD->client != pCD->windowGroup) &&
		    !XFindContext (DISPLAY, pCD->windowGroup, 
			wmGD.windowContextType, (caddr_t *)&leader))
		{
		    pCD->transientFor = pCD->windowGroup;
		    pCD->transientLeader = leader;

		    /*
		     * Insure it is in the same set of workspaces
		     * as the leader.
		     */
		    if (pCD->transientLeader && 
			GetLeaderPresence(pCD, &pIDs, &numIDs))
		    {
			ProcessWorkspaceHintList (pCD, pIDs, numIDs);
		    }
		}
	    }
	}
	else
	{
	    pCD->windowGroup = 0L;
	}
#endif /* NO_OL_COMPAT */
        /*
         * The window manger does not do anything with the input hint.  Input
         * always goes to the selected window.
         */

        if (flags & InputHint)
	{
	    pCD->inputFocusModel = pXWMHints->input;
	}
	else
	{
	    pCD->inputFocusModel = True;
	}


        /*
         *  The default state is NORMAL_STATE.  States other than iconic
         *  (e.g., ZoomState from the R2 ICCC) indicate to the window manager
         *  that the NORMAL_STATE is to be used.
         */

	if (pCD->clientFlags & SM_CLIENT_STATE)
	{
	     if ((pCD->clientState == MINIMIZED_STATE) &&
	    	(!(pCD->clientFunctions & MWM_FUNC_MINIMIZE)))
	     {
	         pCD->clientState = NORMAL_STATE;
	     }
	}
	else
        if ((flags & StateHint) && (pXWMHints->initial_state == IconicState) &&
	    (pCD->clientFunctions & MWM_FUNC_MINIMIZE))
        {
	    pCD->clientState = MINIMIZED_STATE;
	}
        else
        {
	    /*
	     * States other than iconic are treated as normal.
	     */
	    pCD->clientState = NORMAL_STATE;
        }


#ifdef WSM
	if (!ClientInWorkspace (PSD_FOR_CLIENT(pCD)->pActiveWS, pCD))
	{
	    pCD->clientState |= UNSEEN_STATE;
	}
#endif /* WSM */


        /*
	 * If an icon is to be made for the client then ...
         * save the icon image if useClientIcon is True or there is no
	 * user specified icon image.  A client supplied image may be a
	 * pixmap or a window (a client icon window takes precedence over
	 * a pixmap).
         */

	if ((pCD->clientFunctions & MWM_FUNC_MINIMIZE) &&
	    (pCD->transientLeader == NULL))
	{
            if ((ICON_DECORATION(pCD) & ICON_IMAGE_PART) &&
	        (pCD->useClientIcon || !pCD->iconImage))
            {
	        if ((flags & IconWindowHint) &&
		    (pXWMHints->icon_window != pCD->client))
	        {
	            /* 
	             * An icon window has been supplied that is different from
		     * the client window.  Check out the window and get it 
		     * ready to be reparented to the window manager supplied
	             * icon frame.
	             */

	            if (!SetupClientIconWindow (pCD, pXWMHints->icon_window))
		    {
		        /*
		         * Cannot use the client supplied icon window.  Use
		         * an icon image if specified or a default image.
		         */
		    }
	        }
	        if (!pCD->iconWindow && (flags & IconPixmapHint))
	        {
		    iconMask = (flags & IconMaskHint) ?
				pXWMHints->icon_mask : (Pixmap) NULL;
	            /*
	             * A client supplied icon window is NOT 
		     * available so use the client supplied icon image.
	             */

	            if ((pCD->iconPixmap = 
			    MakeClientIconPixmap (pCD,
			      pXWMHints->icon_pixmap, iconMask)) != None)
		    {
		        /*
		         * Indicate that a client supplied icon image is being
		         * used.
		         */

		        pCD->iconFlags |= ICON_HINTS_PIXMAP;
		    }
		    else
		    {
		        /*
		         * Cannot make a client supplied image.  Use a user
		         * specified icon image if it is available or a default
		         * icon image.
		         */
		    }
	        }
	    }

            if ((ICON_DECORATION(pCD) & ICON_IMAGE_PART) && !pCD->iconPixmap)
	    {
	        /*
	         * Use a user supplied icon image if it is available or a
	         * default icon image.
	         */

	        if (pCD->iconImage)
	        {
		    /*
		     * Try to make a user specified icon image.
		     */

		    pCD->iconPixmap = 
			MakeNamedIconPixmap (pCD, pCD->iconImage);
	        }

	        if (!pCD->iconPixmap)
	        {
		    /*
		     * The icon image was not provided or not available.
		     * Use the default icon image.
		     */

		    pCD->iconPixmap = MakeNamedIconPixmap (pCD, NULL);
	        }
	    }
    

            /*
             * Save the client (user?) supplied icon position:
             */

            if ((flags & IconPositionHint) ||
		(pCD->clientFlags & (SM_ICON_X | SM_ICON_Y)))
            {
	        pCD->iconFlags |= ICON_HINTS_POSITION;
	        if (wmGD.iconAutoPlace)
#ifdef WSM
	        {
		    /* 
		     * Initialize icon placement data in all inhabited
		     * workspaces
		     */
		    for (iws = 0; iws< pCD->numInhabited; iws++)
		    {
			pWsc = &(pCD->pWsList[iws]);
			if (pWsTmp=GetWorkspaceData(pCD->pSD, pWsc->wsID))
			{
			    tmpIconX = (pCD->clientFlags & SM_ICON_X) ?
			      pWsc->iconX : pXWMHints->icon_x;
			    tmpIconY = (pCD->clientFlags & SM_ICON_Y) ?
			      pWsc->iconY : pXWMHints->icon_y;
			    pWsc->iconPlace =
				FindIconPlace (pCD, &(pWsTmp->IPData),
					       tmpIconX, tmpIconY);
			    if (pWsc->iconPlace != NO_ICON_PLACE)
			    {
				CvtIconPlaceToPosition ( &(pWsTmp->IPData),
				    pWsc->iconPlace,
				    &pWsc->iconX,
				    &pWsc->iconY);
			    }
			}
		    }
		}
	        else
	        {
		    for (iws = 0; iws< pCD->numInhabited; iws++)
		    {
			pWsc = &(pCD->pWsList[iws]);
			if (pWsTmp=GetWorkspaceData(pCD->pSD, pWsc->wsID))
			{
			    if (!(pCD->clientFlags & SM_ICON_X))
				pWsc->iconX = pXWMHints->icon_x;
			    if (!(pCD->clientFlags & SM_ICON_Y))
				pWsc->iconY = pXWMHints->icon_y;
			}
		    }
                }
#else /* WSM */
	        {
		    tmpIconX = (pCD->clientFlags & SM_ICON_X) ?
		      pCD->iconX : pXWMHints->icon_x;
		    tmpIconY = (pCD->clientFlags & SM_ICON_Y) ?
		      pCD->iconY : pXWMHints->icon_y;
		    pCD->iconPlace = 
			FindIconPlace (pCD, &(pCD->pSD->pActiveWS->IPData),
				       tmpIconX, tmpIconY);
		    if (pCD->iconPlace != NO_ICON_PLACE)
		    {
		        CvtIconPlaceToPosition (&(pCD->pSD->pActiveWS->IPData),
			    pCD->iconPlace, &pCD->iconX, &pCD->iconY);
		    }
	        }
	        else
	        {
		    if (!(pCD->clientFlags & SM_ICON_X))
			pCD->iconX = pXWMHints->icon_x;
		    if (!(pCD->clientFlags & SM_ICON_Y))
			pCD->iconY = pXWMHints->icon_y;
                }
#endif /* WSM */
	    }
	    else
	    {
	        if (wmGD.iconAutoPlace)
	        {
#ifdef WSM
		    /* 
		     * Initialize icon placement data in all inhabited
		     * workspaces
		     */
		    for (iws = 0; iws< pCD->numInhabited; iws++)
		    {
			pWsc = &(pCD->pWsList[iws]);
			pWsc->iconPlace = NO_ICON_PLACE;
			pWsc->iconX = 0;
			pWsc->iconY = 0;
		    }
#else /* WSM */
		    pCD->iconPlace = NO_ICON_PLACE;
		    pCD->iconX = 0;
		    pCD->iconY = 0;
#endif /* WSM */
	        }
	    }
	}

#ifdef NO_OL_COMPAT
        /*
         * Save the window group.
         */

        if (flags & WindowGroupHint)
	{
	    pCD->windowGroup = pXWMHints->window_group;
	}
	else
	{
	    pCD->windowGroup = 0L;
	}
#endif /* NO_OL_COMPAT */
    }
    else /* not the first time the hints are processed */
    {
	if (flags & IconPixmapHint)
	{
	    /*
             * Process an icon image change if the icon image was initially
             * set up with a client supplied icon image OR, if the client
             * now wants to supply an image.
             */
	    iconMask = (flags & IconMaskHint)?
                       pXWMHints->icon_mask : (Pixmap) NULL;

	    if ((iconPixmap = 
		 MakeClientIconPixmap (pCD, pXWMHints->icon_pixmap, 
					     iconMask)) != None)
	    {
		/*
		 * Made new icon image; free up the old image and display
		 * the new image.
		 */
		if (pCD->iconFlags & ICON_HINTS_PIXMAP)
                {
                    /*
                     * ICON_HINTS_PIXMAP was set either initally or
                     * below because a new pixmap was made for the client.
                     * It is now safe to free the previous pixmap since it
                     * is not the shared default iconPixmap
                     */
                    if (pCD->iconPixmap)
                    {
                        XFreePixmap (DISPLAY, pCD->iconPixmap);
                    }
                }
                else
                {
                    pCD->iconFlags |= ICON_HINTS_PIXMAP;
                }
		
                pCD->iconPixmap = iconPixmap;
		
                /*
                 * Display new icon image if the icon is showing:
                 */
		
                if (((pCD->clientState == MINIMIZED_STATE) ||
                     ((pCD->pSD->useIconBox) && (P_ICON_BOX(pCD)))) &&
                    ICON_FRAME_WIN(pCD))
                {
                    IconExposureProc (pCD, True);
                }
	    }
	}
    }

    if (pXWMHints)
    {
	XFree ((char*)pXWMHints);
    }


} /* END OF FUNCTION ProcessWmHints */



/*************************************<->*************************************
 *
 *  ProcessWmNormalHints (pCD, firstTime, manageFlags)
 *
 *
 *  Description:
 *  -----------
 *  This function retrieves the contents of the WM_NORMAL_HINTS property on
 *   the cient window.  There are several versions of the property that must be
 *  handled (currently R2 and CURRENT).
 *
 *
 *  Inputs:
 *  ------
 *  pCD = pointer to client data for the window with the property
 *
 *  firstTime = if True this is the first time the property has been processed
 *
 *  manageFlags = flags that indicate wm state information
 *
 * 
 *  Outputs:
 *  -------
 *  pCD = client location and size fields set
 *
 *
 *  Comments:
 *  --------
 *  If the hints are being reprocessed (!firstTime) the configuration values
 *  will be ignored.  The size constraint values will be processed but the
 *  client configuration will not be changed even if it is not in line with
 *  the new values.  Reconfigurations subsequent to the hints changes will
 *  be done with the new constraints.
 *
 *************************************<->***********************************/

void 
ProcessWmNormalHints (ClientData *pCD, Boolean firstTime, long manageFlags)
{
    register SizeHints *pNormalHints;
    register long       flags;
    int                 diff;
    unsigned long       decoration;
    unsigned int        boxdim, tmpMin;
    unsigned int	oldWidthInc = 0, oldHeightInc = 0;
    unsigned int	oldBaseWidth = 0, oldBaseHeight = 0;
    unsigned int	incWidth = 0, incHeight = 0;

    /*
     * Use a custom verion of the Xlib routine to get WM_NORMAL_HINTS.
     * A custom version is necessary to handle the different versions
     * of WM_NORMAL_HINTS that may be encountered.  If the WM_NORMAL_HINTS
     * property does not exist the flags field will be set to 0.
     */

    pNormalHints = GetNormalHints (pCD);

    pCD->icccVersion = pNormalHints->icccVersion;


    /*
     * Parse the WM_NORMAL_HINTS information:
     */

    if (((flags = pNormalHints->flags) == 0) && !firstTime)
    {
	return;
    }


    /*
     * Process the size only if this is the first time the hints are
     * being processed for the window.
     */

    if (firstTime)
    {
        /*
         * Process client window size flags and information:
         */

        pCD->sizeFlags = flags & (US_POSITION | US_SIZE | P_POSITION | P_SIZE);

        /*
         * The R2 conventions and Xlib manual indicate that the window size
         * and position should be taken out of the WM_NORMAL_HINTS property
         * if they are specified there.  The current conventions indicate that
         * the size and position information should be gotten from the window
         * configuration. Mwm 1.1 always uses the current conventions.
         */

#ifdef R2_COMPAT
    /* 
     * Maintain R2 compatiblity code for CND product xnm
     */
        if ((pNormalHints->icccVersion == ICCC_R2) &&
            (flags & (US_POSITION | P_POSITION)) &&
	    !(manageFlags & MANAGEW_WM_RESTART))
        {
	    if (!(pCD->clientFlags & SM_X))
		pCD->clientX = pNormalHints->x;
	    if (!(pCD->clientFlags & SM_Y))
		pCD->clientY = pNormalHints->y;
        }
        else
        {
	    if (!(pCD->clientFlags & SM_X))
		pCD->clientX = wmGD.windowAttributes.x;
	    if (!(pCD->clientFlags & SM_Y))
		pCD->clientY = wmGD.windowAttributes.y;
        }
#else /* R2_COMPAT */
	if (!(pCD->clientFlags & SM_X))
	    pCD->clientX = wmGD.windowAttributes.x;
	if (!(pCD->clientFlags & SM_Y))
	    pCD->clientY = wmGD.windowAttributes.y;
#endif  /* R2_COMPAT */

	/*
	 * Use current conventions for initial window dimensions.
	 */

#ifdef R2_COMPAT
    /* 
     * Maintain R2 compatiblity code for CND product xnm
     */
	if ((pNormalHints->icccVersion == ICCC_R2) &&
	    (flags & (US_SIZE | P_SIZE)) &&
	    !(manageFlags & MANAGEW_WM_RESTART))
	{
	    if (!(pCD->clientFlags & SM_WIDTH))
		pCD->clientWidth = pNormalHints->width;
	    if (!(pCD->clientFlags & SM_HEIGHT))
		pCD->clientHeight = pNormalHints->height;
	}
	else
	{
	    if (!(pCD->clientFlags & SM_WIDTH))
		pCD->clientWidth = wmGD.windowAttributes.width;
	    if (!(pCD->clientFlags & SM_HEIGHT))
		pCD->clientHeight = wmGD.windowAttributes.height;
	}
#else /* R2_COMPAT */
	if (!(pCD->clientFlags & SM_WIDTH))
	    pCD->clientWidth = wmGD.windowAttributes.width;
	if (!(pCD->clientFlags & SM_HEIGHT))
	    pCD->clientHeight = wmGD.windowAttributes.height;
#endif /* R2_COMPAT */
    }

    /*
     * Process the minimum size:
     */

    if (flags & P_MIN_SIZE)
    {
	pCD->minWidth =
		 (pNormalHints->min_width < 0) ? 0 : pNormalHints->min_width;
	pCD->minHeight =
		 (pNormalHints->min_height < 0) ? 0 : pNormalHints->min_height;
	if (pCD->minWidth > MAX_MAX_SIZE(pCD).width)
	{
	    pCD->minWidth = MAX_MAX_SIZE(pCD).width;
	}
	if (pCD->minHeight > MAX_MAX_SIZE(pCD).height)
	{
	    pCD->minHeight = MAX_MAX_SIZE(pCD).height;
	}
    }
    else if (firstTime)
    {
	pCD->minWidth = 0;
	pCD->minHeight = 0;
    }


    /*
     * Process the resizing increments:
     */

    if (!firstTime)
    {
	oldWidthInc = (pCD->widthInc == 0) ? 1 : pCD->widthInc;
	oldHeightInc = (pCD->heightInc == 0) ? 1 : pCD->heightInc;
    }

    if (flags & P_RESIZE_INC)
    {
	pCD->widthInc =
		 (pNormalHints->width_inc < 1) ? 1 : pNormalHints->width_inc;
	pCD->heightInc =
		 (pNormalHints->height_inc < 1) ? 1 : pNormalHints->height_inc;
    }
    else if (firstTime)
    {
	pCD->widthInc = 1;
	pCD->heightInc = 1;
    }


    /*
     * Process the base size:
     */

    if (!firstTime)
    {
	oldBaseWidth = pCD->baseWidth;
	oldBaseHeight = pCD->baseHeight;
    }

    if (flags & P_BASE_SIZE)
    {
	pCD->baseWidth =
		(pNormalHints->base_width < 0) ? 0 : pNormalHints->base_width;
	pCD->baseHeight =
		(pNormalHints->base_height < 0) ? 0 : pNormalHints->base_height;
    }
    else if ((pNormalHints->icccVersion == ICCC_R2) &&
	     ((firstTime) ||
	      (!firstTime && (flags & P_MIN_SIZE))))
    {
	/*
	 * In this version of the hints the minimum size was effectively
	 * the base size.
	 */
	pCD->baseWidth = pCD->minWidth;
	pCD->baseHeight = pCD->minHeight;
    }
    else if (firstTime)
    {
        if (flags & P_MIN_SIZE)
        {
            pCD->baseWidth = pCD->minWidth;
            pCD->baseHeight = pCD->minHeight;
        }
        else
        {
            pCD->baseWidth = 0;
            pCD->baseHeight = 0;
        }
    }

    if (firstTime)
    {
	if (pCD->clientFlags & SM_WIDTH)
	{
	    pCD->clientWidth = ((pCD->clientWidth * pCD->widthInc) +
				pCD->baseWidth);
	}
	if (pCD->clientFlags & SM_HEIGHT)
	{
    	    pCD->clientHeight =((pCD->clientHeight * pCD->heightInc) +
				pCD->baseHeight);
	}
    }

    /*
     * Process the maximum width.  NOTE: maximumClientSize.width
     * and maximumClientSize.height will be set to BIGSIZE if
     * maximumClientSize is either set to 'horizontal' or 'vertical'.
     */

    pCD->oldMaxWidth = pCD->maxWidth;
    if (pCD->maximumClientSize.width)
    {
	/* If maximumClientSize is full 'horizontal' */
	if (IS_MAXIMIZE_HORIZONTAL(pCD))
	{
	    /* go to min (full screen width, max maximum width) */
	    pCD->maxWidth = DisplayWidth (DISPLAY, SCREEN_FOR_CLIENT(pCD)) -
				          (2 * pCD->clientOffset.x);

	    /*
	     * Hack to set max client to the current client height, maxHeight
	     * will be kept up to date whenever the window is reconfigured
	     */
	    pCD->maxHeight = pCD->clientHeight;

	}
	else
	{
	    pCD->maxWidth = (pCD->maximumClientSize.width * 
			     pCD->widthInc) + pCD->baseWidth;
	}
    }
    else
    {
	if (flags & P_MAX_SIZE)
	{
	    if (pNormalHints->max_width < 0)
	    {
	        /* go to min (full screen width, max maximum width) */
		pCD->maxWidth = DisplayWidth (DISPLAY, SCREEN_FOR_CLIENT(pCD)) -
				          (2 * pCD->clientOffset.x);
	    }
	    else
	    {
	        pCD->maxWidth = pNormalHints->max_width;
	    }
	}
	/* Don't reset maxWidth if it has been set earlier */
	else if (!IS_MAXIMIZE_VERTICAL(pCD))
	{
	    if (firstTime)
	    {
		/* go to min (full screen width, max maximum width) */
		pCD->maxWidth = DisplayWidth (DISPLAY,
					      SCREEN_FOR_CLIENT(pCD)) -
						(2 * pCD->clientOffset.x);
	    }
	    else
	    {
		/* reset the maxHeight before further processing */
		pCD->maxWidth = pCD->maxWidthLimit;
	    }
	}
	else
	{
	    /* 
	     * If the hints changed we need to adjust the maximum
	     * size (if not specified in the hints).
	     */
	    if (!firstTime &&
		((oldBaseWidth != pCD->baseWidth) ||
		 (oldWidthInc != pCD->widthInc)))
	    {
		incWidth = (pCD->maxWidth - oldBaseWidth) / oldWidthInc;
		pCD->maxWidth =  
		    (incWidth * pCD->widthInc) + pCD->baseWidth;
	    }
	    else
	    {
		/* reset the maxHeight before further processing */
		pCD->maxWidth = pCD->maxWidthLimit;
	    }
	}
	if (pCD->maxWidth > MAX_MAX_SIZE(pCD).width)
	{
	    pCD->maxWidth = MAX_MAX_SIZE(pCD).width;
	}
    }



    /*
     * Process the maximum height.
     */

    pCD->oldMaxHeight = pCD->maxHeight;
    if (pCD->maximumClientSize.height)
    {
	/* If maximumClientSize is full 'vertical' */
	if (IS_MAXIMIZE_VERTICAL(pCD))
	{
	    /* go to min (full screen height, max maximum height) */
	    pCD->maxHeight = DisplayHeight (DISPLAY, SCREEN_FOR_CLIENT(pCD)) -
			     (pCD->clientOffset.x +
			      pCD->clientOffset.y);
	    /*
	     * Hack to set max client to the current client width, maxWidth
	     * will be kept up to date whenever the window is reconfigured
	     */
	    pCD->maxWidth = pCD->clientWidth;

	}
	else
	{
	    pCD->maxHeight = (pCD->maximumClientSize.height *
			      pCD->heightInc) + pCD->baseHeight;
	}
    }
    else
    {
	if (flags & P_MAX_SIZE)
	{
	    if (pNormalHints->max_height < 0)
	    {
	        /* go to min (full screen height, max maximum height) */
	        pCD->maxHeight = DisplayHeight (
				 DISPLAY, SCREEN_FOR_CLIENT(pCD)) -
				 (pCD->clientOffset.x +
				  pCD->clientOffset.y);
	    }
	    else
	    {
	        pCD->maxHeight = pNormalHints->max_height;
	    }
	}
	/* Don't reset maxHeight if it has been set above */
	else if (!IS_MAXIMIZE_HORIZONTAL(pCD))
	{
	    if (firstTime)
	    {
		/* go to min (full screen height, max maximum height) */
		pCD->maxHeight = DisplayHeight (DISPLAY,
						SCREEN_FOR_CLIENT(pCD)) -
						  (pCD->clientOffset.x +
						   pCD->clientOffset.y);
	    }
	    else
	    {
		/* reset the maxHeight before further processing */
		pCD->maxHeight = pCD->maxHeightLimit;
	    }
	}
	else
	{
	    /* 
	     * If the hints changed we need to adjust the maximum
	     * size (if not specified in the hints).
	     */
	    if (!firstTime &&
		((oldBaseHeight != pCD->baseHeight) ||
		 (oldHeightInc != pCD->heightInc)))
	    {
		incHeight = (pCD->maxHeight - oldBaseHeight) / oldHeightInc;
		pCD->maxHeight =  
		    (incHeight * pCD->heightInc) + pCD->baseHeight;
	    }
	    else
	    {
		/* reset the maxHeight before further processing */
		pCD->maxHeight = pCD->maxHeightLimit;
	    }
	}
	if (pCD->maxHeight > MAX_MAX_SIZE(pCD).height)
	{
	    pCD->maxHeight = MAX_MAX_SIZE(pCD).height;
	}
    }

    /*
     * Make sure not to exceed the maximumMaximumSize (width and height)
     */

    if (pCD->maxWidth > MAX_MAX_SIZE(pCD).width)
    {
	pCD->maxWidth = MAX_MAX_SIZE(pCD).width;
    }

    if (pCD->maxHeight > MAX_MAX_SIZE(pCD).height)
    {
	pCD->maxHeight = MAX_MAX_SIZE(pCD).height;
    }

    /*
     * Get the initial aspect ratios, if available.  Only use them if:
     *
     *   minAspect.y > 0
     *   maxAspect.y > 0
     *   0 <= minAspect.x / minAspect.y <= maxAspect.x / maxAspect.y 
     */

    if (flags & P_ASPECT)
    {
	pCD->minAspect.x = pNormalHints->min_aspect.x;
	pCD->minAspect.y = pNormalHints->min_aspect.y;
	pCD->maxAspect.x = pNormalHints->max_aspect.x;
	pCD->maxAspect.y = pNormalHints->max_aspect.y;

        if (pCD->minAspect.y > 0 &&
	    pCD->maxAspect.y > 0 &&
	    pCD->minAspect.x > 0 &&
	    pCD->maxAspect.x > 0 &&
	    (pCD->minAspect.x * pCD->maxAspect.y <=
	    pCD->maxAspect.x * pCD->minAspect.y))
        {
	    pCD->sizeFlags |= P_ASPECT;
	}
	else
	{
	    pCD->sizeFlags &= ~P_ASPECT;
	}
    }

    /* compute for minimum frame size */
    if ((decoration = pCD->decor) & MWM_DECOR_TITLE)
    {
	boxdim = TitleBarHeight(pCD);
	tmpMin = boxdim +
	         ((decoration & MWM_DECOR_MENU) ? boxdim : 0) +
	         ((decoration & MWM_DECOR_MINIMIZE) ? boxdim : 0) +
	         ((decoration & MWM_DECOR_MAXIMIZE) ? boxdim : 0) -
		 2*(pCD->matteWidth);
    }
    else {
	tmpMin = 0;
    }


    /*
     * Process the window gravity (for positioning):
     */

    if (flags & P_WIN_GRAVITY)
    {
	pCD->windowGravity = pNormalHints->win_gravity;
    }
    else
    {
        if (pNormalHints->icccVersion == ICCC_R2)
	{
	    pCD->windowGravity = wmGD.windowAttributes.win_gravity;
	}
	else
	{
	    pCD->windowGravity = NorthWestGravity;
	}
    }


    /*
     * Make sure that all the window sizing constraints are compatible:
     */

    /*
     * Make:
     *
     *   minWidth >= tmpMin
     *   minWidth >= max (baseWidth, widthInc) > 0
     *     & an integral number of widthInc from baseWidth.
     *   minHeight >= max (baseHeight, heightInc) > 0
     *     & an integral number of heightInc from baseHeight.
     */

    if (pCD->minWidth < tmpMin)
    {
        if ((diff = ((tmpMin - pCD->baseWidth)%pCD->widthInc)) != 0)
        {
	    pCD->minWidth = tmpMin + pCD->widthInc - diff;
        }
        else
        {
	    pCD->minWidth = tmpMin;
        }
    }

    if (pCD->minWidth < pCD->baseWidth)
    {
	pCD->minWidth = pCD->baseWidth;
    }

    if (pCD->minWidth == 0)
    {
	pCD->minWidth = pCD->widthInc;
    }
    else if ((diff = ((pCD->minWidth - pCD->baseWidth)%pCD->widthInc)) != 0)
    {
	pCD->minWidth += pCD->widthInc - diff;
    }

    if (pCD->minHeight < pCD->baseHeight)
    {
	pCD->minHeight = pCD->baseHeight;
    }

    if (pCD->minHeight == 0)
    {
	pCD->minHeight = pCD->heightInc;
    }
    else if ((diff = ((pCD->minHeight - pCD->baseHeight) % pCD->heightInc)) !=0)
    {
	pCD->minHeight += pCD->heightInc - diff;
    }

    /*
     * Make:
     *
     *   maxWidth >= minWidth 
     *     & an integral number of widthInc from baseWidth.
     *   maxHeight >= minHeight
     *     & an integral number of heightInc from baseHeight.
     */

    if (pCD->maxWidth < pCD->minWidth)
    {
	pCD->maxWidth = pCD->minWidth;
    }

    /*
     * Hack to use maxWidthLimit as the real maxWidth when maximumClientSize
     * set to 'vertical'.
     */
    if (IS_MAXIMIZE_VERTICAL(pCD))
    {
	/* go to min (full screen width, max maximum width) */
	pCD->maxWidthLimit = DisplayWidth (DISPLAY, SCREEN_FOR_CLIENT(pCD)) -
			    (2 * pCD->clientOffset.x);
    }
    else
    {
	pCD->maxWidthLimit = pCD->maxWidth;
    }

    pCD->maxWidth -= ((pCD->maxWidth - pCD->baseWidth) % pCD->widthInc);

    if (firstTime)
    {
	pCD->oldMaxWidth = pCD->maxWidth;
    }

    if (pCD->maxHeight < pCD->minHeight)
    {
	pCD->maxHeight = pCD->minHeight;
    }

    /*
     * Hack to use maxHeightLimit as the real maxHeight when maximumClientSize
     * set to 'horizontal'.
     */
    if (IS_MAXIMIZE_HORIZONTAL(pCD))
    {
	/* go to min (full screen height, max maximum height) */
	pCD->maxHeightLimit = DisplayHeight (DISPLAY, SCREEN_FOR_CLIENT(pCD)) -
			     (pCD->clientOffset.x +
			      pCD->clientOffset.y);
    }
    else
    {
	pCD->maxHeightLimit = pCD->maxHeight;
    }

    pCD->maxHeight -= ((pCD->maxHeight - pCD->baseHeight) % pCD->heightInc);

    if (firstTime)
    {
	pCD->oldMaxHeight = pCD->maxHeight;
    }

    if (!firstTime && pCD->maxConfig)
    {
	/* 
	 * If the hints changed while we were maximized then 
	 * we may need to adjust the normalized size of the window.
	 */
	if (!firstTime &&
	    ((oldBaseWidth != pCD->baseWidth) ||
	     (oldBaseHeight != pCD->baseHeight) ||
	     (oldWidthInc != pCD->widthInc) ||
	     (oldHeightInc != pCD->heightInc)))
	{
	    incWidth = (pCD->clientWidth - oldBaseWidth) / oldWidthInc;
	    incHeight = (pCD->clientHeight - oldBaseHeight) / oldHeightInc;
	    pCD->clientWidth =  
		(incWidth * pCD->widthInc) + pCD->baseWidth;
	    pCD->clientHeight =  
		(incHeight * pCD->heightInc) + pCD->baseHeight;
	}
    }

    /*
     * If using aspect ratios, make:
     *
     *  minWidth / maxHeight <= minAspect.x / minAspect.y 
     *                       <= maxAspect.x / maxAspect.y
     *                       <= maxWidth / minHeight
     */

    if (pCD->sizeFlags & P_ASPECT)
    {
        if (pCD->minWidth * pCD->minAspect.y >
	    pCD->minAspect.x * pCD->maxHeight)
        {
            pCD->minAspect.x = pCD->minWidth;
            pCD->minAspect.y = pCD->maxHeight;
	}

        if (pCD->maxAspect.x * pCD->minHeight >
	    pCD->maxWidth * pCD->maxAspect.y)
        {
            pCD->maxAspect.x = pCD->maxWidth;
            pCD->maxAspect.y = pCD->minHeight;
	}

        FixWindowSize (pCD, (unsigned int *) &(pCD->maxWidth),
	                    (unsigned int *) &(pCD->maxHeight),
			    (unsigned int) (pCD->widthInc), 
			    (unsigned int) (pCD->heightInc));
    }

    /*
     * If this is the first time, make sure the client dimensions are within 
     * range and that they satisfy any aspect ratio constraints:
     *
     *  0 < minWidth  <= clientWidth  <= maxWidth
     *  0 < minHeight <= clientHeight <= maxHeight
     *
     *  minAspect.x / minAspect.y <= clientWidth / clientHeight
     *                            <= maxAspect.x / maxAspect.y
     *
     * Initial max width/height are set to max of max size or normal
     * client size unless a maximumClientSize was specified.
     */

    if (firstTime)
    {
	if (!pCD->maximumClientSize.width)
	{
	    if (pCD->clientWidth > pCD->pSD->maximumMaximumSize.width)
	    {
		pCD->clientWidth = pCD->pSD->maximumMaximumSize.width;
	    }
	}

	if (!pCD->maximumClientSize.height)
	{
	    if (pCD->clientHeight > pCD->pSD->maximumMaximumSize.height)
	    {
		pCD->clientHeight = pCD->pSD->maximumMaximumSize.height;
	    }
	}

        FixWindowSize (pCD, (unsigned int *) &(pCD->clientWidth), 
	                    (unsigned int *) &(pCD->clientHeight),
			    (unsigned int) (pCD->widthInc), 
			    (unsigned int) (pCD->heightInc));
    }

} /* END OF FUNCTION ProcessWmNormalHints */


/*************************************<->*************************************
 *
 *  WmICCCMToXmString (wmNameProp)
 *
 *
 *  Description:
 *  -----------
 *  This function uses a property (WM_NAME or WM_ICON_NAME) that was
 *  retrieved from the window, and converts it to XmString.
 *
 *  Inputs:
 *  ------
 *  wmNameProp	- the text property
 * 
 *  Outputs:
 *  -------
 *  Return = new XmString, or NULL if the property didn't have a value.
 * 
 *************************************<->***********************************/

static XmString
WmICCCMToXmString (XTextProperty *wmNameProp)
{
  int status;
  XmString xms_return;
  XmStringTable xmsTable;
  int i, nStrings = -1;
  char msg[200];

  if (wmNameProp->value == 0 || strlen((char *)wmNameProp->value) == 0)
    {
      return (XmString)NULL;
    }

  if (((status = XmCvtTextPropertyToXmStringTable(DISPLAY, wmNameProp,
						  &xmsTable, &nStrings))
       != Success) || (nStrings <= 0))
  {
      switch (status)
      {
      case XConverterNotFound:
#ifndef MOTIF_ONE_DOT_ONE
	  sprintf(msg, GETMESSAGE (70,5,
		    "Window manager cannot convert property %.100s as clientTitle/iconTitle: XmbTextPropertyToTextList"), 
		  XGetAtomName (DISPLAY,wmNameProp->encoding));
	  Warning(msg);
#endif /* MOTIF_ONE_DOT_ONE */
	  break;

      case XNoMemory:
	  sprintf(msg, GETMESSAGE (70, 6, 
		    "insufficient memory to convert property %.100s as clientTitle/iconTitle: XmbTextPropertyToTextList"),
		  XGetAtomName(DISPLAY,wmNameProp->encoding));
	  Warning(msg);
	  break;

      case XLocaleNotSupported:
	  if ((wmNameProp->encoding == XA_STRING) ||
	      (wmNameProp->encoding == wmGD.xa_COMPOUND_TEXT))
	  {
	      sprintf(msg, LOCALE_MSG, setlocale(LC_ALL, NULL));
	  }
	  else
	  {
	      /* Atom was neither STRING nor COMPOUND_TEXT */
	      sprintf(msg, GETMESSAGE(70, 8, 
			"Window manager received unknown property as clientTitle/iconTitle: %.100s. Property ignored."),
		      XGetAtomName(DISPLAY, wmNameProp->encoding));
	  }
	  Warning(msg);
	  break;
      }

      /* Couldn't convert using Xm; apply a default */
      return XmCvtCTToXmString((char*)wmNameProp->value);
  }

  xms_return = xmsTable[0];
  for (i = 1; i < nStrings; i++)
  {
#ifdef CONCAT_TEXTLIST
      xms_return = XmStringConcatAndFree(xms_return, xmsTable[i]);
#else
      XmStringFree(xmsTable[i]);
#endif /* CONCAT_TEXTLIST */
  }
  XtFree((char *)xmsTable);

  return xms_return;
}


/*************************************<->*************************************
 *
 *  ProcessWmWindowTitle (pCD, firstTime)
 *
 *
 *  Description:
 *  -----------
 *  This function retrieves the contents of the WM_NAME property on the
 *  cient window.  A default name is set if the property does not exist.
 *
 *
 *  Inputs:
 *  ------
 *  pCD		- pointer to client data structure
 *  firstTime	- false if the window is already managed and the title
 *                is being changed.
 *
 * 
 *  Outputs:
 *  -------
 *  pCD		- clientTitle, iconTitle
 * 
 *************************************<->***********************************/

void 
ProcessWmWindowTitle (ClientData *pCD, Boolean firstTime)
{
    XTextProperty wmNameProp;
    XmString title_xms = NULL;

    if ((pCD->clientDecoration & MWM_DECOR_TITLE) &&
#ifdef WSM
	(!firstTime || HasProperty (pCD, XA_WM_NAME)) &&
#endif /* WSM */
	XGetWMName(DISPLAY, pCD->client, &wmNameProp))
    {
      title_xms = WmICCCMToXmString(&wmNameProp);
      if (wmNameProp.value)
	XFree ((char*)wmNameProp.value);
    }

    if (title_xms)
    {
      if (!firstTime && (pCD->iconTitle == pCD->clientTitle))
      {
	/*
	 * The client window title is being used for the icon title so
	 * change the icon title with the window title.
	 */
	pCD->iconTitle = title_xms;
	RedisplayIconTitle (pCD);
      }

      if ((pCD->clientFlags & CLIENT_HINTS_TITLE) &&
	  pCD->clientTitle != wmGD.clientDefaultTitle)
      {
	XmStringFree (pCD->clientTitle);
      }

      pCD->clientTitle = title_xms;
      pCD->clientFlags |= CLIENT_HINTS_TITLE;

      if (!firstTime)
      {
	DrawWindowTitle (pCD, True);
      }
    }
    /*
     * The client frame does not have a place to put the title or the WM_NAME
     * property does not exist or there was some error in getting
     * the property information, so use a default value.
     */
    else if (firstTime)
    {
	if (pCD->clientName)
        {
	    pCD->clientTitle = XmStringCreateLocalized(pCD->clientName);
        }
        else
        {
	    pCD->clientTitle = wmGD.clientDefaultTitle;
        }
    }

    /*
     * If this is a tear-off menu, then make sure title text is not clipped
     */

#ifdef PANELIST
    if ((pCD->window_status & MWM_TEAROFF_WINDOW) ||
        (pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUBPANEL))
#else /* PANELIST */
    if (pCD->window_status & MWM_TEAROFF_WINDOW)
#endif /* PANELIST */
    {
	unsigned int boxdim = TitleBarHeight (pCD);
	unsigned long decor = pCD->decor;
	XmFontList  fontList;
	int minWidth;

	if (DECOUPLE_TITLE_APPEARANCE(pCD))
	    fontList = CLIENT_TITLE_APPEARANCE(pCD).fontList;
	else
	    fontList = CLIENT_APPEARANCE(pCD).fontList;

	/*
	 * Calculations derived from GetTextBox() and GetFramePartInfo()
	 */
	minWidth = XmStringWidth(fontList, pCD->clientTitle) +
#ifdef PANELIST
	    ((pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUBPANEL) ? 4 : 0) +
#endif /* PANELIST */
			    ((decor & MWM_DECOR_MENU) ? boxdim : 0) +
			    ((decor & MWM_DECOR_MINIMIZE) ? boxdim : 0) +
			    ((decor & MWM_DECOR_MAXIMIZE) ? boxdim : 0) +
			      WM_TOP_TITLE_SHADOW + WM_BOTTOM_TITLE_SHADOW +
				WM_TOP_TITLE_PADDING + WM_BOTTOM_TITLE_PADDING;

	if (minWidth > pCD->minWidth)
	{
	    pCD->minWidth = minWidth;
	}
#ifdef PANELIST
	if ((pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUBPANEL) &&
            (pCD->clientWidth < pCD->minWidth))
	{
	    FixSubpanelEmbeddedClientGeometry (pCD);
	}
#endif /* PANELIST */
    }

} /* END OF FUNCTION ProcessWmWindowTitle */

#ifdef PANELIST

/*************************************<->*************************************
 *
 *  FixSubpanelEmbeddedClientGeometry ( pCD )
 *
 *
 *  Description:
 *  -----------
 *  This function adjusts the embedded clients in a subpanel if the 
 *  geometry of the subpanel is adjusted.
 *
 *
 *  Inputs:
 *  ------
 *  pCD		- pointer to client data structure
 *
 * 
 *  Outputs:
 *  -------
 *
 *  Comment:
 *  -------
 *  Only handles change in width right now.
 *
 *************************************<->***********************************/

static void 
FixSubpanelEmbeddedClientGeometry (ClientData *pCD)
{
    WmScreenData *pSD = PSD_FOR_CLIENT(pCD);
    Widget wSubpanel;
    Arg    al[5];
    int    ac;

    /*
     * Get the widget for the subpanel
     */
    wSubpanel = WmPanelistWindowToSubpanel (DISPLAY1, pCD->client);

    if (pSD->wPanelist && wSubpanel)
    {
	WmFpEmbeddedClientData  *pECD; 
	int i;

	/*
	 * set new shell width to minimum width
	 */
	if (pCD->clientWidth < pCD->minWidth)
	{
	    ac = 0;
	    XtSetArg (al[ac], XmNwidth, pCD->minWidth);	ac++;
	    XtSetValues (wSubpanel, al, ac);
	}

	/*
	 * Cause update of client geometries.
	 */
/*	WmPanelistSetClientGeometry (pSD->wPanelist);   */

	/*
	 * Update all affected reparented controls.
	 */

	for (i=0; i<pSD->numEmbeddedClients; i++)
	{
	    pECD =  &(((WmFpEmbeddedClientData *) pSD->pECD)[i]);

	    if (pECD->pCD)
	    {
		ClientData *pCD2 = pECD->pCD;

		if ((pCD2->clientWidth !=  pECD->width) ||
		    (pCD2->clientHeight != pECD->height) ||
		    (pCD2->clientX != pECD->x) ||
		    (pCD2->clientY != pECD->y))
		{
		    pCD2->clientX = pECD->x;
		    pCD2->clientY = pECD->y;
		    pCD2->clientWidth = pECD->width;
		    pCD2->clientHeight = pECD->height;

		    XMoveResizeWindow (DISPLAY1, pCD2->client, 
			pECD->x, pECD->y, pECD->width, pECD->height);
		}
	    }
	}
    }
} /* END OF FUNCTION FixEmbeddedClientGeometry */

#endif /* PANELIST */


/*************************************<->*************************************
 *
 *  ProcessWmIconTitle (pCD, firstTime)
 *
 *
 *  Description:
 *  -----------
 *  This function retrieves the contents of the WM_ICON_NAME property on the
 *  cient window.  The value of the property is a string that is used for the
 *  icon title.  A default title is set if the property does not exist.
 *
 *
 *  Inputs:
 *  ------
 *  pCD		- pointer to client data structure
 *
 *  firstTime	- false if the window is already managed and the title
 *                is being changed.
 *
 * 
 *  Outputs:
 *  -------
 *  pCD		- iconTitle
 * 
 *************************************<->***********************************/

void 
ProcessWmIconTitle (ClientData *pCD, Boolean firstTime)
{
  XTextProperty wmIconNameProp;
  XmString icon_xms = NULL;

  if ((pCD->clientFunctions & MWM_FUNC_MINIMIZE) &&
      (pCD->transientLeader == NULL) &&
#ifdef WSM
      (!firstTime || HasProperty(pCD, XA_WM_ICON_NAME)) &&
#endif /* WSM */
      XGetWMIconName (DISPLAY, pCD->client, &wmIconNameProp))
  {
    icon_xms = WmICCCMToXmString(&wmIconNameProp);
    if (wmIconNameProp.value)
      XFree ((char*)wmIconNameProp.value);
  }

  if (icon_xms)
  {
    if ((pCD->iconFlags & ICON_HINTS_TITLE) &&
	pCD->iconTitle != wmGD.iconDefaultTitle)
    {
      XmStringFree (pCD->iconTitle);
    }

    pCD->iconTitle = icon_xms;
    pCD->iconFlags |= ICON_HINTS_TITLE;

    if (!firstTime)
    {
      RedisplayIconTitle (pCD);
    }
  }
  /*
   * The WM_ICON_NAME property does not exist (or there was some error
   * in getting * the property information), so use a default value.
   */
  else if (firstTime)
  {
    if (pCD->clientTitle && (pCD->clientTitle != wmGD.clientDefaultTitle))
    {
      pCD->iconTitle = pCD->clientTitle;
    }
    else
    {
      pCD->iconTitle = wmGD.iconDefaultTitle;
    }
  }

} /* END OF FUNCTION ProcessWmIconTitle */



/*************************************<->*************************************
 *
 *  ProcessWmTransientFor (pCD)
 *
 *
 *  Description:
 *  -----------
 *  This function retrieves the contents of the WM_TRANSIENT_FOR property on
 *  the cient window.
 *
 *
 *  Inputs:
 *  ------
 *  pCD = pointer to the client data structure for the window with the property
 *
 * 
 *  Outputs:
 *  -------
 *  pCD.transientFor = if tranient then this is the associated main window
 *
 *  pCD.clientFlags = indicate that this is a transient window
 * 
 *************************************<->***********************************/

void 
ProcessWmTransientFor (ClientData *pCD)
{
    Window window;
    ClientData *leader;


#ifdef WSM
    if ((HasProperty (pCD, XA_WM_TRANSIENT_FOR)) &&
	(XGetTransientForHint (DISPLAY, pCD->client, &window)))
#else /* WSM */
    if (XGetTransientForHint (DISPLAY, pCD->client, &window))
#endif /* WSM */
    {
	pCD->clientFlags |= CLIENT_TRANSIENT;

	/*
	 * Only save the (leader) transientFor window if it is NOT the
	 * client window and it is already managed by the window manager.
	 */

	if ((pCD->client != window) &&
	    !XFindContext (DISPLAY, window, wmGD.windowContextType,
		(caddr_t *)&leader))
	{
	    pCD->transientFor = window;
	    pCD->transientLeader = leader;
	}
    }
    else {    /* else this is not a transient window */
	pCD->clientFlags &= ~CLIENT_TRANSIENT;
	pCD->transientFor = (Window)0L;
	pCD->transientLeader = NULL;
    }


} /* END OF FUNCTION ProcessWmTransientFor */



/*************************************<->*************************************
 *
 *  MakeSystemMenu (pCD)
 *
 *
 *  Description:
 *  -----------
 *  This function finds or makes a system menu for the client.  A check
 *  is made for the _MWM_MENU property and, if present, client-specific
 *  items are added to the custom system menu.  Any custom system menu
 *  must be destroyed when the client is unmanaged (or killed).
 *
 *
 *  Inputs:
 *  ------
 *  pCD = pointer to the client data structure for the managed window
 *
 * 
 *  Outputs:
 *  -------
 *  pCD.systemMenuSpec = system menu specification for the client, not added
 *                       to wmGD.acceleratorMenuSpecs 
 *
 *************************************<->***********************************/

void 
MakeSystemMenu (ClientData *pCD)
{
#if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
    MenuItem *lastItem;
#endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */

    pCD->mwmMenuItems = GetMwmMenuItems(pCD);
    pCD->systemMenuSpec = 
       MAKE_MENU (PSD_FOR_CLIENT(pCD), pCD, pCD->systemMenu, F_CONTEXT_WINDOW,
	         F_CONTEXT_WINDOW|F_CONTEXT_ICON, pCD->mwmMenuItems, TRUE);

#ifdef NO_MESSAGE_CATALOG
    if (pCD->systemMenuSpec == NULL)
    {
        /*
	 * As the lookup has failed, let's try just one more time.
         */
	Warning("Retrying - using builtin window menu\n");

	pCD->systemMenuSpec =
	  MAKE_MENU(PSD_FOR_CLIENT(pCD), pCD, builtinSystemMenuName,
		    F_CONTEXT_WINDOW,
		    F_CONTEXT_WINDOW|F_CONTEXT_ICON, pCD->mwmMenuItems, TRUE);
    }
#endif

#if defined(MWM_QATS_PROTOCOL)
    /* Added to fix CDExc23338
     * Not sure what the MWM_QATS_PROTOCOL is trying to accomplish here,
     * but this code is causing the system menu to loose it's default
     * actions whenever client defined actions are added.  I thought
     * it prudent to minimize the changes.  It could be that the
     * #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
     * should be
     * #if ((!defined(WSM)) && defined(MWM_QATS_PROTOCOL))
     * throughout the wm code, but I am loath to make such a change
     * without any documentation.
     */

#if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
    /** BEGIN FIX CR 6941 **/

    /* if we still don't have a menu spec, then just abort. */
    if (pCD->systemMenuSpec == NULL)
      return;

    pCD->systemMenuSpec = DuplicateMenuSpec(pCD->systemMenuSpec);
    XtFree(pCD->systemMenuSpec->name);
    pCD->systemMenuSpec->name = XtNewString("ProtocolsMenu");

    /* Find the last menu item in the menu spec's list. */
    for (lastItem = pCD->systemMenuSpec->menuItems;
	 lastItem->nextMenuItem != (MenuItem *) NULL;
	 lastItem = lastItem->nextMenuItem)
      /*EMPTY*/;
    lastItem->nextMenuItem = pCD->mwmMenuItems;

    /* Now recreate the menu widgets since we've appended the 
       protocol menu items */
    DestroyMenuSpecWidgets(pCD->systemMenuSpec);
    pCD->systemMenuSpec->menuWidget =
      CreateMenuWidget (PSD_FOR_CLIENT(pCD), pCD, "ProtocolsMenu",
			PSD_FOR_CLIENT(pCD)->screenTopLevelW, TRUE,
			pCD->systemMenuSpec, NULL);
    /** END FIX CR 6941 **/
#endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
#endif /* defined(MWM_QATS_PROTOCOL) */

} /* END OF FUNCTION MakeSystemMenu */



/*************************************<->*************************************
 *
 *  InitCColormapData (pCD)
 *
 *
 *  Description:
 *  -----------
 *  This function initializes colormap data for the client window that is
 *  by the window manager in maintaining the colormap focus.  This may
 *  involve retrieving and processing properties that deal with subwindow
 *  colormaps.
 *
 *
 *  Inputs:
 *  ------
 *  pCD = pointer to the client data structure for the managed window
 *
 * 
 *  Outputs:
 *  -------
 *  pCD.clientColormap = client colormap to be installed when the client
 *                       window gets the colormap focus
 *
 *  pCD = (cmapWindows, clientCmapList, clientCmapCount, clientCmapIndex)
 *
 *************************************<->***********************************/

void 
InitCColormapData (ClientData *pCD)
{

    if (wmGD.windowAttributes.colormap == None)
    {
	pCD->clientColormap = WORKSPACE_COLORMAP(pCD);
    }
    else
    {
	pCD->clientColormap = wmGD.windowAttributes.colormap;
    }

    /*
     * Process subwindow colormap windows if they are specified.
     */

    ProcessWmColormapWindows (pCD);
    

} /* END OF FUNCTION InitCColormapData */



/*************************************<->*************************************
 *
 *  CalculateGravityOffset (pCD, xoff, yoff)
 *
 *
 *  Description:
 *  -----------
 *  This function calculates the window offsets based on the window gravity
 *  and the window frame client offset.
 *
 *
 *  Inputs:
 *  ------
 *  pCD = pointer to client data (client window configuration fields)
 *  xoff = pointer to xoffset
 *  yoff = pointer to yoffset
 *
 * 
 *  Outputs:
 *  -------
 *  xoff = pointer to xoffset set
 *  yoff = pointer to yoffset set
 * 
 *************************************<->***********************************/

void
CalculateGravityOffset (ClientData *pCD, int *xoff, int *yoff)
{
    int borderWidth = pCD->xBorderWidth;

    if (pCD->windowGravity < ForgetGravity ||
	pCD->windowGravity > StaticGravity)
    {
	*xoff = 0;
	*yoff = 0;
    }
    else
    {
	switch (pCD->windowGravity)
	{
	    case NorthWestGravity:
	    default:
	    {
		*xoff = pCD->clientOffset.x;
		*yoff = pCD->clientOffset.y;
		break;
	    }

	    case NorthGravity:
	    {
		*xoff = borderWidth;
		*yoff = pCD->clientOffset.y;
		break;
	    }
                
	    case NorthEastGravity:
	    {
		*xoff = -(pCD->clientOffset.x - (2 * borderWidth));
		*yoff = pCD->clientOffset.y;
		break;
	    }

	    case EastGravity:
	    {
		*xoff = -(pCD->clientOffset.x - (2 * borderWidth));
		*yoff = borderWidth +
				(pCD->clientOffset.y - pCD->clientOffset.x)/2;
		break;
	    }

	    case SouthEastGravity:
	    {
		*xoff = -(pCD->clientOffset.x - (2 * borderWidth));
		*yoff = -(pCD->clientOffset.x - (2 * borderWidth));
		break;
	    }

	    case SouthGravity:
	    {
		*xoff = borderWidth;
		*yoff = -(pCD->clientOffset.x - (2 * borderWidth));
		break;
	    }

	    case SouthWestGravity:
	    {
		*xoff = pCD->clientOffset.x;
		*yoff = -(pCD->clientOffset.x - (2 * borderWidth));
		break;
	    }

	    case WestGravity:
	    {
		*xoff = pCD->clientOffset.x;
		*yoff = borderWidth +
				(pCD->clientOffset.y - pCD->clientOffset.x)/2;
		break;
	    }

	    case CenterGravity:
	    {
		*xoff = 0;
		*yoff = 0;
		break;
	    }
	}
    }
} /* END OF FUNCTION CalculateGravityOffset */



/*************************************<->*************************************
 *
 *  InitClientPlacement (pCD, manageFlags)
 *
 *
 *  Description:
 *  -----------
 *  This function sets up the initial client window placement (for both
 *  the normal and maximized state).
 *
 *
 *  Inputs:
 *  ------
 *  pCD = pointer to client data (client window configuration fields)
 *
 *  manageFlags = flags that indicate wm state information (e.g. whether
 *                the window manager is starting up or restarting)
 *
 * 
 *  Outputs:
 *  -------
 *  Return = True if position changed by this routine.
 *  pCD = changes to the client window configuration fields
 * 
 *************************************<->***********************************/

Boolean 
InitClientPlacement (ClientData *pCD, long manageFlags)
{
    Boolean interactivelyPlaced = False;
    Boolean autoPlaced = False;
    Boolean rval = False;
    int xoff, yoff;
    int origX, origY, origWidth, origHeight;
#ifdef WSM
    int iwsc;
#endif /* WSM */


    /*
     * Save initial client values
     */
    origX = pCD->clientX;
    origY = pCD->clientY;
    origWidth = pCD->clientWidth;
    origHeight = pCD->clientHeight;

    /*
     * Do interactive placement if...
     *     + the resource is turned on 
     *     + the window's coming up on the active screen
     *
     * Don't do it if...
     *     + position specified in DB or by Session Manager
     *     + the user has specified a position
     *     + the window is coming up iconic 
     *     + the window is transient
     *     + we're system modal
     */

    if (wmGD.interactivePlacement && 
	(!(pCD->clientFlags & (SM_X | SM_Y))) &&
	!(pCD->sizeFlags & US_POSITION) &&
	(pCD->clientState != MINIMIZED_STATE) &&
        (manageFlags == MANAGEW_NORMAL) &&
	!(pCD->clientFlags & CLIENT_TRANSIENT) &&
	(pCD->inputMode != MWM_INPUT_SYSTEM_MODAL) &&
#ifdef WSM
	(ClientInWorkspace(PSD_FOR_CLIENT(pCD)->pActiveWS, pCD)))
#else /* WSM */
	(PSD_FOR_CLIENT(pCD) == ACTIVE_PSD))
#endif /* WSM */
    {
	/*
	 * Interactively place the window on the screen.
	 */
	interactivelyPlaced = True;
	PlaceWindowInteractively (pCD);
    }


    /*
     * Check out the configuration values to insure that they are within
     * the constraints.
     */

    FixWindowConfiguration (pCD, (unsigned int *) &(pCD->clientWidth), 
	                         (unsigned int *) &(pCD->clientHeight),
				 (unsigned int) (pCD->widthInc), 
	                         (unsigned int) (pCD->heightInc));

    /*
     * Do autoplacement of the client window if appropriate.
     */

    if ((manageFlags == MANAGEW_NORMAL) && !interactivelyPlaced &&
	(!(pCD->clientFlags & (SM_X | SM_Y))) &&
	!(pCD->sizeFlags & US_POSITION) &&
	!(pCD->clientFlags & CLIENT_TRANSIENT) &&
	(pCD->inputMode != MWM_INPUT_SYSTEM_MODAL) && wmGD.clientAutoPlace)
    {
	/*
	 * if (PPosition is on or nonzero), then use current value for
	 * clientX and clientY which was set to windowAttributes.x,y
	 * by ProcessWmNormalHints(), else autoplace client.
	 */

	if ((pCD->sizeFlags & P_POSITION) &&
	    ((pCD->usePPosition == USE_PPOSITION_ON) ||
	     ((pCD->usePPosition == USE_PPOSITION_NONZERO) &&
	      ((pCD->clientX != 0) || (pCD->clientY != 0)))))
	{
	    /* do nothing */
	}
	else
	{
	    FindClientPlacement (pCD);
	    autoPlaced = True;
	}
    }

    /*
     * Do PositionIsFrame processing:
     * Use window gravity to allow the user to specify the window 
     * position on the screen  without having to know the dimensions 
     * of the decoration that mwm is adding.
     */

    if ((wmGD.positionIsFrame) &&
	!interactivelyPlaced && !autoPlaced)
    {
	CalculateGravityOffset (pCD, &xoff, &yoff);
	if (!(pCD->clientFlags & SM_X))
	    pCD->clientX += xoff;
	if (!(pCD->clientFlags & SM_Y))
	    pCD->clientY += yoff;
    }


    /*
     * Do PositionOnScreen processing:
     */


#ifdef WSM
#ifdef PANELIST
    if (pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUBPANEL)
    {
	if (pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUB_RESTORED)
	{
	    SetFrameInfo (pCD);   
	}
	else
	{
	    AdjustSlideOutGeometry (pCD);
	}
    }
    else
#endif /* PANELIST */
#endif /* WSM */
    if (((wmGD.positionOnScreen) && !interactivelyPlaced) &&
	(!(pCD->clientFlags & (SM_X | SM_Y))))
    {
	PlaceFrameOnScreen (pCD, &pCD->clientX, &pCD->clientY,
	    pCD->clientWidth, pCD->clientHeight);
    }


    /*
     * Position the maximized frame:
     */

    pCD->maxX = pCD->clientX;
    pCD->maxY = pCD->clientY;
    PlaceFrameOnScreen (pCD, &pCD->maxX, &pCD->maxY, pCD->maxWidth,
	pCD->maxHeight);


    if (!wmGD.iconAutoPlace)
    {
#ifdef WSM
	if (!(pCD->iconFlags & ICON_HINTS_POSITION))
	{
	    for (iwsc=0; iwsc<pCD->numInhabited; iwsc++)
	    {
		pCD->pWsList[iwsc].iconX = pCD->clientX;
		pCD->pWsList[iwsc].iconY = pCD->clientY;
		PlaceIconOnScreen (pCD, &pCD->pWsList[iwsc].iconX, 
					&pCD->pWsList[iwsc].iconY);
	    }
	}
#else /* WSM */
	if (!(pCD->iconFlags & ICON_HINTS_POSITION))
	{
	    pCD->iconX = pCD->clientX;
	    pCD->iconY = pCD->clientY;
	}
	PlaceIconOnScreen (pCD, &pCD->iconX, &pCD->iconY);
#endif /* WSM */
    }

    /* 
     * if client size or position has been changed by this routine,
     * then indicate in return value
     */
    if ((origX != pCD->clientX) || (origY != pCD->clientY) ||
	(origWidth != pCD->clientWidth) || (origHeight != pCD->clientHeight))
    {
	rval = True;
    }

    return (rval);

} /* END OF FUNCTION InitClientPlacement */

#ifdef PANELIST

/******************************<->*************************************
 *
 * void AdjustSlideOutGeometry (pCD)
 *
 *  Description:
 *  -----------
 *  Adjusts the geometry of the slide out panel
 *
 *  Inputs:
 *  ------
 *  pCD = pointer to a client data of slide out
 * 
 *  Outputs:
 *  -------
 *
 *  Comments:
 *  --------
 *  Subpanel is to appear above or below the front panel, centered
 *  on the vertical axis of the spawning control.
 ******************************<->***********************************/
static void 
AdjustSlideOutGeometry ( ClientData *pCD)
{
    ClientData  *pCD_FP = NULL;
    WmPanelistObject  pPanelist;

    pCD->slideDirection = SLIDE_NORTH;	/* assume up for now */
    pPanelist = (WmPanelistObject) pCD->pSD->wPanelist;
    (void) XFindContext (DISPLAY, XtWindow(O_Shell(pPanelist)),
		  wmGD.windowContextType, (caddr_t *)&pCD_FP);

    if (pCD_FP)
    {
	/*
	* Adjust slide up position if coming from front
	* panel. 
	* (Assumes no nesting of panels !!!)
	* (Assumes horizontal oriented front panel!!!)
	*/
	if (pCD->transientLeader == pCD_FP)
	{
	    /* 
	     * Subpanel should be sort-of centered already,
	     * adjust by width of window manager frame.
	     */
	    pCD->clientX -= pCD->frameInfo.lowerBorderWidth;

	    /* 
	     * Adjust to slide up above front panel.
	     */
	    pCD->clientY = pCD_FP->frameInfo.y - 
			 pCD->frameInfo.lowerBorderWidth -
			 pCD->clientHeight + 3;

/*  RICK -- added the (+ 3)  */


	    if (pCD->clientY < 0)
	    {
		/*
		 * Adjust to slide down below front panel.
		 */
	        pCD->clientY = pCD_FP->frameInfo.y +
			     pCD_FP->frameInfo.height +
			     pCD->frameInfo.titleBarHeight +
			     pCD->frameInfo.upperBorderWidth - 3;
	        pCD->slideDirection = SLIDE_SOUTH;
/*  RICK -- added the (- 3)  */
	    }

	    if ((pCD->clientY + pCD->clientHeight +
		   pCD->frameInfo.lowerBorderWidth) > 
		XDisplayHeight (DISPLAY, pCD->pSD->screen))
	    {
	       /*
		* If the bottom of the slide-up is off the bottom
		* of the screen, then don't slide, just pop it up.
		*/
	       pCD->slideDirection = SLIDE_NOT;
	    }

	    PlaceFrameOnScreen (pCD, &pCD->clientX, &pCD->clientY,
		    pCD->clientWidth, pCD->clientHeight);
        }
	SetFrameInfo (pCD);
    }
}
#endif  /* PANELIST */


/*************************************<->*************************************
 *
 *  PlaceFrameOnScreen (pCD, pX, pY, w, h)
 *
 *
 *  Description:
 *  -----------
 *  This function is used to nudge a client window so that it is totally
 *  onscreen if possible.  At least the top left corner will be onscreen.
 *
 *
 *  Inputs:
 *  ------
 *  pCD		- pointer to client data
 *  pX		- pointer to x-coord
 *  pY		- pointer to y-coord
 *  w		- width of window
 *  h		- height of window
 *
 * 
 *  Outputs:
 *  -------
 *  *pX		- new x-coord
 *  *pY		- new y-coord
 *
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/

void 
PlaceFrameOnScreen (ClientData *pCD, int *pX, int *pY, int w, int h)
{
    int clientOffsetX;
    int clientOffsetY;
    int frameX;
    int frameY;
    int frameWidth;
    int frameHeight;
    int screenHeight;
    int screenWidth;


    clientOffsetX = pCD->clientOffset.x;
    clientOffsetY = pCD->clientOffset.y;
    frameX = *pX - clientOffsetX;
    frameY = *pY - clientOffsetY;
    frameWidth = w + (2 * clientOffsetX);
    frameHeight = h + clientOffsetX + clientOffsetY;
    screenWidth = DisplayWidth (DISPLAY, SCREEN_FOR_CLIENT(pCD));
    screenHeight = DisplayHeight (DISPLAY, SCREEN_FOR_CLIENT(pCD));

    if ((frameX + frameWidth) > screenWidth)
    {
        frameX -= (frameX + frameWidth) - screenWidth;
    }
    if ((frameY + frameHeight) > screenHeight)
    {
        frameY -= (frameY + frameHeight) - screenHeight;
    }
    if (frameX < 0)
    {
        frameX = 0;
    }
    if (frameY < 0)
    {
        frameY = 0;
    }

    *pX = frameX + clientOffsetX;
    *pY = frameY + clientOffsetY;

} /* END OF FUNCTION PlaceFrameOnScreen */



/*************************************<->*************************************
 *
 *  PlaceIconOnScreen (pCD, pX, pY)
 *
 *
 *  Description:
 *  -----------
 *  This function positions an icon on-screen.
 *
 *
 *  Inputs:
 *  ------
 *  pCD		- pointer to client data
 *  pX		- pointer to x-coord
 *  pY		- pointer to y-coord
 * 
 *  Outputs:
 *  -------
 *  *pX		- new x-coord
 *  *pY		- new y-coord
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/

void 
PlaceIconOnScreen (ClientData *pCD, int *pX, int *pY)
{
    int screenWidth;
    int screenHeight;
    int iconX;
    int iconY;


    screenWidth = DisplayWidth (DISPLAY, SCREEN_FOR_CLIENT(pCD));
    screenHeight = DisplayHeight (DISPLAY, SCREEN_FOR_CLIENT(pCD));
    iconX = *pX;
    iconY = *pY;

    if ((iconX + ICON_WIDTH(pCD)) > screenWidth)
    {
        iconX = screenWidth - ICON_WIDTH(pCD);
    }
    else if (iconX < 0)
    {
        iconX = 0;
    }

    if ((iconY + ICON_HEIGHT(pCD)) > screenHeight)
    {
        iconY = screenHeight - ICON_HEIGHT(pCD);
    }
    else if (iconY < 0)
    {
        iconY = 0;
    }

    *pX = iconX;
    *pY = iconY;


} /* END OF FUNCTION PlaceIconOnScreen */



/*************************************<->*************************************
 *
 *  FixWindowConfiguration (pCD, pWidth, pHeight, widthInc, heightInc)
 *
 *
 *  Description:
 *  -----------
 *  This function adjusts the configuration for the client window so that
 *  it is in line with the client window's sizing constraints.
 *
 *
 *  Inputs:
 *  ------
 *  pCD = a pointer to the client window data
 *  pWidth, pHeight = pointers to the window configuration values
 *  widthInc, heightInc = window size increment values
 *
 * 
 *  Outputs:
 *  -------
 *  pWidth, pHeight = adjusted configuration values are returned here
 *
 * 
 *************************************<->***********************************/

void 
FixWindowConfiguration (ClientData *pCD, unsigned int *pWidth, unsigned int *pHeight, unsigned int widthInc, unsigned int heightInc)
{
    register int  delta;

    /*
     * Make sure we're on width/height increment boundaries.
     */

    if ((int) *pWidth < pCD->minWidth)
    {
	*pWidth = pCD->minWidth;
    }
    else if ((delta = (*pWidth - pCD->baseWidth) % pCD->widthInc))
    {
	*pWidth -= delta;
    }

    if ((int) *pHeight < pCD->minHeight)
    {
	*pHeight = pCD->minHeight;
    }
    else if ((delta = (*pHeight - pCD->baseHeight) % pCD->heightInc))
    {
	*pHeight -= delta;
    }

    /*
     * Constrain size within bounds.
     */

    FixWindowSize (pCD, pWidth, pHeight, widthInc, heightInc);

} /* END OF FUNCTION FixWindowConfiguration */



/*************************************<->*************************************
 *
 *  FixWindowSize (pCD, pWidth, pHeight, widthInc, heightInc)
 *
 *
 *  Description:
 *  -----------
 *  This function adjusts the client window width and height so that
 *  it is in line with its sizing constraints.
 *
 *
 *  Inputs:
 *  ------
 *  pCD = a pointer to the client window data
 *  pWidth, pHeight = pointers to the window size values
 *  widthInc, heightInc = window size increment values
 *  pWS->limitResize 
 *
 * 
 *  Outputs:
 *  -------
 *  pWidth, pHeight = adjusted size values.
 *
 * 
 *************************************<->***********************************/

void 
FixWindowSize (ClientData *pCD, unsigned int *pWidth, unsigned int *pHeight, unsigned int widthInc, unsigned int heightInc)
{
    register int  deltaW;
    register int  deltaH;
    WmScreenData *pSD = pCD->pSD;

    /*
     * All occurances of maxHeight and maxWidth in this routing has been
     * hacked to use maxHeightLimit and maxWidthLimit as the real max when
     * maximumClientSize is set to 'horizontal' or 'vertical', since
     * pCD->maxHeight and pCD->maxWidth is fiddle to on reconfiguration.
     */

    if ((int) *pWidth < pCD->minWidth)
    {
	*pWidth = pCD->minWidth;
    }
    else if (*pWidth > pCD->maxWidthLimit &&
             pSD->limitResize && 
	     !(pCD->clientFlags & CLIENT_WM_CLIENTS))
    {
	*pWidth = pCD->maxWidthLimit;
    }

    if ((int) *pHeight < pCD->minHeight)
    {
	*pHeight = pCD->minHeight;
    }
    else if (*pHeight > pCD->maxHeightLimit &&
             pSD->limitResize && 
	     !(pCD->clientFlags & CLIENT_WM_CLIENTS))
    {
	*pHeight = pCD->maxHeightLimit;
    }

    if ((pCD->sizeFlags & P_ASPECT) &&
        *pWidth * pCD->maxAspect.y > *pHeight * pCD->maxAspect.x)
    /* 
     * Client aspect is too big.
     * Candidate height >= client height:
     *   Try to increase the client's height without violating bounds.
     *   If this fails, use maximum height and try to decrease its width.
     * Candidate height < client height:
     *   Try to decrease the client's width without violating bounds.
     *   If this fails, use minimum width and try to increase its height.
     */
    {
        if ((*pHeight >= pCD->clientHeight) ||
            (*pWidth > pCD->clientWidth))
        /* 
         * Candidate height >= client height:
         *   Try to increase the client's height without violating bounds.
         *   If this fails, use maximum height and try to decrease its width.
	 */
        {
            deltaH = makemult (*pWidth * pCD->maxAspect.y / pCD->maxAspect.x -
		               *pHeight, heightInc);
	    if (*pHeight + deltaH <= pCD->maxHeightLimit ||
                !pSD->limitResize ||
		pCD->clientFlags & CLIENT_WM_CLIENTS)
	    {
	        *pHeight += deltaH;
	    }
	    else 
	    {
	        *pHeight = pCD->maxHeightLimit;
	        deltaW = makemult (*pWidth - *pHeight * pCD->maxAspect.x / 
			           pCD->maxAspect.y, widthInc);
	        if (*pWidth - deltaW >= pCD->minWidth)
	        {
	            *pWidth -= deltaW;
                }  
		else
		{
	            *pWidth = pCD->minWidth;
		}
	    }
	}
	else
        /*
         * Candidate height < client height and candidate width <= client width.
         *   Try to decrease the client's width without violating bounds.
         *   If this fails, use minimum width and try to increase its height.
	 */
	{
	    deltaW = makemult (*pWidth - *pHeight * pCD->maxAspect.x / 
			       pCD->maxAspect.y, widthInc);

	    if (*pWidth - deltaW >= pCD->minWidth)
	    {
	        *pWidth -= deltaW;
            }  
	    else
	    {
	        *pWidth = pCD->minWidth;
                deltaH = makemult (*pWidth * pCD->maxAspect.y / 
				   pCD->maxAspect.x - *pHeight, heightInc);
	        if (*pHeight + deltaH <= pCD->maxHeightLimit ||
                     !pSD->limitResize ||
	             pCD->clientFlags & CLIENT_WM_CLIENTS)
	        {
	            *pHeight += deltaH;
	        }
		else
		{
	            *pHeight = pCD->maxHeightLimit;
		}
	    }
	}
    }

    else if ((pCD->sizeFlags & P_ASPECT) &&
             *pHeight * pCD->minAspect.x > *pWidth * pCD->minAspect.y)
    /* 
     * Client aspect is too small.
     * Candidate width >= client width:
     *   Try to increase the client's width without violating bounds.
     *   If this fails, use maximum width and try to decrease its height.
     * Candidate width < client width:
     *   Try to decrease the client's height without violating bounds.
     *   If this fails, use minimum height and try to increase its width.
     */
    {
        if ((*pWidth >= pCD->clientWidth) ||
            (*pHeight > pCD->clientHeight))
        /*
         * Candidate width >= client width:
         *   Try to increase the client's width without violating bounds.
         *   If this fails, use maximum width and try to decrease its height.
	 */
	{
            deltaW = makemult (*pHeight * pCD->minAspect.x / pCD->minAspect.y -
			       *pWidth, widthInc);
	    if (*pWidth + deltaW <= pCD->maxWidthLimit ||
                !pSD->limitResize ||
	        pCD->clientFlags & CLIENT_WM_CLIENTS)
	    {
	        *pWidth += deltaW;
	    }
	    else
	    {
	        *pWidth = pCD->maxWidthLimit;
	        deltaH = makemult (*pHeight - *pWidth * pCD->minAspect.y / 
			           pCD->minAspect.x, heightInc); 
	        if (*pHeight - deltaH >= pCD->minHeight)
	        {
	            *pHeight -= deltaH;
                }
		else
		{
	            *pHeight = pCD->minHeight;
		}
	    }
	}
	else
        /*
         * Candidate width < client width and Candidate height <= client height:
         *   Try to decrease the client's height without violating bounds.
         *   If this fails, use minimum height and try to increase its width.
	 */
	{
	    deltaH = makemult (*pHeight - *pWidth * pCD->minAspect.y / 
			       pCD->minAspect.x, heightInc); 
	    if (*pHeight - deltaH >= pCD->minHeight)
	    {
	        *pHeight -= deltaH;
            }
	    else
	    {
	        *pHeight = pCD->minHeight;
                deltaW = makemult (*pHeight * pCD->minAspect.x / 
				   pCD->minAspect.y - *pWidth, widthInc);
	        if (*pWidth + deltaW <= pCD->maxWidthLimit ||
                     !pSD->limitResize ||
	             pCD->clientFlags & CLIENT_WM_CLIENTS)
	        {
	            *pWidth += deltaW;
	        }
		else
		{
	            *pWidth = pCD->maxWidthLimit;
		}
	    }
	}
    }
} /* END OF FUNCTION FixWindowSize */



/*************************************<->*************************************
 *
 *  FindClientPlacement (pCD)
 *
 *
 *  Description:
 *  -----------
 *  This function finds a position for the client window on the screen.
 *  Windows positions are stepped down the screen.  An attempt is made
 *  to keep windows from being clipped by the edge of the screen.
 *
 *
 *  Inputs:
 *  ------
 *  pCD = pointer to client data (client window configuration fields)
 *
 * 
 *  Outputs:
 *  -------
 *  pCD = changes to the client window configuration fields
 * 
 *************************************<->***********************************/

void 
FindClientPlacement (ClientData *pCD)
{
    static Boolean clientPlacementInitialized = False;
    static int clientPlacementOffset;
    static int clientPlacementX;
    static int clientPlacementY;
    static int clientPlacementOrigin;
    static int clientPlacementXOrigin;

    Boolean placed = False;
    int frameWidth;
    int frameHeight;
    int screenWidth;
    int screenHeight;
    int borderWidth = 0;
    Boolean offScreenX;
    Boolean offScreenY;


    if (!clientPlacementInitialized)
    {
	if (pCD->clientDecoration & WM_DECOR_RESIZEH)
	{
	    borderWidth = ((RESIZE_BORDER_WIDTH(pCD) > FRAME_BORDER_WIDTH(pCD))
			  ? RESIZE_BORDER_WIDTH(pCD) : FRAME_BORDER_WIDTH(pCD));
	}
	else
	{
	    borderWidth = pCD->matteWidth;
	}
	clientPlacementOffset = TitleTextHeight(pCD) + borderWidth;
	clientPlacementOrigin = clientPlacementOffset;
	clientPlacementX = clientPlacementOrigin;
	clientPlacementY = clientPlacementOrigin;
	clientPlacementXOrigin = clientPlacementX;
	clientPlacementInitialized = True;
    }

    frameWidth = pCD->clientWidth + (2 * pCD->clientOffset.x);
    frameHeight = pCD->clientHeight + pCD->clientOffset.y + pCD->clientOffset.x;
    screenWidth = DisplayWidth (DISPLAY, SCREEN_FOR_CLIENT(pCD));
    screenHeight = DisplayHeight (DISPLAY, SCREEN_FOR_CLIENT(pCD));

    while (!placed)
    {
	if ((clientPlacementX - pCD->clientOffset.x + frameWidth)
	    > screenWidth)
	{
	    offScreenX = True;
	}
	else
	{
	    offScreenX = False;
	}
	if ((clientPlacementY - pCD->clientOffset.y + frameHeight)
	    > screenHeight)
	{
	    offScreenY = True;
	}
	else
	{
	    offScreenY = False;
	}

	if (offScreenX || offScreenY)
	{
	    if (clientPlacementX == clientPlacementOrigin)
	    {
		/*
		 * Placement location is already as far to the NW as it is
		 * going to go.
		 */

		placed = True;
	    }
	    else if (clientPlacementY == clientPlacementOrigin)
	    {
		/*
		 * Placement location is as far to the N as it is going to go.
		 * Use the current placement if the window is not off the
		 * screen in the x coordinate otherwise reset the placement
		 * back to the NW origin.
		 */

		if (offScreenX)
		{
		    clientPlacementXOrigin = clientPlacementOrigin;
		    clientPlacementX = clientPlacementXOrigin;
		}
		placed = True;
	    }
	    else
	    {
		/*
		 * If window is off the right edge of screen, just move
		 * window in the X direction onto screen.  Process similarly
		 * for windows that are off the bottom of the screen.
		 */

		if (offScreenX && !offScreenY)
		{
		    clientPlacementX = clientPlacementOrigin;
		}
		else if (offScreenY && !offScreenX)
		{
		    clientPlacementY = clientPlacementOrigin;
		}
		else
		{

		/*
		 * Reset the placement location back to the NW of the
		 * current location.  Go as far N as possible and step the
		 * x coordinate to the E.
		 */

		    clientPlacementXOrigin += clientPlacementOffset;
		    clientPlacementX = clientPlacementXOrigin;
		    clientPlacementY = clientPlacementOrigin;
		}
	    }
	}
	else
	{
	    placed = True;
	}
    }

    /*
     * The window has been placed, now update the placement information.
     */

    pCD->clientX = clientPlacementX;
    pCD->clientY = clientPlacementY;
    clientPlacementX += clientPlacementOffset;

    if (clientPlacementX >= screenWidth)
    {
	clientPlacementXOrigin = clientPlacementOrigin;
	clientPlacementX = clientPlacementXOrigin;
    }
    clientPlacementY += clientPlacementOffset;

    /*
     * Reset Y position to top of screen so that windows start new column of
     * placement that is offset from the previous column.  Previously, the new
     * column was place right over the old column, obscuring it.
     * NOTE: column == diagonal
     */

    if (clientPlacementY >= (screenHeight / 3))
    {
	clientPlacementY = clientPlacementOrigin;
    }


} /* END OF FUNCTION FindClientPlacement */



/*************************************<->*************************************
 *
 *  WmGetWindowAttributes (window)
 *
 *
 *  Description:
 *  -----------
 *  This function gets window attributes if necessary and saves them in the
 *  global window attribute cache.  If the window attributes are already
 *  there then no X call is made.
 *
 *
 *  Inputs:
 *  ------
 *  window = get attributes for window with this id
 *
 * 
 *  Outputs:
 *  -------
 *  wmGD.attributesWindow = set to window that matches windowAttributes
 *
 *  wmGD.windowAttributes = XWindowAttributes of window
 *
 *
 *  Comments:
 *  --------
 *  The attributes in the global cache are (known) current only for a
 *  single pass through the wm event processing loop.  They (should be)
 *  regularly cleared.
 * 
 *************************************<->***********************************/

Boolean 
WmGetWindowAttributes (Window window)
{
    if (wmGD.attributesWindow != window)
    {
	if (!XGetWindowAttributes (DISPLAY, window, &wmGD.windowAttributes))
	{
	    /*
	     * Cannot get window attributes.
	     */

	    wmGD.attributesWindow = (Window)0L;
	    return (False);
	}
	wmGD.attributesWindow = window;
    }

    return (True);

} /* END OF FUNCTION WmGetWindowAttributes */



/*************************************<->*************************************
 *
 *  SetupClientIconWindow (pCD, window)
 *
 *
 *  Description:
 *  -----------
 *  This function prepares a client supplied icon window for insertion into
 *  a window manager icon frame.
 *
 *
 *  Inputs:
 *  ------
 *  pCD = pointer to client data
 *
 *  window = client supplied icon window
 *
 * 
 *  Outputs:
 *  -------
 *  pCD = (iconWindow)
 *
 *  Return = True if the icon window can be used
 *
 *************************************<->***********************************/

Boolean 
SetupClientIconWindow (ClientData *pCD, Window window)
{
    ClientData *pcd;


    /*
     * Check to see if the icon window can be used (i.e there is no conflict
     * of interest.
     */

    if (!XFindContext (DISPLAY, window, wmGD.windowContextType,
	     (caddr_t *)&pcd))
    {
	if (window == pCD->client)
	{
	    /*
	     * The proposed icon window is the same as the client!
	     */

	    return (False);
	}

	/*
	 * The proposed icon window is already being managed. 
	 * Assume that we managed it by mistake. Unmanage the 
	 * window and use it as the icon window for this client.
	 */

	 UnManageWindow (pcd);
    }

    /* update client data */
    pCD->iconWindow = window;

    /* put in window manager's save set */
    XChangeSaveSet (DISPLAY, pCD->iconWindow, SetModeInsert);
    pCD->clientFlags  |=  ICON_IN_SAVE_SET;

    return (True);

} /* END OF FUNCTION SetupClientIconWindow */



/*************************************<->*************************************
 *
 *  ProcessMwmHints (pCD)
 *
 *
 *  Description:
 *  -----------
 *  Process the _MWM_HINTS property on the window (if any).  Setup the
 *  applicable function and decoration masks.
 *
 *
 *  Inputs:
 *  ------
 *  pCD	= pointer to client data
 *
 * 
 *  Outputs:
 *  -------
 *  pCD	= may be changed.
 *
 *************************************<->***********************************/

void 
ProcessMwmHints (ClientData *pCD)
{
    PropMwmHints *pHints;


    /*
     * Fix the client functions and decorations fields if they have
     * default resource values.
     */

    if (pCD->clientFunctions & WM_FUNC_DEFAULT)
    {
	if (pCD->clientFlags & CLIENT_TRANSIENT)
	{
	    pCD->clientFunctions = TRANSIENT_FUNCTIONS(pCD);
	}
	else
	{
	    pCD->clientFunctions = WM_FUNC_ALL;
	}
#ifdef PANELIST
        if (pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUBPANEL)
	{
	    pCD->clientFunctions &= WM_FUNC_SUBPANEL_DEFAULT;   
	    pCD->dtwmFunctions &= ~DtWM_FUNCTION_OCCUPY_WS;
	}
        else if (pCD->dtwmBehaviors & DtWM_BEHAVIOR_PANEL)
	{
	    pCD->clientFunctions &= WM_FUNC_PANEL_DEFAULT;   
	    pCD->dtwmFunctions &= ~DtWM_FUNCTION_OCCUPY_WS;
	}
#endif /* PANELIST */
    }

    if (pCD->clientDecoration & WM_DECOR_DEFAULT)
    {
	if (pCD->clientFlags & CLIENT_TRANSIENT)
	{
	    pCD->clientDecoration = TRANSIENT_DECORATION(pCD);
	}
	else
	{
	    pCD->clientDecoration = WM_DECOR_ALL;
	}
#ifdef PANELIST
        if (pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUBPANEL)
	{
	    pCD->clientDecoration = pCD->pSD->subpanelDecoration;
	}
        else if (pCD->dtwmBehaviors & DtWM_BEHAVIOR_PANEL)
	{
	    pCD->clientDecoration &= WM_DECOR_PANEL_DEFAULT;   
	}
#endif /* PANELIST */
    }


    /*
     * Retrieve the _MWM_HINTS property if it exists.
     */

    pCD->inputMode = MWM_INPUT_MODELESS;

    if ((pHints = GetMwmHints (pCD)) != NULL)
    {
	if (pHints->flags & MWM_HINTS_FUNCTIONS)
	{
	    if (pHints->functions & MWM_FUNC_ALL)
	    {
		/* client indicating inapplicable functions */
		pCD->clientFunctions &= ~(pHints->functions);
	    }
	    else
	    {
		/* client indicating applicable functions */
		pCD->clientFunctions &= pHints->functions;
	    }
#if 0
	    if (!(pCD->clientFlags & GOT_DT_WM_HINTS) &&
		!pHints->functions)
	    {
		/*
		 * !!! Backward compatibility heurisitic !!!
		 * 
		 * If client doesn't want any functions and
		 * no DT_WM_HINTS specified, then remove 
		 * workspace functions.
		 */
		pCD->dtwmFunctions &= ~DtWM_FUNCTION_OCCUPY_WS;
	    }
#endif 
	    /* !!! check for some minimal level of functionality? !!! */
	}

	if (pHints->flags & MWM_HINTS_DECORATIONS)
	{
	    if (pHints->decorations & MWM_DECOR_ALL)
	    {
		/* client indicating decorations to be removed */
		pCD->clientDecoration &= ~(pHints->decorations);
	    }
	    else
	    {
		/* client indicating decorations to be added */
		pCD->clientDecoration &= pHints->decorations;
	    }

	    /*
	     * Fix up decoration configuration.
	     */

	    if (pCD->clientDecoration &
		  (MWM_DECOR_MENU | MWM_DECOR_MINIMIZE | MWM_DECOR_MAXIMIZE))
	    {
		pCD->clientDecoration |= MWM_DECOR_TITLE;
	    }
	    if (pCD->clientDecoration & MWM_DECOR_RESIZEH)
	    {
		pCD->clientDecoration |= MWM_DECOR_BORDER;
	    }
	}

	if (pHints->flags & MWM_HINTS_INPUT_MODE)
	{
	    if ((pHints->inputMode == MWM_INPUT_PRIMARY_APPLICATION_MODAL) ||
		(pHints->inputMode == MWM_INPUT_FULL_APPLICATION_MODAL) ||
		((pHints->inputMode == MWM_INPUT_SYSTEM_MODAL) &&
		 !wmGD.systemModalActive))
		
	    {
	        pCD->inputMode = pHints->inputMode;

	    }

	    /*
	     * Don't allow a system modal window to be a secondary window
	     * (except with respect to applicable functions and frame
	     * decorations). Also, don't allow system modal window to
	     * be minimized.
	     */

	    if (pCD->inputMode == MWM_INPUT_SYSTEM_MODAL)
	    {
		pCD->transientLeader = NULL;
		if (pCD->clientFunctions & MWM_FUNC_MINIMIZE)
		{
		    pCD->clientFunctions &= ~(MWM_FUNC_MINIMIZE);
		}
	    }
	}

	if (pHints->flags & MWM_HINTS_STATUS)
	{
	    pCD->window_status = pHints->status;
	}

	XFree ((char*)pHints);
    }
#ifndef NO_OL_COMPAT
    else
    {
	ProcessOLDecoration (pCD);
    }
#endif /* NO_OL_COMPAT */

#ifdef WSM
    /* 
     * If primary window can't move between workspaces, then
     * secondary window shouldn't either.
     */
    if (pCD->transientLeader &&
	!(pCD->transientLeader->dtwmFunctions & DtWM_FUNCTION_OCCUPY_WS))
    {
	pCD->dtwmFunctions &= ~DtWM_FUNCTION_OCCUPY_WS;
    }
#endif /* WSM */

    /*
     * Fix up functions based on system modal settings.  System modal
     * windows and their descendents cannot be minimized.
     */

    if (!((FindTransientTreeLeader (pCD))->clientFunctions&MWM_FUNC_MINIMIZE))
    {
	pCD->clientFunctions &= ~MWM_FUNC_MINIMIZE;
    }


    /*
     * Fix up decoration configuration based on applicable functions.
     */

    if (!(pCD->clientFunctions & MWM_FUNC_RESIZE))
    {
	pCD->clientDecoration &= ~MWM_DECOR_RESIZEH;
    }

    if (!(pCD->clientFunctions & MWM_FUNC_MINIMIZE))
    {
	pCD->clientDecoration &= ~MWM_DECOR_MINIMIZE;
    }

    if (!(pCD->clientFunctions & MWM_FUNC_MAXIMIZE))
    {
	pCD->clientDecoration &= ~MWM_DECOR_MAXIMIZE;
    }
    
    pCD->decor = pCD->clientDecoration;  /* !!! combine decor ... !!! */


} /* END OF ProcessMwmHints */
