/* 
 * @OPENGROUP_COPYRIGHT@
 * COPYRIGHT NOTICE
 * Copyright (c) 1989, 1990, 1991, 1992, 1993 Open Software Foundation, Inc. 
 * Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group
 * ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for
 * the full copyright text.
 * 
 * This software is subject to an open license. It may only be
 * used on, with or for operating systems which are themselves open
 * source systems. You must contact The Open Group for a license
 * allowing distribution and sublicensing of this software on, with,
 * or for operating systems which are not Open Source programs.
 * 
 * See http://www.opengroup.org/openmotif/license for full
 * details of the license agreement. Any use, reproduction, or
 * distribution of the program constitutes recipient's acceptance of
 * this agreement.
 * 
 * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
 * PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
 * WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
 * OR FITNESS FOR A PARTICULAR PURPOSE
 * 
 * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
 * NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
 * EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
*/ 
/* 
 * Motif Release 1.2.2
*/ 
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$XConsortium: WmWinConf.c /main/8 1996/10/30 11:15:17 drk $"
#endif
#endif
/*
 * (c) Copyright 1987, 1988, 1989, 1990 HEWLETT-PACKARD COMPANY */

/*
 * Included Files:
 */
#include "WmGlobal.h"	/* This should be the first include */
#include <X11/X.h>

#define XK_MISCELLANY
#include <X11/keysymdef.h>


#define MOVE_OUTLINE_WIDTH	2

#define CONFIG_MASK (KeyPressMask|ButtonPressMask|\
			 ButtonReleaseMask|PointerMotionMask)
#define PGRAB_MASK (ButtonPressMask|ButtonReleaseMask|\
		    PointerMotionMask|PointerMotionHintMask)

/* grab types */

#define NotGrabbed	0
#define ResizeGrab	1
#define MoveGrab	2
#ifdef WSM

/* Anchors */
#define ANCHOR_NONE	0
#define ANCHOR_NW	1
#define ANCHOR_NE	2
#define ANCHOR_SE	3
#define ANCHOR_SW	4

#ifndef ABS
#define ABS(x) ((x)>0?(x):(-(x)))
#endif /* ABS */
#endif /* WSM */

/* number of times to poll before blocking on a config event */

#define CONFIG_POLL_COUNT	300

/* mask for all buttons */
#define ButtonMask	\
    (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)

/*
 * include extern functions
 */
#include "WmWinConf.h"
#include "WmCDInfo.h"
#include "WmCDecor.h"
#include "WmCPlace.h"
#include "WmEvent.h"
#include "WmFeedback.h"
#include "WmFunction.h"
#include "WmIDecor.h"
#include "WmIPlace.h"
#include "WmIconBox.h"
#include "WmKeyFocus.h"
#include "WmProtocol.h"
#include "WmWinInfo.h"



/*
 * Global Variables:
 *
 * These statics are set up at the initiation of a configuration 
 * operation and used for succeeding events.
 */

static int pointerX = -1;
static int pointerY = -1;

static int offsetX = 0;
static int offsetY = 0;

static int resizeX, resizeY;	/* root coords of UL corner of frame */
static unsigned int resizeWidth, resizeHeight;	/* size of frame */
static unsigned int resizeBigWidthInc, resizeBigHeightInc;
static int startX, startY; 
static unsigned int startWidth, startHeight;
static unsigned int minWidth, minHeight, maxHeight, maxWidth;
#ifdef WSM
static int marqueeX, marqueeY;	/* root coords of UL corner of are */
static long marqueeWidth, marqueeHeight;	/* size of area */
static unsigned int marqueeAnchor;	/* id of anchor corner */
static long marqueeWidth0, marqueeHeight0;	/* old size of area */
#endif /* WSM */

static int opaqueMoveX = 0;    /* for cancel request on opaque moves */
static int opaqueMoveY = 0;
static int moveX = 0;		/* root coords of UL corner of frame */
static int moveY = 0;
static int moveIBbbX = 0;	/* root coords of icon box bulletin board */
static int moveIBbbY = 0;
static unsigned int moveWidth = 0;	/* size of frame */
static unsigned int moveHeight = 0;
static int moveLastPointerX = 0;	/* last pointer position */
static int moveLastPointerY= 0;

static Boolean anyMotion = FALSE;
static Boolean configGrab = FALSE;
#if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
static Boolean grabServer = TRUE;
#endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */

Dimension clipWidth = 0;
Dimension clipHeight = 0;
Position clipX = 0;
Position clipY = 0;



/*************************************<->*************************************
 *
 *  GetClipDimensions (pcd, fromRoot)
 *
 *
 *  Description:
 *  -----------
 *
 *
 *  Inputs:
 *  ------
 *  pcd		- pointer to client data
 *
 * 
 *  Outputs:
 *  -------
 *
 *
 *  Comments:
 *  --------
 *************************************<->***********************************/
void GetClipDimensions (ClientData *pCD, Boolean fromRoot)
{

    int i;
    Arg getArgs[5];
    Position tmpX, tmpY;

    i=0;
    XtSetArg (getArgs[i], XmNwidth, (XtArgVal) &clipWidth ); i++;
    XtSetArg (getArgs[i], XmNheight, (XtArgVal) &clipHeight ); i++;
    XtSetArg (getArgs[i], XmNx, (XtArgVal) &tmpX ); i++;
    XtSetArg (getArgs[i], XmNy, (XtArgVal) &tmpY ); i++;

    XtGetValues (P_ICON_BOX(pCD)->clipWidget, getArgs, i);

    if (fromRoot)
    {
	XtTranslateCoords(P_ICON_BOX(pCD)->scrolledWidget,
			tmpX, tmpY,
			&clipX, &clipY);
    }
    else
    {
	clipX = tmpX;
	clipY = tmpY;      
    }			

} /* END OF FUNCTION GetClipDimensions */



/*************************************<->*************************************
 *
 *  HandleClientFrameMove (pcd, pev)
 *
 *
 *  Description:
 *  -----------
 *  Provide visual feedback of interactive moving of the window.
 *
 *
 *  Inputs:
 *  ------
 *  pcd		- pointer to client data
 *  pev		- pointer to event
 *
 * 
 *  Outputs:
 *  -------
 *
 *
 *  Comments:
 *  --------
 *************************************<->***********************************/
void HandleClientFrameMove (ClientData *pcd, XEvent *pev)
{
    int tmpX, tmpY, warpX, warpY;
    Window grab_win;
    KeySym keysym;
    Boolean control, moveDone;
    Boolean firstTime;
    int big_inc, keyMultiplier;
    int newX, newY;
    XEvent event, KeyEvent;

    if (pev) {
	firstTime = True;
    }
    else {
	firstTime = False;
    }

    big_inc = DisplayWidth (DISPLAY, SCREEN_FOR_CLIENT(pcd)) / 20;


    /*
     *	Do our grabs and initial setup if we're just starting out
     */
    if (!configGrab) {
	if (!StartClientMove (pcd, pev))
	{
	    /* configuration was not initiated */
	    return;
	}
    }

    grab_win = GrabWin (pcd, pev);

    
    if (pcd->pSD->useIconBox && P_ICON_BOX(pcd))
    {
	GetClipDimensions (pcd, True);
    }

    moveDone = False;
    while (!moveDone) 
    {
	tmpX = tmpY = 0;

	if (firstTime) {
	    /* handle the event we were called with first */
	    firstTime = False;
	}
	else 
	{
	    pev = &event;
	    GetConfigEvent(DISPLAY, grab_win, CONFIG_MASK, 
		moveLastPointerX, moveLastPointerY, moveX, moveY,
		moveWidth, moveHeight, &event);
	}

	if (pev->type == KeyPress) 
	{
	    keyMultiplier = 1;
	    while (keyMultiplier <= big_inc && 
		      XCheckIfEvent (DISPLAY, &KeyEvent, IsRepeatedKeyEvent, 
		      (char *) pev))
	    {
		  keyMultiplier++;
	    }

	    keysym = XKeycodeToKeysym (DISPLAY, pev->xkey.keycode, 0);
	    control = (pev->xkey.state & ControlMask) != 0;
	    tmpX = tmpY = 0;

	    switch (keysym) {
		case XK_Left:
		    tmpX = keyMultiplier * ((control) ? (-big_inc) : (-1));
		    break;

		case XK_Up:
		    tmpY = keyMultiplier * ((control) ? (-big_inc) : (-1));
		    break;

		case XK_Right:
		    tmpX = keyMultiplier * ((control) ? big_inc : 1);
		    break;

		case XK_Down:
		    tmpY = keyMultiplier * ((control) ? big_inc : 1);
		    break;

		case XK_Return:
		    CompleteFrameConfig (pcd, pev);
		    return;

		case XK_Escape:
		    CancelFrameConfig (pcd);
		    CheckEatButtonRelease (pcd, pev);
		    return;

		default:
		    break;
	    }

	    if (tmpX || tmpY)  {
		warpX = moveLastPointerX + tmpX;
		warpY = moveLastPointerY + tmpY;

		ForceOnScreen(SCREEN_FOR_CLIENT(pcd), &warpX, &warpY);

		if ((warpX != moveLastPointerX) || (warpY != moveLastPointerY))
		{
		    SetPointerPosition (warpX, warpY, &newX, &newY);

		    tmpX = newX - moveLastPointerX;
		    tmpY = newY - moveLastPointerY;
		    moveLastPointerX = newX;
		    moveLastPointerY = newY;
		    moveX += tmpX;
		    moveY += tmpY;
		}
		else 
		{
		    /*
		     * make like motion event and move frame.
		     */
		    moveX += tmpX;
		    moveY += tmpY;
		}
	    }
	}
	else if (pev->type == ButtonRelease) 
	{
	    /*
	     *  Update (x,y) to the location of the button release
	     */
	    moveX += pev->xbutton.x_root - moveLastPointerX;
	    moveY += pev->xbutton.y_root - moveLastPointerY;

	    CompleteFrameConfig (pcd, pev);
	    moveDone = True;
	}
	else if (pev->type == MotionNotify) 
	{	
	    tmpX = pev->xmotion.x_root - moveLastPointerX;
	    tmpY = pev->xmotion.y_root - moveLastPointerY;
	    moveLastPointerX = pev->xmotion.x_root;
	    moveLastPointerY = pev->xmotion.y_root;
	    moveX += tmpX;
	    moveY += tmpY;
	    anyMotion = True;
	}

	/* draw outline if there is something to draw */
	if (tmpX || tmpY) {
	    FixFrameValues (pcd, &moveX, &moveY, &moveWidth, &moveHeight,
			    FALSE /* no size checks */);
	    if (pcd->pSD->moveOpaque)
	    {
		MoveOpaque (pcd, moveX, moveY, moveWidth, moveHeight);
	    }
	    else
	    {
		MoveOutline(moveX, moveY, moveWidth, moveHeight);
	    }
	    
	    if ( !wmGD.movingIcon &&
		 (wmGD.showFeedback & WM_SHOW_FB_MOVE))
	    {
		DoFeedback (pcd, moveX, moveY, moveWidth, moveHeight, 
			    (unsigned long) 0, FALSE /* no size checks */);
	    }
	}
    }

} /* END OF FUNCTION HandleClientFrameMove */



/*************************************<->*************************************
 *
 *  UpdateAndDrawResize ()
 *
 *
 *  Description:
 *  -----------
 *
 *  Inputs:
 *  ------
 *  pcd		- pointer to client data
 * 
 *  Outputs:
 *  -------
 *
 *
 *  Comments:
 *  --------
 *************************************<->***********************************/
void UpdateAndDrawResize (ClientData *pcd)
{
    int tmpHeight, tmpWidth;
    
    /* 
     * Handle a motion event or a keypress that's like a motion 
     * event
     */
    
    /* set height */
    
    switch (wmGD.configPart) {
      case FRAME_RESIZE_NW:
      case FRAME_RESIZE_N:
      case FRAME_RESIZE_NE:
	tmpHeight = (int) startHeight + (startY - pointerY);
	if (tmpHeight < (int) minHeight)
	{
	    resizeHeight = minHeight;
	    resizeY = startY + startHeight - minHeight;
	}
	else if (pcd->pSD->limitResize 
		 && (tmpHeight > (int) maxHeight)
		 && (!(pcd->clientFlags & ICON_BOX)))
	{
	    resizeHeight = maxHeight;
	    resizeY = startY + startHeight - maxHeight;
	}
	else
	{
	    resizeHeight = (unsigned int) tmpHeight;
	    resizeY = pointerY;
	}
	break;
	
      case FRAME_RESIZE_SW:
      case FRAME_RESIZE_S:
      case FRAME_RESIZE_SE:
	resizeY = startY;
	tmpHeight = pointerY - startY + 1;
	if (tmpHeight < (int) minHeight)
	{
	    resizeHeight = minHeight;
	}
	else if (pcd->pSD->limitResize 
		 && (tmpHeight > (int) maxHeight)
		 && (!(pcd->clientFlags & ICON_BOX)))
	{
	    resizeHeight = maxHeight;
	}
	else
	{
	    resizeHeight = (unsigned int) tmpHeight;
	}
	break;
	
      default:
	resizeY = startY;
	resizeHeight = startHeight;
	break;
	
    }
    
    /* set width */
    
    switch (wmGD.configPart) {
      case FRAME_RESIZE_NW:
      case FRAME_RESIZE_W:
      case FRAME_RESIZE_SW:
	tmpWidth = (int) startWidth + (startX - pointerX);
	if (tmpWidth < (int) minWidth)
	{
	    resizeWidth = minWidth;
	    resizeX = startX + startWidth - minWidth;
	}
	else if (pcd->pSD->limitResize 
		 && (tmpWidth > (int) maxWidth)
		 && (!(pcd->clientFlags & ICON_BOX)))
	{
	    resizeWidth = maxWidth;
	    resizeX = startX + startWidth - maxWidth;
	}
	else
	{
	    resizeWidth = (unsigned int) tmpWidth;
	    resizeX = pointerX;
	}
	break;
	
      case FRAME_RESIZE_NE:
      case FRAME_RESIZE_E:
      case FRAME_RESIZE_SE:
	resizeX = startX;
	tmpWidth = pointerX - startX + 1;
	if (tmpWidth < (int) minWidth)
	{
	    resizeWidth = minWidth;
	}
	else if (pcd->pSD->limitResize 
		 && (tmpWidth > (int) maxWidth)
		 && (!(pcd->clientFlags & ICON_BOX)))
	{
	    resizeWidth = maxWidth;
	}
	else
	{
	    resizeWidth = (unsigned int) tmpWidth;
	}
	break;
	
      default:
	resizeX = startX;
	resizeWidth = startWidth;
	break;
    }
    
    FixFrameValues (pcd, &resizeX, &resizeY, &resizeWidth, 
		    &resizeHeight, TRUE /* do size checks */);
    MoveOutline (resizeX, resizeY, resizeWidth, resizeHeight);
    if (wmGD.showFeedback & WM_SHOW_FB_RESIZE)
    {
	DoFeedback(pcd, resizeX, resizeY, resizeWidth, resizeHeight,
		   (unsigned long) 0, TRUE /* do size checks */);
    }
}


/*************************************<->*************************************
 *
 *  HandleClientFrameResize (pcd, pev)
 *
 *
 *  Description:
 *  -----------
 *  Provide visual feedback of interactive resizing of the window.
 *
 *
 *  Inputs:
 *  ------
 *  pcd		- pointer to client data
 *  pev		- pointer to event
 *
 * 
 *  Outputs:
 *  -------
 *
 *
 *  Comments:
 *  --------
 *  o The window sizes refer to the frame, not the client window.
 * 
 *************************************<->***********************************/
void HandleClientFrameResize (ClientData *pcd, XEvent *pev)
{
    Window grab_win;
    Boolean resizeDone;
    XEvent event;


    /*
     * Do our grabs the first time through
     */
    if (!configGrab) {
	if (StartResizeConfig (pcd, pev))
	{
	    configGrab = TRUE;
	}
	else
	{
	    /* resize could not be initiated */
	    return;
	}
    }

    grab_win = GrabWin (pcd, pev);

    resizeDone = False;
    while (!resizeDone) 
    {
	if (!pev) 	/* first time through will already have event */
	{
	    pev = &event;

	    GetConfigEvent(DISPLAY, grab_win, CONFIG_MASK, 
		pointerX, pointerY, resizeX, resizeY,
		resizeWidth, resizeHeight, &event);
	}

	if (pev->type == MotionNotify)
	{
	    pointerX = pev->xmotion.x_root;
	    pointerY = pev->xmotion.y_root;
	    anyMotion = TRUE;

	    /*
	     * Really start resizing once the pointer hits a resize area
	     * (This only applies to accelerator and keyboard resizing!)
	     */
	    if (!wmGD.configSet && !SetPointerResizePart (pcd, pev)) {
		pev = NULL;
		continue;		/* ignore this event */
	    }
	}
	else if (pev->type == KeyPress) {

	    /* 
	     * Handle key event. 
	     */
	    resizeDone = HandleResizeKeyPress (pcd, pev);
	}
	else if (pev->type == ButtonRelease) {

	    /*
	     *  Update (x,y) to the location of the button release
	     */
	    pointerX = pev->xbutton.x_root;
	    pointerY = pev->xbutton.y_root;
	    UpdateAndDrawResize(pcd);

	    CompleteFrameConfig (pcd, pev);
	    resizeDone = True;
	}
	else  {
	    pev = NULL;
	    continue;			/* ignore this event */
	}

	if (!resizeDone)
	{
	    UpdateAndDrawResize(pcd);
	}

	pev = NULL;	/* reset event pointer */

    }  /* end while */

} /* END OF FUNCTION HandleClientFrameResize */



/*************************************<->*************************************
 *
 *  HandleResizeKeyPress (pcd, pev)
 *
 *
 *  Description:
 *  -----------
 *  Handles keypress events during resize of window
 *
 *
 *  Inputs:
 *  ------
 *  pcd 	- pointer to client data
 *  pev		- pointer to event
 *
 * 
 *  Outputs:
 *  -------
 *  Return	- True if this event completes (or cancels) resizing 
 * 
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/
Boolean HandleResizeKeyPress (ClientData *pcd, XEvent *pev)
{
    KeySym keysym;
    Boolean control;
    int warpX, warpY, currentX, currentY, newX, newY;
    int junk, keyMult;
    Window junk_win;
    XEvent KeyEvent;

    /*
     * Compress repeated keys 
     */
    keyMult = 1;
    while (keyMult <= 10 && 
	      XCheckIfEvent (DISPLAY, &KeyEvent, IsRepeatedKeyEvent, 
	      (char *) pev))
    {
	  keyMult++;
    }

    keysym = XKeycodeToKeysym (DISPLAY, pev->xkey.keycode, 0);
    control = (pev->xkey.state & ControlMask) != 0;

    switch (keysym) {
	case XK_Left:
	    switch (wmGD.configPart) {
		case FRAME_NONE:
		    wmGD.configPart = FRAME_RESIZE_W;
		    ReGrabPointer(pcd->clientFrameWin, pev->xkey.time);
		    warpY = resizeY + resizeHeight/2;
		    warpX = resizeX + ((control) ? 
					  (-resizeBigWidthInc) : 
					  (-pcd->widthInc));
		    break;

		case FRAME_RESIZE_N:
		    wmGD.configPart = FRAME_RESIZE_NW;
		    ReGrabPointer(pcd->clientFrameWin, pev->xkey.time);
		    warpX = resizeX + ((control) ? 
					  (-resizeBigWidthInc) : 
					  (-pcd->widthInc));
		    warpY = pointerY;
		    break;

		case FRAME_RESIZE_S:
		    wmGD.configPart = FRAME_RESIZE_SW;
		    ReGrabPointer(pcd->clientFrameWin, pev->xkey.time);
		    warpX = resizeX + ((control) ? 
					  (-resizeBigWidthInc) : 
					  (-pcd->widthInc));
		    warpY = pointerY;
		    break;
		
		default:
		    warpX = pointerX + ((control) ? 
					(-resizeBigWidthInc * keyMult) : 
					(-pcd->widthInc * keyMult));
		    warpY = pointerY;
		    break;
	    }
	    break;

	case XK_Up:
	    switch (wmGD.configPart) {
		case FRAME_NONE:
		    wmGD.configPart = FRAME_RESIZE_N;
		    warpX = resizeX + resizeWidth/2;
		    warpY = resizeY + ((control) ? 
					  (-resizeBigHeightInc) : 
					  (-pcd->heightInc));
		    ReGrabPointer(pcd->clientFrameWin, pev->xkey.time);
		    break;

		case FRAME_RESIZE_W:
		    wmGD.configPart = FRAME_RESIZE_NW;
		    ReGrabPointer(pcd->clientFrameWin, pev->xkey.time);
		    warpX = pointerX;
		    warpY = resizeY + ((control) ? 
					  (-resizeBigHeightInc) : 
					  (-pcd->heightInc));
		    break;

		case FRAME_RESIZE_E:
		    wmGD.configPart = FRAME_RESIZE_NE;
		    ReGrabPointer(pcd->clientFrameWin, pev->xkey.time);
		    warpX = pointerX;
		    warpY = resizeY + ((control) ? 
					      (-resizeBigHeightInc) : 
					      (-pcd->heightInc));
		    break;

		default: 
		    warpX = pointerX;
		    warpY = pointerY + ((control) ? 
					(-resizeBigHeightInc * keyMult) : 
					(-pcd->heightInc * keyMult));
		    break;
	    }
	    break;

	case XK_Right:
	    switch (wmGD.configPart) {
		case FRAME_NONE:
		    wmGD.configPart = FRAME_RESIZE_E;
		    warpY = resizeY + resizeHeight/2;
		    warpX = resizeX + resizeWidth - 1 + 
			       ((control) ? resizeBigWidthInc : 
					    pcd->widthInc);
		    ReGrabPointer(pcd->clientFrameWin, pev->xkey.time);
		    break;

		case FRAME_RESIZE_N:
		    wmGD.configPart = FRAME_RESIZE_NE;
		    ReGrabPointer(pcd->clientFrameWin, pev->xkey.time);
		    warpX = resizeX + resizeWidth - 1 + 
			       ((control) ? resizeBigWidthInc : 
					    pcd->widthInc);
		    warpY = pointerY;
		    break;

		case FRAME_RESIZE_S:
		    wmGD.configPart = FRAME_RESIZE_SE;
		    ReGrabPointer(pcd->clientFrameWin, pev->xkey.time);
		    warpX = resizeX + resizeWidth - 1 + 
			       ((control) ? resizeBigWidthInc : 
					    pcd->widthInc);
		    warpY = pointerY;
		    break;

		default:
		    warpX = pointerX + ((control) ? 
				 	(resizeBigWidthInc * keyMult) : 
				  	(pcd->widthInc * keyMult));
		    warpY = pointerY;
		    break;
	    }
	    break;

	case XK_Down:
	    switch (wmGD.configPart) {
		case FRAME_NONE:
		    wmGD.configPart = FRAME_RESIZE_S;
		    warpX = resizeX + resizeWidth/2;
		    warpY = resizeY + resizeHeight - 1 + 
			       ((control) ? resizeBigHeightInc : 
					    pcd->heightInc);
		    ReGrabPointer(pcd->clientFrameWin, pev->xkey.time);
		    break;

		case FRAME_RESIZE_E:
		    wmGD.configPart = FRAME_RESIZE_SE;
		    ReGrabPointer(pcd->clientFrameWin, pev->xkey.time);
		    warpX = pointerX;
		    warpY = resizeY + resizeHeight - 1 + 
			       ((control) ? resizeBigHeightInc : 
					    pcd->heightInc);
		    break;

		case FRAME_RESIZE_W:
		    wmGD.configPart = FRAME_RESIZE_SW;
		    ReGrabPointer(pcd->clientFrameWin, pev->xkey.time);
		    warpX = pointerX;
		    warpY = resizeY + resizeHeight - 1 + 
			       ((control) ? resizeBigHeightInc : 
					    pcd->heightInc);
		    break;

		default:
		    warpX = pointerX;
		    warpY = pointerY + ((control) ? 
					(resizeBigHeightInc * keyMult) : 
					(pcd->heightInc * keyMult));
		    break;
	    }
	    break;

	case XK_Return:
	    CompleteFrameConfig (pcd, pev);
	    return (True);

	case XK_Escape:
	    CancelFrameConfig (pcd);
	    CheckEatButtonRelease (pcd, pev);
	    return (True);

	default:
	    return (False);		/* ignore this key */

    } /* end switch(keysym) */

    /*
     * Make sure the new pointer position is on screen before doing
     * the warp. Warp only if the pointer position changes.
     */
    pointerX = warpX;
    pointerY = warpY;

    ForceOnScreen(SCREEN_FOR_CLIENT(pcd), &warpX, &warpY);

    /*
     * Don't query pointer if enable warp is off.
     */
    if (!wmGD.enableWarp ||
	XQueryPointer (DISPLAY, ROOT_FOR_CLIENT(pcd), &junk_win, &junk_win,
	       &currentX, &currentY, &junk, &junk, (unsigned int *)&junk))
    {
	if ( (warpX != currentX) || (warpY != currentY) ) 
	{
	    SetPointerPosition (warpX, warpY, &newX, &newY);
	    return (False);
	}
    }
    return (False);

} /* END OF FUNCTION HandleResizeKeyPress */


/*************************************<->*************************************
 *
 *  DoFeedback (pcd, x, y, width, height, newStyle, resizing)
 *
 *
 *  Description:
 *  -----------
 *  Start or update feedback of size/position info
 *
 *
 *  Inputs:
 *  ------
 *  pcd		- pointer to client data
 *  x		-
 *  y		-
 *  width	- 
 *  height	-
 *  newStyle	- style flags. 
 *  resizing    - check size constraints iff TRUE
 *  
 * 
 *  Outputs:
 *  -------
 *
 *
 *  Comments:
 *  --------
 *  o If newStyle has FB_POSITION  and/or FB_SIZE bits set, then it is
 *    assumed that this is an initial call and a feedback window of the
 *    desired style should be popped up. If newStyle is zero, then it
 *    is assumed that the feedback window is already up and the values
 *    passed in are updates.
 * 
 *************************************<->***********************************/
void DoFeedback (ClientData *pcd, int x, int y, unsigned int width, unsigned int height, unsigned long newStyle, Boolean resizing)
{
    int cx = x;
    int cy = y;
    unsigned int cwidth, cheight;

    /* compute client window coordinates from frame coordinates */
    FrameToClient (pcd, &cx, &cy, &width, &height);

    /* use frame (not client) position if user wishes it */
    if (wmGD.positionIsFrame) {
	cx = x;
	cy = y;
    }

    /* If resizing, make sure configuration is valid. */
    if (resizing)
    {
        FixWindowConfiguration (pcd, &width, &height,
				 (unsigned int) pcd->widthInc, 
				 (unsigned int) pcd->heightInc);
    }

    /*
     * Put size in client specific units.  Do not include base into calculations
     * when increment is not specified (i.e. = 1).
     */
    cwidth = (width - ((pcd->widthInc==1) ? 0 : pcd->baseWidth))
		/ pcd->widthInc;
    cheight = (height - ((pcd->heightInc==1) ? 0 : pcd->baseHeight))
		/ pcd->heightInc;

    if (newStyle) {
	ShowFeedbackWindow (pcd->pSD, cx, cy, cwidth, cheight, newStyle);
    }
    else {
	UpdateFeedbackInfo (pcd->pSD, cx, cy, cwidth, cheight);
    }
} /* END OF FUNCTION DoFeedback  */



/*************************************<->*************************************
 *
 *  CheckVisualPlace
 *
 *
 *  Description:
 *  -----------
 *  Prevents icons in the icon box from being moved outside the clip window
 *
 *
 *  Inputs:
 *  ------
 *  pcd		- pointer to client data

 *
 * 
 *  Outputs:
 *  -------
 *
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/

Boolean CheckVisualPlace (ClientData *pCD, int tmpX, int tmpY)
{
    Boolean rval = True;
    Window child;
    int newX;
    int newY;
    
    GetClipDimensions(pCD, True);


    /* 
     * Get root coordinates of X and Y for icon.
     * We use root coordinates of clip window since clipX and
     * clipY are not 0, but the icon X and Y may be 0 in
     * local coordinates
     */
     
    XTranslateCoordinates(DISPLAY, XtWindow(P_ICON_BOX(pCD)->bBoardWidget),
    			  ROOT_FOR_CLIENT(pCD), tmpX, tmpY,
			  &newX, &newY, &child);


    if (newX < clipX) 
    {
        return(False);
    }
    if (newY < clipY) 
    {
        return(False);
    }


    if (((int)newX) > ((int)clipX + 
    	(int)clipWidth - ((int)ICON_WIDTH(pCD)))) 
    {
        return(False);
    }
    if (((int)newY) > ((int)clipY + 
    	(int)clipHeight - ((int)ICON_HEIGHT(pCD))))
    {
        return(False);
    }
    
    return (rval);
 
} /* END OF FUNCTION CheckVisualPlace */



/*************************************<->*************************************
 *
 *  CompleteFrameConfig (pcd, pev)
 *
 *
 *  Description:
 *  -----------
 *  Clean up graphic feedback when user stops configuring.
 *
 *
 *  Inputs:
 *  ------
 *  pcd		- pointer to client data
 *  pev		- pointer to event
 *
 * 
 *  Outputs:
 *  -------
 *
 *
 *  Comments:
 *  --------
 *  o This routine assumes that it is called in response to a button release
 *    event.
 * 
 *************************************<->***********************************/
void CompleteFrameConfig (ClientData *pcd, XEvent *pev)
{
    unsigned int tmpWidth, tmpHeight;
    int tmpX, tmpY;
    Boolean inIconBox;
    
    
    if (wmGD.configAction == RESIZE_CLIENT) {
	/* release the grabs */
	UndoGrabs();

	/*
	 * Honor the implied constrained anchor points on the window
	 * so that the resize doesn't cause the window to move 
	 * unexpectedly.
	 */

#ifndef CONFIG_RELATIVE_TO_CLIENT

	tmpX = resizeX;
	tmpY = resizeY;

	/* Use dummy x,y so we don't add frame offset to client location */
	FrameToClient (pcd, &tmpX, &tmpY, &resizeWidth, &resizeHeight);
#else
	FrameToClient (pcd, &resizeX, &resizeY, &resizeWidth, &resizeHeight);
#endif

	tmpWidth = resizeWidth;
	tmpHeight = resizeHeight;

	FixWindowConfiguration (pcd, &tmpWidth, &tmpHeight,
				     (unsigned int) pcd->widthInc, 
				     (unsigned int) pcd->heightInc);

        AdjustPos (&resizeX, &resizeY,
		   resizeWidth, resizeHeight, tmpWidth, tmpHeight);

	/* reconfigure the window(s) */
	ProcessNewConfiguration (pcd, resizeX, resizeY, 
				 resizeWidth, resizeHeight, FALSE);

    }
    else if (wmGD.configAction == MOVE_CLIENT)
    {
	/* release the grabs */
	UndoGrabs();

	/* make sure title bar is popped out */
	if ((wmGD.configAction == MOVE_CLIENT) &&
	    (wmGD.gadgetClient == pcd) && 
	    (wmGD.gadgetDepressed == FRAME_TITLE))
	{
	    PopGadgetOut (pcd, FRAME_TITLE);
	    FrameExposureProc(pcd);			/* repaint frame */
	}

	/* handle both icon and normal frames */
	if (wmGD.movingIcon)
	{

	    inIconBox = (pcd->pSD->useIconBox && P_ICON_BOX(pcd));

	    /* only need to move the icon */
	    if (wmGD.iconAutoPlace || inIconBox)
	    {
		int centerX;
		int centerY;
		int place;
		IconPlacementData *pIPD;

		/* 
		 * Get correct icon placement data
		 */
		if (inIconBox) 
		{
		    pIPD = &P_ICON_BOX(pcd)->IPD;
		    moveX -= moveIBbbX;
		    moveY -= moveIBbbY;
		}
		else
		{
		    pIPD = &(ACTIVE_WS->IPData);
		}

                /*
		 * Check to make sure that there is an unoccupied place
		 * where the icon is being moved to:
		 */

		centerX = moveX + ICON_WIDTH(pcd) / 2;
		centerY = moveY + ICON_HEIGHT(pcd) / 2;
		place = CvtIconPositionToPlace (pIPD, centerX, centerY);

		if (place != ICON_PLACE(pcd))
		{
		    if (pIPD->placeList[place].pCD)
		    {
			/*
			 * Primary place occupied, try to find an unoccupied
			 * place in the proximity.
			 */

			place = FindIconPlace (pcd, pIPD, centerX, centerY);
			if (place == NO_ICON_PLACE)
			{
			    /*
			     * Can't find an unoccupied icon place.
			     */

			    F_Beep (NULL, pcd, (XEvent *)NULL);

			    if (pcd->pSD->moveOpaque && !inIconBox)
			    {
				/*
				 * Replace icon into same place - as if it
				 * didn't move.
				 */
				
				XMoveWindow (DISPLAY, ICON_FRAME_WIN(pcd),
					     ICON_X(pcd), ICON_Y(pcd));
				if ((ICON_DECORATION(pcd) & 
				     ICON_ACTIVE_LABEL_PART) &&
				    (wmGD.keyboardFocus == pcd))
				{
				    MoveActiveIconText(pcd);
				    ShowActiveIconText(pcd);
				}
			    }
			}
		    }
		    if ((place != NO_ICON_PLACE) && 
			(place != ICON_PLACE(pcd)))
		    {
			if (inIconBox)
			{
			    CvtIconPlaceToPosition (pIPD, place,
			    			&tmpX, &tmpY);
	    		    if( (CheckIconBoxSize (P_ICON_BOX(pcd))) &&
				(CheckVisualPlace(pcd, tmpX, tmpY)))
			    {
				/*
				 * Move the icon to the new place.
				 */

				MoveIconInfo (pIPD, ICON_PLACE(pcd), place);
				CvtIconPlaceToPosition (pIPD, place, 
						&ICON_X(pcd), &ICON_Y(pcd));


				XtMoveWidget (
				    pIPD->placeList[ICON_PLACE(pcd)].theWidget,
				    ICON_X(pcd), ICON_Y(pcd));

				SetNewBounds (P_ICON_BOX(pcd));
				if (ICON_DECORATION(pcd) &
                                    ICON_ACTIVE_LABEL_PART)
                                {
                                    MoveActiveIconText(pcd);
                                }
			    }
			    else
			    {
				F_Beep (NULL, pcd, (XEvent *)NULL);
			    }
			}
			else 
			{
			    /*
			     * Move the icon to the new place.
			     */
			    MoveIconInfo (pIPD, ICON_PLACE(pcd), place);
			    CvtIconPlaceToPosition (pIPD, place, &ICON_X(pcd), 
						    &ICON_Y(pcd));

			    XMoveWindow (DISPLAY, ICON_FRAME_WIN(pcd), 
					 ICON_X(pcd), ICON_Y(pcd));

			    if (pcd->pSD->moveOpaque &&
				(ICON_DECORATION(pcd) & 
				 ICON_ACTIVE_LABEL_PART) &&
				(wmGD.keyboardFocus == pcd))
			    {
				MoveActiveIconText(pcd);
				ShowActiveIconText(pcd);
			    }
			}
		    }
		}
		else if (pcd->pSD->moveOpaque && !inIconBox)
                {
		    /*
		     * Replace icon into same place - as if it
		     * didn't move.
		     */
		    XMoveWindow (DISPLAY, ICON_FRAME_WIN(pcd),
				 ICON_X(pcd), ICON_Y(pcd));
		    if ((ICON_DECORATION(pcd) & 
			 ICON_ACTIVE_LABEL_PART) &&
			(wmGD.keyboardFocus == pcd))
		    {
			MoveActiveIconText(pcd);
			ShowActiveIconText(pcd);
		    }
                }
            }
	    else
	    {
		XMoveWindow (DISPLAY, ICON_FRAME_WIN(pcd), moveX, moveY);
		ICON_X(pcd) = moveX;
		ICON_Y(pcd) = moveY;
	    }
	    if ((ICON_DECORATION(pcd) & ICON_ACTIVE_LABEL_PART) &&
		(wmGD.keyboardFocus == pcd))
	    {
		MoveActiveIconText(pcd);
	    }
	}
	else {	/* assume normal window frame */
	    /* reconfigure the window(s) */
	    ProcessNewConfiguration (pcd, 
#ifndef CONFIG_RELATIVE_TO_CLIENT
				     moveX,
				     moveY,
#else
				     moveX + offsetX,
				     moveY + offsetY,
#endif
				     (unsigned int) 
					 (moveWidth - 2*offsetX),
				     (unsigned int) 
					 (moveHeight - offsetX - offsetY),
				     FALSE);
	}
    }
#ifdef WSM
    else if (wmGD.configAction == MARQUEE_SELECT)
    {
	WmScreenData *pSD;

	UndoGrabs();

	pSD = pcd ? pcd->pSD : ACTIVE_PSD;

	dtSendMarqueeSelectionNotification(pSD, DT_MARQUEE_SELECT_END, 
			marqueeX, marqueeY, marqueeWidth, marqueeHeight);
    }
#endif /* WSM */

    /*
     * Clear configuration flags and data.
     */

    wmGD.configAction = NO_ACTION;
    wmGD.configPart = FRAME_NONE;
    wmGD.configSet = False;
    configGrab = FALSE;
    anyMotion = FALSE;
    wmGD.movingIcon = FALSE;

#ifdef WSM
    if (pcd)
    {
#endif /* WSM */
    /* hide the move/resize config data */
    HideFeedbackWindow(pcd->pSD);

    /*
     * Set the focus back to something reasonable
     */
    RepairFocus ();	
#ifdef WSM
    }
#endif /* WSM */

} /* END OF FUNCTION CompleteFrameConfig */


/*************************************<->*************************************
 *
 *  MoveOpaque (pcd, x, y, width, height)
 *
 *
 *  Description:
 *  -----------
 *  Move a window or icon on the root or icon box.
 *
 *
 *  Inputs:
 *  ------
 *  pcd         - client data pointer
 *  x		- x coordinate (on root)
 *  y		- y coordinate (on root)
 *  width	- pixel width of frame
 *  height	- pixel height of frame
 * 
 *  Outputs:
 *  -------
 *
 *
 *  Comments:
 *  --------
 *  o use MoveOutline() for icons in an icon box.
 *  
 *************************************<->***********************************/
void MoveOpaque (ClientData *pcd, int x, int y,
		 unsigned int width, unsigned int height)


{
    /* Check if moving icon */
    if (wmGD.movingIcon)
    {
	if (pcd->pSD->useIconBox && P_ICON_BOX(pcd))
	{
	    /*
	     * For now just fall back to move outline when the
	     * icon is in the icon box
	     */   
	    
	    MoveOutline (x, y, width, height);
	}
	else
	{
	    XMoveWindow (DISPLAY,ICON_FRAME_WIN(pcd) , x, y);
	}
    }
    else
    {
	/* This is a window */
	XMoveWindow (DISPLAY, pcd->clientFrameWin, x, y);
	
    }
    
    /* cleanup exposed frame parts */
    PullExposureEvents ();
    
} /* END OF FUNCTION MoveOpaque */



/* thickness of outline */
#define OUTLINE_WIDTH	2

/* number of points to draw outline once */
#define SEGS_PER_DRAW	(4*OUTLINE_WIDTH)

/* number of points to flash outline (draw then erase) */
#define SEGS_PER_FLASH	(2*SEGS_PER_DRAW)


/*************************************<->*************************************
 *
 *  DrawSegments (dpy, win, gc, outline, nsegs)
 *
 *  Description:
 *  -----------
 *  Draw segments using either using normal X or using the ALLPLANES
 *  extension, depending on #ifdef ALLPLANES and whether the server actually
 *  supports the extension.  This is a thin wrapper around the Xlib
 *  XDrawSegments() call.
 *
 *  Inputs:
 *  ------
 *  dpy		- the X display
 *  win		- the window on which to draw
 *  gc		- the gc to use, typically whose function is GXxor
 *  outline	- array of segments
 *  nsegs	- number of segments in the outline array
 * 
 *  Outputs:
 *  -------
 *  (none)
 *
 *  Comments:
 *  --------
 *  Note: no GC is used when drawing with the ALLPLANES extension;
 *  therefore, the GC parameter is ignored in that case.
 * 
 *************************************<->***********************************/


static void
DrawSegments (Display *dpy, Window win, GC gc, XSegment *outline, int nsegs)
{
#if defined(sun) && defined(ALLPLANES)
	if (wmGD.allplanes)
	    XAllPlanesDrawSegments(dpy, win, outline, nsegs);
	else
#endif /* defined(sun) && defined(ALLPLANES) */
	    XDrawSegments(dpy, win, gc, outline, nsegs);
} /* END OF FUNCTION  DrawSegments */


/*************************************<->*************************************
 *
 *  MoveOutline (x, y, width, height)
 *
 *
 *  Description:
 *  -----------
 *  Draw a window outline on the root window.
 *
 *
 *  Inputs:
 *  ------
 *  x		- x coordinate (on root)
 *  y		- y coordinate (on root)
 *  width	- pixel width of frame
 *  height	- pixel height of frame
 * 
 *  Outputs:
 *  -------
 *
 *
 *  Comments:
 *  --------
 *  o get display, root window ID, and xorGC out of global data.  
 * 
 *************************************<->***********************************/
void MoveOutline (int x, int y, unsigned int width, unsigned int height)
{
    if (wmGD.freezeOnConfig)
    {
	DrawOutline (x, y, width, height);
    }
    else
    {
#ifdef WSM
      if (wmGD.useWindowOutline)
	WindowOutline(x,y,width,height);
      else
#endif
	FlashOutline(x, y, width, height);
    }
} /* END OF FUNCTION  MoveOutline */



/*************************************<->*************************************
 *
 *  FlashOutline ()
 *
 *
 *  Description:
 *  -----------
 *  flash a window outline on the root window.
 *
 *
 *  Inputs:
 *  ------
 *  x		- x coordinate (on root)
 *  y		- y coordinate (on root)
 *  width	- pixel width of frame
 *  height	- pixel height of frame
 * 
 *  Outputs:
 *  -------
 *
 *
 *  Comments:
 *  --------
 *  o get display, root window ID, and xorGC out of global data.  
 *  o draw on root and erase "atomically"
 * 
 *************************************<->***********************************/
void FlashOutline (int x, int y, unsigned int width, unsigned int height)
{
    static XSegment  outline[SEGS_PER_FLASH];

    /*
     * Do nothing if no box to draw 
     */
    if (x == 0 && y == 0 &&
	width == 0 && height == 0)
	return;

    /*
     * Draw outline an even number of times (draw then erase)
     */
    SetOutline (outline, x, y, width, height, OUTLINE_WIDTH);
    memcpy ( (char *) &outline[SEGS_PER_DRAW], (char *) &outline[0], 
	SEGS_PER_DRAW*sizeof(XSegment));

    /*
     * Flash the outline at least once, then as long as there's 
     * nothing else going on
     */
    DrawSegments(DISPLAY, ACTIVE_ROOT, ACTIVE_PSD->xorGC,
			outline, SEGS_PER_FLASH);
    XSync(DISPLAY, FALSE);

    while (!XtAppPending(wmGD.mwmAppContext)) {
    	DrawSegments(DISPLAY, ACTIVE_ROOT, ACTIVE_PSD->xorGC, 
			outline, SEGS_PER_FLASH);
	XSync(DISPLAY, FALSE);
    }
} /* END OF FUNCTION  FlashOutline */

#ifdef WSM

/*************************************<->*************************************
 *
 *  CreateOutlineWindows (pSD)
 *
 *
 *  Description:
 *  -----------
 *  create the outline windows
 *
 *
 *  Inputs:
 *  ------
 * 
 *  Outputs:
 *  -------
 *
 *  Comments:
 *  --------
 *  variables are affected:
 *      woN
 *      woS
 *      woE
 *      woW
 * 
 *************************************<->***********************************/
static void 
CreateOutlineWindows (WmScreenData *pSD)
{
    XSetWindowAttributes xswa;
    unsigned int xswamask;
    int x, y, width, height;


    x = -10;
    y = -10;
    width = OUTLINE_WIDTH;
    height = OUTLINE_WIDTH;

    xswa.override_redirect = True;    
    xswa.backing_store = NotUseful;
    xswa.save_under = True;
    xswa.background_pixmap = XmGetPixmap(
				XtScreen(pSD->screenTopLevelW),
				"50_foreground", 
				pSD->clientAppearance.foreground,
				pSD->clientAppearance.background);

    xswamask = (CWOverrideRedirect | 
		CWBackingStore | 
		CWBackPixmap |
		CWSaveUnder);
    
    pSD->woN = XCreateWindow(DISPLAY, pSD->rootWindow, 
		       x, y, width, height,
		       0, 
		       XDefaultDepth(DISPLAY,pSD->screen), 
		       CopyFromParent,
		       CopyFromParent, 
		       xswamask, 
		       &xswa);

    pSD->woS = XCreateWindow(DISPLAY, pSD->rootWindow, 
		       x, y, width, height,
		       0, 
		       XDefaultDepth(DISPLAY,pSD->screen), 
		       CopyFromParent,
		       CopyFromParent, 
		       xswamask, 
		       &xswa);

    pSD->woE = XCreateWindow(DISPLAY, pSD->rootWindow, 
		       x, y, width, height,
		       0, 
		       XDefaultDepth(DISPLAY,pSD->screen), 
		       CopyFromParent,
		       CopyFromParent, 
		       xswamask, 
		       &xswa);

    pSD->woW = XCreateWindow(DISPLAY, pSD->rootWindow, 
		       x, y, width, height,
		       0, 
		       XDefaultDepth(DISPLAY,pSD->screen), 
		       CopyFromParent,
		       CopyFromParent, 
		       xswamask, 
		       &xswa);

} /* END OF FUNCTION  CreateOutlineWindows */


/*************************************<->*************************************
 *
 *  WindowOutline ()
 *
 *
 *  Description:
 *  -----------
 *  show an outline on the root window using windows.
 *
 *
 *  Inputs:
 *  ------
 *  x		- x coordinate (on root)
 *  y		- y coordinate (on root)
 *  width	- pixel width of frame
 *  height	- pixel height of frame
 * 
 *  Outputs:
 *  -------
 *
 *
 *  Comments:
 *  --------
 *  Always unmap during move/resize of outline windows to let saveunder
 *  stuff work. HP server's toss saveunder stuff for windows that
 *  configure themselves while mapped.
 * 
 *************************************<->***********************************/
void WindowOutline (int x, int y, unsigned int width, unsigned int height)
{
    static int  lastOutlineX = 0;
    static int  lastOutlineY = 0;
    static int  lastOutlineWidth = 0;
    static int  lastOutlineHeight = 0;
    WmScreenData *pSD = ACTIVE_PSD;
    int iX, iY;
    int iW, iH;

    if (pSD->woN == (Window)0L)
    {
	CreateOutlineWindows(pSD);
    }

    if (x == lastOutlineX && y == lastOutlineY && 
	width == lastOutlineWidth && height == lastOutlineHeight)
    {
	return;		/* no change */
    }

    XUnmapWindow(DISPLAY, pSD->woN);
    XUnmapWindow(DISPLAY, pSD->woS);
    XUnmapWindow(DISPLAY, pSD->woE);
    XUnmapWindow(DISPLAY, pSD->woW);

    if ((width == 0) && (height == 0))
    {
	lastOutlineWidth = lastOutlineHeight = 0;
	lastOutlineX = lastOutlineY = 0;
    }
    else
    {
	/* North */
	iX = x;
	iY = y;
	iW = (int) width;
	iH = OUTLINE_WIDTH;
	if (iW < 0) iW = 1;
	XMoveResizeWindow (DISPLAY, pSD->woN, iX, iY, iW, iH);

	/* West */
	iX = x;
	iY = y + OUTLINE_WIDTH;
	iW = OUTLINE_WIDTH;
	iH = (int) height - OUTLINE_WIDTH;
	if (iH < 0) iH = 1;
	XMoveResizeWindow (DISPLAY, pSD->woW, iX, iY, iW, iH);

	/* East */
	iX = x + (int)width - OUTLINE_WIDTH;
	iY = y + OUTLINE_WIDTH;
	iW = OUTLINE_WIDTH;
	iH = (int)height - OUTLINE_WIDTH;
	if (iH < 0) iH = 1;
	XMoveResizeWindow (DISPLAY, pSD->woE, iX, iY, iW, iH);

	/* South */
	iX = x + OUTLINE_WIDTH;
	iY = y + (int)height - OUTLINE_WIDTH;
	iW = (int)width - 2*OUTLINE_WIDTH;
	iH = OUTLINE_WIDTH;
	if (iW < 0) iW = 1;
	XMoveResizeWindow (DISPLAY, pSD->woS, iX, iY, iW, iH);

	lastOutlineX = x;
	lastOutlineY = y;
	lastOutlineWidth = width;
	lastOutlineHeight = height;

	XMapRaised (DISPLAY, pSD->woN);
	XMapRaised (DISPLAY, pSD->woS);
	XMapRaised (DISPLAY, pSD->woE);
	XMapRaised (DISPLAY, pSD->woW);

	/* cleanup exposed frame parts */
	PullExposureEvents ();
    }

} /* END OF FUNCTION  WindowOutline */

#endif /* WSM */


/*************************************<->*************************************
 *
 *  DrawOutline (x, y, width, height)
 *
 *
 *  Description:
 *  -----------
 *  Draw a window outline on the root window.
 *
 *
 *  Inputs:
 *  ------
 *  x		- x coordinate (on root)
 *  y		- y coordinate (on root)
 *  width	- pixel width of frame
 *  height	- pixel height of frame
 * 
 *  Outputs:
 *  -------
 *
 *
 *  Comments:
 *  --------
 *  o get display, root window ID, and xorGC out of global data.  
 * 
 *************************************<->***********************************/
void DrawOutline (int x, int y, unsigned int width, unsigned int height)
{
    static int  lastOutlineX = 0;
    static int  lastOutlineY = 0;
    static int  lastOutlineWidth = 0;
    static int  lastOutlineHeight = 0;
    XSegment  outline[SEGS_PER_DRAW];


    if (x == lastOutlineX && y == lastOutlineY && 
	width == lastOutlineWidth && height == lastOutlineHeight)
    {
	return;		/* no change */
    }

    if (lastOutlineWidth || lastOutlineHeight) {
	SetOutline (outline, lastOutlineX, lastOutlineY, lastOutlineWidth,
	    lastOutlineHeight, OUTLINE_WIDTH);

    	DrawSegments(DISPLAY, ACTIVE_ROOT, ACTIVE_PSD->xorGC, 
			outline, SEGS_PER_DRAW);
    }

    lastOutlineX = x;
    lastOutlineY = y;
    lastOutlineWidth = width;
    lastOutlineHeight = height;

    if (lastOutlineWidth || lastOutlineHeight) {

	SetOutline (outline, lastOutlineX, lastOutlineY, lastOutlineWidth,
	    lastOutlineHeight, OUTLINE_WIDTH);

    	DrawSegments(DISPLAY, ACTIVE_ROOT, ACTIVE_PSD->xorGC, 
			outline, SEGS_PER_DRAW);
    }
} /* END OF FUNCTION  DrawOutline */



/*************************************<->*************************************
 *
 *  WindowIsOnScreen (pCD, dx, dy)
 *
 *
 *  Description:
 *  -----------
 *  This function is used to check if a window is atleast partially on the
 *  screen or not.  If the window is completely off the screen, dx and dy
 *  will contain the minimum distance to move some part of the window's frame
 *  back onto the screen.
 *
 *
 *  Inputs:
 *  ------
 *  pCD		- pointer to client data
 *
 * 
 *  Outputs:
 *  -------
 *  dx		- minimum x distance to move the window back to the screen
 *  dy		- minimum y distance to move the window back to the screen
 *
 *
 *  Returns:
 *  --------
 *  true	- if the window has some part on the screen
 *  false       - if the window is completely off the screen
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/

Boolean WindowIsOnScreen (ClientData *pCD, int *dx, int *dy)
{
  int x1 = pCD->clientX;
  int x2 = pCD->clientX + pCD->clientWidth;
  int y1 = pCD->clientY;
  int y2 = pCD->clientY + pCD->clientHeight;
  int screenW = DisplayWidth (DISPLAY, SCREEN_FOR_CLIENT(pCD));
  int screenH = DisplayHeight(DISPLAY, SCREEN_FOR_CLIENT(pCD));

  *dx = *dy = 0;
  
  if (x2 < 0)			/* right frame border off left side of screen. */
    *dx =  -x2;
  else if (x1 > screenW)	/* left frame border off right side of screen. */
    *dx = screenW - x1;
  
  if (y2 < 0)			/* bottom frame border off top of screen. */
    *dy = -y2;
  else if (y1 > screenH)	/* top frame border off bottom of screen. */
    *dy = screenH - y1;
  
  return ((*dx == 0) && (*dy == 0));
}



/*************************************<->*************************************
 *
 *  ProcessNewConfiguration (pCD, x, y, width, height, clientRequest)
 *
 *
 *  Description:
 *  -----------
 *  This function is used to configure a client window following receipt of
 *  a client request or an interactive configuration action.
 *
 *
 *  Inputs:
 *  ------
 *  pCD		- pointer to client data
 *  x		- x coord of client window
 *  y		- y coord of client window
 *  width	- width of client window
 *  height	- height of client window
 *  clientRequest	- true if configuration requested by client program
 *
 * 
 *  Outputs:
 *  -------
 *
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/

void ProcessNewConfiguration (ClientData *pCD, int x, int y, unsigned int width, unsigned int height, Boolean clientRequest)
{
    unsigned int changedValues = 0;
    int          xoff = 0, yoff = 0;
    int          dx, dy;
    Boolean      originallyOnScreen = WindowIsOnScreen(pCD, &dx, &dy);
    Boolean newMax = False;
    Boolean toNewMax = False;

    /*
     * Fix the configuration values to be compatible with the configuration
     * constraints for this class of windows.
     */

    

    FixWindowConfiguration (pCD, &width, &height,
				 (unsigned int) pCD->widthInc, 
				 (unsigned int) pCD->heightInc);

    if ((pCD->maxWidth != pCD->oldMaxWidth) ||
	 (pCD->maxHeight != pCD->oldMaxHeight))
    {
	/*
	 * We've got a new maximum size.
	 */
	newMax = True;
    }

    /*
     * If the configuration has changed, update client data
     * 
     * Changes in width or height cause maximized windows to return to
     * normal state and update normal geometry (x, y, width, height)
     */
    if (pCD->maxConfig) 
    {
	if (newMax &&
	    (pCD->maxWidth == width) &&
	    (pCD->maxHeight == height))
	{
	    /* we're changing to the new max size */
	    toNewMax = True;
	}

	changedValues |= (width != pCD->oldMaxWidth) ? CWWidth : 0;
	changedValues |= (height != pCD->oldMaxHeight) ? CWHeight : 0;

	if (!toNewMax && (changedValues & CWWidth)) {
	    /*
	     * Hacked to update maxWidth for 'vertical' max clients
	     */
	    if (IS_MAXIMIZE_VERTICAL(pCD)) {
		pCD->maxWidth = width;
	    }
	    pCD->clientWidth = width;
	    if (changedValues & CWHeight) {
		/*
		 * Hacked to update maxHeight for 'horizontal' max client
		 */
		if (IS_MAXIMIZE_HORIZONTAL(pCD)) {
		    pCD->maxHeight = height;
		}
		pCD->clientHeight = height;
	    }
	    else {
		pCD->clientHeight = pCD->oldMaxHeight;
	    }
	}
	else if (!toNewMax && (changedValues & CWHeight)) {
	    /*
	     * Hacked to update maxHeight for 'horizontal' max client
	     */
	    if (IS_MAXIMIZE_HORIZONTAL(pCD)) {
		pCD->maxHeight = height;
	    }
	    pCD->clientHeight = height;
	    pCD->clientWidth = pCD->oldMaxWidth;
	}
    }
    else {
	if (width != pCD->clientWidth)
	{
	    /*
	     * Hacked to update maxWidth for 'vertical' max clients
	     */
	    if (IS_MAXIMIZE_VERTICAL(pCD)) {
		pCD->maxWidth = width;
	    }

	    changedValues |= CWWidth;
	    pCD->clientWidth = width;

	}

	if (height != pCD->clientHeight)
	{
	    /*
	     * Hacked to update maxHeight for 'horizontal' max client
	     */
	    if (IS_MAXIMIZE_HORIZONTAL(pCD)) {
		pCD->maxHeight = height;
	    }

	    changedValues |= CWHeight;
	    pCD->clientHeight = height;
	}
    }

#ifndef CONFIG_RELATIVE_TO_CLIENT
    /*
     * If positionIsFrame or user initiated configuration request,
     * then adjust client position to by frame_width and frame_height.
     */
    if (wmGD.positionIsFrame || (!clientRequest))
    {
	xoff = pCD->clientOffset.x;
	yoff = pCD->clientOffset.y;
    }
#endif

    /*
     * Changes in position update maximum geometry on maximized windows
     * if there was no change in size.
     */
    if (pCD->maxConfig) {
	if (x != pCD->maxX) {
	    changedValues |= CWX;
	    if (!toNewMax && (changedValues & (CWWidth | CWHeight)))
		pCD->clientX = x + xoff;
	    else
		pCD->maxX = x + xoff;
	}
	else if (!toNewMax && (changedValues & (CWWidth | CWHeight)))
	{
	    pCD->clientX = pCD->maxX;
	}

	if (y != pCD->maxY) {
	    changedValues |= CWY;
	    if (!toNewMax && (changedValues & (CWWidth | CWHeight)))
		pCD->clientY = y + yoff;
	    else
		pCD->maxY = y + yoff;
	}
	else if (!toNewMax && (changedValues & (CWWidth | CWHeight))) 
	{
	    pCD->clientY = pCD->maxY;
	}
    }
    else {
	if (x + xoff != pCD->clientX) {
	    changedValues |= CWX;
	    pCD->clientX = x + xoff;
	}

	if (y + yoff != pCD->clientY) {
	    changedValues |= CWY;
	    pCD->clientY = y + yoff;
	}
    }

    /* check if the window has reconfigured itself off the screen. */
    if (originallyOnScreen && !WindowIsOnScreen(pCD, &dx, &dy))
      {
	if (dx != 0)
	  {
	    changedValues |= CWX;
	    pCD->clientX += dx;
	  }

	if (dy != 0)
	  {
	    changedValues |= CWY;
	    pCD->clientY += dy;
	  }
      }


    /*
     * Resize the client window if necessary:
     */

    if (changedValues & (CWWidth | CWHeight))
    {
	if (pCD->maxConfig) 
	{
	    if (!toNewMax)
	    {
		/* maximized window resized, return to normal state */
		pCD->maxConfig = FALSE;
		pCD->clientState = NORMAL_STATE;
	    }
	}

	XResizeWindow (DISPLAY, pCD->client, width, height);
	RegenerateClientFrame(pCD);
    }
    if (changedValues & (CWX | CWY)) {
	if (pCD->maxConfig)
	{
	  /*
	   * Fix for 5217 - If the request is from the client, use the clients
	   *                offsets instead of the static offsets
	   */
	  if (clientRequest)
	    {
	      XMoveWindow (DISPLAY, pCD->clientFrameWin,
			   pCD->maxX - pCD->clientOffset.x,
			   pCD->maxY - pCD->clientOffset.y);
	    }
	  else
	    {
	      XMoveWindow (DISPLAY, pCD->clientFrameWin, 
			   pCD->maxX - offsetX,
			   pCD->maxY - offsetY);
	    }
	  /* End fix 5217 */
	}
	else 
	{
            if (clientRequest)
            {
                XMoveWindow (DISPLAY, pCD->clientFrameWin,
                             pCD->clientX - pCD->clientOffset.x,
                             pCD->clientY - pCD->clientOffset.y);
            }
            else
            {
                XMoveWindow (DISPLAY, pCD->clientFrameWin,
                             pCD->clientX - offsetX,
                             pCD->clientY - offsetY);
            }
	}
	SetFrameInfo (pCD);
#ifdef PANELIST
	if (pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUBPANEL)
	{
	    /* turn off subpanel behavior if moved */
	    pCD->dtwmBehaviors &= ~DtWM_BEHAVIOR_SUBPANEL;
	}
#endif /* PANELIST */
    }

    /*
     * Send a configure notify  message if appropriate:
     *   1. rejected client configuration request.
     *   2. client request and move without resize 
     */


    if ((!changedValues && clientRequest) ||
	(changedValues && !(changedValues & (CWWidth | CWHeight))))
    {
	SendConfigureNotify (pCD);
    }

    /*
     * Try to send notice directly to icon box that the window
     * has changed size
     */

    if ((pCD->clientFlags & ICON_BOX) && 
	(changedValues & (CWWidth | CWHeight)))
    {
	CheckIconBoxResize(pCD, changedValues, width, height);
    }

} /* END OF FUNCTION ProcessNewConfiguration */



/*************************************<->*************************************
 *
 *  StartResizeConfig (pcd, pev)
 *
 *
 *  Description:
 *  -----------
 *  Start resize of client window 
 *
 *
 *  Inputs:
 *  ------
 *  pcd		- pointer to client data
 *  pev		- pointer to event
 * 
 *  Outputs:
 *  -------
 *  return	- true if configuration can begin, else false
 *
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/

Boolean StartResizeConfig (ClientData *pcd, XEvent *pev)
{
    Window grab_win, junk_win;
    Boolean grabbed;
    int big_inc, tmp_inc;
    int junk, junkX, junkY;

    /*
     *	Do our grabs 
     */
    if (!configGrab)
    {
	grab_win = GrabWin (pcd, pev);

	if (pev)
	{
	    grabbed = DoGrabs (grab_win, ConfigCursor((int) wmGD.configPart), 
			PGRAB_MASK, pev->xbutton.time, pcd, True);
	}
	else
	{
	    grabbed = DoGrabs (grab_win, ConfigCursor((int) wmGD.configPart), 
			PGRAB_MASK, CurrentTime, pcd, True);
	}
	if (!grabbed)
	{
	    return (False);
	}
	configGrab = TRUE;
    }
    else
    {
	/* continue with the configuration in progress (!!!) */
	return (True);
    }

    /* 
     * Set up static variables for succeeding events 
     */
    if (!XQueryPointer (DISPLAY, ROOT_FOR_CLIENT(pcd), &junk_win, &junk_win,
		   &pointerX, &pointerY, &junk, &junk, (unsigned int *)&junk))
    {
	CancelFrameConfig (pcd);	/* release grabs */
	return (False);
    };
    wmGD.preMoveX = pointerX;
    wmGD.preMoveY = pointerY;
    anyMotion = FALSE;

    offsetX = pcd->clientOffset.x;
    offsetY = pcd->clientOffset.y;

    /* 
     * get window geometry information and convert to frame coordinates
     */
    if (pcd->maxConfig) {
	resizeX = pcd->maxX;
	resizeY = pcd->maxY;
	resizeWidth = pcd->maxWidth;
	resizeHeight = pcd->maxHeight;
    }
    else {
	resizeX = pcd->clientX;
	resizeY = pcd->clientY;
	resizeWidth = pcd->clientWidth;
	resizeHeight = pcd->clientHeight;
    }
    ClientToFrame(pcd, &resizeX, &resizeY, &resizeWidth, &resizeHeight);

    /* save start values to see where we came from */
    startX = resizeX;
    startY = resizeY;
    startWidth = resizeWidth;
    startHeight = resizeHeight;

    /* get min and max frame sizes */
    minWidth = pcd->minWidth;
    minHeight = pcd->minHeight;
    junkX = junkY = 0;
    ClientToFrame(pcd, &junkX, &junkY, &minWidth, &minHeight);

    /*
     * Hack 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.
     */
    maxWidth = pcd->maxWidthLimit;
    maxHeight = pcd->maxHeightLimit;
    junkX = junkY = 0;
    ClientToFrame(pcd, &junkX, &junkY, &maxWidth, &maxHeight);

    /* compute big increment values */
    big_inc = DisplayWidth (DISPLAY, SCREEN_FOR_CLIENT(pcd)) / 20;

    tmp_inc = big_inc - big_inc%pcd->widthInc;
    if (tmp_inc > 5*pcd->widthInc)
	resizeBigWidthInc = tmp_inc;
    else 
	resizeBigWidthInc = 5*pcd->widthInc;

    tmp_inc = big_inc - big_inc%pcd->heightInc;
    if (tmp_inc > 5*pcd->heightInc)
	resizeBigHeightInc = tmp_inc;
    else 
	resizeBigHeightInc = 5*pcd->heightInc;

    /* pop up feedback window */
    if (wmGD.showFeedback & WM_SHOW_FB_RESIZE)
    {
	DoFeedback (pcd, resizeX, resizeY, resizeWidth, resizeHeight, 
		    FB_SIZE, TRUE /* do size checks */);
    }

    /* set configuring data */
    wmGD.configAction = RESIZE_CLIENT;
    wmGD.configButton = pev ? pev->xbutton.button: 0;

    return (True);

} /* END OF FUNCTION StartResizeConfig */



/*************************************<->*************************************
 *
 *  StartClientResize (pcd, pev)
 *
 *
 *  Description:
 *  -----------
 *  Start resize of client window as invoked from menu
 *
 *
 *  Inputs:
 *  ------
 *  pcd		- pointer to client data
 *  pev		- pointer to event
 * 
 *  Outputs:
 *  -------
 *
 *
 *  Comments:
 *  --------
 *  o This should only be called as the result of a Resize function 
 *    being selected from the system menu.
 * 
 *************************************<->***********************************/
void StartClientResize (ClientData *pcd, XEvent *pev)
{

    /* do initial setup for resize */
    wmGD.configPart = FRAME_NONE;	/* determined by later action */
    wmGD.configSet = False;		/* don't know what it is yet */
    if (!StartResizeConfig (pcd, pev))
    {
	/* resize could not be initiated */
	return;
    }


    /*
     *  Warp pointer to middle of window if started from the keyboard
     *  or menu (no event).
     */
    if ( !pev || pev->type == KeyPress )
    {
	pointerX = resizeX + resizeWidth/2;
	pointerY = resizeY + resizeHeight/2;

	ForceOnScreen(SCREEN_FOR_CLIENT(pcd), &pointerX, &pointerY);
	if (wmGD.enableWarp)
	{
	    XWarpPointer(DISPLAY, None, ROOT_FOR_CLIENT(pcd), 
		     0, 0, 0, 0, pointerX, pointerY);
	}
    }

} /* END OF FUNCTION StartClientResize  */


/*************************************<->*************************************
 *
 *  StartClientMove (pcd, pev)
 *
 *
 *  Description:
 *  -----------
 *  Handle move of client window as invoked from menu
 *
 *
 *  Inputs:
 *  ------
 *  pcd		- pointer to client data
 *  pev		- pointer to event
 * 
 *  Outputs:
 *  -------
 *  Return	- True if configuration was initiated, else False
 *
 *
 *  Comments:
 *  --------
 *  o This should only be called as the result of a Move function 
 *    being selected from the system menu.
 * 
 *************************************<->***********************************/
Boolean StartClientMove (ClientData *pcd, XEvent *pev)
{
    Window grab_win, junk_win;
    Boolean grabbed;
    int junk;
    Window child;

    /*
     *	Do our grabs if we're just starting out
     */
    if (!configGrab)
    {
	grab_win = GrabWin (pcd, pev);
	if (grab_win == ICON_FRAME_WIN(pcd))
	{
	    wmGD.movingIcon = True;
	}

	if (pev)
	{
	    grabbed = DoGrabs (grab_win, wmGD.configCursor, 
			PGRAB_MASK, pev->xbutton.time, pcd, False);
	}
	else
	{
	    grabbed = DoGrabs (grab_win, wmGD.configCursor, 
			PGRAB_MASK, CurrentTime, pcd, False);
	}
	if (!grabbed)
	{
	    wmGD.movingIcon = False;
	    return (False);
	}
	configGrab = TRUE;
    }

    /* 
     * Set up static variables for succeeding events if we're not 
     * entering with a motion event. If we are, we assume that the
     * preMove variables have been setup.
     */
    if (pev && ((pev->type == ButtonPress) || (pev->type == ButtonRelease)))
    {
	wmGD.preMoveX = pev->xbutton.x_root;
	wmGD.preMoveY = pev->xbutton.y_root;
    }
    else if ((pev && (pev->type != MotionNotify)) || !pev)
    {
	if (!XQueryPointer (DISPLAY, ROOT_FOR_CLIENT(pcd), 
		   &junk_win, &junk_win,
		   &(wmGD.preMoveX), &(wmGD.preMoveY),
		   &junk, &junk, (unsigned int *)&junk))
	{
	    CancelFrameConfig (pcd);
	    return (False);
	}
    }

    offsetX = pcd->clientOffset.x;
    offsetY = pcd->clientOffset.y;

    anyMotion = FALSE;
    moveLastPointerX = wmGD.preMoveX;
    moveLastPointerY = wmGD.preMoveY;

    /* get frame window geometry */
    if (wmGD.movingIcon)
    {
	moveWidth = ICON_WIDTH(pcd);
	moveHeight = ICON_HEIGHT(pcd);

	moveX = ICON_X(pcd);
	moveY = ICON_Y(pcd);

	if (pcd->pSD->useIconBox && P_ICON_BOX(pcd))
	{
	    /* get root coords of icon box bulletin board */
	    XTranslateCoordinates(DISPLAY, 
	        XtWindow(P_ICON_BOX(pcd)->bBoardWidget), ROOT_FOR_CLIENT(pcd), 
	        0, 0, &moveIBbbX, &moveIBbbY, &child);

	    moveX += moveIBbbX;
	    moveY += moveIBbbY;
	}
	else if (pcd->pSD->moveOpaque &&
		 (ICON_DECORATION(pcd) & ICON_ACTIVE_LABEL_PART) &&
		 (wmGD.keyboardFocus == pcd))
	{
	    HideActiveIconText ((WmScreenData *)NULL);
	}
    }
    else 
    {
	if (pcd->maxConfig) {	/* maximized */
	    moveWidth = pcd->maxWidth;
	    moveHeight = pcd->maxHeight;
	    moveX = pcd->maxX;
	    moveY = pcd->maxY;
	}
	else {			/* normal */
	    moveWidth = pcd->clientWidth;
	    moveHeight = pcd->clientHeight;
	    moveX = pcd->clientX;
	    moveY = pcd->clientY;
	}
	ClientToFrame (pcd, &moveX, &moveY, &moveWidth, &moveHeight);
    }

    if (pcd->pSD->moveOpaque)
    {
	opaqueMoveX = moveX;
	opaqueMoveY = moveY;
    }

    /*
     *  Warp pointer to middle of window if started from the menu (no event).
     */
    if ( !pev || pev->type == KeyPress )
    {
	moveLastPointerX = moveX + moveWidth/2;
	moveLastPointerY = moveY + moveHeight/2;

	ForceOnScreen (SCREEN_FOR_CLIENT(pcd), 
		       &moveLastPointerX, &moveLastPointerY);
	if (wmGD.enableWarp)
	{
	    XWarpPointer(DISPLAY, None, ROOT_FOR_CLIENT(pcd), 0, 0, 0, 0, 
		moveLastPointerX, moveLastPointerY);
	}
    }

    /* pop up feedback window */
    if ( !wmGD.movingIcon && (wmGD.showFeedback & WM_SHOW_FB_MOVE))
    {
	DoFeedback (pcd, moveX, moveY, moveWidth, moveHeight, 
		    FB_POSITION, FALSE /* no size checks */);
    }
    
    /* set configuring data */
    wmGD.configAction = MOVE_CLIENT;
    if (pev && pev->type != KeyPress)
	wmGD.configButton = pev->xbutton.button;
    else 
	wmGD.configButton = 0;


    return (True);


} /* END OF FUNCTION StartClientMove */


#if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
/*************************************<->*************************************
 *
 *  SetGrabServer ()
 *
 *
 *  Description:
 *  -----------
 *  Sets Boolean grabServer to False
 *
 *  Inputs:
 *  ------
 *  None
 *  
 *  Outputs:
 *  -------
 *  None
 *  
 *  Comments
 *  -------
 *  This will only get called when an automated test is running. The
 *  purpose of this is to prevent mwm from grbbing the server, since
 *  this confuses the automation input synthesis code
 *  
 *************************************<->***********************************/
void SetGrabServer (void)
{
    grabServer = FALSE;
}
#endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */


/*************************************<->*************************************
 *
 *  DoGrabs (grab_win, cursor, pmask, grabTime, alwaysGrab)
 *
 *
 *  Description:
 *  -----------
 *  Do the grabs for window configuration
 *
 *
 *  Inputs:
 *  ------
 *  grab_win	- window to grab on
 *  cursor	- cursor shape to attach to the pointer
 *  pmask	-
 *  grabTime	- time stamp
 *  alwaysGrab  - 
 *
 * 
 *  Outputs:
 *  -------
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/
Boolean DoGrabs (Window grab_win, Cursor cursor, unsigned int pmask, Time grabTime, ClientData *pCD, Boolean alwaysGrab)
{

#ifdef WSM
    Window root;

    if (pCD)
	root = ROOT_FOR_CLIENT(pCD);
    else
	root = RootWindow (DISPLAY, ACTIVE_PSD->screen);

    if (pCD && pCD->pSD->useIconBox && wmGD.movingIcon && P_ICON_BOX(pCD))
#else
    if (pCD->pSD->useIconBox && wmGD.movingIcon && P_ICON_BOX(pCD))
#endif
    {
	/*
	 * Confine the pointer to the icon box clip window
	 */
	if (XGrabPointer(DISPLAY, 
			 grab_win,
			 FALSE,			/* owner_events */
			 pmask,
			 GrabModeAsync,		/* pointer_mode */
			 GrabModeAsync,		/* keyboard_mode */
						/* confine_to window */
			 XtWindow(P_ICON_BOX(pCD)->clipWidget),
			 cursor,
			 grabTime) != GrabSuccess)
	{	
	    return(FALSE);
	}
    }
    else
    {
	/*
	 * Just confine the pointer to the root window
	 */
	if (XGrabPointer(DISPLAY, 
			 grab_win,
			 FALSE,			/* owner_events */
			 pmask,
			 GrabModeAsync,		/* pointer_mode */
			 GrabModeAsync,		/* keyboard_mode */
#ifdef WSM
			 root,
#else
			 ROOT_FOR_CLIENT(pCD),		/* confine_to window */
#endif
			 cursor,
			 grabTime) != GrabSuccess)
	{
	    return(FALSE);
	}
    }

    /*
     * Don't grab keyboard away from menu widget to prevent 
     * hosing of traversal.
     */
    if (!wmGD.menuActive) 
    {
	if ((XGrabKeyboard(DISPLAY, 
			   grab_win,
			   FALSE,			/* owner_events */
			   GrabModeAsync,		/* pointer_mode */
			   GrabModeAsync,		/* keyboard_mode */
			   grabTime)) != GrabSuccess)
	{
	    XUngrabPointer (DISPLAY, CurrentTime);
	    return(FALSE);
	}
    }
    
    
	/* 
	 * If running automation version of mwm, do not grab the server, since
	 * this will confuse the automation input synthesis code.
	 */
# if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
if (grabServer == TRUE)
# endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */

    if (wmGD.freezeOnConfig) 
	
    {
#ifdef WSM
	if (!pCD || ((pCD->pSD->moveOpaque && alwaysGrab) ||
	           (!(pCD->pSD->moveOpaque))))
#else /* WSM */
	if ((pCD->pSD->moveOpaque && alwaysGrab) ||
	    (!(pCD->pSD->moveOpaque)))
#endif /* WSM */
	{
	    XGrabServer(DISPLAY);
        }
    }
    
    return(TRUE);
} /* END OF FUNCTION DoGrabs   */


/*************************************<->*************************************
 *
 *  UndoGrabs ()
 *
 *
 *  Description:
 *  -----------
 *  Release the grabs
 *
 *
 *  Inputs:
 *  ------
 *
 * 
 *  Outputs:
 *  -------
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/
void UndoGrabs (void)
{
    /* erase outline */
    MoveOutline(0, 0, 0, 0);
    XSync (DISPLAY, FALSE /*don't discard events*/);

    /* give up grabs */
    if (wmGD.freezeOnConfig) {
	XUngrabServer(DISPLAY);
    }

    /*
     * Don't Ungrab keyboard away from menu widget to prevent 
     * hosing of traversal.
     */
    if (!wmGD.menuActive)
	XUngrabKeyboard (DISPLAY,CurrentTime);

    XUngrabPointer (DISPLAY, CurrentTime);	/* event time NOT used */
    XFlush (DISPLAY);

} /* END OF FUNCTION UndoGrabs  */



/*************************************<->*************************************
 *
 *  CancelFrameConfig (pcd)
 *
 *
 *  Description:
 *  -----------
 *  Cance a frame configuration (move/resize) operation.
 *
 *
 *  Inputs:
 *  ------
 *  pcd 	- pointer to client data
 *
 * 
 *  Outputs:
 *  -------
 *
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/
void CancelFrameConfig (ClientData *pcd)
{

    /* remove keyboard, pointer, and server grabs */
    UndoGrabs();

    /* turn off feedback window */
#ifdef WSM
    if (pcd)
    {
#endif /* WSM */
    HideFeedbackWindow(pcd->pSD);

    /* make sure title bar is popped out */
    if ((wmGD.configAction == MOVE_CLIENT) &&
	(wmGD.gadgetClient == pcd) && (wmGD.gadgetDepressed == FRAME_TITLE))
    {
	PopGadgetOut (pcd, FRAME_TITLE);
	FrameExposureProc(pcd);			/* repaint frame */
    }
    if ((pcd->pSD->moveOpaque) &&
	(wmGD.configAction == MOVE_CLIENT))
	
    {
	if ((pcd->clientState == MINIMIZED_STATE) &&
	    (!(pcd->pSD->useIconBox && P_ICON_BOX(pcd))))
	{
	    /*
	     * Replace icon into pre-move position
	     */

	    XMoveWindow (DISPLAY, ICON_FRAME_WIN(pcd),
			 ICON_X(pcd),  ICON_Y(pcd));
	    if ((ICON_DECORATION(pcd) & ICON_ACTIVE_LABEL_PART))
	    {
		ShowActiveIconText(pcd);
	    }
	}
	else if (! wmGD.movingIcon) /* we are not moving in the iconbox */
	{
	    XMoveWindow (DISPLAY, pcd->clientFrameWin, 
			 opaqueMoveX, opaqueMoveY);
	}
    }
#ifdef WSM
    }
    if (wmGD.configAction == MARQUEE_SELECT)
    {
       dtSendMarqueeSelectionNotification(ACTIVE_PSD, DT_MARQUEE_SELECT_CANCEL, 
			    marqueeX, marqueeY, 0, 0);
    }
#endif /* WSM */

    /* replace pointer if no motion events received */
#ifdef WSM
    if (pcd)
#endif /* WSM */
    if (!anyMotion && wmGD.enableWarp) {
	XWarpPointer(DISPLAY, None, ROOT_FOR_CLIENT(pcd), 
			 0, 0, 0, 0, wmGD.preMoveX, wmGD.preMoveY);
    }
    anyMotion = FALSE;

    /* Clear configuration flags and data */
    wmGD.configAction = NO_ACTION;
    wmGD.configPart = FRAME_NONE;
    wmGD.configSet = False;
    configGrab = FALSE;
    wmGD.movingIcon = FALSE;
    
    /* set the focus back to a reasonable window */
    RepairFocus ();	
} /* END OF FUNCTION  CancelFrameConfig */



/*************************************<->*************************************
 *
 *  CheckEatButtonRelease (pcd, pev)
 *
 *
 *  Description:
 *  -----------
 *  Set up to eat button releases if buttons are down.
 *
 *
 *  Inputs:
 *  ------
 *  pcd  - pointer to client data
 *  pev	 - pointer to key event that caused cancel
 * 
 *  Outputs:
 *  -------
 *  none
 *
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/
void
CheckEatButtonRelease (ClientData *pcd, XEvent *pev)
{
    Window grab_win;
#ifdef WSM
    Window root;

    if (pcd != (ClientData *)NULL)
	root = ROOT_FOR_CLIENT(pcd);
    else
	root = RootWindow (DISPLAY, ACTIVE_PSD->screen);
#endif /* WSM */

#ifdef WSM
    if (pcd == (ClientData *) NULL)
	grab_win = root;
    else
#endif /* WSM */
    grab_win = GrabWin(pcd, pev);

    if ((pev->type == KeyPress || pev->type == KeyRelease) &&
	(pev->xbutton.state & ButtonMask))
    {
	/*
	 * Some buttons are down... 
	 * Set up conditions to wait for these buttons to go up.
	 */
	if (XGrabPointer(DISPLAY, 
			 grab_win,
			 False,			/* owner_events */
			 ButtonReleaseMask,
			 GrabModeAsync,		/* pointer_mode */
			 GrabModeAsync,		/* keyboard_mode */
#ifdef WSM
			 root,			/* confine_to window */
#else /* WSM */
			 ROOT_FOR_CLIENT(pcd),	/* confine_to window */
#endif /* WSM */
			 wmGD.configCursor,
			 pev->xbutton.time) == GrabSuccess)
	{
	    EatButtonRelease (pev->xbutton.state & ButtonMask);
	}
    }
}


/*************************************<->*************************************
 *
 *  EatButtonRelease (releaseButtons)
 *
 *
 *  Description:
 *  -----------
 *  Eat up button release events
 *
 *
 *  Inputs:
 *  ------
 *  releaseButtons = button mask of button releases to eat
 * 
 *  Outputs:
 *  -------
 *  none
 *
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/
void
EatButtonRelease (unsigned int releaseButtons)
{
    unsigned int new_state;
    XEvent event;

    while (releaseButtons)
    {
#ifdef WSM
	PullExposureEvents ();
#endif /* WSM */
	XMaskEvent (DISPLAY, ButtonReleaseMask, &event);

	if (event.type == ButtonRelease)
	{
	    /* look at the state after this button is released */
	    new_state = 
		event.xbutton.state & ~ButtonStateBit(event.xbutton.button);

	    if (!(new_state & releaseButtons))
	    {
		/* all the buttons we were waiting for have been
		 * released.
		 */

		XUngrabPointer (DISPLAY, event.xbutton.time);
		releaseButtons = 0;
	    }
	}
    }
}



/*************************************<->*************************************
 *
 *  ButtonStateBit (button)
 *
 *
 *  Description:
 *  -----------
 *  Converts a button number to a button state bit
 *
 *
 *  Inputs:
 *  ------
 *  button = button number (Button1, Button2, etc.)
 * 
 *  Outputs:
 *  -------
 *  Return = bit used in xbutton state field 
 *		(Button1Mask, Button2Mask,...)
 *
 *
 *  Comments:
 *  --------
 *  
 * 
 *************************************<->***********************************/
unsigned int
ButtonStateBit (unsigned int button)
{
#define MAX_BUTTON 5
    typedef struct {
	unsigned int button;
	unsigned int maskbit;
    } ButtonAssoc;

    static ButtonAssoc bmap[MAX_BUTTON] = {
	 {Button1, Button1Mask},
	 {Button2, Button2Mask},
	 {Button3, Button3Mask},
	 {Button4, Button4Mask},
	 {Button5, Button5Mask},
    };

    int i;
    unsigned int rval = 0;

    for (i = 0; i < MAX_BUTTON; i++)
    {
	if (bmap[i].button == button)
	{
	    rval = bmap[i].maskbit;
	    break;
	}
    }

    return (rval);

}

/*************************************<->*************************************
 *
 *  ConfigCursor (frame_part)
 *
 *
 *  Description:
 *  -----------
 *  return the config cursor that goes with the config part specified
 *
 *
 *  Inputs:
 *  ------
 *  frame_part	- frame part id
 * 
 *  Outputs:
 *  -------
 *  return	- cursor to use 
 *
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/
Cursor ConfigCursor (int frame_part)
{
    Cursor cursor;

    switch (frame_part) {
	case FRAME_RESIZE_NW:
	    cursor = wmGD.stretchCursors[STRETCH_NORTH_WEST];
	    break;
	case FRAME_RESIZE_N:
	    cursor = wmGD.stretchCursors[STRETCH_NORTH];
	    break;
	case FRAME_RESIZE_NE:
	    cursor = wmGD.stretchCursors[STRETCH_NORTH_EAST];
	    break;
	case FRAME_RESIZE_E:
	    cursor = wmGD.stretchCursors[STRETCH_EAST];
	    break;
	case FRAME_RESIZE_SE:
	    cursor = wmGD.stretchCursors[STRETCH_SOUTH_EAST];
	    break;
	case FRAME_RESIZE_S:
	    cursor = wmGD.stretchCursors[STRETCH_SOUTH];
	    break;
	case FRAME_RESIZE_SW:
	    cursor = wmGD.stretchCursors[STRETCH_SOUTH_WEST];
	    break;
	case FRAME_RESIZE_W:
	    cursor = wmGD.stretchCursors[STRETCH_WEST];
	    break;
	default:
	    cursor = wmGD.configCursor;
    }

    return(cursor);

} /* END OF FUNCTION ConfigCursor  */


/*************************************<->*************************************
 *
 *  ReGrabPointer (grab_win, grabTime)
 *
 *
 *  Description:
 *  -----------
 *  Grab the pointer again to change the cursor
 *
 *
 *  Inputs:
 *  ------
 *  grab_win	- 
 *  grabTime	- time stamp
 * 
 *  Outputs:
 *  -------
 *
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/
void ReGrabPointer (Window grab_win, Time grabTime)
{
    XGrabPointer(DISPLAY, 
		 grab_win,
		 FALSE,			/* owner_events */
		 PGRAB_MASK,
		 GrabModeAsync,		/* pointer_mode */
		 GrabModeAsync,		/* keyboard_mode */
		 ACTIVE_ROOT,		/* confine_to window */
		 ConfigCursor((int)wmGD.configPart),
		 grabTime);

} /* END OF FUNCTION  ReGrabPointer */



/*************************************<->*************************************
 *
 *  SetPointerResizePart (pcd, pev)
 *
 *
 *  Description:
 *  -----------
 *  Sets the global configuration part for resize based on the current
 *  configuration part and the location of the event
 *
 *
 *  Inputs:
 *  ------
 *  pcd 	- pointer to client data
 *  pev		- pointer to event
 *
 * 
 *  Outputs:
 *  -------
 *  Return	- TRUE if wmGD.configPart is a valid resize part
 *
 *
 *  Comments:
 *  --------
 *  o Assumes the static data for resizing has been set up.
 *************************************<->***********************************/
Boolean SetPointerResizePart (ClientData *pcd, XEvent *pev)
{
    int newPart;
    Time grabTime;

    newPart = ResizeType(pcd, pev);	/* get part id for this event */
    grabTime = (pev) ? pev->xmotion.time : CurrentTime;

    switch (wmGD.configPart) {
	case FRAME_NONE:
	    if (newPart == FRAME_NONE)
		return(FALSE);		/* still not valid */

	    wmGD.configPart = newPart;
	    ReGrabPointer(pcd->clientFrameWin, grabTime);
	    return(TRUE);

	case FRAME_RESIZE_N:
	    switch (newPart) {
		case FRAME_RESIZE_W:
		case FRAME_RESIZE_NW:
		    wmGD.configPart = FRAME_RESIZE_NW;
		    ReGrabPointer(pcd->clientFrameWin, grabTime);
		    break;

		case FRAME_RESIZE_E:
		case FRAME_RESIZE_NE:
		    wmGD.configPart = FRAME_RESIZE_NE;
		    ReGrabPointer(pcd->clientFrameWin, grabTime);
		    break;

		default:
		    break;
	    }
	    break;

	case FRAME_RESIZE_E:
	    switch (newPart) {
		case FRAME_RESIZE_N:
		case FRAME_RESIZE_NE:
		    wmGD.configPart = FRAME_RESIZE_NE;
		    ReGrabPointer(pcd->clientFrameWin, grabTime);
		    break;

		case FRAME_RESIZE_S:
		case FRAME_RESIZE_SE:
		    wmGD.configPart = FRAME_RESIZE_SE;
		    ReGrabPointer(pcd->clientFrameWin, grabTime);
		    break;

		default:
		    break;
	    }
	    break;

	case FRAME_RESIZE_S:
	    switch (newPart) {
		case FRAME_RESIZE_E:
		case FRAME_RESIZE_SE:
		    wmGD.configPart = FRAME_RESIZE_SE;
		    ReGrabPointer(pcd->clientFrameWin, grabTime);
		    break;

		case FRAME_RESIZE_W:
		case FRAME_RESIZE_SW:
		    wmGD.configPart = FRAME_RESIZE_SW;
		    ReGrabPointer(pcd->clientFrameWin, grabTime);
		    break;

		default:
		    break;
	    }
	    break;

	case FRAME_RESIZE_W:
	    switch (newPart) {
		case FRAME_RESIZE_N:
		case FRAME_RESIZE_NW:
		    wmGD.configPart = FRAME_RESIZE_NW;
		    ReGrabPointer(pcd->clientFrameWin, grabTime);
		    break;

		case FRAME_RESIZE_S:
		case FRAME_RESIZE_SW:
		    wmGD.configPart = FRAME_RESIZE_SW;
		    ReGrabPointer(pcd->clientFrameWin, grabTime);
		    break;

		default:
		    break;
	    }
	    break;

	case FRAME_RESIZE_NW:
	case FRAME_RESIZE_NE:
	case FRAME_RESIZE_SW:
	case FRAME_RESIZE_SE:
	    break;

	default:
	    return(FALSE);	/* not a valid resize part */
    }
    return(TRUE);

} /* END OF FUNCTION  SetPointerResizePart */


/*************************************<->*************************************
 *
 *  ResizeType (pcd, pev)
 *
 *
 *  Description:
 *  -----------
 *  Returns a resize part ID for an event outside of the current 
 *  resize area.
 *
 *
 *  Inputs:
 *  ------
 *  pcd 	- pointer to client data
 *  pev		- pointer to event
 *
 * 
 *  Outputs:
 *  -------
 *
 *
 *  Comments:
 *  --------
 *  o Assumes the static data for resizing has been set up.
 *************************************<->***********************************/
int ResizeType (ClientData *pcd, XEvent *pev)
{
    int x, y;

    if (!pev) return(FRAME_NONE);

    x = pev->xmotion.x_root;
    y = pev->xmotion.y_root;

    /* if inside all resize areas, then forget it */
    if ( (x > resizeX) &&
	 (y > resizeY) &&
	 (x < (resizeX + resizeWidth - 1)) &&
	 (y < (resizeY + resizeHeight - 1)) )
    {
	return(FRAME_NONE);
    }

    /* left side */
    if (x <= resizeX) {
	if (y < resizeY + (int)pcd->frameInfo.cornerHeight)
	    return (FRAME_RESIZE_NW);
	else if (y >= resizeY + resizeHeight -(int)pcd->frameInfo.cornerHeight)
	    return (FRAME_RESIZE_SW);
	else 
	    return (FRAME_RESIZE_W);
    } 

    /* right side */
    if (x >= resizeX + resizeWidth - 1) {
	if (y < resizeY + (int)pcd->frameInfo.cornerHeight)
	    return (FRAME_RESIZE_NE);
	else if (y >= resizeY + resizeHeight -(int)pcd->frameInfo.cornerHeight)
	    return (FRAME_RESIZE_SE);
	else 
	    return (FRAME_RESIZE_E);
    } 

    /* top side */
    if (y <= resizeY) {
	if (x < resizeX + (int)pcd->frameInfo.cornerWidth)
	    return (FRAME_RESIZE_NW);
	else if (x >= resizeX + resizeWidth - (int)pcd->frameInfo.cornerWidth)
	    return (FRAME_RESIZE_NE);
	else 
	    return (FRAME_RESIZE_N);
    } 

    /* bottom side */
    if (y >= resizeY + resizeHeight - 1) {
	if (x < resizeX + (int)pcd->frameInfo.cornerWidth)
	    return (FRAME_RESIZE_SW);
	else if (x >= resizeX + resizeWidth - (int)pcd->frameInfo.cornerWidth)
	    return (FRAME_RESIZE_SE);
	else 
	    return (FRAME_RESIZE_S);
    } 

    return(FRAME_NONE);

} /* END OF FUNCTION  ResizeType */



/*************************************<->*************************************
 *
 *  FixFrameValues (pcd, pfX, pfY, pfWidth, pfHeight, resizing)
 *
 *
 *  Description:
 *  -----------
 *  Fix up the frame values so that they do not exceed maximum or minimum
 *  size and that at least part of the frame is on screen
 *
 *
 *  Inputs:
 *  ------
 *  pcd 	- pointer to client data
 *  pfX		- pointer to frame x-coord
 *  pfY		- pointer to frame y-coord
 *  pfWidth	- pointer to frame width
 *  pfHeight	- pointer to frame height
 *  resizing      - check size constraints iff TRUE
 *
 * 
 *  Outputs:
 *  -------
 *  *pfX	- fixed up frame x-coord
 *  *pfY	- fixed up frame y-coord
 *  *pfWidth	- fixed up frame width
 *  *pfHeight	- fixed up frame height
 *
 *
 *  Comments:
 *  --------
 *  1. This could be more efficient
 *  2. Interactive resize with aspect ratio constraints may cause part of the
 *     outline to disappear off screen.  The critical case is when the title 
 *     bar disappears ABOVE the screen. 
 * 
 *************************************<->***********************************/

void FixFrameValues (ClientData *pcd, int *pfX, int *pfY, unsigned int *pfWidth, unsigned int *pfHeight, Boolean resizing)
{
    unsigned int lswidth;
    unsigned int oWidth, oHeight;


    /* 
     * Fix size if resizing and not icon.
     */

    if (resizing && !wmGD.movingIcon)
    {
	FrameToClient(pcd, pfX, pfY, pfWidth, pfHeight);
    
	oWidth = *pfWidth;
	oHeight = *pfHeight;

	FixWindowSize (pcd, pfWidth, pfHeight, 1, 1);

        AdjustPos (pfX, pfY, oWidth, oHeight, *pfWidth, *pfHeight);

	ClientToFrame(pcd, pfX, pfY, pfWidth, pfHeight);
    }

    /* 
     * Don't move if we'd end up totally offscreen 
     */

    if (wmGD.movingIcon)
    {
	lswidth = FRAME_BORDER_WIDTH(pcd);
    }
    else
    {
        lswidth = pcd->frameInfo.lowerBorderWidth;
    }
    if (lswidth < 5) lswidth = 5;

    if (wmGD.movingIcon && P_ICON_BOX(pcd))
    {
	/* 
	 *  Constrain outline to icon box
	 */
	/* left edge of outline */
	if (*pfX < clipX)
	{
	    *pfX = clipX;
	}

	/* top of outline */
	if (*pfY < clipY)
	{
	    *pfY = clipY;
	}

	/* right edge of outline */
	if (((int)*pfX) > ((int)clipX + (int)clipWidth - ((int)*pfWidth)))
	{
	    *pfX = clipX + clipWidth - *pfWidth;
	}

	/* bottom edge of outline */
	if (((int)*pfY) > ((int)clipY + (int)clipHeight - ((int)*pfHeight)))
	{
	    *pfY = clipY + clipHeight - *pfHeight;
	}

    }
    else
    {
	/* 
	 * keep outline on screen 
	 */


	/* keep right border on screen */
	if (*pfX < ((int) lswidth - (int) *pfWidth))
	{
	    *pfX = (int) lswidth - (int) *pfWidth;
	}

	/* keep bottom border on screen */
	if (*pfY < ((int) lswidth - (int) *pfHeight))
	{
	    *pfY = (int) lswidth - (int) *pfHeight;
	}

	/* keep left border on screen */
	if (*pfX > (DisplayWidth(DISPLAY, SCREEN_FOR_CLIENT(pcd)) - 
	    (int) lswidth))
	{
	    *pfX = DisplayWidth(DISPLAY, SCREEN_FOR_CLIENT(pcd)) - 
		(int) lswidth;
	}

	/* keep top border on screen */
	if (*pfY > (DisplayHeight(DISPLAY,SCREEN_FOR_CLIENT(pcd)) - 
	    (int) lswidth))
	{
	    *pfY = DisplayHeight(DISPLAY, SCREEN_FOR_CLIENT(pcd)) - 
		 (int) lswidth;
	}
    }

} /* END OF FUNCTION FixFrameValues */



/*************************************<->*************************************
 *
 *  ForceOnScreen (screen, pX, pY)
 *
 *
 *  Description:
 *  -----------
 *  Correct (if necessary) the coords specified to make them on screen
 *
 *
 *  Inputs:
 *  ------
 *  screen	- screen number
 *  pX		- pointer to x-coord
 *  pY		- pointer to y-coord
 * 
 *  Outputs:
 *  -------
 *  *pX		- x-coord (on screen)
 *  *pY		- y-coord (on screen)
 *
 *
 *  Comments:
 *  --------
 *  XXComments ...
 * 
 *************************************<->***********************************/
void ForceOnScreen (int screen, int *pX, int *pY)
{
    if (*pX >= (DisplayWidth(DISPLAY, screen)))
	*pX = DisplayWidth(DISPLAY, screen) - 1;
    else if (*pX < 0)
	*pX = 0;

    if (*pY >= (DisplayHeight(DISPLAY, screen)))
	*pY = DisplayHeight(DISPLAY, screen) - 1;
    else if (*pY < 0)
	*pY = 0;

} /* END OF FUNCTION  ForceOnScreen  */


/*************************************<->*************************************
 *
 *  SetPointerPosition (newX, newY, actualX, actualY)
 *
 *
 *  Description:
 *  -----------
 *  Attempt to set the pointer to position at newX, newY. 
 *
 *
 *  Inputs:
 *  ------
 *  newX	- X-coordinate to set pointer at
 *  newY	- Y-coordinate to set pointer at
 *
 * 
 *  Outputs:
 *  -------
 *  *actualX	- actual X-coord of pointer on return
 *  *actualY	- actual Y-coord of pointer on return
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/
void SetPointerPosition (int newX, int newY, int *actualX, int *actualY)
{
    int junk;
    Window junk_win;

    /*
     * Warp pointer ...
     */
    if (wmGD.enableWarp)
    {
	XWarpPointer(DISPLAY, None, ACTIVE_ROOT, 
	     0, 0, 0, 0, newX, newY);
    }


    /*
     * Get pointer position
     * NOTE: if we are not warping, we don't want to do the Query pointer,
     *       hence enableWarp is tested first.
     */
    if (!wmGD.enableWarp || 
        !XQueryPointer (DISPLAY, ACTIVE_ROOT, &junk_win, &junk_win, 
		actualX, actualY, &junk, &junk, (unsigned int *)&junk))

    {
	/* failed to get pointer position or not warping, return something */
	*actualX = newX;
	*actualY = newY;
    }

} /* END OF FUNCTION SetPointerPositio  */



/*************************************<->*************************************
 *
 *  GetConfigEvent (display, window, mask, curX, curY, oX, oY, 
 *     oWidth, oHeight, pev,)
 *
 *
 *  Description:
 *  -----------
 *  Get next configuration event
 *
 *
 *  Inputs:
 *  ------
 *  display	- pointer to display
 *  window	- window to get event relative to
 *  mask	- event mask - acceptable events to return
 *  pev		- pointer to a place to put the event
 *  curX	- current X value of pointer
 *  curY	- current Y value of pointer
 *  oX		- X value of outline
 *  oY		- Y value of outline
 *  oWidth	- width of outline
 *  oHeight	- height of outline
 * 
 *  Outputs:
 *  -------
 *  *pev	- event returned.
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/
void GetConfigEvent (Display *display, Window window, unsigned long mask, int curX, int curY, int oX, int oY, unsigned oWidth, unsigned oHeight, XEvent *pev)
{
    Window root_ret, child_ret;
    int root_x, root_y, win_x, win_y;
    unsigned int mask_ret;
    Boolean polling;
    int pollCount;
    Boolean gotEvent;
    Boolean eventToReturn = False;

    while (!eventToReturn)
    {
	/* 
	 * Suck up pointer motion events 
	 */
	gotEvent = False;
	while (XCheckWindowEvent(display, window, mask, pev))
	{
	    gotEvent = True;
	    if (pev->type != MotionNotify)
		break;
	}

	/*
	 * Only poll if we are warping the pointer. 
	 * (uses PointerMotionHints exclusively).
	 */
	polling = wmGD.enableWarp;
	pollCount = CONFIG_POLL_COUNT;

	if (!gotEvent && (polling || !wmGD.freezeOnConfig))
	{
	    /*
             * poll for events and flash the frame outline 
	     * if not move opaque
	     */

	    while (True)
	    {
		if (XCheckWindowEvent(display, window, 
				      (mask & ~PointerMotionMask), pev))
		{
		    gotEvent = True;
		    break;
		}
		
		if (!wmGD.freezeOnConfig && !wmGD.pActiveSD->moveOpaque)
		{
                    /* flash the outline if server is not grabbed */
		    MoveOutline (oX, oY, oWidth, oHeight);
		}

		if (!XQueryPointer (display, window, &root_ret, &child_ret, 
			&root_x, &root_y, &win_x, &win_y, &mask_ret))
		{
		    continue;	/* query failed, try again */
		}

		if ((root_x != curX) || (root_y != curY))
		{
		    /* 
		     * Pointer moved to a new position.
		     * Cobble a motion event together. 
		     * NOTE: SOME FIELDS NOT SET !!! 
		     */

		    pev->type = MotionNotify;
		    /* pev->xmotion.serial = ??? */
		    pev->xmotion.send_event = False;
		    pev->xmotion.display = display;
		    pev->xmotion.window = root_ret;
		    pev->xmotion.subwindow = child_ret;
		    pev->xmotion.time = CurrentTime;		/* !!! !!! */
		    pev->xmotion.x = root_x;
		    pev->xmotion.y = root_y;
		    pev->xmotion.x_root = root_x;
		    pev->xmotion.y_root = root_y;
		    /* pev->xmotion.state = ??? */
		    /* pev->xmotion.is_hint  = ???? */
		    /* pev->xmotion.same_screen = ??? */

		    eventToReturn = True;
		    break;	/* from while loop */
		}
		else if (wmGD.freezeOnConfig)
		{
		    if (!(--pollCount))
		    {
			/* 
			 * No pointer motion in some time. Stop polling
			 * and wait for next event.
			 */
			polling = False;
			break; /* from while loop */ 
		    }
		}
	    }  /* end while */
	}

	if (!gotEvent && !polling && wmGD.freezeOnConfig) 
	{
	    /* 
	     * Wait for next event on window 
	     */

	    XWindowEvent (display, window, mask, pev);
	    gotEvent = True;
	}

	if (gotEvent)
	{
	    eventToReturn = True;
	    if (pev->type == MotionNotify &&
		pev->xmotion.is_hint == NotifyHint)
	    {
		/* 
		 * "Ack" the motion notify hint 
		 */
		if ((XQueryPointer (display, window, &root_ret, 
			&child_ret, &root_x, &root_y, &win_x, 
			&win_y, &mask_ret)) &&
		    ((root_x != curX) ||
		     (root_y != curY)))
		{
		    /*
		     * The query pointer values say that the pointer
		     * moved to a new location.
		     */
		    pev->xmotion.window = root_ret;
		    pev->xmotion.subwindow = child_ret;
		    pev->xmotion.x = root_x;
		    pev->xmotion.y = root_y;
		    pev->xmotion.x_root = root_x;
		    pev->xmotion.y_root = root_y;

		}
		else {
		    /*
		     * Query failed. Change curX to force position
		     * to be returned on first sucessful query.
		     */
		    eventToReturn = False;
		    curX++;
		}
	    }
	}
    } /* end while */

} /* END OF FUNCTION GetConfigEvent  */


/*************************************<->*************************************
 *
 *  SetOutline (pOutline, x, y, width, height, fatness)
 *
 *
 *  Description:
 *  -----------
 *  Sets the outline of for config/move/placement operations
 *
 *
 *  Inputs:
 *  ------
 *  pOutline	- ptr to outline structure to fill in
 *  x		- x of upper-left corner of outline
 *  y		- y of upper-left corner of outline
 *  width	- width of outline.
 *  height	- height of outline.
 *  fatness	- pixel-width of outline
 * 
 *  Outputs:
 *  -------
 *
 *  Comments:
 *  --------
 *  o Be sure that pOutline points to a big enough area of memory 
 *    for the outline to be set!
 * 
 *************************************<->***********************************/

void SetOutline (XSegment *pOutline, int x, int y, unsigned int width, unsigned int height, int fatness)
{
    int i;

    for (i=0; i<fatness; i++)
    {
	pOutline->x1 = x;
	pOutline->y1 = y;
	pOutline->x2 = x + width -1;
	pOutline++->y2 = y;

	pOutline->x1 = x + width -1;
	pOutline->y1 = y;
	pOutline->x2 = x + width -1;
	pOutline++->y2 = y + height - 1;

	pOutline->x1 = x + width -1;
	pOutline->y1 = y + height - 1;
	pOutline->x2 = x;
	pOutline++->y2 = y + height - 1;

	pOutline->x1 = x;
	pOutline->y1 = y + height - 1;
	pOutline->x2 = x;
	pOutline++->y2 = y;

	/*
	 * Modify values for next pass (if any)
	 * Next outline will be on inside of current one.
	 */
        x += 1;
	y += 1;
	width -= 2;
	height -= 2;
    }

} /* END OF FUNCTION SetOutline  */


/*************************************<->*************************************
 *
 *  AdjustPos (pX, pY, oWidth, oHeight, nWidth, nHeight)
 *
 *
 *  Description:
 *  -----------
 *  Adjusts the position according to wmGD.configPart and any change in
 *  client size.
 *
 *
 *  Inputs:
 *  ------
 *  pX, pY -- pointers to positions
 *  oWidth, oHeight -- original dimensions
 *  nWidth, nHeight -- new dimensions
 *  wmGD.configPart
 * 
 *  Outputs:
 *  -------
 *  pX, pY -- pointers to adjusted positions
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/

void AdjustPos (int *pX, int *pY, unsigned int oWidth, unsigned int oHeight, unsigned int nWidth, unsigned int nHeight)
{
    switch (wmGD.configPart) 
    {
        case FRAME_RESIZE_NW:
	    /* anchor lower right corner */
	    *pX += oWidth - nWidth;
	    *pY += oHeight - nHeight;
	    break;

	case FRAME_RESIZE_N:
	    /* anchor bottom */
	    *pY += oHeight - nHeight;
	    break;

	case FRAME_RESIZE_NE:
	    /* anchor lower left corner */
	    *pY += oHeight - nHeight;
	    break;

	case FRAME_RESIZE_E:
	    /* anchor left side */
	    break;

	case FRAME_RESIZE_SE:
	    /* anchor upper left corner */
	    break;

	case FRAME_RESIZE_S:
	    /* anchor top */
	    break;

	case FRAME_RESIZE_SW:
	    /* anchor upper right corner */
	    *pX += oWidth - nWidth;
	    break;

	case FRAME_RESIZE_W:
	    /* anchor right side */
	    *pX += oWidth - nWidth;
	    break;

	default:
	    break;
    }

} /* END OF FUNCTION AdjustPos */



/*************************************<->*************************************
 *
 *  GrabWin (pcd, pev)
 *
 *
 *  Description:
 *  -----------
 *  return window to do grab on for config operation
 *
 *
 *  Inputs:
 *  ------
 *  pcd		- ptr to client data
 *  pev		- ptr to event
 *
 *  Outputs:
 *  -------
 *  Return 	- window 
 *
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/
Window GrabWin (ClientData *pcd, XEvent *pev)
{
    Window grab_win;
    
    /*
     * The grab window is the icon if the client is minimized
     * or if the event was on a "normalized" icon in the icon box.
     */

    if ((pcd->clientState == MINIMIZED_STATE) ||
        (pcd->pSD->useIconBox && pev &&
         ((pev->xany.window == ICON_FRAME_WIN(pcd)) ||
          (pev->xany.window == ACTIVE_ICON_TEXT_WIN))))
    {
        grab_win = ICON_FRAME_WIN(pcd);
    }
    else if (pev &&
             (pev->xany.window == pcd->clientFrameWin ||
              pev->xany.window == pcd->clientBaseWin ))
    {
        grab_win = pcd->clientFrameWin;
    }
    else if (pcd->pSD->useIconBox  &&
             P_ICON_BOX(pcd) &&
             wmGD.grabContext == F_SUBCONTEXT_IB_WICON)
    {
        grab_win = ICON_FRAME_WIN(pcd);
    }
    else
    {
        grab_win = pcd->clientFrameWin;
    }

    return (grab_win);

} /* END OF FUNCTION GrabWin */
#ifdef WSM

/*************************************<->*************************************
 *
 *  HandleMarqueeSelect (pSD, event)
 *
 *
 *  Description:
 *  -----------
 *  Does a marquee selection on the root window
 *
 *
 *  Inputs:
 *  ------
 *
 *  Outputs:
 *  -------
 *
 *  Comments:
 *  --------
 *  Selection info is dumped into a root window property:
 *    _DT_MARQUEE_SELECTION
 * 
 *************************************<->***********************************/
void
HandleMarqueeSelect (WmScreenData *pSD, XEvent *pev)
{
    Window grab_win;
    Boolean bDone;
    XEvent event;

    grab_win = RootWindow (DISPLAY, pSD->screen);
    bDone = False;

    while (!bDone && (wmGD.configAction == MARQUEE_SELECT))
    {
	if (!pev) 	/* first time through will already have event */
	{
	    pev = &event;

	    GetConfigEvent(DISPLAY, grab_win, CONFIG_MASK, 
		pointerX, pointerY, resizeX, resizeY,
		resizeWidth, resizeHeight, &event);
	}

	if (pev->type == MotionNotify)
	{
	    pointerX = pev->xmotion.x_root;
	    pointerY = pev->xmotion.y_root;
	    UpdateMarqueeSelectData (pSD);
	}
	else if (pev->type == KeyPress) {

	    /* 
	     * Handle key event. 
	     */
	    bDone = HandleMarqueeKeyPress (pSD, pev);
	}
	else if (pev->type == ButtonRelease) {

	    /*
	     *  Update (x,y) to the location of the button release
	     */
	    pointerX = pev->xbutton.x_root;
	    pointerY = pev->xbutton.y_root;
	    UpdateMarqueeSelectData (pSD);
	    CompleteFrameConfig ((ClientData *)NULL, pev);
	    bDone = True;
	}
	else  {
	    pev = NULL;
	    continue;			/* ignore this event */
	}

	if (!bDone)
	{
	    MoveOutline (marqueeX, marqueeY, marqueeWidth, marqueeHeight);
	}

	pev = NULL;	/* reset event pointer */

    }  /* end while */

} /* END OF FUNCTION HandleMarqueeSelect */


/*************************************<->*************************************
 *
 *  StartMarqueeSelect ()
 *
 *
 *  Description:
 *  -----------
 *  Start marquee selection on root window
 *
 *
 *  Inputs:
 *  ------
 * 
 *  Outputs:
 *  -------
 *
 *
 *  Comments:
 *  --------
 * 
 *************************************<->***********************************/
void
StartMarqueeSelect(WmScreenData *pSD, XEvent *pev)
{
    Window grab_win, junk_win;
    Boolean grabbed;
    int big_inc;
    int junk, junkX, junkY;

    if (!pSD->bMarqueeSelectionInitialized)
    {
	/* 
	 * If we haven't initialized the marquee selection messaging
	 * then do so here before we do any grabs. Sending a dummy
	 * message will do.
	 *
	 * (If we move off of ICCCM messaging, then this can go away.)
	 */
	dtSendMarqueeSelectionNotification(pSD, DT_MARQUEE_SELECT_END, 
				0, 0, 0, 0);
	pSD->bMarqueeSelectionInitialized = True;
    }

    /*
     *	Do our grabs 
     */
    if (!configGrab)
    {
	grab_win = RootWindow (DISPLAY, pSD->screen);

	if (pev)
	{
	    grabbed = DoGrabs (grab_win, wmGD.configCursor, 
			PGRAB_MASK, pev->xbutton.time, NULL, True);
	}
	else
	{
	    grabbed = DoGrabs (grab_win, wmGD.configCursor, 
			PGRAB_MASK, CurrentTime, NULL, True);
	}
	if (!grabbed)
	{
	    return;
	}
	configGrab = TRUE;
    }
    else
    {
	/* continue with the configuration in progress (!!!) */
	return;
    }

    /* 
     * Set up static variables for succeeding events 
     */
    if ((pev->type == ButtonPress) || (pev->type == ButtonRelease))
    {
	pointerX = pev->xbutton.x_root;
	pointerY = pev->xbutton.y_root;
    }
    else if (!XQueryPointer (DISPLAY, pSD->rootWindow,
			&junk_win, &junk_win,
		   	&pointerX, &pointerY, 
			&junk, &junk, (unsigned int *)&junk))
    {
	CancelFrameConfig ((ClientData *)NULL);	/* release grabs */
	return;
    }

    /* save start values to see where we came from */
    marqueeX = startX = pointerX;
    marqueeY = startY = pointerY;
    marqueeWidth0 = marqueeWidth = 0;
    marqueeHeight0 = marqueeHeight = 0;
    marqueeAnchor = ANCHOR_NW;

    /* compute increment value for dynamic update */
    big_inc = DisplayWidth (DISPLAY, pSD->screen) / 20;

    /* set configuring data */
    wmGD.configAction = MARQUEE_SELECT;
    wmGD.configButton = pev ? pev->xbutton.button: 0;

    dtSendMarqueeSelectionNotification(pSD, DT_MARQUEE_SELECT_BEGIN, 
	    marqueeX, marqueeY, marqueeWidth, marqueeHeight);

} /* END OF FUNCTION StartMarqueeSelect  */


/*************************************<->*************************************
 *
 *  UpdateMarqueeSelectData ()
 *
 *
 *  Description:
 *  -----------
 *
 *  Inputs:
 *  ------
 *  pSD		- pointer to screen data
 * 
 *  Outputs:
 *  -------
 *
 *
 *  Comments:
 *  --------
 *************************************<->***********************************/
void UpdateMarqueeSelectData (WmScreenData *pSD)
{
    /* validate and update anchor point and marquee data */
    
    switch (marqueeAnchor) 
    {
      case ANCHOR_NW:
	marqueeWidth = pointerX - marqueeX;
	marqueeHeight = pointerY - marqueeY;

	if (marqueeWidth < 0)
	{
	    marqueeWidth = -marqueeWidth;
	    marqueeX = pointerX;

	    if (marqueeHeight < 0)
	    {
		marqueeHeight = -marqueeHeight;
		marqueeY = pointerY;
		marqueeAnchor = ANCHOR_SE;
	    }
	    else
	    {
		marqueeAnchor = ANCHOR_NE;
	    }
	}
	else if (marqueeHeight < 0)
	{
	    marqueeHeight = -marqueeHeight;
	    marqueeY = pointerY;
	    marqueeAnchor = ANCHOR_SW;
	}
	break;

      case ANCHOR_NE:
	marqueeWidth += marqueeX - pointerX;
	marqueeHeight = pointerY - marqueeY;
	marqueeX = pointerX;

	if (marqueeWidth < 0)
	{
	    marqueeWidth = -marqueeWidth;
	    marqueeX = pointerX - marqueeWidth;

	    if (marqueeHeight < 0)
	    {
		marqueeHeight = -marqueeHeight;
		marqueeY = pointerY;
		marqueeAnchor = ANCHOR_SW;
	    }
	    else
	    {
		marqueeAnchor = ANCHOR_NW;
	    }
	}
	else if (marqueeHeight < 0)
	{
	    marqueeHeight = -marqueeHeight;
	    marqueeY = pointerY;
	    marqueeAnchor = ANCHOR_SE;
	}
	break;

      case ANCHOR_SE:
	marqueeWidth += marqueeX - pointerX;
	marqueeHeight += marqueeY - pointerY;
	marqueeX = pointerX;
	marqueeY = pointerY;

	if (marqueeWidth < 0)
	{
	    marqueeWidth = -marqueeWidth;
	    marqueeX = pointerX - marqueeWidth;

	    if (marqueeHeight < 0)
	    {
		marqueeHeight = -marqueeHeight;
		marqueeY = pointerY - marqueeHeight;
		marqueeAnchor = ANCHOR_NW;
	    }
	    else
	    {
		marqueeAnchor = ANCHOR_SW;
	    }
	}
	else if (marqueeHeight < 0)
	{
	    marqueeHeight = -marqueeHeight;
	    marqueeY = pointerY - marqueeHeight;
	    marqueeAnchor = ANCHOR_NE;
	}
	break;

      case ANCHOR_SW:
	marqueeWidth = pointerX - marqueeX;
	marqueeHeight += marqueeY - pointerY;
	marqueeY = pointerY;

	if (marqueeWidth < 0)
	{
	    marqueeWidth = -marqueeWidth;
	    marqueeX = pointerX;

	    if (marqueeHeight < 0)
	    {
		marqueeHeight = -marqueeHeight;
		marqueeY = pointerY - marqueeHeight;
		marqueeAnchor = ANCHOR_NE;
	    }
	    else
	    {
		marqueeAnchor = ANCHOR_SE;
	    }
	}
	else if (marqueeHeight < 0)
	{
	    marqueeHeight = -marqueeHeight;
	    marqueeY = pointerY - marqueeHeight;
	    marqueeAnchor = ANCHOR_NW;
	}
	break;
    }

    if ((wmGD.marqueeSelectGranularity > 0) &&
        ((ABS(marqueeWidth-marqueeWidth0) > wmGD.marqueeSelectGranularity) ||
	 (ABS(marqueeHeight-marqueeHeight0)>wmGD.marqueeSelectGranularity)))
    {
	dtSendMarqueeSelectionNotification(pSD, DT_MARQUEE_SELECT_CONTINUE, 
		marqueeX, marqueeY, marqueeWidth, marqueeHeight);

	marqueeWidth0 = marqueeWidth;
	marqueeHeight0 = marqueeHeight;
    }
}


/*************************************<->*************************************
 *
 *  HandleMarqueeKeyPress (pSD, pev)
 *
 *
 *  Description:
 *  -----------
 *  Handles keypress events during resize of window
 *
 *
 *  Inputs:
 *  ------
 *  pSD 	- pointer to screen data
 *  pev		- pointer to event
 *
 * 
 *  Outputs:
 *  -------
 *  Return	- True if this event completes (or cancels) resizing 
 * 
 * 
 *  Comments: 
 *  --------
 * 
 *************************************<->***********************************/
Boolean HandleMarqueeKeyPress (WmScreenData *pSD, XEvent *pev)
{
    KeySym keysym;
    Boolean control;
    int keyMult;
    XEvent KeyEvent;

    /*
     * Compress repeated keys 
     */
    keyMult = 1;
    while (keyMult <= 10 && 
	      XCheckIfEvent (DISPLAY, &KeyEvent, IsRepeatedKeyEvent, 
	      (char *) pev))
    {
	  keyMult++;
    }

    keysym = XKeycodeToKeysym (DISPLAY, pev->xkey.keycode, 0);
    control = (pev->xkey.state & ControlMask) != 0;

    switch (keysym) {

	case XK_Return:
	    CompleteFrameConfig ((ClientData *)NULL, pev);
	    return (True);

	case XK_Escape:
	    CancelFrameConfig ((ClientData *)NULL);
	    CheckEatButtonRelease ((ClientData *)NULL, pev);
	    return (True);

	default:
	    return (False);		/* ignore this key */

    } /* end switch(keysym) */

} /* END OF FUNCTION HandleResizeKeyPress */
#endif /* WSM */
