/* 
 * @OPENGROUP_COPYRIGHT@
 * COPYRIGHT NOTICE
 * Copyright (c) 1989, 1990, 1991, 1992, 1993, 1994 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.4
*/ 
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$TOG: WmFunction.c /main/19 1998/04/20 13:00:48 mgreess $"
#endif
#endif
/*
 * (c) Copyright 1987, 1988, 1989, 1990, 1993, 1994 HEWLETT-PACKARD COMPANY 
 * (c) Copyright 1993, 1994 International Business Machines Corp.
 * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
 * (c) Copyright 1993, 1994 Novell, Inc.
 */

/*
 * Included Files:
 */

#include "WmGlobal.h"
#include <sys/types.h>
#ifndef X_NOT_STDC_ENV
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#else
extern int putenv();
extern char *getenv();
extern int atoi();
extern pid_t wait();

#ifndef PORT_NOVFORK
extern pid_t vfork();
#endif /* PORT_NOVFORK */
#endif
#ifndef WSM
#include <signal.h>
#endif
#include <stdio.h>
#include <X11/Xos.h>
#include "WmICCC.h"
#ifdef WSM
#include "WmWrkspace.h"  /* for ClientInWorkspace() test */
#include <Dt/EnvControlP.h>  /* for restoring **environ before an exec() */
#include "WmResNames.h"
#include <Dt/Message.h>
#include <Dt/Help.h>
#endif /* WSM */
#ifdef PANELIST
#include <Dt/DtStrDefs.h>
#include "WmPanelP.h"
#include "WmSignal.h"
#endif /* PANELIST */

/*
 * include extern functions
 */
#include "WmFunction.h"
#include "WmCEvent.h"
#ifdef WSM
#include "WmHelp.h"
#endif /* WSM */
#include "WmCDInfo.h"
#include "WmColormap.h"
#include "WmError.h"
#include "WmEvent.h"
#include "WmFeedback.h"
#ifdef WSM
#include "WmIPC.h"
#endif /* WSM */
#include "WmIPlace.h"
#include "WmIconBox.h"
#include "WmKeyFocus.h"
#include "WmMenu.h"
#ifdef WSM
#include "WmPresence.h"
#endif /* WSM */
#include "WmProperty.h"
#include "WmProtocol.h"
#include "WmResParse.h"
#include "WmWinConf.h"
#include "WmWinInfo.h"
#include "WmWinList.h"
#include "WmWinState.h"
#include "WmXSMP.h"

#include <Xm/RowColumnP.h> /* for MS_LastManagedMenuTime */
extern XmMenuState _XmGetMenuState();

static unsigned int GetEventInverseMask(XEvent *event);

#ifdef WSM

#if (defined(USL) || defined(__uxp__) || defined(linux)) && !defined(_NFILE)
#define _NFILE FOPEN_MAX
#endif
#define CLOSE_FILES_ON_EXEC() \
{int ifx; for (ifx=3; ifx < _NFILE; ifx++) (void) fcntl (ifx, F_SETFD, 1);}

#endif /* WSM */
/*
 * Global Variables:
 */

/*
 * The 'dirty' variables are used to keep track of the transient window
 * that has been lowered via "f.lower freeFamily".
 */
static ClientData *dirtyStackEntry = NULL;
static ClientData *dirtyLeader = NULL;

#ifdef WSM

/***********************<->*************************************
 *
 *  F_Action (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for invoking actions.
 *
 *
 *  Inputs:
 *  ------
 *  args = action function and arguments
 *
 *  pCD = pointer to the ClientData for the whole front panel
 *
 *  event = X event that invoked the function (key, button, or menu/NULL)
 *
 *
 *  Outputs:
 *  -------
 *  RETURN = if True then further button binding/function processing can
 *           be done for the event that caused this function to be called.
 *
 *  Comments:
 *  -------
 *  The pCD->controlWindow is a temporary area used solely for
 *  this function invocation--it stores the pCW of the control
 *  that want the function to happen.
 ******************************<->***********************************/

Boolean
F_Action (String actionName, ClientData *pCD, XEvent *event)
{

    WmActionArg *pAP = (WmActionArg *) actionName;

    /* make sure the command runs on the right display. */
    if (wmGD.pActiveSD->displayString)
    {
	putenv(wmGD.pActiveSD->displayString);
    }

    if (wmGD.dtSD)
    {
	WmFrontPanelSetBusy (True);
    }

    
    DtActionInvoke (wmGD.pActiveSD->screenTopLevelW1,
		    pAP->actionName, pAP->aap, pAP->numArgs,
                    pAP->szExecParms, NULL, NULL, 1, NULL, NULL);
    
    /*
     * Restore original DISPLAY environment variable 
     */
    if(wmGD.pActiveSD->displayString && wmGD.displayString)
    {
	putenv(wmGD.displayString);
    }

    return (True);
    
} /* END OF FUNCTION F_Action */
#endif /* WSM */


/******************************<->*************************************
 *
 *  F_Beep (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for beeping.
 *
 *
 *  Inputs:
 *  ------
 *  args = function arguments (specified in .mwmrc file)
 *
 *  pCD = pointer to the client data for the client window to which the
 *        function is to be applied
 *
 *  event = X event that invoked the function (key, button, or menu/NULL)
 *
 *
 *  Outputs:
 *  -------
 *  RETURN = if True then further button binding/function processing can
 *           be done for the event that caused this function to be called.
 *
 ******************************<->***********************************/

Boolean F_Beep (String args, ClientData *pCD, XEvent *event)
{

    /* !!! what is a good value for percent (the second arg) !!! */
    XBell (DISPLAY, 0);

    return (True);

} /* END OF FUNCTION F_Beep */



/*
 * Handle Special case where the dirty window is the top most
 * transient window.  When this is the case, raising the window
 * that was on top (the window just below the dirty window) will
 * fail because Mwm stack database is out of sync.  So the solution
 * is to restack the dirty transient relative to the second to the
 * top transient.  This function is used to support freeFamily stacking.
 */
ClientData * FindSecondToTopTransient (pcd)
ClientData *pcd;
{
    ClientData *pcdNext;
    static ClientData *second;

    pcdNext = pcd->transientChildren;
    while (pcdNext)
    {
	if (pcdNext->transientChildren)
	{
	    if (!pcdNext->transientChildren->transientChildren)
	    {
		second = pcdNext;
	    }
	    FindSecondToTopTransient (pcdNext);
	}
	pcdNext = pcdNext->transientSiblings;
	if (pcdNext && !pcdNext->transientSiblings)
	{
	    second = pcdNext;
	}
    }

    return (second);

} /* END OF FUNCTION */



Boolean ForceLowerWindow (ClientData *pcd)
{
#if 0
    Window stackWindow;
    WmScreenData *pSD = (ACTIVE_WS)->pSD;
#endif
    XWindowChanges changes;
    Boolean restack = False;
#ifdef WSM
    Window stackWindow;
    WmScreenData *pSD = (ACTIVE_WS)->pSD;
    unsigned int mask;
    ClientListEntry 	*pCLE;

    /* 
     * Find lowest window in this workspace. We'll stack this transient
     * below it.
     */
    pCLE = pSD->lastClient;
    stackWindow = None;
    mask = CWStackMode;
    while (pCLE != NULL)
    {
	if ((pCLE->pCD != pcd) &&
	    (ClientInWorkspace (ACTIVE_WS, pCLE->pCD)))
	{
	    if ((pCLE->type == MINIMIZED_STATE) &&
		(pCLE->pCD->clientState == MINIMIZED_STATE))
	    {
		stackWindow = ICON_FRAME_WIN(pCLE->pCD);
	    }
	    else if ((pCLE->type == NORMAL_STATE) &&
		     ((pCLE->pCD->clientState == NORMAL_STATE) ||
		      (pCLE->pCD->clientState == MAXIMIZED_STATE)))
	    {
		stackWindow = pCLE->pCD->clientFrameWin;
	    }

	    if (stackWindow != None)
	    {
		mask |= CWSibling;
		changes.sibling = stackWindow;
		break;
	    }
	}
	if (stackWindow == None)
	{
	    pCLE = pCLE->prevSibling;
	}
    }
#endif /* WSM */
#if 0
    if (pSD->lastClient->type == MINIMIZED_STATE)
    {
	stackWindow = ICON_FRAME_WIN(pSD->lastClient->pCD);
    }
    else
    {
	stackWindow = pSD->lastClient->pCD->clientFrameWin;
    }
#endif

    changes.stack_mode = Below;
#ifdef WSM
    if (mask)
    {
	XConfigureWindow (DISPLAY, pcd->clientFrameWin, mask, &changes);
    }
#else /* WSM */
    XConfigureWindow (DISPLAY, pcd->clientFrameWin, CWStackMode,
		      &changes);
#endif /* WSM */

    return (restack);
}



/*************************************<->*************************************
 *
 *  F_Lower (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for bottoming a client window
 *  or icon.
 *
 *
 *  Inputs:
 *  ------
 *  args = function arguments (specified in .mwmrc file)
 *
 *  pCD = pointer to the client data for the client window to which the
 *        function is to be applied
 *
 *  event = X event that invoked the function (key, button, or menu/NULL)
 *
 *
 *  Outputs:
 *  -------
 *  RETURN = if True then further button binding/function processing can
 *           be done for the event that caused this function to be called.
 *
 *************************************<->***********************************/

Boolean F_Lower (String args, ClientData *pCD, XEvent *event)
{
    ClientListEntry *pEntry;
    ClientListEntry *pNextEntry;
    ClientListEntry *pStackEntry;
    String string = args;
    int flags = STACK_NORMAL;
#ifdef WSM
    WmWorkspaceData *pWS = ACTIVE_WS;
#endif /* WSM */

    if (string)
    {
	/* process '-client' argument */
	if (string[0] == '-')
	{
	    string = &string[1];
	    string = (String) GetString ((unsigned char **) &string);

	    pStackEntry = NULL;
	    pNextEntry = ACTIVE_PSD->lastClient;
	    while (pNextEntry &&
		   (pEntry = FindClientNameMatch (pNextEntry, False,
							string,	F_GROUP_ALL)))
	    {
		pNextEntry = pEntry->prevSibling;
#ifdef WSM
	        if (ClientInWorkspace (pWS, pEntry->pCD))
	        {
#endif /* WSM */
		Do_Lower (pEntry->pCD, pStackEntry, STACK_NORMAL);
		pStackEntry = pEntry;
#ifdef WSM
	        }
#endif /* WSM */
	    }
	}
	/* process family stacking stuff */
	else if (*string)
	{
	    unsigned int  slen, len, index;

	    slen = strlen(args) - 2;		/* subtract '\n' and NULL */
	    for (index = 0; index < slen; string = &args[index+1])
	    {
		if ((string = (String) GetString ((unsigned char **) &string)) == NULL)
		   break;
		len = strlen(string);
		if (!strcmp(string,"within"))
		{
		    flags |= STACK_WITHIN_FAMILY;
		}
		else if (!strcmp(string,"freeFamily"))
		{
		    flags |= STACK_FREE_FAMILY;
		}
		index += len;
	    }
#ifdef WSM
	    if (ClientInWorkspace (pWS, pCD))
	    {
#endif /* WSM */
	    Do_Lower (pCD, (ClientListEntry *) NULL, flags);
#ifdef WSM
	    }
#endif /* WSM */
	}
    }
    else if (pCD)
    {
#ifdef WSM
	    if (ClientInWorkspace (pWS, pCD))
	    {
#endif /* WSM */
	Do_Lower (pCD, (ClientListEntry *) NULL, STACK_NORMAL);
#ifdef WSM
	    }
#endif /* WSM */
    }

    /*
     * If caused by button press, event may ALSO cause focus to be
     * passed to this client - prepare to disable focusAutoRaise.
     */
    if (pCD && event && (event->type == ButtonPress))
      pCD->focusAutoRaiseDisablePending = True;

    wmGD.passButtonsCheck = False;
    return (True);

} /* END OF FUNCTION F_Lower */



/*************************************<->*************************************
 *
 *  Do_Lower (pCD, pStackEntry)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for lowering the client window
 *  so that it does not obscure any other window above the stack entry
 *  window.
 *
 *
 *  Inputs:
 *  ------
 *  pCD = pointer to the client data of the window (or icon) to be lowered.
 * 
 *  pStackEntry = pointer to client list entry for window that is to be 
 *	below the lowered window (if NULL, window is lowered to the bottom
 *	of the	stack).
 *
 *************************************<->***********************************/

void Do_Lower (ClientData *pCD, ClientListEntry *pStackEntry, int flags)
{
    Boolean restackTransients;
    ClientData *pcdLeader;
    WmWorkspaceData *pWS = ACTIVE_WS;
#ifdef WSM
    Boolean bLeaderRestacked;
#endif /* WSM */

#ifdef PANELIST
    if (pCD->pECD)
    {
	/*
	 * Window has been reparented into the front panel. 
	 * Don't follow through on window stacking change.
	 */
	return;
    }
    else 
#else /* PANELIST */
#endif /* PANELIST */
#ifdef WSM
    if (ClientInWorkspace(pWS, pCD)  && 
	(!pStackEntry || ClientInWorkspace (pWS, pStackEntry->pCD)))
    {
	/* 
	 * Both clients are in the current workspace. Set
	 * client indices so that the access macros work.
	 */
	SetClientWsIndex (pCD);
	if (pStackEntry)
	{
	    SetClientWsIndex (pStackEntry->pCD);
	}
    }
    else
    {
	/*
	 * One or both of the clients are not in the current workspace
	 * Do nothing.
	 */
	return;
    }
#endif /* WSM */

    pcdLeader = (pCD->transientLeader) ? FindTransientTreeLeader (pCD) : pCD;

    if ((pcdLeader->clientState == MINIMIZED_STATE) && !P_ICON_BOX(pcdLeader))
    {
        /*
         * If a dirtyStackEntry exists, return it to its original place 
         * in the stack (for all stacking types)
         */
        if (dirtyStackEntry)
        {
            if (dirtyStackEntry->transientChildren ||
                dirtyStackEntry->transientLeader)
                RestackTransients (dirtyStackEntry);
            dirtyStackEntry = NULL;
            dirtyLeader = NULL;
	}

	/*
	 * Only restack the icon if it is not currently lowered.
	 */

	if (pStackEntry)
	{
	    if (pStackEntry->prevSibling != &pcdLeader->iconEntry)
	    {
		StackWindow (pWS, &pcdLeader->iconEntry, True /*above*/,
		    pStackEntry);
		MoveEntryInList (pWS, &pcdLeader->iconEntry, True /*above*/,
		    pStackEntry);
	    }
	}
	else
	{
	    if (ACTIVE_PSD->lastClient != &pcdLeader->iconEntry)
	    {
		StackWindow (pWS, &pcdLeader->iconEntry, 
			     False /*on bottom*/, (ClientListEntry *) NULL);
		MoveEntryInList (pWS, &pcdLeader->iconEntry, 
			     False /*on bottom*/, (ClientListEntry *) NULL);
	    }
	}
    }
    else /* NORMAL_STATE, MAXIMIZED_STATE, adoption */
    {
#ifdef WSM
        /*
	 * Handle restacking of primary/secondary windows
	 * within the transient window tree.
	 */
        bLeaderRestacked = False;
	if ((pcdLeader->transientChildren) &&
	    (!pcdLeader->secondariesOnTop) &&
	    (!wmGD.bSuspendSecondaryRestack))
	{
	    if (pCD == pcdLeader)
	    {
		/*
		 * Lower requested on the leader itself, insure it's
		 * at the bottom.
		 */
		bLeaderRestacked = BumpPrimaryToBottom (pcdLeader);
	    }
	    else if (pCD->transientChildren)
	    {
		/*
		 * Lower requested on the leader of a subtree. Insure
		 * that this subtree leader is at the bottom of the
		 * subtree.
		 */
		bLeaderRestacked = BumpPrimaryToBottom (pCD);
	    }
	    else if (pCD->transientLeader)
	    {
		ClientData *pcdLdr;

		/*
		 * Lower requested on a transient. Insure all the
		 * subtree leaders up to the top are at the bottom
		 * of their respective transient subtrees.
		 */
		for (pcdLdr = pCD->transientLeader;
			pcdLdr; 
				pcdLdr = pcdLdr->transientLeader)
		{
		    bLeaderRestacked |= BumpPrimaryToBottom (pcdLdr);
		}
	    }

	}
#endif /* WSM */
	/*
	 * If this is a transient window then put it below its
	 * sibling transient windows.
	 */

	restackTransients = False;
	if (pCD->transientLeader)
	{

	    /*
	     * If freeFamily stacking, then put dirty transient window
	     * (if any) back in place before force lowering current window
	     * to the bottom of the global window stack.  Then return.
	     */

	    if (flags & STACK_FREE_FAMILY)
	    {
		/* Restore dirty transient if not current window. */
		if ((dirtyStackEntry) &&
		    (dirtyStackEntry != pCD))
		{
		    RestackTransients (dirtyStackEntry);
		}

		dirtyStackEntry = pCD;
		dirtyLeader = pcdLeader;

		ForceLowerWindow (pCD);
		return;
	    }

	    /*
	     * Reach here only if NOT doing a f.lower freeFamily (see
	     * return; statement above).  Put current transient below
	     * its sibling transient windows.
	     */
	    restackTransients = PutTransientBelowSiblings (pCD);
	}

	/*
	 * If doing a regular f.lower and you have a dirty window, then
	 * clean up dirty transient window.
	 */

	if (dirtyStackEntry)
	{
	    /* 
	     * If lowering a window in the same family as the dirty
	     * transient window, then just restack before lowering.
	     * Else, restore the dirty transient in place before
	     * lowering the current window.  Clear dirtyStack.
	     */
	    if (dirtyLeader == pcdLeader)
	    {
		restackTransients = True;
	    }
	    else
	    {
		RestackTransients (dirtyStackEntry);
	    }

	    dirtyStackEntry = NULL;
	}

	/*
	 * Only restack the window or transient window tree if it is
	 * not currently lowered and the window is not a system
	 * modal window.
	 */

	if (pStackEntry)
	{
	    if ((pStackEntry->prevSibling != &pcdLeader->clientEntry) &&
		!(wmGD.systemModalActive &&
		  (pcdLeader == wmGD.systemModalClient)))
	    {
	        StackWindow (pWS, &pcdLeader->clientEntry, True /*above*/,
		    pStackEntry);
		MoveEntryInList (pWS, &pcdLeader->clientEntry, True /*above*/,
		    pStackEntry);
	    }
#ifdef WSM
	    else if ((restackTransients) || (bLeaderRestacked))
#else /* WSM */
	    else if (restackTransients)
#endif /* WSM */
	    {
		RestackTransients (pCD);
	    }
	}
	else
	{
	    if ((pWS->pSD->lastClient != &pcdLeader->clientEntry) &&
		!(wmGD.systemModalActive &&
		  (pcdLeader == wmGD.systemModalClient)) &&
		!(flags & STACK_WITHIN_FAMILY))
	    {
	        StackWindow (pWS, &pcdLeader->clientEntry, False /*on bottom*/,
		    (ClientListEntry *) NULL);
		MoveEntryInList (pWS, &pcdLeader->clientEntry,
		    False /*on bottom*/, (ClientListEntry *) NULL);
	    }
#ifdef WSM
	    else if ((restackTransients) || (bLeaderRestacked))
#else /* WSM */
	    else if (restackTransients)
#endif /* WSM */
	    {
		RestackTransients (pCD);
	    }
	}
    }

} /* END OF FUNCTION Do_Lower */



/*************************************<->*************************************
 *
 *  F_CircleDown (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for moving the client window
 *  on top of stack to the bottom.
 *
 *
 *  Inputs:
 *  ------
 *  args = function arguments (specified in .mwmrc file)
 *
 *  pCD = pointer to the client data for the client window to which the
 *        function is to be applied
 *
 *  event = X event that invoked the function (key, button, or menu/NULL)
 *
 *
 *  Outputs:
 *  -------
 *  RETURN = if True then further button binding/function processing can
 *           be done for the event that caused this function to be called.
 *
 *************************************<->***********************************/

Boolean F_Circle_Down (String args, ClientData *pCD, XEvent *event)
{
    unsigned long types;
    unsigned long windowType;
    ClientListEntry *pNextEntry;
    ClientData *pcdNext;


    /*
     * Go down through the client list looking for a window of an
     * appropriate type that is obscuring lower windows.
     */

    types = (unsigned long)args;
    pNextEntry = ACTIVE_PSD->clientList;
    while (pNextEntry)
    {
	/*
	 * Only check out the window if it is onscreen.
	 */

	pcdNext = pNextEntry->pCD;
	if (((pNextEntry->type == NORMAL_STATE) &&
	     (pcdNext->clientState != MINIMIZED_STATE)) ||
	    ((pNextEntry->type == MINIMIZED_STATE) &&
	     (pcdNext->clientState == MINIMIZED_STATE)))
	{
	    if (pcdNext->clientState == MINIMIZED_STATE)
	    {
		windowType = F_GROUP_ICON;
	    }
	    else
	    {
		windowType = F_GROUP_WINDOW;
		if (pcdNext->transientLeader || pcdNext->transientChildren)
		{
		    windowType |= F_GROUP_TRANSIENT;
		}
	    }
	    if (types & windowType)
	    {
		if (CheckIfClientObscuringAny (pcdNext))
		{
		    /*
		     * This window (or window tree) is obscuring another window
		     * on the screen.  Lower the window.
		     */

#ifdef WSM
		    wmGD.bSuspendSecondaryRestack = True;
#endif /* WSM */
		    F_Lower (NULL, pcdNext, (XEvent *) NULL);
#ifdef WSM
		    wmGD.bSuspendSecondaryRestack = False;
#endif /* WSM */
		    break;
		}
	    }
	}
	pNextEntry = pNextEntry->nextSibling;
    }

    return (True);

} /* END OF FUNCTION F_Circle_Down */



/*************************************<->*************************************
 *
 *  F_Circle_Up (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for moving the client window
 *  on the bottom of the stack to the top.
 *
 *
 *  Inputs:
 *  ------
 *  args = function arguments (specified in .mwmrc file)
 *
 *  pCD = pointer to the client data for the client window to which the
 *        function is to be applied
 *
 *  event = X event that invoked the function (key, button, or menu/NULL)
 *
 *
 *  Outputs:
 *  -------
 *  RETURN = if True then further button binding/function processing can
 *           be done for the event that caused this function to be called.
 *
 *************************************<->***********************************/

Boolean F_Circle_Up (String args, ClientData *pCD, XEvent *event)
{
    unsigned long types;
    unsigned long windowType;
    ClientListEntry *pNextEntry;
    ClientData *pcdNext;


    /*
     * Go up through the client list looking for a window of an
     * appropriate type that is obscured by higher windows.
     */

    types = (unsigned long)args;
    pNextEntry = ACTIVE_PSD->lastClient;
    while (pNextEntry)
    {
	/*
	 * Only check out the window if it is onscreen.
	 */

	pcdNext = pNextEntry->pCD;
	if (((pNextEntry->type == NORMAL_STATE) &&
	     (pcdNext->clientState != MINIMIZED_STATE)) ||
	    ((pNextEntry->type == MINIMIZED_STATE) &&
	     (pcdNext->clientState == MINIMIZED_STATE)))
	{
	    if (pcdNext->clientState == MINIMIZED_STATE)
	    {
		windowType = F_GROUP_ICON;
	    }
	    else
	    {
		windowType = F_GROUP_WINDOW;
		if (pcdNext->transientLeader || pcdNext->transientChildren)
		{
		    windowType |= F_GROUP_TRANSIENT;
		}
	    }
	    if (types & windowType)
	    {
		if (CheckIfClientObscuredByAny (pcdNext))
		{
		    /*
		     * This window (or window tree) is obscured by another
		     * window on the screen.  Raise the window.
		     */

#ifdef WSM
		    wmGD.bSuspendSecondaryRestack = True;
#endif /* WSM */
		    F_Raise (NULL, pcdNext, (XEvent *) NULL);
#ifdef WSM
		    wmGD.bSuspendSecondaryRestack = False;
#endif /* WSM */
		    break;
		}
	    }
	}
	pNextEntry = pNextEntry->prevSibling;
    }

    return (True);


} /* END OF FUNCTION F_Circle_Up */



/*************************************<->*************************************
 *
 *  F_Focus_Color (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for setting the colormap
 *  focus to a client window or reinstalling the default colormap.
 *
 *************************************<->***********************************/

Boolean F_Focus_Color (String args, ClientData *pCD, XEvent *event)
{

    if (wmGD.colormapFocusPolicy == CMAP_FOCUS_EXPLICIT)
    {
        if (pCD)
        {
	    /*
	     * The window selected for the colormap focus is a top-level client
	     * window.  If there are subwindow colormaps then determine if the
	     * selection was in one of the subwindows.
	     */

	    if (pCD->clientState == MINIMIZED_STATE)
	    {
		/* !!! colormap for client supplied icon window !!! */
		pCD = NULL;
	    }
        }

        SetColormapFocus (ACTIVE_PSD, pCD);
    }

    return (True);

} /* END OF FUNCTION F_Focus_Color */



/*************************************<->*************************************
 *
 *  F_Exec (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for executing a command
 *  (with /bin/sh).
 *
 *************************************<->***********************************/

Boolean F_Exec (String args, ClientData *pCD, XEvent *event)
{
    int   status;
    int   pid;
    int   w;
#ifndef WSM
    void (*intStat) ();
    void (*quitStat) ();
    void (*chldStat) ();
#endif /* WSM */
    char *shell;
    char *shellname;


    /* make sure the f.exec command runs on the right display. */
    if (wmGD.pActiveSD->displayString)
      {
	putenv(wmGD.pActiveSD->displayString);
      }
    
#ifdef PANELIST
    if (wmGD.dtSD)
    {
	/*
	 * Start the busy indicator, waiting for a pushbutton window
	 * for the given duration
	 */
       WmFrontPanelSetBusy (True);
    }
#endif /* PANELIST */

#ifndef WSM
    /* For now use only for non WSM code.  May integrate to WSM later. */
    /*
     * Disable SIGCHLD while we wait for this child to exit, otherwise
     * we will go into the ChildProcSignalHandler and will never get the
     * correct child pid in the while loop below. pgw@ixi 30-5-95 IBIS 20585.
     *
     * Moved before fork() to avoid race condition.
     * Change handler to SIG_DFL, SIG_IGN causes bug. paulsh@sequent 31-08-95.
     */
    chldStat = (void (*)())signal (SIGCHLD, SIG_DFL); 
#endif

    /*
     * Fork a process to exec a shell to run the specified command:
     */

#ifdef PORT_NOVFORK
    if ((pid = fork ()) == 0)
#else
    if ((pid = vfork ()) == 0)
#endif
    {

#ifndef NO_SETPGRP
#if defined(SVR4) || defined(__OSF1__) || defined(__osf__) || defined(_POSIX_JOB_CONTROL)
	setsid();
#else
#ifdef SYSV
	setpgrp();
#else
	int tpid;

	tpid = getpid();
	setpgrp(tpid, tpid);
#endif /* SYSV */
#endif /* SVR4 */
#endif /* NO_SETPGRP */
#ifdef WSM 
	/*
	 * Clean up window manager resources.
	 * The X file descriptor should be automatically closed.
	 */

	/*
	 * Fix up signal handling.
	 */
	RestoreDefaultSignalHandlers ();

	/*
	 * Fix up the child application's environment NOT to
	 * inherit the XFILESEARCHPATH, XBMLANGPATH, NLSPATH, etc.
	 * used by dtwm.
	 */
	 _DtEnvControl(DT_ENV_RESTORE_PRE_DT);

	 CLOSE_FILES_ON_EXEC();
#endif /* WSM */

	/*
	 * Exec the command using $MWMSHELL if set or 
	 * $SHELL if set and $MWMSHELL not set or sh.
	 */

        if (((shell = getenv ("MWMSHELL")) != NULL) ||
	    ((shell = getenv ("SHELL")) != NULL))

	{
	    shellname = strrchr (shell, '/');
	    if (shellname == NULL)
	    {
		/*
		If the shell pathname obtained from SHELL or MWMSHELL does not
		have a "/" in the path and if the user expects this shell to be
		obtained using the PATH variable rather than the current
		directory, then we must call execlp and not execl
		*/
		shellname = shell;
		execlp (shell, shellname, "-c", args, 0);
	    }
	    else
	    {
		shellname++;
		execl (shell, shellname, "-c", args, 0);
	    }
	}

	/*
	 * There is no SHELL environment variable or the first execl failed.
	 * Try /bin/sh .
	 */
#ifdef SVR4
        execl ("/usr/bin/sh", "sh", "-c", args, 0);
#else
        execl ("/bin/sh", "sh", "-c", args, 0);
#endif


	/*
	 * Error - command could not be exec'ed.
	 */

	_exit (127);
    }

    else if (pid == -1)
      return(True);

    /*
     * Have the window manager wait for the shell to complete.
     */

#ifndef WSM
    intStat = (void (*)())signal (SIGINT, SIG_IGN);
    quitStat = (void (*)())signal (SIGQUIT, SIG_IGN);
#endif /* WSM */

#ifdef WSM
    /*
     * Don't need to wait because WSM sets SIGCLD handler
     */
#else /* WSM */
    while ((w = wait (&status)) != pid && (w != -1));

    /*
     * Currently the only purpose for setting the local variable "status"
     * here is as a convenience for setting break points or querying the
     * value of "status" when using a debugger.
     * Otherwise the value of "status" is unused beyond this point.
     */
    if (w == -1)
    {
	status = -1;
    }
#endif /* WSM */

#ifndef WSM
    signal (SIGINT, intStat);
    signal (SIGQUIT, quitStat);
    signal (SIGCHLD, chldStat);
#endif /* WSM */

    /*
     * Restore original DISPLAY environment variable value
     * so a restart will start on the same screen
     */

    if(wmGD.pActiveSD->displayString &&
       wmGD.displayString)
    {
	putenv(wmGD.displayString);
    }


    return (True);


} /* END OF FUNCTION F_Exec */



/*************************************<->*************************************
 *
 *  F_Quit_Mwm (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for terminating the window
 *  manager.
 *
 *************************************<->***********************************/

Boolean F_Quit_Mwm (String args, ClientData *pCD, XEvent *event)
{
    if (wmGD.showFeedback & WM_SHOW_FB_QUIT)
    {
	ConfirmAction (ACTIVE_PSD, QUIT_MWM_ACTION);
    }
    else
    {
	Do_Quit_Mwm(False);
    }
    
    return (False);

} /* END OF FUNCTION F_Quit_Mwm */



/*************************************<->*************************************
 *
 *  Do_Quit_Mwm (diedOnRestart)
 *
 *
 *  Description:
 *  -----------
 *  Callback to do the f.quit_mwm function.
 *
 *************************************<->***********************************/

void Do_Quit_Mwm (Boolean diedOnRestart)
{
    int scr;
    ClientListEntry *pNextEntry;


    /*
     * Close the X connection to get all the X resources cleaned up.
     * !!! maybe windows should be reparented / rebordered  before closing? !!!
     * !!! clean up the _MOTIF_WM_INFO property on the root window !!!
     */


    if (DISPLAY)
    {
        XSetInputFocus(DISPLAY, PointerRoot, RevertToPointerRoot, CurrentTime);
	for (scr = 0; scr < wmGD.numScreens; scr++)
	{
	    if (wmGD.Screens[scr].managed)
	    {
#ifdef WSM
		SaveResources(&wmGD.Screens[scr]);
#endif /* WSM */
		pNextEntry = wmGD.Screens[scr].lastClient;
		while (pNextEntry)
		{
		    if (pNextEntry->type == NORMAL_STATE)
		    {
			if (!(pNextEntry->pCD->clientFlags & 
			      CLIENT_WM_CLIENTS))
			{
			    ReBorderClient (pNextEntry->pCD, diedOnRestart);
			}
		    }
		    pNextEntry = pNextEntry->prevSibling;
		}
#if defined(PANELIST)
	        UnParentControls (&wmGD.Screens[scr], False);
#endif /* PANELIST */

#ifndef WSM
		XDeleteProperty(DISPLAY, wmGD.Screens[scr].rootWindow,
				wmGD.xa_MWM_INFO);
#endif /* WSM */
	    }
	}
#ifdef WSM
	/* shut down the messaging connection */
	dtCloseIPC();
#endif /* WSM */
	ResignFromSM();
        XSync (DISPLAY, False);
        XCloseDisplay (DISPLAY);
    }
    
    if(diedOnRestart)
    {
	exit (WM_ERROR_EXIT_VALUE);
    }
    else
    {
	exit (0);
    }

} /* END OF FUNCTION Do_Quit_Mwm */


/*************************************<->*************************************
 *
 *  ReBorderClient (pCD, reMapClient)
 *
 *
 *  Description:
 *  -----------
 *  Restores X border for client window and reparents the
 *  window back to the root.
 *
 *
 *  Inputs:
 *  -------
 *  pCD = pointer to the client data for the window to be re-bordered.
 *
 *************************************<->***********************************/

void ReBorderClient (ClientData *pCD, Boolean reMapClient)
{
    int x, y;
    int xoff, yoff;
    XWindowChanges windowChanges;

    while (pCD)
    {
        if (pCD->iconWindow && (pCD->clientFlags & ICON_REPARENTED) &&
	    (!(reMapClient)))
        {
	    XUnmapWindow (DISPLAY, pCD->iconWindow);
#ifdef WSM
	    XReparentWindow (DISPLAY, pCD->iconWindow, 
		ROOT_FOR_CLIENT(pCD), pCD->pWsList->iconX, 
		pCD->pWsList->iconY);
#else /* WSM */
	    XReparentWindow (DISPLAY, pCD->iconWindow, 
		ROOT_FOR_CLIENT(pCD), pCD->iconX, pCD->iconY);
#endif /* WSM */
        }

	if (!(reMapClient))
	{
	    if (pCD->maxConfig)
	    {
		x = pCD->maxX;
		y = pCD->maxY;
	    }
	    else
	    {
		if(wmGD.positionIsFrame)
		{
		    CalculateGravityOffset (pCD, &xoff, &yoff);
		    x = pCD->clientX - xoff;
		    y = pCD->clientY - yoff;
		}
		else
		{
		    x = pCD->clientX;
		    y = pCD->clientY;
		}
	    }
	    XUnmapWindow(DISPLAY, pCD->clientFrameWin);
	    XReparentWindow (DISPLAY, pCD->client, 
			     ROOT_FOR_CLIENT(pCD), x, y);
	}
	else
	{
	    XMapWindow(wmGD.display, pCD->client);
	}

	if (pCD->transientChildren)
	{
	    ReBorderClient (pCD->transientChildren, reMapClient);
	}

	if (!(reMapClient))
	{
	    /*
	     * restore X border
	     */
	    windowChanges.x = x;
	    windowChanges.y = y;
	    windowChanges.border_width = pCD->xBorderWidth;
	    XConfigureWindow (DISPLAY, pCD->client, 
			      CWBorderWidth | CWX | CWY, &windowChanges);
	}

	if (pCD->transientLeader)
	{
	    pCD = pCD->transientSiblings;
	}
	else
	{
	    pCD = NULL;
	}
    }

} /* END OF FUNCTION ReBorderClient */



/*************************************<->*************************************
 *
 *  F_Focus_Key (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for setting the keyboard
 *  focus to a particular client window.
 *
 *
 *  Inputs:
 *  ------
 *  args = (immediate value) focus flags
 *
 *  pCD = pointer to the client data
 *
 *  event = X event that invoked the function (key, button, or menu/NULL)
 *
 *************************************<->***********************************/

Boolean F_Focus_Key (String args, ClientData *pCD, XEvent *event)
{
    long focusFlags = (long)args;


    if (pCD && (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT))
    {
	Do_Focus_Key (pCD, GetFunctionTimestamp ((XButtonEvent *)event),
	    (focusFlags | ALWAYS_SET_FOCUS));
    }

    return (True);

} /* END OF FUNCTION F_Focus_Key */


/*************************************<->*************************************
 *
 *  FindSomeReasonableClient
 *
 *  Description:
 *  -----------
 *  Find a client, any client to set the focus to, return client or NULL.
 *  This code is ripped off from AutoResetKeyFocus(). 
 *  
 *************************************<->***********************************/

static Window FindSomeReasonableClient(void)
{
   ClientData *pcdNoFocus=NULL;

    ClientListEntry *pNextEntry;
    ClientData *pCD;
    ClientData *pcdLastFocus = (ClientData *) NULL;
    ClientData *pcdFocus;
    Window focusWindow = (Window) NULL;

    /*
     * Scan through the list of clients to find a window to get the focus.
     */

    pNextEntry = ACTIVE_PSD->clientList;

    while (pNextEntry)
    {
	pCD = pNextEntry->pCD;
	if (!wmGD.systemModalActive ||
	    (wmGD.systemModalClient == pCD))
	{
	    if ((pNextEntry->type != MINIMIZED_STATE) &&
	        (pCD->clientState != MINIMIZED_STATE) &&
#ifdef WSM
                (ClientInWorkspace (ACTIVE_WS, pCD)) &&
#endif /* WSM */
	        (pCD != pcdNoFocus))
	    {
	        if (pCD->transientChildren)
	        {
		    pcdFocus = FindLastTransientTreeFocus (pCD, pcdNoFocus);
	        }
	        else
	        {
		    pcdFocus = pCD;
	        }
	        if (pcdFocus &&
		    ((pcdLastFocus == NULL) ||
		     (pcdFocus->focusPriority > pcdLastFocus->focusPriority)))
	        {
		    pcdLastFocus = pcdFocus;
	        }
	    }
	}
	pNextEntry = pNextEntry->nextSibling;
    }

    /*
     * Set the focus window if one is found
     */

#ifdef WSM
    if (pcdLastFocus && 
	ClientInWorkspace (ACTIVE_WS, pcdLastFocus))
#else /* WSM */
    if (pcdLastFocus)
#endif /* WSM */
      focusWindow = pcdLastFocus->client;

    /*
     * If a client window could not be found, then just put focus
     * on any icon.
     */

    if (focusWindow == (Window) NULL)
    {
	pNextEntry = ACTIVE_PSD->clientList;

	while (pNextEntry)
	{
	    pCD = pNextEntry->pCD;

#ifdef WSM
          if (ClientInWorkspace (ACTIVE_WS, pCD))
	  {
#endif /* WSM */
	    if ((pNextEntry->type == MINIMIZED_STATE) ||
	        (pCD->clientState == MINIMIZED_STATE))
	    {
		focusWindow = ICON_FRAME_WIN(pCD);
		break;
	    }
#ifdef WSM
	  }
#endif /* WSM */
	    pNextEntry = pNextEntry->nextSibling;
	}
    }

    return (focusWindow);

} /* END OF FUNCTION FindSomeReasonableClient */




/*************************************<->*************************************
 *
 *  Do_Focus_Key (pCD, focusTime, flags)
 *
 *
 *  Description:
 *  -----------
 *  This function is used to set the focus to a window.  The focus indication
 *  is not changed until the FocusIn event is received.
 *
 *
 *  Inputs:
 *  ------
 *  pCD = pointer to the client data
 *
 *  focusTime = focus change time
 *
 *  flags = wm focus change flags
 *
 *************************************<->***********************************/

void Do_Focus_Key (ClientData *pCD, Time focusTime, long flags)
{
    ClientData *pcdFocus;
    Window focusWindow;


    /* Clear the replay flag */
    wmGD.replayEnterEvent = False;

    pcdFocus = pCD;
#ifdef WSM
    /* 
     * Make sure the client is in the current workspace
     */
    if ((pCD) &&
	(ClientInWorkspace (ACTIVE_WS, pCD)))
#else /* WSM */
    if (pCD)
#endif /* WSM */
    {
	if (pCD->clientState == MINIMIZED_STATE)
	{
	    focusWindow = ICON_FRAME_WIN(pCD);
	}
	else if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
	{
	    /*
	     * Set the keyboard focus to the indicated client window.
	     * If the window has an application modal subordinate then
	     * set the input focus to that window if the focus isn't
	     * already owned by a subordinate.
	     */

	    if (IS_APP_MODALIZED(pCD))
	    {
		ClientData *pcdFocusLeader,*currFocusLeader;

		/*
		 * Handle case where a modal window exists when Mwm starts up.
		 * wmGD.keyboardFocus is NULL, give focus to the modal dialog.
		 */

	        if (wmGD.keyboardFocus)
		{
		    currFocusLeader = wmGD.keyboardFocus->transientLeader;
		}
		else
		{
		    currFocusLeader = (ClientData *) NULL;
		}

		/*
		 * Find focus leader for pCD
		 */

		pcdFocusLeader = pCD;
		while (pcdFocusLeader->transientLeader &&
		       (pcdFocusLeader != currFocusLeader))
		{
		    pcdFocusLeader = pcdFocusLeader->transientLeader;
		}

		if (pcdFocusLeader == currFocusLeader)
		{
		    pcdFocus = wmGD.keyboardFocus;
		    flags = 0;
		}
		else
		{
		    pcdFocus = FindTransientFocus (pcdFocusLeader);
		}
	    }

	    /*
	     * !!!  !!!  !!!  !!!  !!!  !!!  !!!  !!!  !!!  !!!  
	     * We must look at why FindTransientFocus is
	     * returning a NULL pcd.  The old code simply set
	     *	focusWindow = pcdFocus->client;
	     * !!!  !!!  !!!  !!!  !!!  !!!  !!!  !!!  !!!  !!!  
	     *
	     * 11/26/96 rswiston - In tracking down CDExc22816, we
	     * discovered that pCD could get tricked into thinking
	     * it had modal transients when in fact all its transients
	     * had been withdrawn (fixed in WithdrawTransientChildren()).
	     * As a result, FindTransientFocus() returns wmGD.keyboardFocus;
	     * if nobody has the focus, FindTransientFocus() returns NULL.
	     */
	    if (pcdFocus)
	    {
		focusWindow = pcdFocus->client;
	    }
	    else
	    {
		focusWindow = (wmGD.keyboardFocus) ?
		    wmGD.keyboardFocus->client : ACTIVE_PSD->wmWorkspaceWin;
	    }
	}
	else
	{
	    /*
	     * If the focus policy is "pointer" don't set the focus to a
	     * window if it has an application modal subordinate.
	     */

	    if (IS_APP_MODALIZED(pCD))
	    {
		pcdFocus = NULL;
		focusWindow = ACTIVE_PSD->wmWorkspaceWin;

                /* Replay this later when the modal window is removed. */
                wmGD.replayEnterEvent = True;
	    }
	    else
	    {
		focusWindow = pcdFocus->client;
	    }
	}
    }
    else
    {
	/*
	 * Set up the default (non client specific) keyboard input focus.
	 */

	if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
	{
	    focusWindow = PointerRoot;
	}
	else
	{
	    /*
	     * The WORKSPACE_IF_NULL flag is used to prevent client
	     * windows from flashing when deiconifying a client.
	     */

	    if (WORKSPACE_IF_NULL & flags)
	    {
	    	focusWindow = ACTIVE_PSD->wmWorkspaceWin;
	    }
	    else
	    {
		/* find some reasonable client so that focus is not lost */

		focusWindow = FindSomeReasonableClient();
		if (focusWindow == (Window)NULL)
		{
		    focusWindow = ACTIVE_PSD->wmWorkspaceWin;
		}
	    }
	}
    }

    if ((pcdFocus != wmGD.keyboardFocus) || (flags & ALWAYS_SET_FOCUS))
    {
        if (pcdFocus)
	{
	    /*
	     * Set the focus and/or send a take focus client message.  This
	     * is not done if a client area button press was done to set
	     * set the focus and the window is a globally active input
	     * style window (See ICCCM).
	     */

	    if ( (flags & CLIENT_AREA_FOCUS)                           &&
		 (pcdFocus->protocolFlags & PROTOCOL_WM_TAKE_FOCUS)    &&
		! pcdFocus->inputFocusModel                            &&
		 (pcdFocus == pCD)                                     &&
		 (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT) &&
                !(pcdFocus->clientState == MINIMIZED_STATE)
	       )
	    {
	      /*
	       * We get here if:
	       * 1. User clicked in the client area   AND
	       * 2. Input model is Globally Active    AND
	       * 3. Keyboard focus policy is explicit
	       */

	      /* this window has WM_TAKE_FOCUS set and InputField false. */
	      /* just send a message.                                    */
	      SendClientMsg (pcdFocus->client, 
			     (long) wmGD.xa_WM_PROTOCOLS,
			     (long) wmGD.xa_WM_TAKE_FOCUS, 
			     focusTime, NULL, 0);
	    }
	    else
	    {
	        if ((pcdFocus->protocolFlags & PROTOCOL_WM_TAKE_FOCUS) &&
                    !(pcdFocus->clientState == MINIMIZED_STATE))
	        {
		  /*
		   * Locally Active Input Model - Send a take focus message to the client.
		   */

		  SendClientMsg (pcdFocus->client, 
				 (long) wmGD.xa_WM_PROTOCOLS,
				 (long) wmGD.xa_WM_TAKE_FOCUS, 
				 focusTime, NULL, 0);
	        }

		/*
		 * Don't set the input focus if the window has input_field set
		 * to False or has expressed an interest in WM_TAKE_FOCUS
		 * (ie. 'No Input', 'Globally Active', or 'Locally Active'),
		 * and the user click in the client area.  If the user clicks
		 * on the titlebar or traverses to this window via f.next_key,
		 * set the focus so that the user can access the window menu
		 * and accelerators.
		 */

		if ( wmGD.enforceKeyFocus       ||  /* res - default == True. */
		     (flags & ALWAYS_SET_FOCUS) ||
		    !(flags & CLIENT_AREA_FOCUS)||  /* clicked on frame? */
		     pcdFocus->inputFocusModel  ||  /* Pass.|Glob. Active */
		     (pcdFocus->clientState == MINIMIZED_STATE)
		   )
		{
		  if ( !(flags & CLIENT_AREA_FOCUS) &&
		       !pcdFocus->inputFocusModel &&
                       !(pcdFocus->clientState == MINIMIZED_STATE))
		  {
		   /* the window doesn't want the focus - set it to the frame */
		   /* user clicked on the frame but we don't want the focus */
		   /* set it to the client's frame */
		   XSetInputFocus (DISPLAY, pcdFocus->clientBaseWin,
				RevertToPointerRoot, CurrentTime);
		  }
		  else if ( !(flags & CLIENT_AREA_FOCUS)                   &&
		       !(pcdFocus->protocolFlags & PROTOCOL_WM_TAKE_FOCUS) &&
		        pcdFocus->inputFocusModel
		     )
		  {
		    XSetInputFocus (DISPLAY, focusWindow,
				    RevertToPointerRoot, CurrentTime);
		  }
		  else
		  {
		    XSetInputFocus (DISPLAY, focusWindow,
				      RevertToParent, CurrentTime);
		  }
		}
		else
		{
		  /*
		   * We've decided that the window shouldn't get the focus,
		   * so don't change the focus.
		   */
		  pcdFocus = wmGD.nextKeyboardFocus;
		}
	    }
	}
	else
	{
	    XSetInputFocus (DISPLAY, focusWindow, RevertToPointerRoot,
					focusTime);
	}

	wmGD.nextKeyboardFocus = pcdFocus;
    }


} /* END OF FUNCTION Do_Focus_Key */


#ifdef WSM

/***********************<->*************************************
 *
 *  F_Goto_Workspace (args, pCD, event)
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for switching
 *  to another workspace by name.
 *
 *  Inputs:
 *  ------
 *  args = action function and arguments
 *
 *  pCD = pointer to the ClientData
 *
 *  event = X event that invoked the function (key, button, or menu/NULL)
 *
 *  Outputs:
 *  -------
 *  Always False
 *
 *  Comments:
 *  -------
 ******************************<->***********************************/
Boolean
F_Goto_Workspace (String args, ClientData *pCD, XEvent *event)
{
    WmScreenData *pSD = ACTIVE_PSD;
    int iwsx;
    XmString xms;

    /* 
     * Compare argument against both resource name 
     * and workspace title, take the first match.
     */
    xms = XmStringCreate (args, XmFONTLIST_DEFAULT_TAG);
    for (iwsx = 0; iwsx < pSD->numWorkspaces; iwsx++)
    {
	if (!strcmp(pSD->pWS[iwsx].name, args) ||
	    XmStringCompare (xms, pSD->pWS[iwsx].title))
	{
	    break;
	}
    }

    XmStringFree (xms);

    /* check bounds */
    if (iwsx >= pSD->numWorkspaces)
    {
	Warning (((char *)GETMESSAGE(26, 4, 
		"Invalid workspace name specified for f.goto_workspace")));
    }
    else
    {
	ChangeToWorkspace (&pSD->pWS[iwsx]);

    }

    return (False);
}  /* END OF FUNCTION F_Goto_Workspace */

#endif /* WSM */

#ifdef WSM

/******************************<->*************************************
 *
 *  Boolean F_Help (String args, ClientData *pCD, XEvent *event)
 *
 *  Description:
 *  -----------
 *  Invoke help on the workspace manager
 *
 *  Inputs:
 *  ------
 *  args - incoming values
 *  pCD  - associated client data structure
 *  event - what triggered this call
 * 
 *  Outputs:
 *  -------
 *  Return - True if the call occurs; false otherwise.
 *
 *  Comments:
 *  --------
 *
 ******************************<->***********************************/
Boolean
F_Help (String args, ClientData *pCD, XEvent *event)
{
#ifdef PANELIST
    Boolean rval;

    rval = WmDtHelp(args);
    return (rval);
#endif /* PANELIST */    
    

}  /* END OF FUNCTION F_Help */


/******************************<->*************************************
 *
 *  Boolean F_Help_Mode (String args, ClientData *pCD, XEvent *event)
 *
 *  Description:
 *  -----------
 *  Invoke item help on the frontpanel
 *
 *  Inputs:
 *  ------
 *  args - NULL
 *  pCD  - associated client data structure ??
 *  event - what triggered this call
 * 
 *  Outputs:
 *  -------
 *  Return - True if the call occurs; false otherwise.
 *
 *  Comments:
 *  --------
 *
 ******************************<->***********************************/
Boolean
F_Help_Mode (String args, ClientData *pCD, XEvent *event)
{
#ifdef PANELIST
    /*
     * Help mode event processing interferes
     * with slide up windows. Don't continue
     * if windows are sliding.
     */
    if (wmGD.iSlideUpsInProgress == 0)
    {
	(void) WmDtHelpMode();
    }
    return (False);
#endif /* PANELIST */    

}  /* END OF FUNCTION F_Help_Mode */

#endif /* WSM */

/******************************<->*************************************
 *
 *  F_Next_Key (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for setting the keyboard
 *  input focus to the next window in the set of managed windows.
 *
 *
 *  Inputs:
 *  ------
 *  args = (immediate value) window type flags
 *
 *  pCD = pointer to the client data
 *
 *  event = X event that invoked the function (key, button, or menu/NULL)
 *
 *************************************<->***********************************/

Boolean F_Next_Key (String args, ClientData *pCD, XEvent *event)
{
#ifdef ROOT_ICON_MENU
    Boolean focused = False;
#endif /*  ROOT_ICON_MENU */
    if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
    {
#ifdef ROOT_ICON_MENU
	focused = 
#endif /*  ROOT_ICON_MENU */
	FocusNextWindow ((unsigned long)args,
			 GetFunctionTimestamp ((XButtonEvent *)event));
#ifdef ROOT_ICON_MENU
        if (focused && wmGD.iconClick &&
            event && event->type == KeyPress &&
            wmGD.nextKeyboardFocus &&
            wmGD.nextKeyboardFocus->clientState == MINIMIZED_STATE &&
            !P_ICON_BOX(wmGD.nextKeyboardFocus))
        {
            /*
             * Post system menu from the icon
             */
            F_Post_SMenu (args, wmGD.nextKeyboardFocus, event);
            return (False);
        }
#endif /*  ROOT_ICON_MENU */
    }

    return (True);

} /* END OF FUNCTION F_Next_Key */



/*************************************<->*************************************
 *
 *  F_Prev_Cmap (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler installing the previous
 *  colormap in the list of client window colormaps.
 *
 *************************************<->***********************************/

Boolean F_Prev_Cmap (String args, ClientData *pCD, XEvent *event)
{
    if (pCD == NULL)
    {
	pCD = ACTIVE_PSD->colormapFocus;
    }

    if (pCD && (pCD->clientCmapCount > 0) &&
        ((pCD->clientState == NORMAL_STATE) ||
	 (pCD->clientState == MAXIMIZED_STATE)))
    {
	if (--(pCD->clientCmapIndex) < 0)
	{
	    pCD->clientCmapIndex = pCD->clientCmapCount - 1;
	}
	pCD->clientColormap = pCD->clientCmapList[pCD->clientCmapIndex];
	if (ACTIVE_PSD->colormapFocus == pCD)
	{
#ifndef OLD_COLORMAP /* colormap */
	    /*
	     * We just re-ordered the colormaps list,
	     * so we need to re-run the whole thing.
	     */
	    pCD->clientCmapFlagsInitialized = 0;
	    ProcessColormapList (ACTIVE_PSD, pCD);
#else /* OSF original */
	    WmInstallColormap (ACTIVE_PSD, pCD->clientColormap);
#endif
	}
    }

    return (True);

} /* END OF FUNCTION F_Prev_Cmap */



/*************************************<->*************************************
 *
 *  F_Prev_Key (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for setting the keyboard
 *  input focus to the previous window in the set of managed windows.
 *
 *
 *  Inputs:
 *  ------
 *  args = (immediate value) window type flags
 *
 *  pCD = pointer to the client data
 *
 *  event = X event that invoked the function (key, button, or menu/NULL)
 *
 *************************************<->***********************************/

Boolean F_Prev_Key (String args, ClientData *pCD, XEvent *event)
{
#ifdef ROOT_ICON_MENU
    Boolean focused = False;
#endif /*  ROOT_ICON_MENU */
    if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
    {
#ifdef ROOT_ICON_MENU
	focused = 
#endif /*  ROOT_ICON_MENU */
	FocusPrevWindow ((unsigned long)args,
			    GetFunctionTimestamp ((XButtonEvent *)event));
#ifdef ROOT_ICON_MENU
        if (focused && wmGD.iconClick &&
            event && event->type == KeyPress &&
            wmGD.nextKeyboardFocus &&
            wmGD.nextKeyboardFocus->clientState == MINIMIZED_STATE &&
            !P_ICON_BOX(wmGD.nextKeyboardFocus))
        {
            /*
             * Post system menu from the icon
             */
            F_Post_SMenu (args, wmGD.nextKeyboardFocus, event);
            return (False);
        }
#endif /*  ROOT_ICON_MENU */

    }

    return (True);

} /* END OF FUNCTION F_Prev_Key */

#ifdef PANELIST

/***********************<->*************************************
 *
 *  F_Post_FpMenu (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for posting
 *  the Front Panel window menu.
 *
 *  Inputs:
 *  ------
 *  args = arguments (none)
 *
 *  pCD = pointer to the FP ClientData
 *
 *  event = X button press that invoked the function
 *
 ******************************<->***********************************/

Boolean
F_Post_FpMenu (String args, ClientData *pCD, XEvent *event)
{
    static MenuSpec *fpMenuSpec = (MenuSpec *)NULL;

    if (event->type != ButtonPress)
	return False;

    if (!fpMenuSpec)
    {
	WmScreenData *pSD = (pCD) ? PSD_FOR_CLIENT(pCD) : ACTIVE_PSD;
	MenuSpec *oldSpec;
	Widget tmpWidget;
	char *newMenuName;

	newMenuName = pCD ? pCD->systemMenu : "DtPanelMenu";

	for (oldSpec = pSD->menuSpecs;
	     oldSpec != (MenuSpec *)NULL;
	     oldSpec = oldSpec->nextMenuSpec)
	{
	    if (oldSpec->name && (strcmp(oldSpec->name, newMenuName) == 0))
		break;
	}
	if (!oldSpec)
	    return False;

	fpMenuSpec = DuplicateMenuSpec(oldSpec);

	/*
	 * TEMPORARILY modify pSD so the new menu will be
	 * created on DISPLAY1 instead of DISPLAY.
	 */
	fpMenuSpec->nextMenuSpec = pSD->menuSpecs;
	pSD->menuSpecs = fpMenuSpec;
	tmpWidget = pSD->screenTopLevelW;
	pSD->screenTopLevelW = pSD->screenTopLevelW1;

	(void)MAKE_MENU (pSD, pCD, newMenuName,
			 F_CONTEXT_NORMAL, F_CONTEXT_NORMAL,
			 (MenuItem *) NULL, FALSE);

	/* Restore pSD */
	pSD->screenTopLevelW = tmpWidget;
	pSD->menuSpecs = fpMenuSpec->nextMenuSpec;
    }

    PostMenu (fpMenuSpec, pCD, event->xbutton.x_root, event->xbutton.y_root,
	      event->xbutton.button, F_CONTEXT_NORMAL, POST_AT_XY, event);

    _XmGetMenuState(XtParent(fpMenuSpec->menuWidget))
	->MS_LastManagedMenuTime = event->xbutton.time;

    return False;
}


/***********************<->*************************************
 *
 *  F_Push_Recall (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for invoking/topping
 *  push_recall clients.
 *
 *
 *  Inputs:
 *  ------
 *  args = arguments
 *
 *  pCD = pointer to the ClientData 
 *
 *  event = X event that invoked the function (key, button, or menu/NULL)
 *
 *
 *  Outputs:
 *  -------
 *  RETURN = if True then further button binding/function processing can
 *           be done for the event that caused this function to be called.
 *
 *  Comments:
 *  -------
 ******************************<->***********************************/

Boolean
F_Push_Recall (String args, ClientData *pCD, XEvent *event)
{
    WmPushRecallArg *pPRP;
    WmScreenData *pSD;
    WmFpPushRecallClientData *pPRCD;

    pPRP = (WmPushRecallArg *) args;
    pSD = (pCD) ? PSD_FOR_CLIENT(pCD) : ACTIVE_PSD;

    if (pPRP->ixReg  < pSD->numPushRecallClients)
    {
	/* get slot for this client */
	pPRCD = &(pSD->pPRCD[pPRP->ixReg]);

	/*
	 * If the client is already running, then top it in this workspace,
	 * else invoke the function to start it.
	 */
	if (pPRCD->pCD)
	{
	    /* Client is managed already. */ 
	    if (!(ClientInWorkspace (pSD->pActiveWS, pPRCD->pCD)))
	    {
		WorkspaceID *wsRemoveList;
		int sizeRemoveList;

		/* 
		 * Move client to current workspace 
		 */
	        wsRemoveList = GetListOfOccupiedWorkspaces (pPRCD->pCD, 
					&sizeRemoveList);
		RemoveClientFromWorkspaces (pPRCD->pCD, wsRemoveList,
                                        sizeRemoveList);
		XtFree ((char *)wsRemoveList);
		AddClientToWorkspaces (pPRCD->pCD, &(pSD->pActiveWS->id), 1);
		SetClientWsIndex(pPRCD->pCD);
		SetClientState(pPRCD->pCD, 
	            pPRCD->pCD->clientState & ~UNSEEN_STATE, CurrentTime);
	    }

	    /* Make this client visible */
#ifdef WSM
		    wmGD.bSuspendSecondaryRestack = True;
#endif /* WSM */
	    F_Normalize_And_Raise (NULL, pPRCD->pCD, event);
#ifdef WSM
		    wmGD.bSuspendSecondaryRestack = False;
#endif /* WSM */
	}
	else 
	{
	    struct timeval tvNow;
	    struct timezone tz;
	    Boolean bWaiting = False;

	    if (pPRCD->tvTimeout.tv_sec != 0)
	    {
		gettimeofday (&tvNow, &tz);

		if ((pPRCD->tvTimeout.tv_sec > tvNow.tv_sec) ||
		    ((pPRCD->tvTimeout.tv_sec == tvNow.tv_sec) &&
		     (pPRCD->tvTimeout.tv_usec > tvNow.tv_usec)))
		{
		    /* still waiting for client to start */
		    bWaiting = True;
		}
	    }

	    if (!bWaiting)
	    {
		long clientTimeout;
		Arg al[5];
		int ac;
		WmPanelistObject  pPanelist;

		pPanelist = (WmPanelistObject) pSD->wPanelist;

		/* invoke the function to start the client */
		pPRP->wmFunc ( pPRP->pArgs, pCD, event);

		if (pPanelist && panel.busy_light_data)
		{
		    /* set timeout value */
		    ac = 0;
		    XtSetArg (al[ac], 
			XmNclientTimeoutInterval, &clientTimeout);	ac++; 
		    XtGetValues (panel.busy_light_data->icon, (ArgList)al, ac);
		}

		/*
		 * ClientTimeout is in milliseconds, timeval values
		 * are in seconds and microseconds.
		 */
		gettimeofday (&(pPRCD->tvTimeout), &tz);

		pPRCD->tvTimeout.tv_sec += clientTimeout / 1000;
		pPRCD->tvTimeout.tv_usec += 
		    (clientTimeout % 1000) * 1000;

		pPRCD->tvTimeout.tv_sec += pPRCD->tvTimeout.tv_usec / 1000000;
		pPRCD->tvTimeout.tv_usec %= 1000000;
	    }
	}
    }

    return (True);

} /* END OF FUNCTION F_Push_Recall */
#endif /* PANELIST */


/*************************************<->*************************************
 *
 *  F_Pass_Key (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is a function stub for the f.pass_key window manager function.
 *
 *
 *  Inputs:
 *  ------
 *  args = (immediate value) window type flags
 *
 *  pCD = pointer to the client data
 *
 *  event = X event that invoked the function (key, button, or menu/NULL)
 *
 *************************************<->***********************************/

Boolean F_Pass_Key (args, pCD, event)
    String args;
    ClientData *pCD;
    XEvent *event;

{
    if (wmGD.passKeysActive)
    {
	/*
	 * Get out of pass keys mode.
	 */

	wmGD.passKeysActive = False;
	wmGD.passKeysKeySpec = NULL;
    }
    else
    {
	/*
	 * Get into pass keys mode.
	 */

	wmGD.passKeysActive = True;
    }

    return (False);

} /* END OF FUNCTION F_Pass_Key */



/*************************************<->*************************************
 *
 *  F_Maximize (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for maximizing a client
 *  window.
 *
 *************************************<->***********************************/

Boolean F_Maximize (String args, ClientData *pCD, XEvent *event)
{
    if (pCD && (pCD->clientFunctions & MWM_FUNC_MAXIMIZE))
    {
	SetClientStateWithEventMask (pCD, MAXIMIZED_STATE,
	    GetFunctionTimestamp ((XButtonEvent *)event),
		GetEventInverseMask(event));
    }

    return (False);

} /* END OF FUNCTION F_Maximize */



/*************************************<->*************************************
 *
 *  F_Menu (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for posting a menu.
 *  This function can only be invoked by a key or button event.
 *   wmGD.menuUnpostKeySpec is assumed set appropriately; it will be set to
 *     NULL when the menu is unposted.
 *
 *************************************<->***********************************/

Boolean F_Menu (String args, ClientData *pCD, XEvent *event)
{
    MenuSpec    *menuSpec;
    Context      menuContext;
    unsigned int button;
    int          x;
    int		 y;
    long         flags = POST_AT_XY;
    WmScreenData *pSD;


    if (event && 
	((event->type == ButtonPress) || (event->type == ButtonRelease)))
    {
        button = event->xbutton.button;
	x = event->xbutton.x_root;
	y = event->xbutton.y_root;
        if (event->type == ButtonRelease)
	{
	    flags |= POST_TRAVERSAL_ON;
	}
#ifdef WSM
	/*
	 * Root menu, if posted with button press, then 
	 * set up to handle root menu click to make the menu
	 * sticky.
	 */
	else if (wmGD.rootButtonClick && (event->type == ButtonPress))
	{
	    if (wmGD.bReplayedButton)
	    {
		/* This button was replayed, it most likely dismissed
		   a previous sticky menu, don't post a menu here */
		return (False);
	    }
	    wmGD.checkHotspot = True;
	    wmGD.hotspotRectangle.x = x - wmGD.moveThreshold/2;
	    wmGD.hotspotRectangle.y = y - wmGD.moveThreshold/2;
	    wmGD.hotspotRectangle.width = wmGD.moveThreshold;
	    wmGD.hotspotRectangle.height = wmGD.moveThreshold;
	}
#endif /* WSM */
    }
    else if (event && 
	((event->type == KeyPress) || (event->type == KeyRelease)))
    {
        button = NoButton;
	x = event->xkey.x_root;
	y = event->xkey.y_root;
    }
    else
    {
	/*
	 * A button or key event must be used to post a menu using this 
	 * function.
	 */

	return (False);
    }

    if (pCD)
    {
	if (pCD->clientState == NORMAL_STATE)
	{
	    menuContext = F_CONTEXT_NORMAL;
	}
	else if (pCD->clientState == MAXIMIZED_STATE)
	{
	    menuContext = F_CONTEXT_MAXIMIZE;
	}
	else 
	{
	    menuContext = F_CONTEXT_ICON;
	}
	if (P_ICON_BOX(pCD) &&
            event->xany.window == ICON_FRAME_WIN(pCD))
	{
	    if (pCD->clientState == MINIMIZED_STATE)
	    {
		menuContext = F_SUBCONTEXT_IB_IICON;
	    }
	    else
	    {
		menuContext = F_SUBCONTEXT_IB_WICON;
	    }
	}
    }
    else
    {
	menuContext = F_CONTEXT_ROOT;
    }


    /* We do not add this MenuSpec to wmGD.acceleratorMenuSpecs.
     * This should have been done in MakeWmFunctionResources().
     */

    pSD = (pCD) ? PSD_FOR_CLIENT(pCD) : ACTIVE_PSD;
    if ((menuSpec = MAKE_MENU (pSD, pCD, args, menuContext, 
			      menuContext, (MenuItem *) NULL, FALSE)) != NULL)
    {
        PostMenu (menuSpec, pCD, x, y, button, menuContext, flags, event);
    }

    return (False);

} /* END OF FUNCTION F_Menu */


/*************************************<->*************************************
 *
 *  F_Minimize (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for minimizing a client
 *  window.
 *
 *************************************<->***********************************/

Boolean F_Minimize (String args, ClientData *pCD, XEvent *event)
{
    ClientData *pcdLeader;


    if (pCD)
    {
	/*
	 * If the window is a transient then minimize the entire transient
	 * tree including the transient leader.
	 */
	
	pcdLeader = (pCD->transientLeader) ?
					FindTransientTreeLeader (pCD) : pCD;
	if (pcdLeader->clientFunctions & MWM_FUNC_MINIMIZE)
	{
	    SetClientStateWithEventMask (pCD, MINIMIZED_STATE,
		GetFunctionTimestamp ((XButtonEvent *)event),
		GetEventInverseMask(event));
	}
    }

    return (False);

} /* END OF FUNCTION F_Minimize */



/*************************************<->*************************************
 *
 *  F_Move (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for moving a client window
 *  or icon.
 *
 *************************************<->***********************************/

Boolean F_Move (String args, ClientData *pCD, XEvent *event)
{
    if (pCD && (pCD->clientFunctions & MWM_FUNC_MOVE))
    {
	StartClientMove (pCD, event);
	HandleClientFrameMove (pCD, event);
    }

    return (False);

} /* END OF FUNCTION F_Move */



/*************************************<->*************************************
 *
 *  F_Next_Cmap (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler installing the next
 *  colormap in the list of client window colormaps.
 *
 *************************************<->***********************************/

Boolean F_Next_Cmap (String args, ClientData *pCD, XEvent *event)
{
    if (pCD == NULL)
    {
	pCD = ACTIVE_PSD->colormapFocus;
    }

    if (pCD && (pCD->clientCmapCount > 0) &&
        ((pCD->clientState == NORMAL_STATE) ||
	 (pCD->clientState == MAXIMIZED_STATE)))
    {
	if (++(pCD->clientCmapIndex) >= pCD->clientCmapCount)
	{
	    pCD->clientCmapIndex = 0;
	}
	pCD->clientColormap = pCD->clientCmapList[pCD->clientCmapIndex];
	if (ACTIVE_PSD->colormapFocus == pCD)
	{
#ifndef OLD_COLORMAP /* colormap */
	    /*
	     * We just re-ordered the colormaps list,
	     * so we need to re-run the whole thing.
	     */
	    pCD->clientCmapFlagsInitialized = 0;
	    ProcessColormapList (ACTIVE_PSD, pCD);
#else /* OSF original */
	    WmInstallColormap (ACTIVE_PSD, pCD->clientColormap);
#endif
	}
    }

    return (True);

} /* END OF FUNCTION F_Next_Cmap */



/*************************************<->*************************************
 *
 *  F_Nop (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for doing nothing.
 *
 *************************************<->***********************************/

Boolean F_Nop (String args, ClientData *pCD, XEvent *event)
{

    return (True);

} /* END OF FUNCTION F_Nop */



/*************************************<->*************************************
 *
 *  F_Normalize (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for putting a client window
 *  in the normal state.
 *
 *************************************<->***********************************/

Boolean F_Normalize (String args, ClientData *pCD, XEvent *event)
{

    if (pCD)
    {
	SetClientStateWithEventMask (pCD, NORMAL_STATE,
	    GetFunctionTimestamp ((XButtonEvent *)event),
		GetEventInverseMask(event));
    }

    return (False);

} /* END OF FUNCTION F_Normalize */



/*************************************<->*************************************
 *
 *  F_Normalize_And_Raise (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for putting a client window
 *  in the normal state and raising it from and icon.
 *
 *************************************<->***********************************/

Boolean F_Normalize_And_Raise (String args, ClientData *pCD, XEvent *event)
{
#ifdef PANELIST
    WmScreenData 	*pSD;
    WmWorkspaceData 	*pWS;

    if (args)
    {
	if (pCD) 
	    pSD = PSD_FOR_CLIENT (pCD);
	else
	    pSD = ACTIVE_PSD;

	pWS =  pSD->pActiveWS;

	if (pSD->useIconBox && 
	    wmGD.useFrontPanel && 
	    pSD->iconBoxControl &&
	    (!strcmp(args, WmNiconBox)))
	{
	    /* 
	     * There's an icon box in the front panel and this is a 
	     * request to pop up the icon box.
	     */
	    IconBoxPopUp (pWS, True);
	    return (False);
	}
    }
#endif /* PANELIST */
    if (pCD)
    {
        if (pCD->clientState == MINIMIZED_STATE)
        {
            /* normalize window  */
            SetClientStateWithEventMask (pCD, NORMAL_STATE,
                          (Time)
                          (event
                           ? GetFunctionTimestamp ((XButtonEvent *)event)
                           : GetTimestamp ()),
			GetEventInverseMask(event));
        }
        else
        {
	    /* Make sure we are in NORMAL_STATE */
	    SetClientStateWithEventMask (pCD, NORMAL_STATE,
			    GetFunctionTimestamp ((XButtonEvent *)event),
				GetEventInverseMask(event));

            /* Raise the window and set the keyboard focus to the window */
#ifdef WSM
	    wmGD.bSuspendSecondaryRestack = True;
#endif /* WSM */
            F_Raise (NULL, pCD, (XEvent *)NULL);
#ifdef WSM
	    wmGD.bSuspendSecondaryRestack = False;
#endif /* WSM */
	    if (wmGD.raiseKeyFocus)
	    {
		F_Focus_Key (NULL, pCD,
			     (event 
			      ? ((XEvent *)event)
			      : ((XEvent *)NULL)));
	    }
        }
	wmGD.clickData.clickPending = False;
	wmGD.clickData.doubleClickPending = False;
    }

    return (False);

} /* END OF FUNCTION F_Normalize_And_Raise */



/*************************************<->*************************************
 *
 *  F_Restore (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for putting a client window
 *  in the normal state.
 *
 *************************************<->***********************************/

Boolean F_Restore (String args, ClientData *pCD, XEvent *event)
{
    int newState;

    if (pCD)
    {
	/*
	 * If current state is MAXIMIZED state then just go to NORMAL state,
	 * otherwise (you are in MINIMIZED state) return to previous state.
	 */

	if (pCD->clientState == MAXIMIZED_STATE)
	{
	    SetClientStateWithEventMask (pCD, NORMAL_STATE,
			    GetFunctionTimestamp ((XButtonEvent *)event),
				GetEventInverseMask(event));
	}
	else
	{
	    if (pCD->maxConfig)
	    {
		newState = MAXIMIZED_STATE;
	    }
	    else
	    {
		newState = NORMAL_STATE;
	    }

	    SetClientStateWithEventMask (pCD, newState,
			    GetFunctionTimestamp ((XButtonEvent *)event),
				GetEventInverseMask(event));
	}
    }

    return (False);

} /* END OF FUNCTION F_Restore */



/*************************************<->*************************************
 *
 *  F_Restore_And_Raise (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for putting a client window
 *  in the normal state and raising it from and icon.
 *
 *************************************<->***********************************/

Boolean F_Restore_And_Raise (String args, ClientData *pCD, XEvent *event)
{
    int newState;
    
    if (pCD)
    {
        if (pCD->clientState == MINIMIZED_STATE)
        {
            /* Restore window  */
	    if (pCD->maxConfig)
	    {
		newState = MAXIMIZED_STATE;
	    }
	    else
	    {
		newState = NORMAL_STATE;
	    }

            SetClientStateWithEventMask (pCD, newState,
                          (Time)
                          (event
                           ? GetFunctionTimestamp ((XButtonEvent *)event)
                           : GetTimestamp ()),
			GetEventInverseMask(event));
        }
        else
        {
	    /* Make sure we restore the window first */
	    F_Restore (NULL, pCD, event);

            /* Raise the window and set the keyboard focus to the window */
#ifdef WSM
	    wmGD.bSuspendSecondaryRestack = True;
#endif /* WSM */
            F_Raise (NULL, pCD, (XEvent *)NULL);
#ifdef WSM
	    wmGD.bSuspendSecondaryRestack = False;
#endif /* WSM */
	    if (wmGD.raiseKeyFocus)
	    {
		F_Focus_Key (NULL, pCD,
			     (event 
			      ? ((XEvent *)event)
			      : ((XEvent *)NULL)));
	    }
        }
	wmGD.clickData.clickPending = False;
	wmGD.clickData.doubleClickPending = False;
    }

    return (False);

} /* END OF FUNCTION F_Restore_And_Raise */



/*************************************<->*************************************
 *
 *  F_Pack_Icons (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for packing icons in the
 *  icon box or on the desktop.
 *
 *************************************<->***********************************/

Boolean F_Pack_Icons (String args, ClientData *pCD, XEvent *event)
{
    
    IconBoxData *pIBD;

    if (ACTIVE_PSD->useIconBox)
    {
	pIBD = ACTIVE_WS->pIconBox;
	if (pCD)
	{
	    while (pCD != pIBD->pCD_iconBox)
	    {
		if (pIBD->pNextIconBox)
		{
		    pIBD = pIBD->pNextIconBox;
		}
		else
		{
		    pIBD = NULL;
		    break;
		}
	    }
	}
	if (pIBD)
	{
	    PackIconBox (pIBD, False, False, 0, 0);
	}
	else
	{
	   PackRootIcons ();
	}
    }
    else
    {
	PackRootIcons ();
    }

    return (True);


} /* END OF FUNCTION F_Pack_Icons */


#if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
/*************************************<->*************************************
 *
 *  F_Post_RMenu (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for posting the
 *  root window menu.
 *  This function can only be invoked by a key event.
 *
 *************************************<->***********************************/

Boolean F_Post_RMenu (String args, ClientData *pCD, XEvent *event)
{
    MenuSpec    *rootMenu;
    unsigned int button = NoButton;
    int          x, y;
    long         flags = POST_AT_XY;
    Window       rwin, cwin;
    int          winx, winy;
    unsigned int mask;


    if ((event->type == KeyPress) || (event->type == KeyRelease))
      {

	/* Find the root menu spec */
	for (rootMenu = ACTIVE_PSD->menuSpecs;
	     rootMenu != (MenuSpec *) NULL;
	     rootMenu = rootMenu->nextMenuSpec)
	  {
	    if (strcmp(rootMenu->name, ACTIVE_PSD->rootMenu) == 0)
	      break;
	  }
    
	/* If we couldn't find the root menu, then do nothing. */
	if (rootMenu == (MenuSpec *) NULL)
	  return (False);

	else
    	  {
	    XQueryPointer(DISPLAY, ACTIVE_ROOT,
			  &rwin, &cwin, &x, &y, &winx, &winy, &mask);

	    PostMenu (rootMenu, NULL, x, y, NoButton, F_CONTEXT_ROOT,
		      flags, event);
	  }
      }

    return (False);

} /* END OF FUNCTION F_Post_RMenu */
#endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */


/*************************************<->*************************************
 *
 *  F_Post_SMenu (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for posting the system menu
 *  for the specified client.
 *  This function can only be invoked by a key or button event.
 *  wmGD.menuUnpostKeySpec is assumed set appropriately; it will be set to
 *    NULL when the menu is unposted.
 *
 *************************************<->***********************************/

Boolean F_Post_SMenu (String args, ClientData *pCD, XEvent *event)
{
    Context menuContext;


    /*
     * An event must be used to post the system menu using this function.
     */

    if (event && pCD && pCD->systemMenuSpec)
    {
        /*
	 * Determine whether the keyboard is posting the menu and post
	 * the menu at an appropriate place.
         */

	if (pCD->clientState == NORMAL_STATE)
	{
	    menuContext = F_CONTEXT_NORMAL;
	}
	else if (pCD->clientState == MAXIMIZED_STATE)
	{
	    menuContext = F_CONTEXT_MAXIMIZE;
	}
	else 
	{
	    menuContext = F_CONTEXT_ICON;
	}
	if (P_ICON_BOX(pCD) &&
            event->xany.window == ICON_FRAME_WIN(pCD))
	{
	    if (pCD->clientState == MINIMIZED_STATE)
	    {
		menuContext = F_SUBCONTEXT_IB_IICON;
	    }
	    else
	    {
		menuContext = F_SUBCONTEXT_IB_WICON;
	    }
	}

	if ((event->type == KeyPress) || (event->type == KeyRelease))
	{
	    /*
	     * Set up for "sticky" menu processing if specified.
	     */

	    if (pCD->clientState == MINIMIZED_STATE ||
		menuContext == (F_SUBCONTEXT_IB_IICON | F_SUBCONTEXT_IB_WICON))
	    {
		if (wmGD.iconClick)
		{
		    wmGD.checkHotspot = True;
		}
	    }
	    else if (wmGD.systemButtonClick && (pCD->decor & MWM_DECOR_MENU))
	    {
		wmGD.checkHotspot = True;
	    }

	    PostMenu (pCD->systemMenuSpec, pCD, 0, 0, NoButton, menuContext,
		      0, event);
	}
	else if (event->type == ButtonPress)
	{
#ifdef WSM
	    /*
	     * Root menu, if posted with button press, then 
	     * set up to handle root menu click to make the menu
	     * sticky.
	     */
	    if (wmGD.rootButtonClick && (!wmGD.checkHotspot))
	    {
		wmGD.checkHotspot = True;
		wmGD.hotspotRectangle.x = 
			    event->xbutton.x_root - wmGD.moveThreshold/2;
		wmGD.hotspotRectangle.y = 
			    event->xbutton.y_root - wmGD.moveThreshold/2;
		wmGD.hotspotRectangle.width = wmGD.moveThreshold;
		wmGD.hotspotRectangle.height = wmGD.moveThreshold;
	    }
#endif /* WSM */
	    PostMenu (pCD->systemMenuSpec, pCD, 
		event->xbutton.x_root, event->xbutton.y_root,
	  	event->xbutton.button, menuContext, POST_AT_XY, event);
	}
	else if (event->type == ButtonRelease)
	{
	    PostMenu (pCD->systemMenuSpec, pCD, 
		event->xbutton.x_root, event->xbutton.y_root,
	  	event->xbutton.button, menuContext,
		POST_AT_XY | POST_TRAVERSAL_ON, event);
	}
    }

    return (False);

} /* END OF FUNCTION F_PostSMenu */



/*************************************<->*************************************
 *
 *  F_Kill (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for terminating a client.
 *  Essentially the client connection is shut down.
 *
 *************************************<->***********************************/

Boolean F_Kill (String args, ClientData *pCD, XEvent *event)
{
    if (pCD && (pCD->clientFunctions & MWM_FUNC_CLOSE))
    {
	Boolean do_delete_window =
		pCD->protocolFlags & PROTOCOL_WM_DELETE_WINDOW;
	Boolean do_save_yourself =
		pCD->protocolFlags & PROTOCOL_WM_SAVE_YOURSELF;

#ifdef PANELIST
	if (pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUBPANEL)
	{
	    Widget 		wPanel;
	    
	    /*
	     * Get the widget for the subpanel
	     * (Should be only child of the shell!)
	     */
	    wPanel = WmPanelistWindowToSubpanel (DISPLAY1, pCD->client);
            if (wPanel)
	    {
		SlideSubpanelBackIn (pCD, wPanel);
	    }
	    return (False);
	}
        if (pCD->clientFlags & ICON_BOX)
	{
	    /*
	     * When the front panel is used with the icon box,
	     * "Close" hides the icon box into the front panel.
	     */
	    if ((wmGD.useFrontPanel) &&
		(pCD->pSD->iconBoxControl) &&
		(IconBoxShowing(pCD->pSD->pActiveWS)))
	    {
		IconBoxPopUp (pCD->pSD->pActiveWS, False);
	    }
	}
	else
#endif /* PANELIST */
	if (!do_delete_window && !do_save_yourself)
	{
	    XKillClient (DISPLAY, pCD->client);
	}
	else
	{
	    if (do_delete_window)
 	    {
		/*
		 * The client wants to be notified, not killed.
		 */

		SendClientMsg (pCD->client, (long) wmGD.xa_WM_PROTOCOLS,
		    (long) wmGD.xa_WM_DELETE_WINDOW, CurrentTime, NULL, 0);
	    }
#ifdef WSM
	    /*
	     * HP does not want to send a client message for both
	     * delete_window AND save_yourself.  The current OSF
	     * patch did just that.  This "else if" returns dtwm
	     * to the behavior of dt 2.01
	     */
            else if (do_save_yourself)
#else /* WSM */
	    if (do_save_yourself)
#endif /* WSM */
	    {
		/*
		 * Send a WM_SAVE_YOURSELF message and wait for a change to
		 * the WM_COMMAND property.
		 * !!! button and key input should be kept from the window !!!
		 */

		if (AddWmTimer (TIMER_QUIT, 
		    (unsigned long) wmGD.quitTimeout, pCD))
		{
		    SendClientMsg (pCD->client, (long) wmGD.xa_WM_PROTOCOLS,
			(long) wmGD.xa_WM_SAVE_YOURSELF, CurrentTime, NULL, 0);

		    pCD->clientFlags |= CLIENT_TERMINATING;
		}
		else
		{
		    XKillClient (DISPLAY, pCD->client);
		}
	    }
	}
    }

    return (False);

} /* END OF FUNCTION F_Kill */

#ifdef WSM

/*************************************<->*************************************
 *
 *  F_Marquee_Selection (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for selecting 
 *  non-window manager objects on the root window.
 *
 *************************************<->***********************************/

Boolean F_Marquee_Selection (String args, ClientData *pCD, XEvent *event)
{
    if (!pCD)
    {
	/*
	 * This function only valid in root context
	 */
	StartMarqueeSelect (ACTIVE_PSD, event);
	HandleMarqueeSelect (ACTIVE_PSD, event);
    }

    return (False);

} /* END OF FUNCTION F_Marquee_Selection */

/*************************************<->*************************************
 *
 *  RefreshByClearing (win)
 *
 *
 *  Description:
 *  -----------
 *  Recursively refresh this window and its children by doing
 *  XClearAreas
 *
 *************************************<->***********************************/
static void
RefreshByClearing (Window win)
{
    Status status;
    int i;
    Window root, parent;
    unsigned int nchildren;
    Window *winChildren;

    /* clear this window */
    XClearArea(DISPLAY, win, 0, 0, 0, 0, True);

    /* find any children and clear them, too */
    status = XQueryTree(DISPLAY, win, &root, &parent, &winChildren,
		    &nchildren);
    if (status != 0)
    {
	/* recurse for each child window */
	for (i=0; i<nchildren; ++i) 
        {
	    RefreshByClearing(winChildren[i]);
	}

	/* clean up */
	if (nchildren > 0) 
	    XFree((char *)winChildren);
    }
}
#endif /* WSM */


/*************************************<->*************************************
 *
 *  F_Refresh (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for causing all windows
 *  in the workspace to be redrawn.
 *
 *************************************<->***********************************/

Boolean F_Refresh (String args, ClientData *pCD, XEvent *event)
{
    Window win;

#ifdef WSM
    if (wmGD.refreshByClearing)
    {
	RefreshByClearing (ACTIVE_ROOT);
    }
    else
    {
#endif /* WSM */
			 /* default background_pixmap is None */
    win = XCreateWindow (DISPLAY,
			 ACTIVE_ROOT, 0, 0,
	                 (unsigned int) DisplayWidth (DISPLAY, 
			     ACTIVE_SCREEN),
	                 (unsigned int) DisplayHeight (DISPLAY, 
			     ACTIVE_SCREEN),
	                 0, 
                         0,
	                 InputOutput,
                         CopyFromParent,
	                 0, 
			 (XSetWindowAttributes *)NULL);   

    XMapWindow (DISPLAY, win);
    XDestroyWindow (DISPLAY, win);
#ifdef WSM 
    }
#endif /* WSM */
    XFlush (DISPLAY);

    return (True);

} /* END OF FUNCTION F_Refresh */



/*************************************<->*************************************
 *
 *  F_Resize (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for resizing a client window.
 *
 *************************************<->***********************************/

Boolean F_Resize (String args, ClientData *pCD, XEvent *event)
{
    if (pCD && (pCD->clientFunctions & MWM_FUNC_RESIZE) &&
	((pCD->clientState == NORMAL_STATE) ||
					(pCD->clientState == MAXIMIZED_STATE)))
    {
	StartClientResize (pCD, event);
	HandleClientFrameResize (pCD, event);
    }

    return (False);

} /* END OF FUNCTION F_Resize */



/*************************************<->*************************************
 *
 *  F_Restart (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for restarting the window
 *  manager.
 *
 *************************************<->***********************************/

Boolean F_Restart (String args, ClientData *pCD, XEvent *event)
{
#ifdef WSM
    if (args && *args && !strcmp (args, DTWM_REQP_NO_CONFIRM))
    {
	RestartWm (MWM_INFO_STARTUP_CUSTOM);
    }
    else
#endif /* WSM */
    if (wmGD.showFeedback & WM_SHOW_FB_RESTART)
    {
	ConfirmAction (ACTIVE_PSD, RESTART_ACTION);
    }
    else
    {
	RestartWm (MWM_INFO_STARTUP_CUSTOM);
    }
    return (False);

} /* END OF FUNCTION F_Restart */



/*************************************<->*************************************
 *
 *  Do_Restart (dummy)
 *
 *
 *  Description:
 *  -----------
 *  Callback function for restarting the window manager.
 *
 *************************************<->***********************************/

void Do_Restart (Boolean dummy)
{
    RestartWm (MWM_INFO_STARTUP_CUSTOM);

} /* END OF FUNCTION Do_Restart */



/*************************************<->*************************************
 *
 *  RestartWm (startupFlags)
 *
 *
 *  Description:
 *  -----------
 *  Actually restarts the window manager.
 *
 *
 *  Inputs:
 *  ------
 *  startupFlags = flags to be put into the Wm_INFO property for restart.
 *
 *************************************<->***********************************/

void RestartWm (long startupFlags)
{
    ClientListEntry *pNextEntry;
    int scr;


    for (scr=0; scr<wmGD.numScreens; scr++)
    {
	if(wmGD.Screens[scr].managed)
	{
	    
	    /*
	     * Set up the _MOTIF_WM_INFO property on the root window 
	     * to indicate a restart.
	     */
	    
	    SetMwmInfo (wmGD.Screens[scr].rootWindow, startupFlags, 0);
#ifdef WSM
	    SaveResources(&wmGD.Screens[scr]);
#endif /* WSM */
	    /*
	     * Unmap client windows and reparent them to the root window.
	     */
	    
	    pNextEntry = wmGD.Screens[scr].lastClient;
	    while (pNextEntry)
	    {
		if (pNextEntry->type == NORMAL_STATE)
		{
		    if (pNextEntry->pCD->clientFlags & CLIENT_WM_CLIENTS)
		    {
			if (pNextEntry->pCD->clientState != MINIMIZED_STATE)
			{
			    XUnmapWindow (DISPLAY, 
					  pNextEntry->pCD->clientFrameWin);
			}
		    }
		    else
		    {
			DeFrameClient (pNextEntry->pCD);
		    }
		}
		pNextEntry = pNextEntry->prevSibling;
	    }
#if defined(PANELIST)
	    UnParentControls (&wmGD.Screens[scr], True);
#endif /* PANELIST */
	}
	
    }
    
#ifdef WSM
    /* shut down the messaging connection */
    dtCloseIPC();
#endif /* WSM */
    ResignFromSM();

    /*
     * This fixes restart problem when going from explicit focus to
     * pointer focus.  Window under pointer was not getting focus indication
     * until pointer was moved to new window, or out of and into the
     * window.
     */

    XSetInputFocus (DISPLAY, PointerRoot, RevertToPointerRoot, CurrentTime);
    XSync (DISPLAY, False);

#ifdef WSM
    CLOSE_FILES_ON_EXEC();
    _DtEnvControl(DT_ENV_RESTORE_PRE_DT); 
#endif /* WSM */
    /*
     * Restart the window manager with the initial arguments plus
     * the restart settings.
     */

    execvp (*(wmGD.argv), wmGD.argv);

#ifdef WSM
    Warning (((char *)GETMESSAGE(26, 1, 
"The window manager restart failed. The window manager program could not \
be found or could not be executed.")));
#else /* WSM */
    Warning ("Cannot restart the window manager");
#endif /* WSM */
    Do_Quit_Mwm (True);



} /* END OF FUNCTION RestartWm */


/*************************************<->*************************************
 *
 *  DeFrameClient (pCD)
 *
 *
 *  Description:
 *  -----------
 *  Unmaps a client window (and client icon window) and reparents the
 *  window back to the root.
 *
 *
 *  Inputs:
 *  -------
 *  pCD = pointer to the client data for the window to be de-framed.
 *
 *************************************<->***********************************/

void DeFrameClient (ClientData *pCD)
{
    int x, y;
    int xoff, yoff;
    XWindowChanges windowChanges;

    while (pCD)
    {
        if (pCD->clientState != MINIMIZED_STATE)
        {
	    XUnmapWindow (DISPLAY, pCD->clientFrameWin);
        }

        if (pCD->iconWindow && (pCD->clientFlags & ICON_REPARENTED))
        {
	    XUnmapWindow (DISPLAY, pCD->iconWindow);
	    XRemoveFromSaveSet (DISPLAY, pCD->iconWindow);
#ifdef WSM
	    XReparentWindow (DISPLAY, pCD->iconWindow, 
		ROOT_FOR_CLIENT(pCD), pCD->pWsList->iconX, 
		pCD->pWsList->iconY);
#else /* WSM */
	    XReparentWindow (DISPLAY, pCD->iconWindow, 
		ROOT_FOR_CLIENT(pCD), pCD->iconX, pCD->iconY);
#endif /* WSM */
        }

        if (pCD->maxConfig)
        {
	    x = pCD->maxX;
	    y = pCD->maxY;
        }
        else
        {
	    if(wmGD.positionIsFrame)
	    {
		CalculateGravityOffset (pCD, &xoff, &yoff);
		x = pCD->clientX - xoff;
		y = pCD->clientY - yoff;
	    }
	    else
	    {
		x = pCD->clientX;
		y = pCD->clientY;
	    }
        }

#ifndef UNMAP_ON_RESTART
	if (pCD->clientState == MINIMIZED_STATE)
	{
	    XUnmapWindow (DISPLAY, pCD->client);
	}
#else
	XUnmapWindow (DISPLAY, pCD->client);
#endif
	XRemoveFromSaveSet (DISPLAY, pCD->client);
        XReparentWindow (DISPLAY, pCD->client, 
	    ROOT_FOR_CLIENT(pCD), x, y);

	if (pCD->transientChildren)
	{
	    DeFrameClient (pCD->transientChildren);
	}

	/*
	 * restore X border
	 */
	windowChanges.x = x;
	windowChanges.y = y;
	windowChanges.border_width = pCD->xBorderWidth;
	XConfigureWindow (DISPLAY, pCD->client, CWBorderWidth | CWX | CWY,
			  &windowChanges);

	if (pCD->transientLeader)
	{
	    pCD = pCD->transientSiblings;
	}
	else
	{
	    pCD = NULL;
	}
    }

} /* END OF FUNCTION DeFrameClient */

#if defined(PANELIST)

/******************************<->*************************************
 *
 *  F_Toggle_Front_Panel (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for toggling the
 *  front panel off and on.
 ******************************<->***********************************/

Boolean
F_Toggle_Front_Panel (String args, ClientData *pCD, XEvent *event)
{

    WmPanelistObject  pPanelist;

    if (pCD)
    {
        pPanelist = (WmPanelistObject) pCD->pSD->wPanelist;
    }
    else
    {
        pPanelist = (WmPanelistObject) ACTIVE_PSD->wPanelist;
    }

    pCD = NULL;
    if (pPanelist)
    {
	(void) XFindContext (DISPLAY, XtWindow(O_Shell(pPanelist)),
			    wmGD.windowContextType, (caddr_t *)&pCD);
    }


    if (pCD)
    {
	if (pCD->clientState & MINIMIZED_STATE)
	{
	    SetClientState (pCD, NORMAL_STATE, 
		    GetFunctionTimestamp ((XButtonEvent *)event));
	}
	else
	{
	    SetClientState (pCD, MINIMIZED_STATE, 
		    GetFunctionTimestamp ((XButtonEvent *)event));
	}
    }

    return(True);
} /* END OF FUNCTION F_Toggle_Front_Panel */


/******************************<->*************************************
 *
 *  Boolean F_Version (String args, ClientData *pCD, XEvent *event)
 *
 *  Description:
 *  -----------
 *  Invoke the help on version dialogue.
 *
 *  Inputs:
 *  ------
 *  args - incoming values
 *  pCD  - associated client data structure
 *  event - what triggered this call
 * 
 *  Outputs:
 *  -------
 *  Return - True if the call occurs; false otherwise.
 *
 *  Comments:
 *  --------
 *
 ******************************<->***********************************/
Boolean
F_Version (String args, ClientData *pCD, XEvent *event)
{

    WmPanelistObject  pPanelist;

    if (pCD)
    {
        pPanelist = (WmPanelistObject) pCD->pSD->wPanelist;
    }
    else
    {
        pPanelist = (WmPanelistObject) ACTIVE_PSD->wPanelist;
    }

    if (pPanelist)
    {
	WmDtHelpOnVersion (O_Shell (pPanelist));
    }

    return (True);

}  /* END OF FUNCTION F_Version */
#endif /* PANELIST */


/******************************<->*************************************
 *
 *  F_Send_Msg (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for sending a client
 *  message event to a client window.
 *
 *
 *  Inputs:
 *  ------
 *  args = (immediate value) message id
 *
 *  pCD = pointer to the client data
 *
 *  event = X event that invoked the function (key, button, or menu/NULL)
 *
 *
 ******************************<->***********************************/

Boolean F_Send_Msg (String args, ClientData *pCD, XEvent *event)
{
    register int i;


    if (pCD && pCD->mwmMessagesCount)
    {
	/*
	 * A message id must be made "active" by being included in the
	 * _MWM_MESSAGES property before the associated message can be sent.
	 */

	for (i = 0; i < pCD->mwmMessagesCount; i++)
	{
	    if (pCD->mwmMessages[i] == (long)args)
	    {
		SendClientMsg (pCD->client, (long) wmGD.xa_MWM_MESSAGES, 
		    (long)args, CurrentTime, NULL, 0);
		return (True);
	    }
	}
    }

    return (True);

} /* END OF FUNCTION F_Send_Msg */



/*************************************<->*************************************
 *
 *  F_Separator (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is a placeholder function; it should never be called.
 *
 *************************************<->***********************************/

Boolean F_Separator (String args, ClientData *pCD, XEvent *event)
{

    return (True);

} /* END OF FUNCTION F_Separator */


Boolean ForceRaiseWindow (ClientData *pcd)
{
#if 0
    Window stackWindow;
    WmScreenData *pSD = (ACTIVE_WS)->pSD;
#endif
    XWindowChanges changes;
    Boolean restack = False;

#if 0
    if (pSD->clientList->type == MINIMIZED_STATE)
    {
	stackWindow = ICON_FRAME_WIN(pSD->clientList->pCD);
    }
    else
    {
	stackWindow = pSD->clientList->pCD->clientFrameWin;
    }
#endif

    /*
     * Windows did not raise on regular f.raise because the raise was
     * not relative to another window (methinks).
     */
    changes.stack_mode = Above;
    XConfigureWindow (DISPLAY, pcd->clientFrameWin, CWStackMode,
		      &changes);

    return (restack);
}



/*************************************<->*************************************
 *
 *  F_Raise (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for topping the client window
 *  so that it is unobscured.
 *
 *************************************<->***********************************/

Boolean F_Raise (String args, ClientData *pCD, XEvent *event)
{
    ClientListEntry *pEntry;
    ClientListEntry *pNextEntry;
    ClientListEntry *pStackEntry;
    String string = args;
    int flags = STACK_NORMAL;
#ifdef WSM
	WmWorkspaceData *pWS = ACTIVE_WS;
#endif /* WSM */

    if (string)
    {
	/* process '-client' argument */
	if (string[0] == '-')
	{
	    string = &string[1];
	    string = (String) GetString ((unsigned char **) &string);

	    pStackEntry = NULL;
	    pNextEntry = ACTIVE_PSD->clientList;
	    while (pNextEntry &&
		   (pEntry = FindClientNameMatch (pNextEntry, True, string,
						  F_GROUP_ALL)))
	    {
		pNextEntry = pEntry->nextSibling;
#ifdef WSM
	        if (ClientInWorkspace (pWS, pEntry->pCD))
		{
#endif /* WSM */
		Do_Raise (pEntry->pCD, pStackEntry, STACK_NORMAL);
		pStackEntry = pEntry;
#ifdef WSM
	        }
#endif /* WSM */
	    }
	}
	/* process family stacking stuff */
	else if (*string)
	{
	    unsigned int  slen, len, index;

	    slen = strlen(args) - 2;		/* subtract '\n' and NULL */
	    for (index = 0; index < slen; string = &args[index+1])
	    {
		if ((string = (String) GetString ((unsigned char **) &string)) == NULL)
		   break;
		len = strlen(string);
		if (!strcmp(string,"within"))
		{
		    flags |= STACK_WITHIN_FAMILY;
		}
		else if (!strcmp(string,"freeFamily"))
		{
		    flags |= STACK_FREE_FAMILY;
		}
		index += len;
	    }
#ifdef WSM
	    if (ClientInWorkspace (pWS, pCD))
	    {
#endif /* WSM */
	    Do_Raise (pCD, (ClientListEntry *) NULL, flags);
#ifdef WSM
	    }
#endif /* WSM */
	}
    }
    else if (pCD)
    {
#ifdef WSM
	if (ClientInWorkspace (pWS, pCD))
	{
#endif /* WSM */
	Do_Raise (pCD, (ClientListEntry *) NULL, STACK_NORMAL);
#ifdef WSM
	}
#endif /* WSM */
    }

    return (True);

} /* END OF FUNCTION F_Raise */



/*************************************<->*************************************
 *
 *  Do_Raise (pCD, pStackEntry)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for topping the client window
 *  so that it is unobscured.
 *
 *
 *  Inputs:
 *  ------
 *  pCD = pointer to the client data of the window (or icon) to be raised.
 * 
 *  pStackEntry = pointer to client list entry for window that is to be 
 *	above the raised window (if NULL window is raised to the top of the
 *	stack).
 *
 *************************************<->***********************************/

void Do_Raise (ClientData *pCD, ClientListEntry *pStackEntry, int flags)
{
    Boolean restackTransients;
    ClientData *pcdLeader;
    WmWorkspaceData *pWS = ACTIVE_WS;
#ifdef WSM
    Boolean bLeaderRestacked;
#endif /* WSM */

#ifdef PANELIST
    if (pCD->pECD)
    {
	/*
	 * Window has been reparented into the front panel. 
	 * Don't follow through on window stacking change.
	 */
	return;
    }
    else 
#else /* PANELIST */
#endif /* PANELIST */
#ifdef WSM
    if (ClientInWorkspace(pWS, pCD)  && 
	(!pStackEntry || ClientInWorkspace (pWS, pStackEntry->pCD)))
    {
	/* 
	 * Both clients are in the current workspace. Set
	 * client indices so that the access macros work.
	 */
	SetClientWsIndex (pCD);
	if (pStackEntry)
	{
	    SetClientWsIndex (pStackEntry->pCD);
	}
    }
    else
    {
	/*
	 * One or both of the clients are not in the current workspace
	 * Do nothing.
	 */
	return;
    }
#endif /* WSM */

    pcdLeader = (pCD->transientLeader) ? FindTransientTreeLeader (pCD) : pCD;

    if (wmGD.systemModalActive && (pcdLeader != wmGD.systemModalClient))
    {
	/*
	 * Don't raise the window above the system modal window.
	 */
    }
    else if ((pcdLeader->clientState == MINIMIZED_STATE) &&
	     !P_ICON_BOX(pcdLeader))
    {
        /*
         * If a dirtyStackEntry exists, return it to its original place 
         * in the stack (for all stacking types)
         */
        if (dirtyStackEntry)
        {
            if (dirtyStackEntry->transientChildren ||
                dirtyStackEntry->transientLeader)
                RestackTransients (dirtyStackEntry);
            dirtyStackEntry = NULL;
            dirtyLeader = NULL;
	}

	/*
	 * Only restack the icon if it is not currently raised.
	 */

	if (pStackEntry)
	{
	    if (pStackEntry->nextSibling != &pcdLeader->iconEntry)
	    {
	        StackWindow (pWS, &pcdLeader->iconEntry, False /*below*/,
			     pStackEntry);
	        MoveEntryInList (pWS, &pcdLeader->iconEntry, False /*below*/,
				 pStackEntry);
	    }
	}
	else
	{
	    if (ACTIVE_PSD->clientList != &pcdLeader->iconEntry)
	    {
	        StackWindow (pWS, &pcdLeader->iconEntry, 
		    True /*on top*/, (ClientListEntry *) NULL);
	        MoveEntryInList (pWS, &pcdLeader->iconEntry, 
		    True /*on top*/, (ClientListEntry *) NULL);
	    }
	}
    }
    else /* NORMAL_STATE, MAXIMIZED_STATE, adoption */
    {
#ifdef WSM
        /*
	 * Handle restacking of primary/secondary windows
	 * within the transient window tree. Don't raise this
	 * window above any modal transients.
	 */
        bLeaderRestacked = False;
	if ((pcdLeader->transientChildren) &&
	    (!pCD->secondariesOnTop) &&
	    (!wmGD.bSuspendSecondaryRestack) &&
	    (!IS_APP_MODALIZED(pCD)))
	{
	    if (pCD != pcdLeader)
	    {
		/* 
		 * This is not the transient leader, make sure
		 * the transient leader isn't on top.
		 * (Brute force solution)
		 */
		bLeaderRestacked = NormalizeTransientTreeStacking (pcdLeader);

		if (pCD->transientChildren)
		{
		    /*
		     * This isn't the overall leader of the transient 
		     * tree, but it does have transient's of its own.
		     * Move it to the top of its own transient sub-tree.
		     */
		    bLeaderRestacked |= BumpPrimaryToTop (pCD);
		}
	    }
	    else 
	    {
		/*
		 * This is the transient leader, move it to the
		 * top.
		 */
		bLeaderRestacked = BumpPrimaryToTop (pcdLeader);
	    }

	}
#endif /* WSM */
	/*
	 * If this is a transient window then put it on top of its
	 * sibling transient windows.
	 */

	restackTransients = False;


/*
 * Fix for 5325 - The following code has been reorganized to cause the
 *                action of F_Raise to match the current documentation.
 *                The new algorithm is as follows:
 *
 *                if (dirtyStackEntry)
 *                  restore dirty tree
 *                if (not withinFamily)
 *                  bring window group to the top of global stack
 *                if (freeFamily)
 *                  raise the requested window to top of family
 *                else
 *                  raise requested window to top of siblings
 *                if (need to restack windows)
 *                  restack windows
 *                return
 */
        /*
         * If a dirtyStackEntry exists, return it to its original place 
         * in the stack (for all stacking types)
         */
        if (dirtyStackEntry)
        {
            /*
             * Check to make sure that the dirty pCD has either transient
             * children or a transient leader.  If not, do not restore
             * the transients.
             */
            if (dirtyStackEntry->transientChildren ||
                dirtyStackEntry->transientLeader)
                RestackTransients (dirtyStackEntry);
            dirtyStackEntry = NULL;
            dirtyLeader = NULL;
	}

        /*
         * If the flags do not indicate "within", raise the window family
         * to the top of the window stack. If the window is the primary,
         * raise it to the top regardless of the flags.
         */
        if (!pCD->transientLeader || !(flags & STACK_WITHIN_FAMILY))
        {
            if (pStackEntry)
            {
                if (pStackEntry->nextSibling != &pcdLeader->clientEntry)
                {
                    StackWindow (pWS, &pcdLeader->clientEntry, 
                        False /*below*/, pStackEntry);
                    MoveEntryInList (pWS, &pcdLeader->clientEntry, 
                        False /*below*/, pStackEntry);
                }
            }
            else
            {
                if (ACTIVE_PSD->clientList != &pcdLeader->clientEntry)
                {
                    StackWindow (pWS, &pcdLeader->clientEntry,
                        True /*on top*/, (ClientListEntry *) NULL);
                    MoveEntryInList (pWS, &pcdLeader->clientEntry,
                        True /*on top*/, (ClientListEntry *) NULL);
                }
            }
        }
  
        /*
         * If freeFamily stacking is requested, check to make sure that
         * the window has either a transientChild or Leader.  This will
         * guarantee that windows that form their own family are not
         * labelled as dirty (what's to dirty it up?).  If it has either,
         * raise the window to the top of the family stack.
         */
        if ((flags & STACK_FREE_FAMILY) &&
            (pCD->transientLeader || pCD->transientChildren))
        {
            dirtyStackEntry = pCD;
	    dirtyLeader = pcdLeader;
  
            restackTransients = ForceRaiseWindow (pCD);
        }
  
        /*
         * If withinFamily stacking is requested, put the current transient
         * on top of its sibling transient windows.
         */
        else
        {
  	    restackTransients = PutTransientOnTop (pCD);
  	}
  
        /* At this point, if doing a regular f.raise the window family has
         * already been brought to the top of the stack, so nothing further
         * needs to be done for it.
         */
  
        /* Restack the transients if needed */
  
#ifdef WSM
        if ((restackTransients) || (bLeaderRestacked))
#else /* WSM */
        if (restackTransients)
#endif /* WSM */
        {
	    RestackTransients (pCD);
  	}
    }

} /* END OF FUNCTION Do_Raise */



/*************************************<->*************************************
 *
 *  F_Raise_Lower (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This window manager function tops an obscured window or icon and bottoms 
 *  a window or icon that is on top of the window stack.
 *
 *************************************<->***********************************/

Boolean F_Raise_Lower (String args, ClientData *pCD, XEvent *event)
{
    ClientData *pcdLeader;

    if (pCD)
    {
	pcdLeader = (pCD->transientLeader) ?
					FindTransientTreeLeader (pCD) : pCD;

	/*
	 * Treat a raise/lower on a window in a transient tree as if it is
	 * a raise/lower for the whole tree.
	 */

	if (CheckIfClientObscuredByAny (pcdLeader))
	{
	    /*
	     * The window is obscured by another window, raise the window.
	     */

#ifdef WSM
	    F_Raise (NULL, pCD, (XEvent *)NULL);
#else /* WSM */
	    F_Raise (NULL, pcdLeader, (XEvent *)NULL);
#endif /* WSM */
	}
	else if (CheckIfClientObscuringAny (pcdLeader) &&
	        !(wmGD.systemModalActive &&
	         (pcdLeader == wmGD.systemModalClient)))
	{
	    /*
             * The window is obscuring another window and is
             * not system modal, lower the window.
	     */

	    F_Lower (NULL, pcdLeader, (XEvent *)NULL);
#ifdef WSM
	    if ((pcdLeader->secondariesOnTop == False) &&
		(pCD->transientLeader != NULL) &&
		(!IS_APP_MODALIZED(pcdLeader)))
	    {
		/* Push transient below primary */
		(void) BumpPrimaryToTop (pcdLeader);
	        RestackTransients (pcdLeader);
	    }
#endif /* WSM */
	}
#ifdef WSM
        else if ((pcdLeader->secondariesOnTop == False) &&
		 (pcdLeader->transientChildren != NULL) &&
		 (!wmGD.systemModalActive) &&
		 (!IS_APP_MODALIZED(pcdLeader)))
	{
	    if (LeaderOnTop(pcdLeader))
	    {
		/* Push primary below transient */
		(void) BumpPrimaryToBottom (pcdLeader);
	        RestackTransients (pcdLeader);
	    }
	    else
	    {
		F_Raise (NULL, pCD, (XEvent *)NULL);
		/* Push transient below primary */
		(void) BumpPrimaryToTop (pcdLeader);
	        RestackTransients (pcdLeader);
	    }
	}
#endif /* WSM */
    }

    return (True);

} /* END OF FUNCTION F_Raise_Lower */



/*************************************<->*************************************
 *
 *  F_Refresh_Win (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for causing a client window
 *  to redisplay itself.
 *
 *************************************<->***********************************/

Boolean F_Refresh_Win (String args, ClientData *pCD, XEvent *event)
{
    Window win;
    unsigned int w, h;

    if (pCD && ((pCD->clientState == NORMAL_STATE) ||
		(pCD->clientState == MAXIMIZED_STATE)))
    {
        if (pCD->clientState == NORMAL_STATE)
	{
	    w = (unsigned int) pCD->clientWidth;
	    h = (unsigned int) pCD->clientHeight;
	}
	else
	{
	    w = (unsigned int) pCD->maxWidth;
	    h = (unsigned int) pCD->maxHeight;
	}

#ifdef WSM
        if (wmGD.refreshByClearing)
	{
	    RefreshByClearing (pCD->clientFrameWin);
	}
	else
	{
#endif /* WSM */
			 /* default background_pixmap is None */
        win = XCreateWindow (DISPLAY,
		         pCD->clientBaseWin,
		         pCD->matteWidth,
		         pCD->matteWidth,
		         w, h,
	                 0, 
	                 0,
	                 InputOutput,
                         CopyFromParent,
	                 0, 
			 (XSetWindowAttributes *)NULL);  

        XMapWindow (DISPLAY, win);
        XDestroyWindow (DISPLAY, win);
#ifdef WSM
	}
#endif /* WSM */
        XFlush (DISPLAY);
    }

    return (True);

} /* END OF FUNCTION F_Refresh_Win */



/*************************************<->*************************************
 *
 *  F_Set_Behavior (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This function is used to switch the window manager configuration between
 *  the built-in configuration (for CXI behavior) and the user's custom
 *  configuration.
 *
 *************************************<->***********************************/

Boolean F_Set_Behavior (String args, ClientData *pCD, XEvent *event)
{
    /*
     * Go system modal in starting to do the set behavior.
     */

    /* !!! grab the server and the pointer !!! */


    /*
     * Confirm that a set_behavior should be done.
     * Execute restart if so.
     */

    if (wmGD.showFeedback & WM_SHOW_FB_BEHAVIOR)
    {
	ConfirmAction (ACTIVE_PSD, (wmGD.useStandardBehavior) ?
		       CUSTOM_BEHAVIOR_ACTION : DEFAULT_BEHAVIOR_ACTION);
    }
    else
    {
	RestartWm ((long) ((wmGD.useStandardBehavior) ?
			MWM_INFO_STARTUP_CUSTOM : MWM_INFO_STARTUP_STANDARD));
    }
    return (False);

} /* END OF FUNCTION F_Set_Behavior */



/*************************************<->*************************************
 *
 *  Do_Set_Behavior (dummy)
 *
 *
 *  Description:
 *  -----------
 *  Callback to do the f.set_behavior function.
 *
 *************************************<->***********************************/

void Do_Set_Behavior (Boolean dummy)
{
    RestartWm ((long) ((wmGD.useStandardBehavior) ?
			MWM_INFO_STARTUP_CUSTOM : MWM_INFO_STARTUP_STANDARD));

} /* END OF FUNCTION Do_Set_Behavior */

#ifdef WSM

/*************************************<->*************************************
 *
 *  F_Set_Context (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This function is used to set a client context for subsequent
 *  WM_REQUESTs
 *
 *************************************<->***********************************/

Boolean F_Set_Context (String args, ClientData *pCD, XEvent *event)
{
 
    wmGD.requestContextWin = (Window) args;
    return (True);

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


/*************************************<->*************************************
 *
 *  F_Title (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is a placeholder function; it should never be called.
 *
 *************************************<->***********************************/

Boolean F_Title (String args, ClientData *pCD, XEvent *event)
{

    return (True);

} /* END OF FUNCTION F_Title */



/******************************<->*************************************
 *
 *  F_Screen (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function handler for warping to screens
 *
 *
 *  Inputs:
 *  ------
 *  args = (immediate value) window type flags
 *
 *  pCD = pointer to the client data
 *
 *  event = X event that invoked the function (key, button, or menu/NULL)
 *
 *  NOTE: May want to consider tracking changes in screen because in
 *	  managing a new window (ie. in ManageWindow()).
 *
 *  Outputs:
 *  -------
 *  RETURN = if True then further button binding/function processing can
 *           be done for the event that caused this function to be called.
 *
 *************************************<->***********************************/

Boolean F_Screen (String args, ClientData *pCD, XEvent *event)
{
    Window dumwin;
    int x, y, dumint;
    unsigned int dummask;
    WmScreenData *newscr = NULL;
    int scr, inc;
    static int PreviousScreen = -1;
    char pch[80];
    

    if (PreviousScreen == -1)
    {
	PreviousScreen = DefaultScreen(DISPLAY);
    }

    if (strcmp (args, "next") == 0)
    {
	scr = ACTIVE_PSD->screen + 1;
	inc = 1;
    }
    else if (strcmp (args, "prev") == 0)
    {
	scr = ACTIVE_PSD->screen - 1;
	inc = -1;
    }
    else if (strcmp (args, "back") == 0)
    {
	scr = PreviousScreen;
	inc = 0;
    }
    else
    {
	scr = atoi (args);
	inc = 0;
    }

    while (!newscr) {
					/* wrap around */
	if (scr < 0) 
	  scr = wmGD.numScreens - 1;
	else if (scr >= wmGD.numScreens)
	  scr = 0;

	newscr = &(wmGD.Screens[scr]);
	if (!wmGD.Screens[scr].managed) { /* make sure screen is managed */
	    if (inc) {			/* walk around the list */
		scr += inc;
		continue;
	    }
	    sprintf(pch, 
		    "Unable to warp to unmanaged screen %d\n", scr);
	    Warning (&pch[0]);
	    XBell (DISPLAY, 0);
	    return (False);
	}
    }

    if (ACTIVE_PSD->screen == scr) return (False);  /* already on that screen */

    PreviousScreen = ACTIVE_PSD->screen;
    XQueryPointer (DISPLAY, ACTIVE_ROOT, &dumwin, &dumwin, &x, &y,
		   &dumint, &dumint, &dummask);

    XWarpPointer (DISPLAY, None, newscr->rootWindow, 0, 0, 0, 0, x, y);

    if (newscr && (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT))
    {
	/*
	 * Set the ACTIVE_PSD to the new screen so that Do_Focus_Key can 
	 * uses the new screen instead of the old screen.  Then call
	 * Do_Focus_Key with a NULL pCD to find a reasonable client to
	 * set focus to.
	 */
	SetActiveScreen (newscr);
        Do_Focus_Key (NULL, GetFunctionTimestamp ((XButtonEvent *)event),
		      ALWAYS_SET_FOCUS);
    }

    return (False);
}



#if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
/*************************************<->*************************************
 *
 *  F_InvokeCommand (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager function for invoking client inserted menu
 *  commands.
 *
 *************************************<->***********************************/

Boolean F_InvokeCommand (String args, ClientData *pCD, XEvent *event)
{
    CARD32 commandID, clientWindow;
    Atom notifySelection;

    if (args == (String) NULL) return(FALSE);

    if (sscanf(args, "%d %d %ld", &commandID, &clientWindow,
	       &notifySelection) != 3)
      return(FALSE);

    SendInvokeMessage(commandID,
		      (pCD == (ClientData *) NULL ? 0 : pCD->client),
		      notifySelection,
		      LastTime());

    return (True);
} /* END OF FUNCTION F_InvokeCommand */
#endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */


/*************************************<->*************************************
 *
 *  GetFunctionTimestamp (pEvent)
 *
 *
 *  Description:
 *  -----------
 *  This function is used to extract a timestamp from a key or button event.
 *  If the event passed in is not a key or button event then a timestamp
 *  is generated.
 *
 *
 *  Inputs:
 *  ------
 *  event = pointer to an X event
 *
 *
 *  Outputs:
 *  -------
 *  RETURN = a timestamp
 *
 *************************************<->***********************************/

Time GetFunctionTimestamp (XButtonEvent *pEvent)
{
    Time time;

    if (pEvent &&
	(((pEvent->type == ButtonPress) || (pEvent->type == ButtonRelease)) ||
	 ((pEvent->type == KeyPress) || (pEvent->type == KeyRelease))))
    {
	time = pEvent->time;
    }
    else
    {
	time = GetTimestamp ();
    }

    return (time);

} /* END OF FUNCTION GetFunctionTimestamp */


/*
** name the event mask we need for a grab in order to find the matching 
** event for an event; right now handle only button-presses
*/
static unsigned int GetEventInverseMask(XEvent *event)
{
	if ((XEvent*)NULL == event)
		return 0;
	if (ButtonPress == event->type)
		return ButtonReleaseMask;	/* detail ? */
	/*
	expansion further here
	*/
	else 
		return 0;
}



/*************************************<->*************************************
 *
 *  ClearDirtyStackEntry (pCD)
 *
 *
 *  Description:
 *  -----------
 *  This function is used to clear the static dirtyStackEntry structure and
 *  the dirtyLeader static variable when a pCD is destroyed.  This 
 *  guarantees that freed memory will not be accessed.
 *
 *
 *  Inputs:
 *  ------
 *  pCD = pointer to clientData being freed
 *
 *
 *  Outputs:
 *  -------
 *  RETURN = void
 *
 *************************************<->***********************************/

void ClearDirtyStackEntry (ClientData *pCD)
{
  if (pCD == dirtyStackEntry)
    {
      dirtyStackEntry = NULL;
      dirtyLeader = NULL;
    }
}
#if defined(DEBUG) && defined(WSM)

/***********************<->*************************************
 *
 *  F_ZZ_Debug (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This is the window manager debug (multi) function
 *
 *
 *  Inputs:
 *  ------
 *  args = arguments
 *
 *  pCD = pointer to the ClientData for the whole front panel
 *
 *  event = X event that invoked the function (key, button, or menu/NULL)
 *
 *
 *  Outputs:
 *  -------
 *  RETURN = if True then further button binding/function processing can
 *           be done for the event that caused this function to be called.
 *
 *  Comments:
 *  -------
 *  Argument 1 determines the debug function to execute:
 *
 *  Valid arguments:
 *
 *      "color_server_info"  - dump out color server info
 *
 ******************************<->***********************************/

Boolean
F_ZZ_Debug (String subFcn, ClientData *pCD, XEvent *event)
{
    /* Only do something is sub function is specified */

    if (subFcn)
    {
	if (!(strcmp(subFcn, "dump_resources")))
	{
	    int scr;
	    char szRes[80];

	    for (scr=0; scr<wmGD.numScreens; scr++)
	    {
		sprintf (szRes, "/tmp/dtwm.resources.%d", scr);

		XrmPutFileDatabase(XtScreenDatabase(
				       XScreenOfDisplay(DISPLAY, scr)), 
				   szRes);
	    }
	}
    }
    return (True);
}
#endif /* DEBUG */

#ifdef WSM

/*************************************<->*************************************
 *
 *  F_Next_Workspace (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This function switches to the next workspace in the list
 *
 *************************************<->***********************************/

Boolean F_Next_Workspace (String args, ClientData *pCD, XEvent *event)
{
    WmScreenData *pSD = ACTIVE_PSD;
    int iwsx;

    for (iwsx = 0; iwsx < pSD->numWorkspaces; iwsx++)
    {
	if (pSD->pWS[iwsx].id == pSD->pActiveWS->id)
	{
	    iwsx++;
	    break;
	}
    }

    /* check bounds and wrap */
    if (iwsx >= pSD->numWorkspaces)
	iwsx = 0;

    ChangeToWorkspace (&pSD->pWS[iwsx]);


    return (False);

} /* END OF FUNCTION F_Next_Workspace */


/*************************************<->*************************************
 *
 *  F_Prev_Workspace (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This function switches to the previous workspace in the list
 *
 *************************************<->***********************************/

Boolean F_Prev_Workspace (String args, ClientData *pCD, XEvent *event)
{
    WmScreenData *pSD = ACTIVE_PSD;
    int iwsx;

    for (iwsx = 0; iwsx < pSD->numWorkspaces; iwsx++)
    {
	if (pSD->pWS[iwsx].id == pSD->pActiveWS->id)
	{
	    iwsx--;
	    break;
	}
    }

    /* check bounds and wrap */
    if (iwsx < 0)
	iwsx = pSD->numWorkspaces - 1;

    ChangeToWorkspace (&pSD->pWS[iwsx]);


    return (False);

} /* END OF FUNCTION F_Prev_Workspace */



/*************************************<->*************************************
 *
 *  F_Workspace_Presence (args, pCD, event)
 *
 *
 *  Description:
 *  -----------
 *  This function pops up the workspace presence dialog box
 *
 *************************************<->***********************************/

Boolean F_Workspace_Presence (String args, ClientData *pCD, XEvent *event)
{
    Context wsContext = (Context)NULL;

    if (pCD && (pCD->dtwmFunctions & DtWM_FUNCTION_OCCUPY_WS))
    {
	if (pCD->clientState == NORMAL_STATE)
	{
	    wsContext = F_CONTEXT_NORMAL;
	}
	else if (pCD->clientState == MAXIMIZED_STATE)
	{
	    wsContext = F_CONTEXT_MAXIMIZE;
	}
	else 
	{
	    wsContext = F_CONTEXT_ICON;
/*	    return (False); */
	}
	ShowPresenceBox (pCD, wsContext);
    }
    return (False);

} /* END OF FUNCTION F_Workspace_Presence */

#ifdef DEBUG
void
DumpWindowList ()
{
    WmScreenData *pSD = (ACTIVE_WS)->pSD;
    ClientListEntry 	*pCLE;

    fprintf (stdout, "Window stacking (bottom to top)\n");
    pCLE = pSD->lastClient;
    while (pCLE)
    {
	if (ClientInWorkspace (ACTIVE_WS, pCLE->pCD))
	    fprintf (stdout, "* ");
	else
	    fprintf (stdout, "  ");

	fprintf (stdout, "%08lx\t%s\n", 
	    pCLE->pCD->client,
	    pCLE->pCD->clientName);

	pCLE = pCLE->prevSibling;
    }
}
#endif /* DEBUG */

#endif /* WSM */



