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

/*
 * Included Files:
 */

#include "WmGlobal.h"
#include "WmResNames.h"
#ifdef WSM
#include "WmHelp.h"
#endif /* WSM */
#include "WmICCC.h"
#ifndef NO_OL_COMPAT
#include "WmOL.h"
#endif /* NO_OL_COMPAT */
#include <X11/Xos.h>
#include <X11/cursorfont.h>
#include <Xm/Xm.h>
#include <X11/Shell.h>
#include <X11/Core.h>
#include <X11/keysym.h>
#include <Xm/AtomMgr.h>
#include <Xm/DrawingA.h>

#ifdef WSM
#include <Dt/GetDispRes.h>
#include <Dt/SessionP.h>
#include <Dt/DtP.h>
#include <Dt/Message.h>
#include <Dt/WsmM.h>
#endif /* WSM */

#include <X11/Xlibint.h>
#include <X11/extensions/Xrandr.h>

/*
 * include extern functions
 */
#ifdef WSM
#include "WmBackdrop.h"
#endif /* WSM */
#include "WmCDInfo.h"
#include "WmColormap.h"
#include "WmError.h"
#include "WmEvent.h"
#include "WmFeedback.h"
#include "WmFunction.h"
#include "WmIDecor.h"
#ifdef WSM
#include "WmIPC.h"
#endif /* WSM */
#include "WmIPlace.h"
#include "WmIconBox.h"
#include "WmKeyFocus.h"
#include "WmManage.h"
#include "WmMenu.h"
#ifdef WSM
#include "WmPresence.h"
#endif /* WSM */
#include "WmProperty.h"
#include "WmResCvt.h"
#include "WmResource.h"
#include "WmSignal.h"
#include "WmProtocol.h"
#include "WmCDecor.h"
#include "stdio.h"
#include "WmResParse.h"
#ifdef WSM
#include <stdlib.h>
#endif /* WSM */
#include "WmXSMP.h"
#include "WmXmP.h"
#include "WmXinerama.h"
#include "WmEwmh.h"

/*
 * Function Declarations:
 */

#include "WmInitWs.h"

#if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
# include "WmWsmLib/wsm_proto.h"
# include "WmWsmLib/utm_send.h"
#endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */

#ifdef WSM
static void InsureDefaultBackdropDir(char **ppchBackdropDirs);
#endif /* WSM */
void InitWmDisplayEnv (void);
#ifndef NO_MESSAGE_CATALOG
void InitNlsStrings (void);
#endif

#ifdef WSM
/* limited to 3 chars max */
#define UNSPECIFIED_SCREEN_NAME		"fbk"
char        **dpy2Argv;    /* copy  for second display */
int           dpy2Argc;
WmScreenData *dtSD;       /* for the "DT screen" of the display */
#endif  /* WSM */
/*
 * Global Variables:
 */
extern int firstTime;
#ifndef NO_MESSAGE_CATALOG
extern char * pWarningStringFile;
extern char * pWarningStringLine;
#endif

/*
 * InitMouseBinding
 *
 * Special case for a two button mouse; move the BMENU binding 
 * from Button3 to Button2.  Fails for one-button mice.
 */
static void
InitMouseBinding(void)
{
    wmGD.numMouseButtons = XGetPointerMapping(DISPLAY, (unsigned char *)0, 0);
    
    if (wmGD.numMouseButtons < 3) {
        wmGD.bMenuButton = Button2;
    } else {
        wmGD.bMenuButton = Button3;
    }
}

/******************************<->*************************************
 *
 *  BuildLockMaskSequence ()
 *
 *  Set up the sequence of modifier masks to use to when grabbing 
 *  key- and button-bindings. This sequence of masks is NULL
 *  terminated.
 *
 *  Input:
 *  	wmGD.lockingModMask
 *
 *  Output:
 *	wmGD.pLockMaskSequence
 *
 *
 *************************************<->***********************************/
static void
BuildLockMaskSequence(void)
{
    int j, k;
    unsigned int mask;
    unsigned int thisbit;
    Boolean bit_on;
    int num_masks;
    int num_bits;
    int bit;
    int run;

    /*
     * Count the bits to determine the number of elements in 
     * the mask sequence.  The actual number of masks is
     * 2^<bitcount> - 1. We're not interested in the case
     * where there none of the mask bits are set.
     */
    mask = wmGD.lockingModMask;

    num_bits=0;
    while (mask)
    {
	if (mask & 0x1)
	{
	    num_bits++;
	}
	mask = mask >> 1;
    }
    num_masks = (0x1 << num_bits) - 1;

    /*
     * Allocate the space for the mask sequence + terminator.
     */
    wmGD.pLockMaskSequence = (unsigned int *) 
			XtCalloc (num_masks+1, sizeof (unsigned int));

    /*
     * Fill in the mask sequence
     */
    mask = wmGD.lockingModMask;
    thisbit = 0x1;
    bit = 0;
    while (mask && thisbit)
    {
	/* find next bit */
	while (!(thisbit & mask))
	{
	    thisbit = thisbit << 1;
	}

	/* clear it from mask */
	mask &= ~thisbit;

	bit++;

	/* 
	 * Set it in the appropriate slots in the
	 * mask sequence. The start of the loop is
	 * funny because we skip the case of all the
	 * bits cleared.
	 */
	run = (0x1 << (bit-1));	/* number of consecutive masks to set
				   bits in */
	bit_on = False;		/* are we setting bits or not? */

	for (j=0, k=run-1; j<num_masks; j++, k--)
	{
	    if (k < 1)
	    {
		if (bit_on)
		    bit_on = False;
		else
		    bit_on = True;

		k = run; 
	    }

	    if (bit_on) wmGD.pLockMaskSequence[j] |= thisbit;
	}
    }
}


/******************************<->*************************************
 *
 *  SetupLockingModifierMask ()
 *
 *  Set up the mask used to ignore locking modifier keys (e.g. Shift Lock)
 *  when processing key- and button-bindings.
 *
 *  We want to try to ignore the set of locking modifers 
 *  such as Shift Lock, Num Lock, Kana Lock, etc. This involves
 *  some amount of guessing since these things can be mapped
 *  onto any of the Mod1-Mod5 modifiers. The approach taken is to 
 *  identify the mapping of the locking modifier keysyms to
 *  Mod1-Mod5 and build the set of masks needed to ignore them.
 *
 *************************************<->***********************************/

/*
 * This is the set of locking modifiers keysyms that might be
 * bound to Mod1-Mod5. (Caps Lock is handled independently of
 * this set.)
 */
static KeySym pksLockingMods[] = {
    XK_Scroll_Lock,
    XK_Kana_Lock,
    XK_Num_Lock,
    XK_Mode_switch
};

#define NUM_LOCKING_MODS (sizeof(pksLockingMods)/sizeof(KeySym))

static void
SetupLockingModifierMask(void)
{
    int i, j, start_index;
    XModifierKeymap *modifier_map = NULL;
    static Modifiers mod_masks[] = { None, Mod1Mask, Mod2Mask,
                                        Mod3Mask, Mod4Mask, Mod5Mask };
    Display *dpy = wmGD.display;
    int pkcLockingMods[NUM_LOCKING_MODS];

    int kc;

    for (i=0; i<NUM_LOCKING_MODS; i++)
    {
	pkcLockingMods[i] = XKeysymToKeycode(dpy, pksLockingMods[i]);
    }

    /* 
     * Start out with Caps lock and add others we discover.
     */
    wmGD.lockingModMask = LockMask;

    modifier_map = XGetModifierMapping(dpy);

    /* just check Mod1 through Mod5 */
    start_index = modifier_map->max_keypermod * Mod1MapIndex;

    for (i = start_index; i < modifier_map->max_keypermod * 8; i++) {
        int this_mod = ((i - start_index) / modifier_map->max_keypermod) + 1;
 
        kc = modifier_map->modifiermap[i];
        if (kc)
	{
	    for (j=0; j<NUM_LOCKING_MODS; j++)
	    {
		if (pkcLockingMods[j] == kc)
		{
		    wmGD.lockingModMask |= mod_masks[this_mod];
		    break;
		}
	    }
	}
    }

    BuildLockMaskSequence();

    if(modifier_map != NULL)
	XFreeModifiermap(modifier_map);

}

/******************************<->*************************************
 *
 *  MappingEventHandler (Widget, XtPointer, XEvent *, Boolean *)
 *
 *  Catch and handle changes to the mapping of the modifier keys.
 *
 *************************************<->***********************************/

static void
MappingEventHandler(
        Widget w,
        XtPointer client_data,
        XEvent *event,
        Boolean *cont_to_dispatch)
{
        if(event->xany.type != MappingNotify ||
                event->xmapping.request == MappingPointer)
                return;
 
        if(event->xmapping.request == MappingModifier)
                SetupLockingModifierMask();
}


/******************************<->*************************************
 *
 *  InitWmGlobal (argc, argv, environ)
 *
 *
 *  Description:
 *  -----------
 *  This function initializes the workspace manager.
 *
 *
 *  Inputs:
 *  ------
 *  argc = number of command line arguments (+1)
 *
 *  argv = window manager command line arguments
 *
 *  environ = window manager environment
 *
 * 
 *  Outputs:
 *  -------
 *  wmGD = (initialize the global data structure)
 * 
 *************************************<->***********************************/

void InitWmGlobal (int argc, char *argv [], char *environ [])
{
    XSetWindowAttributes sAttributes;
    int scr;
    int managed = 0;
    char pch[80];
    Boolean activeSet = False;
    Boolean processedGlobalResources = False;
    WmScreenData *pSD;
    Arg args[20];
    int argnum;
    char *res_class;
    int savedArgc;

    wmGD.errorFlag = False;
#ifdef WSM
    dtSD = NULL; 
#endif  /* WSM */

    SetupWmSignalHandlers (0); /* dummy paramater */


    /*
     * Do (pre-toolkit) initialization:
     */

    wmGD.windowContextType = XUniqueContext ();
    wmGD.screenContextType = XUniqueContext ();
    wmGD.cmapWindowContextType = XUniqueContext ();

#ifdef WSM
    wmGD.mwmWindowContextType = XUniqueContext ();
#endif /* WSM */

    /* copy argv (the XtInititalize changes the original) for use in restart */
    savedArgc = argc;
    CopyArgv (argc, argv);

    wmGD.environ = environ;

#ifdef WSM
    wmGD.pWmPB = _DtWmParseNewBuf();
#endif /* WSM */



    /* set our name */
    if ((wmGD.mwmName = (char*)strrchr (wmGD.argv[0], '/')) != NULL)
    {
        wmGD.mwmName++;
    }
    else
    {
        wmGD.mwmName = wmGD.argv[0];
    }
#ifdef WSM
    if (MwmBehavior)
    {
	res_class = WM_RESOURCE_CLASS;
    }
    else 
    {
	res_class = DT_WM_RESOURCE_CLASS;
    }
    wmGD.statusColorServer = CSERVE_NOT_AVAILABLE;

#else /* WSM */
    res_class = WM_RESOURCE_CLASS;
#endif /* WSM */

    wmGD.display = (Display *)NULL;
    wmGD.topLevelW = (Widget)NULL;

    /*
     * Do X Tookit initialization:
     */   

    XtToolkitInitialize();
    wmGD.mwmAppContext = XtCreateApplicationContext();
    AddWmResourceConverters ();
	XtAppSetFallbackResources(wmGD.mwmAppContext, NULL);
    wmGD.display = XtOpenDisplay (wmGD.mwmAppContext,
				  NULL,
				  wmGD.mwmName,
				  res_class,
				  NULL,
				  0,
				  &argc, /* R5 changed from Cardinal to int*/
				  argv);
    
    if (!wmGD.display)
    {
	Warning(((char *)GETMESSAGE(40, 1, "Could not open display.")));
	ExitWM (WM_ERROR_EXIT_VALUE);
    }

    /*
     * Setup error handling:
     */

    WmInitErrorHandler(wmGD.display);

    /*
     * Initialize cursor size info and 
     * display the startup cursor.
     */
    
    InitCursorInfo ();
#ifdef WSM
    InitWmDisplayEnv ();
#endif
    ShowWaitState (TRUE);
	
    /*
     * Initialize support for BMenu virtual mouse binding
     */
    InitMouseBinding();
    /*
     * Set up the _MOTIF_BINDINGS property on the root window
     * of screen 0.  Must do this before we create shells.
     */
    
    ProcessMotifBindings ();
    
    argnum = 0;
    XtSetArg (args[argnum], XtNgeometry, NULL);	argnum++;
    XtSetArg (args[argnum], XtNx, 10000);	argnum++;
    XtSetArg (args[argnum], XtNy, 0);		argnum++;
    XtSetArg (args[argnum], XtNwidth, 10);	argnum++;
    XtSetArg (args[argnum], XtNheight, 10);	argnum++;
    XtSetArg (args[argnum], XtNmappedWhenManaged, False);	argnum++;
    XtSetArg (args[argnum], XtNjoinSession, True);		argnum++;
#ifdef WSM
    XtSetArg (args[argnum], XtNrestartStyle, SmRestartNever);	argnum++;
#else
    XtSetArg (args[argnum], XtNrestartStyle, SmRestartIfRunning); argnum++;
#endif
    XtSetArg (args[argnum], XtNargc, savedArgc); argnum++;
    XtSetArg (args[argnum], XtNargv, wmGD.argv); argnum++;

    /* create topmost shell (application shell) */
    wmGD.topLevelW = XtAppCreateShell (NULL, 
			      res_class,
			      sessionShellWidgetClass,
			      DISPLAY,
			      args,
			      argnum);

#ifdef __osf__
    _XmColorObjCreate ( wmGD.topLevelW, NULL, NULL);
    _XmColorObjCreate ( wmGD.topLevelW, NULL, NULL);
#endif

    XtAddEventHandler(wmGD.topLevelW, NoEventMask, True,
			MappingEventHandler, NULL);

    /* Add callbacks used for communication with Session Manager. */
    AddSMCallbacks ();

    /* allocate namespace for screens */
    InitScreenNames();
    
    /* 
     * Determine the screen management policy (all or none)
     * Process command line arguments that we handle 
     * This could change the number of screens we manage 
     */
    ProcessGlobalScreenResources ();
    ProcessCommandLine (argc, argv);

#ifdef WSM
    /*
     * Make sure backdrops are in our icon search path. 
     * This call MUST occur before ANY icons are looked up either
     * explicitly or through resource processing!!!
     * Uses variables set by ProcessGlobalScreenResources and
     * ProcessCommandLine.
     */
    {
	int sNum;
	Boolean         useMaskRtn;
	Boolean         useMultiColorIcons;
	Boolean         useIconFileCacheRtn;
	String		sBdPath;

	sNum = (wmGD.numScreens == 1) ? DefaultScreen(DISPLAY) : 0;

	XmeGetIconControlInfo(ScreenOfDisplay(DISPLAY, sNum), &useMaskRtn,
		    &useMultiColorIcons, &useIconFileCacheRtn);

        sBdPath = wmGD.backdropDirs;
	InsureDefaultBackdropDir ((char **) &sBdPath);

	_DtWsmSetBackdropSearchPath(XScreenOfDisplay(DISPLAY, sNum), 
			sBdPath, useMultiColorIcons);

        XtFree(sBdPath);
    }
#endif /* WSM */

    /*
     * Allocate data and initialize for screens we manage:
     */

    if (!(wmGD.Screens = (WmScreenData *) 
	    XtCalloc (wmGD.numScreens, sizeof(WmScreenData))))
    {
	ShowWaitState (FALSE);
	Warning (((char *)GETMESSAGE(40, 2, "Insufficient memory for Screen data")));
	ExitWM (WM_ERROR_EXIT_VALUE);
    }
    else 
    {

	sAttributes.event_mask = SubstructureRedirectMask;

	for (scr=0; scr<wmGD.numScreens; scr++) 
	{
	    int sNum;
	    
	    /* 
	     * Gain control of the root windows of each screen:
	     */

	    sNum = (wmGD.numScreens == 1) ? DefaultScreen(DISPLAY) : scr;
	    wmGD.errorFlag = False;

	    XChangeWindowAttributes (DISPLAY, RootWindow (DISPLAY, sNum), 
		CWEventMask, &sAttributes);
	    /*
	     * Do XSync to force server action and catch errors
	     * immediately.
	     */
	    XSync (DISPLAY, False /* do not discard events */);

	    if ((wmGD.errorFlag) &&
		(RootWindow (DISPLAY, sNum) == (Window) wmGD.errorResource) &&
		(wmGD.errorRequestCode == X_ChangeWindowAttributes))
	    {
		sprintf(pch, 
		    ((char *)GETMESSAGE(40, 3, "Another window manager is running on screen %d")), sNum);
		Warning ((char *) &pch[0]);
		wmGD.Screens[scr].managed = False;
	    }
	    else 
	    {
		if (!processedGlobalResources)
		{
#ifdef WSM
		    enum { 
		      XA_DT_SESSION_HINTS, XA_DT_SM_WM_PROTOCOL,
		      XA_DT_SM_START_ACK_WINDOWS, XA_DT_SM_STOP_ACK_WINDOWS,
		      XA_DT_WM_WINDOW_ACK, XA_DT_WM_EXIT_SESSION,
		      XA_DT_WM_LOCK_DISPLAY, XA_DT_WM_READY, NUM_ATOMS };
		    static char *atom_names[] = {
		      _XA_DT_SESSION_HINTS, _XA_DT_SM_WM_PROTOCOL,
		      _XA_DT_SM_START_ACK_WINDOWS, _XA_DT_SM_STOP_ACK_WINDOWS,
		      _XA_DT_WM_WINDOW_ACK, _XA_DT_WM_EXIT_SESSION,
		      _XA_DT_WM_LOCK_DISPLAY, _XA_DT_WM_READY };

		    Atom atoms[XtNumber(atom_names)];
		    XInternAtoms(DISPLAY, atom_names, XtNumber(atom_names), 
				 False, atoms);

		    wmGD.xa_DT_SESSION_HINTS = atoms[XA_DT_SESSION_HINTS];
		    wmGD.xa_DT_SM_WM_PROTOCOL = atoms[XA_DT_SM_WM_PROTOCOL];
		    wmGD.xa_DT_SM_START_ACK_WINDOWS =
		      atoms[XA_DT_SM_START_ACK_WINDOWS]; 
		    wmGD.xa_DT_SM_STOP_ACK_WINDOWS =
		      atoms[XA_DT_SM_STOP_ACK_WINDOWS]; 
		    wmGD.xa_DT_WM_WINDOW_ACK = atoms[XA_DT_WM_WINDOW_ACK];
		    wmGD.xa_DT_WM_EXIT_SESSION = atoms[XA_DT_WM_EXIT_SESSION];
                    wmGD.xa_DT_WM_LOCK_DISPLAY = atoms[XA_DT_WM_LOCK_DISPLAY];
                    wmGD.xa_DT_WM_READY = atoms[XA_DT_WM_READY];
#endif /* WSM */
#ifndef NO_OL_COMPAT
		    InitOLCompat();
#endif /* NO_OL_COMPAT */
#ifndef NO_SHAPE
		    wmGD.hasShape = XShapeQueryExtension (DISPLAY,
							  &wmGD.shapeEventBase,
							  &wmGD.shapeErrorBase);
#endif /*  NO_SHAPE  */

                    wmGD.replayEnterEvent = False;
		    wmGD.menuActive = NULL;
		    wmGD.menuUnpostKeySpec = NULL;
		    wmGD.F_NextKeySpec = NULL;
		    wmGD.F_PrevKeySpec = NULL;
		    wmGD.passKeysActive = False;
		    wmGD.passKeysKeySpec = NULL;
		    wmGD.checkHotspot = False;
		    wmGD.configAction = NO_ACTION;
		    wmGD.configPart = FRAME_NONE;
		    wmGD.configSet = False;
		    wmGD.preMove = False;
		    wmGD.gadgetClient = NULL;
		    wmGD.wmTimers = NULL;
		    wmGD.clientDefaultTitle = 
			XmStringCreateLocalized(DEFAULT_CLIENT_TITLE);
		    wmGD.iconDefaultTitle = 
			XmStringCreateLocalized(DEFAULT_ICON_TITLE);
		    wmGD.attributesWindow = (Window)NULL;
		    wmGD.clickData.pCD = NULL;
		    wmGD.clickData.clickPending = False;
		    wmGD.clickData.doubleClickPending = False;
		    wmGD.systemModalActive = False;
		    wmGD.activeIconTextDisplayed = False;
		    wmGD.movingIcon = False;
		    wmGD.queryScreen = True;
		    wmGD.dataType = GLOBAL_DATA_TYPE;

		    wmGD.pLockMaskSequence = NULL;
		    SetupLockingModifierMask ();
#ifdef WSM
		    wmGD.requestContextWin = (Window) 0L;
		    wmGD.cppCommand = NULL;
		    wmGD.evLastButton.button = 0;
		    wmGD.bReplayedButton = False;
		    wmGD.bSuspendSecondaryRestack = False;
		    /*
		     *  Get a second display connection for 
		     *  internal WM windows.
		     */
		    wmGD.display1 = XtOpenDisplay (wmGD.mwmAppContext,
						   NULL,
						   wmGD.mwmName,
						   res_class,
						   NULL,
						   0,
						   &dpy2Argc,
						   dpy2Argv);
		    if (!wmGD.display1)
		    {
			ShowWaitState (FALSE);
			Warning(((char *)GETMESSAGE(40, 4, "Could not open second display connection.")));
			ExitWM (WM_ERROR_EXIT_VALUE);
		    }

		    _DtGetSmWindow(DISPLAY, 
				  RootWindow(DISPLAY, 0), 
				  &wmGD.dtSmWindow) ;

		    /* create topmost shell (application shell) */
		    argnum = 0;
		    XtSetArg (args[argnum], XtNgeometry, NULL);	argnum++;
		    XtSetArg (args[argnum], XtNx, 10000);	argnum++;
		    XtSetArg (args[argnum], XtNy, 0);		argnum++;
		    XtSetArg (args[argnum], XtNwidth, 10);	argnum++;
		    XtSetArg (args[argnum], XtNheight, 10);	argnum++;
		    XtSetArg (args[argnum], 
				XtNmappedWhenManaged, False);	argnum++;

		    wmGD.topLevelW1 = 
			XtAppCreateShell (NULL, 
					  res_class,
					  applicationShellWidgetClass,
					  DISPLAY1,
					  args,
					  argnum);

#endif /* WSM */
		    

		    /* 
		     * if this is the first screen we can manage, 
		     * process global.
		     */
		    
		    processedGlobalResources = True;

		    /*
		     * Get the _MOTIF_WM_INFO property and determine 
		     * the startup / restart state.
		     */
		    
		    ProcessMotifWmInfo (RootWindow (DISPLAY, sNum));
		    
		    /*
		     * Process global window manager resources:
		     */
#ifndef NO_MESSAGE_CATALOG
    		    InitBuiltinSystemMenu();
#endif
		    
		    ProcessWmResources ();

		}
		
		InitWmScreen (&(wmGD.Screens[scr]), sNum);
		wmGD.Screens[scr].managed = True;
		managed++;
#ifdef WSM
		GetDtSessionHints(&(wmGD.Screens[scr]), sNum);
#endif /* WSM */

		if (!activeSet) 
		{
		    activeSet = True;
		    ACTIVE_PSD = &wmGD.Screens[scr];
		}
	    }
	}

	if (managed == 0) 
	{
	    /*
	     * No screens for me to manage, give up.
	     */
	    ShowWaitState (FALSE);
	    Warning (((char *)GETMESSAGE(40, 5, "Unable to manage any screens on display.")));
	    ExitWM (WM_ERROR_EXIT_VALUE);
	}
    }
#ifdef WSM
    /*  
     * Initialize the IPC mechanism
     */
    dtInitialize(argv[0], wmGD.mwmAppContext);
#ifndef NO_MESSAGE_CATALOG
    /*
     * Set up NLS error messages.
     * Must be done after DtInitialize.
     */
    InitNlsStrings ();
#endif

    /*
     *  For multiple connections to the server, turn off
     *  the geometry manager's insistence on synchronous
     *  management.
     */

    argnum = 0;
    XtSetArg (args[argnum], XmNuseAsyncGeometry, True);	argnum++;
    XtSetValues (wmGD.topLevelW, args, argnum);
    XtSetValues (wmGD.topLevelW1, args, argnum);

#endif /* WSM */
    

    /*
     * Prepare to have child processes (e.g., exec'ed commands).
     * The X connection should not be passed on to child processes
     * (it should be automatically closed when a fork is done).
     */

    if (fcntl (ConnectionNumber (DISPLAY), F_SETFD, 1) == -1)
    {
	ShowWaitState (FALSE);
	Warning (((char *)GETMESSAGE(40, 6, "Cannot configure X connection")));
	ExitWM (WM_ERROR_EXIT_VALUE);
    }

#ifdef WSM

    {
      enum { XA_DT_WORKSPACE_HINTS, XA_DT_WORKSPACE_PRESENCE,
	     XA_DT_WORKSPACE_INFO, XA_WmNall,
	     XA_DT_WORKSPACE_EMBEDDED_CLIENTS, XA_DT_WM_REQUEST,
	     XA_DT_WORKSPACE_LIST, XA_DT_WORKSPACE_CURRENT, NUM_ATOMS };
      static char *atom_names[] = {
	     _XA_DT_WORKSPACE_HINTS, _XA_DT_WORKSPACE_PRESENCE,
	     _XA_DT_WORKSPACE_INFO, WmNall,
	     _XA_DT_WORKSPACE_EMBEDDED_CLIENTS, _XA_DT_WM_REQUEST,
	     _XA_DT_WORKSPACE_LIST, _XA_DT_WORKSPACE_CURRENT };

      Atom atoms[XtNumber(atom_names)];
      XInternAtoms(DISPLAY, atom_names, XtNumber(atom_names), False, atoms);

      wmGD.xa_DT_WORKSPACE_HINTS = atoms[XA_DT_WORKSPACE_HINTS];
      wmGD.xa_DT_WORKSPACE_PRESENCE = atoms[XA_DT_WORKSPACE_PRESENCE];
      wmGD.xa_DT_WORKSPACE_INFO = atoms[XA_DT_WORKSPACE_INFO];
      wmGD.xa_ALL_WORKSPACES = atoms[XA_WmNall];
      wmGD.xa_DT_EMBEDDED_CLIENTS = atoms[XA_DT_WORKSPACE_EMBEDDED_CLIENTS];
      wmGD.xa_DT_WM_REQUEST = atoms[XA_DT_WM_REQUEST];
      wmGD.xa_DT_WORKSPACE_LIST = atoms[XA_DT_WORKSPACE_LIST];
      wmGD.xa_DT_WORKSPACE_CURRENT = atoms[XA_DT_WORKSPACE_CURRENT];
    }

#endif /* WSM */

    /* Initialize properties used in session management. */
    wmGD.xa_SM_CLIENT_ID =
      XmInternAtom (DISPLAY, _XA_DT_SM_CLIENT_ID, False);
    wmGD.xa_WMSAVE_HINT =
      XmInternAtom (DISPLAY, _XA_DT_WMSAVE_HINT, False);

    /* Load client resource database. */
    wmGD.clientResourceDB = LoadClientResourceDB();

    /*
     * Make the window manager workspace window.
     * Setup the _MOTIF_WM_INFO property on the root window.
     */

    SetupWmWorkspaceWindows ();


    /* make the cursors that the window manager uses */
    MakeWorkspaceCursors ();


    /* Sync the table used by Mwm's modifier parser to actual modMasks used */
    SyncModifierStrings();

    /*
     * Setup screen data and resources (after processing Wm resources.
     */
    for (scr = 0; scr < wmGD.numScreens; scr++)
    {
	pSD = &(wmGD.Screens[scr]);

	if (pSD->managed)
	{
#ifdef WSM
	    if (XDefaultScreen (wmGD.display) == pSD->screen)
	    {
		wmGD.commandWindow = wmGD.Screens[scr].wmWorkspaceWin;
	    }

#endif /* WSM */
	    /*
	     * Initialize workspace colormap data.
	     */

	    InitWorkspaceColormap (pSD);

	    /*
	     * Process the window manager resource description file (.mwmrc):
	     */

	    ProcessWmFile (pSD);

	    /*
	     * Setup default resources for the system menu and key bindings:
	     */

	    SetupDefaultResources (pSD);


	    /*
	     * Make global window manager facilities:
	     */

	    if(pSD->iconDecoration & ICON_ACTIVE_LABEL_PART)
	    {
		/* create active icon window */
		CreateActiveIconTextWindow(pSD); 
	    }


	    /*
	     * Make menus and other resources that are used by window manager
	     * functions that are activated by menus, buttons and keys.
	     */

	    MakeWmFunctionResources (pSD);
	}

#ifdef WSM
        /*
	 *
	 *  Set root cursor to be a pointer for dtwm
	 *
	 */

# ifdef __osf__
	/* Fixes problem on multiscreen where cursor is only
         * set on primary screen.
	 */
	if (DtwmBehavior)
	{
	    XDefineCursor (DISPLAY,
		RootWindow (DISPLAY, scr),
		wmGD.workspaceCursor);
	}
# endif
#endif /* WSM */

    }
#ifdef WSM
    /*
     * Point second display's resource data base
     * to the first display's resource data base
     * so dtwm "clients" change colors dynamically.
     *
     *  NEW LOCATION
     */
      wmGD.display1->db = wmGD.display->db;
#endif /*  WSM */

    /*
     * Realize the top level widget, make the window override
     * redirect so we don't manage it, and then move it out of the way
     */

    XtRealizeWidget (wmGD.topLevelW);
#ifdef WSM
    XtRealizeWidget (wmGD.topLevelW1);

    /*
     * Initialize the message handling.
     * (This must be done after the realize because a window
     *  is required for ICCCM-style messaging).
     */
    dtInitializeMessaging (wmGD.topLevelW);
#endif /* WSM */

    sAttributes.override_redirect = True;
    XChangeWindowAttributes (DISPLAY, XtWindow (wmGD.topLevelW),
		CWOverrideRedirect, &sAttributes);
	
	/* Check for Xinerama support and initialize session data */
	SetupXinerama();

    /* setup window manager inter-client communications conventions handling */
    SetupWmICCC ();

    /* Initialize EWMH support */
    SetupWmEwmh();
	
	/* Initialize Xrandr and set up for screen change notifications */
	if(XRRQueryExtension(DISPLAY,&wmGD.xrandr_base_evt,&wmGD.xrandr_base_err)){
		wmGD.xrandr_present = True;
		XRRSelectInput(DISPLAY,XtWindow(wmGD.topLevelW),
			RRScreenChangeNotifyMask);
	} else {
		wmGD.xrandr_present = False;
	}
	
    /*
     * Use the WM_SAVE_YOURSELF protocol
     * for notification of when to save ourself
     */
#ifdef WSM
    SetMwmSaveSessionInfo(wmGD.commandWindow);
#endif
    /*
     * Initialize window manager event handling:
     */

    InitEventHandling ();



    /*
     * Initialize frame component graphics
     */
    {
	for (scr = 0; scr < wmGD.numScreens; scr++)
	{
	    pSD = &(wmGD.Screens[scr]);

	    if (pSD->managed)
	    {
		InitClientDecoration (pSD);

		/*
		 * Make an icon box if specificed:
		 */
		if (pSD->useIconBox)
		{
		    InitIconBox (pSD);
		}

		/*
		 * Adopt client windows that exist before wm startup:
		 */

		AdoptInitialClients (pSD);

		/*
		 * Setup initial keyboard focus and colormap focus:
		 */

		InitColormapFocus (pSD);

	    }
	}

        for (scr = 0; scr < wmGD.numScreens; scr++)
        {
#ifdef WSM
	    int iws;
#endif /* WSM */
            pSD = &(wmGD.Screens[scr]);
	    
            if (pSD->managed)
            {
                ACTIVE_PSD = &wmGD.Screens[scr];
#ifdef WSM
                MapIconBoxes (pSD->pActiveWS);

		ChangeBackdrop (pSD->pActiveWS);

#ifdef HP_VUE
		UpdateWorkspaceInfoProperty (pSD); /* backward compatible */
#endif /* HP_VUE */

		SetCurrentWorkspaceProperty (pSD);
		SetWorkspaceListProperty (pSD);

		for (iws=0; iws < pSD->numWorkspaces; iws++)
		{
		    SetWorkspaceInfoProperty (&(pSD->pWS[iws]));
		}


		XFlush (DISPLAY);
		
		RestoreHelpDialogs(pSD);
#else /* WSM */
                MapIconBoxes (pSD->pActiveWS);
#endif /* WSM */
            }
        }
        firstTime = 0;
    }
    
    InitKeyboardFocus ();

#ifndef WSM
    InitWmDisplayEnv ();
#endif
    ShowWaitState (FALSE);

#ifdef WSM
    /*
     * Tell the rest of DT that we're up
     */
    dtReadyNotification();
#endif /* WSM */

#ifdef DEBUG_RESOURCE_DATABASE
    XrmPutFileDatabase(wmGD.display->db, "/tmp/dtwm.resDB");
#endif /* DEBUG_RESOURCE_DATABASE */

} /* END OF FUNCTION InitWmGlobal */



/******************************<->*************************************
 *
 *  InitWmScreen
 *
 *
 *  Description:
 *  -----------
 *  This function initializes a screen data block.
 *
 *  Inputs:
 *  -------
 *  pSD = pointer to preallocated screen data block
 *  sNum = screen number for this screen
 *
 *  Outputs:
 *  -------
 *************************************<->***********************************/

void
InitWmScreen (WmScreenData *pSD, int sNum)
{
    Arg args[12];
    int argnum;

#ifdef WSM
    int wsnum;
    WmWorkspaceData *pwsI;
    int buf_size;
    int i;
    static int dupnum = 0;
    int iwsx;
#endif /* WSM */

    char *pDisplayName;
#define LENCBUFFER 256
    char buffer[LENCBUFFER];		/* screen name & display name! */
    char displayName[LENCBUFFER];
    char *token1, *token2;


   /*
    * Set screen data values
    */

    pSD->rootWindow = RootWindow (DISPLAY, sNum);
    pSD->clientCounter = 0;
    pSD->defaultSystemMenuUseBuiltin = TRUE;
    pSD->displayString = NULL;
    pSD->acceleratorMenuCount = 0;
    pSD->activeIconTextWin = (Window)NULL;
    pSD->focusPriority = 0;
    pSD->inputScreenWindow = (Window)NULL;
    pSD->colormapFocus = NULL;
    pSD->keySpecs = NULL;
    pSD->screen = sNum;
    pSD->confirmboxW[DEFAULT_BEHAVIOR_ACTION] = NULL;
    pSD->confirmboxW[CUSTOM_BEHAVIOR_ACTION] = NULL;
    pSD->confirmboxW[RESTART_ACTION] = NULL;
    pSD->confirmboxW[QUIT_MWM_ACTION] = NULL;
    pSD->feedbackWin = (Window)NULL;
    pSD->fbStyle = FB_OFF;
    pSD->fbWinWidth = 0;
    pSD->fbWinHeight = 0;
    pSD->fbLocation = NULL;
    pSD->fbSize = NULL;
    pSD->fbLocX = 0;
    pSD->fbLocY = 0;
    pSD->fbSizeX = 0;
    pSD->fbSizeY = 0;
    pSD->fbLastX = -1;
    pSD->fbLastY = -1;
    pSD->fbLastWidth = -1;
    pSD->fbLastHeight = -1;
    pSD->fbTop = NULL;
    pSD->fbBottom = NULL;
    pSD->actionNbr = -1;
    pSD->clientList = NULL;
    pSD->lastClient = NULL;
    pSD->lastInstalledColormap = (Colormap)NULL;
    pSD->shrinkWrapGC = NULL;
    pSD->bitmapCache = NULL;
    pSD->bitmapCacheSize = 0;
    pSD->bitmapCacheCount = 0;
    pSD->dataType = SCREEN_DATA_TYPE;
    pSD->managed = False;
#if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
    pSD->cciTree = NULL;
#endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */

#ifdef WSM
    pSD->initialWorkspace=NULL;
    pSD->presence.shellW = NULL;
    pSD->presence.onScreen = False;
    pSD->presence.userDismissed = True;
    pSD->workspaceList = NULL;
    pSD->numWorkspaces = 0;
    pSD->numWsDataAllocated = 0;
    pSD->lastBackdropWin = NULL;
    pSD->pDtSessionItems = NULL;
    pSD->totalSessionItems = 0;
    pSD->remainingSessionItems = 0;

    pSD->cachedHelp = NULL;
    pSD->dtHelp.shell  = (Widget)NULL;
    pSD->dtHelp.dialog = (Widget)NULL;
    pSD->dtHelp.errorDialog = (Widget)NULL;
    pSD->dtHelp.xPos = 0;
    pSD->dtHelp.yPos = 0;
    pSD->dtHelp.restored = False;
    pSD->dtHelp.onScreen = False;
    pSD->dtHelp.userDismissed = False;
    pSD->dtHelp.pCDforClient= NULL;
    pSD->helpResources=NULL;
    pSD->bMarqueeSelectionInitialized = False;
    pSD->woN = (Window) 0L;
    pSD->woS = (Window) 0L;
    pSD->woE = (Window) 0L;
    pSD->woW = (Window) 0L;
    pSD->displayResolutionType = _DtGetDisplayResolution(DISPLAY, sNum);

    /*
     *  We've got display resolution type--now, let's get color
     *  characteristics.
     */

    ProcessWmColors (pSD);

    if (!(strcmp ((char *)wmGD.screenNames[sNum], UNSPECIFIED_SCREEN_NAME)))
    {
	sprintf (buffer, "%d", sNum);

	buf_size = strlen(buffer) + 1;

	if ((wmGD.screenNames[sNum] = 
	     (unsigned char *)XtRealloc (wmGD.screenNames[sNum], buf_size)) == NULL)
	{
	    Warning (((char *)GETMESSAGE(40, 7, "Cannot create enough memory for the screen names")));
	    ExitWM (WM_ERROR_EXIT_VALUE);
	}
	else
	{
	    strcpy((char *)wmGD.screenNames[sNum], buffer);
	}
    } /* if wmGD.screenNames[sNum] == UNSPECIFIED_SCREEN_NAME */

#endif /* WSM */
    /*
     * Save screen context
     */
    XSaveContext (DISPLAY, pSD->rootWindow, wmGD.screenContextType,
	(caddr_t)pSD);
    /*
     * Create shell widget for screen resource hierarchy
     */

    argnum = 0;
    XtSetArg (args[argnum], XtNgeometry, NULL);	argnum++;
    XtSetArg (args[argnum], XtNx, 10000);	argnum++;
    XtSetArg (args[argnum], XtNy, 10000);	argnum++;
    XtSetArg (args[argnum], XtNwidth, 10);	argnum++;
    XtSetArg (args[argnum], XtNheight, 10);	argnum++;
    XtSetArg (args[argnum], XtNoverrideRedirect, True);	argnum++;

    XtSetArg (args[argnum], XtNdepth, 
	    DefaultDepth(DISPLAY, sNum));	argnum++;
    XtSetArg (args[argnum], XtNscreen, 
	    ScreenOfDisplay(DISPLAY, sNum)); 	argnum++;
    XtSetArg (args[argnum], XtNcolormap, 
	    DefaultColormap(DISPLAY, sNum)); 	argnum++;
    XtSetArg (args[argnum], XtNvisual, 
	    DefaultVisual(DISPLAY, sNum)); 	argnum++;

    pSD->screenTopLevelW = XtCreatePopupShell ((String) wmGD.screenNames[sNum],
					       vendorShellWidgetClass,
					       wmGD.topLevelW,
					       args,
					       argnum);

#if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
    /* Create a DrawingArea as a child of the popupShell.  This will be used
     * to handle UTM traffic relating to cci.  We need this
     * particular widget to get the callbacks from conversion requests made
     * against Mwm and the requests Mwm makes against other clients.
     */
    pSD->utmShell = XmCreateDrawingArea(pSD->screenTopLevelW, "UTM_Shell",
					NULL, 0);
    XtManageChild(pSD->utmShell);

    /*
     * Setup the destinationCallback handler to handle conversion
     * requests made by Mwm against other clients.
     */
    XtAddCallback(pSD->utmShell, XmNdestinationCallback, UTMDestinationProc,
		  NULL);

    /* Must realize to own WM_i if unmapped, causes mwm to
       freeze when menu is displayed. */
    XtPopup(pSD->screenTopLevelW, XtGrabNone);
#endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */

#ifdef WSM
    argnum = 0;
    XtSetArg (args[argnum], XtNgeometry, NULL);			argnum++;
    XtSetArg (args[argnum], XtNx, 10000);			argnum++;
    XtSetArg (args[argnum], XtNy, 10000);			argnum++;
    XtSetArg (args[argnum], XtNwidth, 10);			argnum++;
    XtSetArg (args[argnum], XtNheight, 10);			argnum++;
    XtSetArg (args[argnum], XtNoverrideRedirect, True);		argnum++;
    XtSetArg (args[argnum], XtNmappedWhenManaged, False);	argnum++;

    XtSetArg (args[argnum], XtNdepth, 
	    DefaultDepth(DISPLAY1, sNum));	argnum++;
    XtSetArg (args[argnum], XtNscreen, 
	    ScreenOfDisplay(DISPLAY1, sNum)); 	argnum++;
    XtSetArg (args[argnum], XtNcolormap, 
	    DefaultColormap(DISPLAY1, sNum)); 	argnum++;

    pSD->screenTopLevelW1 = XtCreatePopupShell ((String) wmGD.screenNames[sNum],
					       vendorShellWidgetClass,
					       wmGD.topLevelW1,
					       args,
					       argnum);
    XtRealizeWidget (pSD->screenTopLevelW1);
#endif /* WSM */
    /*
     * Fetch screen based resources
     */
    ProcessScreenResources (pSD, wmGD.screenNames[sNum]);

    /*
     * Initialize other screen resources and parameters
     */
    MakeXorGC (pSD);
    InitIconSize(pSD);

#ifdef WSM
    /*
     *  Complete initialization of workspace structures
     */
    for (wsnum = 0, 
	 pwsI = pSD->pWS; wsnum < pSD->numWorkspaces; 
	 wsnum++, pwsI++)
    {
	/*
	 * Set up workspace for this screen
	 */
	InitWmWorkspace (pwsI, pSD);

    }

    if (pSD->initialWorkspace)
    {
	/* 
	 * restore to the last initialWorkspace saved from
	 * Quit, Restart, OR save session 
	 */

	/*
	 * Compare initialWorkspace against workspace name,
	 * NOT workspace title.
	 */
	for (iwsx = 0; iwsx < pSD->numWorkspaces; iwsx++)
	{
	    if (!strcmp(pSD->pWS[iwsx].name, pSD->initialWorkspace))
	    {
		break;
	    }
	}
	/* check bounds */
	if (iwsx >= pSD->numWorkspaces)
	{
	    /* make first workspace in list the active one to start with */
	    pSD->pActiveWS = pSD->pWS;
	}
	else
	{
	    pSD->pActiveWS = &pSD->pWS[iwsx];
	}
    }
    else
    {
	/* make first workspace in list the active one to start with */
	pSD->pActiveWS = pSD->pWS;
    }
#else /* WSM */
    /*
     *  Allocate and initialize a workspace structure
     */
    
    if (!(pSD->pWS = (WmWorkspaceData *) XtMalloc (sizeof(WmWorkspaceData))))
    {
	ShowWaitState (FALSE);
	Warning (((char *)GETMESSAGE(40, 8, "Insufficient memory for Workspace data")));
	ExitWM (WM_ERROR_EXIT_VALUE);
    }

    /*
     * Set up workspace for this screen
     */
    InitWmWorkspace (pSD->pWS, pSD);
    pSD->pActiveWS = pSD->pWS;
#endif /* WSM */


    pDisplayName = DisplayString (DISPLAY);

    /*
     * Construct displayString for this string.  
     *
     * NOTE: The variable buffer is reused here. It was
     * used earlier to generate a screen name.
     */

    strcpy(displayName, pDisplayName);

    token1 = (char*)strtok(displayName, ":");		/* parse of hostname */

    if((token2 = (char*)strtok(NULL, ".")) ||		/* parse off dpy & scr # */
       (token2 = (char*)strtok(NULL, "")) ||
       (displayName[0] == ':'))
    {
	if (displayName[0] == ':')		/* local dpy (special case) */
	{
	    if ((token2 = (char*)strtok(token1, ".")) != NULL)	/* parse dpy# */
		sprintf(buffer, "DISPLAY=:%s.%d",
			token2,	sNum);
	} else {				/* otherwise process normally */
	    sprintf(buffer, "DISPLAY=%s:%s.%d",
		    token1, token2, sNum);
	}

	/*		
	 * Allocate space for the display string
	 */
    
	if ((pSD->displayString =
	     (String)XtMalloc ((unsigned int) (strlen(buffer) + 1))) == NULL)
	{
	    Warning (((char *)GETMESSAGE(40, 9, 
				    "Insufficient memory for displayString")));
	}
	else
	{
	    strcpy(pSD->displayString, buffer);
	}

    }



} /* END OF FUNCTION  InitWmScreen */


/*************************************<->*************************************
 *
 *  InitWmWorkspace
 *
 *
 *  Description:
 *  -----------
 *  This function initializes a workspace data block.
 *
 *  Inputs:
 *  -------
 *  pWS = pointer to preallocated workspace data block
 *  pSD = ptr to parent screen data block
 *
 *  Outputs:
 *  -------
 *************************************<->***********************************/

void InitWmWorkspace (WmWorkspaceData *pWS, WmScreenData *pSD)
{
    Arg args[10];
    int argnum;

#ifndef WSM
#define DEFAULT_WS_NAME "workspace"
#endif /* not WSM */

    pWS->pSD = pSD;
    pWS->pIconBox = NULL;
    pWS->dataType = WORKSPACE_DATA_TYPE;
#ifdef WSM
    pWS->backdrop.window = 0;
    pWS->backdrop.nameAtom = 0;
    pWS->backdrop.image = NULL;
    pWS->numClients = 0;
    pWS->sizeClientList = 0;
    pWS->ppClients = 0;
    pWS->buttonW = NULL;
#else /* WSM */

    if ((pWS->name = (char *) 
	    XtMalloc ((1+strlen(DEFAULT_WS_NAME)) * sizeof (char))) == NULL)
    {
	ShowWaitState (FALSE);
	ExitWM (WM_ERROR_EXIT_VALUE);
    }
    strcpy (pWS->name, DEFAULT_WS_NAME);
#endif /* WSM */

    /*
     * Create widget for workspace resource hierarchy
     */
    argnum = 0;
    XtSetArg (args[argnum], XtNdepth, 
	    DefaultDepth(DISPLAY, pSD->screen));	argnum++;
    XtSetArg (args[argnum], XtNscreen, 
	    ScreenOfDisplay(DISPLAY, pSD->screen)); 	argnum++;
    XtSetArg (args[argnum], XtNcolormap, 
	    DefaultColormap(DISPLAY, pSD->screen)); 	argnum++;
    XtSetArg (args[argnum], XtNwidth,  5);		argnum++;
    XtSetArg (args[argnum], XtNheight,  5);		argnum++;

    pWS->workspaceTopLevelW = XtCreateWidget (	pWS->name,
						xmPrimitiveWidgetClass,
    						pSD->screenTopLevelW,
					   	args,
						argnum);

#ifdef WSM
    /* internalize the workspace name */
    pWS->id = XInternAtom (DISPLAY, pWS->name, False);
#endif /* WSM */

    /*
     * Process workspace based resources
     */
    ProcessWorkspaceResources (pWS);	

    /* setup icon placement */
    if (wmGD.iconAutoPlace)
    {
	InitIconPlacement (pWS); 
    }

} /* END OF FUNCTION  InitWmWorkspace */

#ifdef WSM

/******************************<->*************************************
 *
 *  InsureDefaultBackdropDir(char **ppchBackdropDirs)
 *
 *
 *  Description:
 *  -----------
 *  This function checks and edits a directory path to insure
 *  that the system backdrop directroy (/usr/dt/backdrops) is in the 
 *  path. If not it adds it to the end. Further, it always adds the user's 
 *  backdrop directory ($HOME/.dt/backdrops) to the beginning of the path 
 *  and the system admin directory (/etc/dt/backdrops) before the system
 *  directory.
 *
 *  Inputs:
 *  -------
 *  ppchBackdropDirs  - Pointer to a pointer to a directory path 
 *			(must be allocated memory)
 *
 *  Outputs:
 *  -------
 *  *ppchBackdropDirs - Directory path may be modified, path 
 *			pointer may be realloc'ed.
 * 
 *  Comments:
 *  --------
 *  Assumes that the default directory does not start with a
 *  multi-byte character.
 * 
 ******************************<->***********************************/
static void
InsureDefaultBackdropDir(char **ppchBackdropDirs)
{
  int len;
  Boolean bFound = False;
  char *pch, *pchEnd, *pch2, *tmpptr;
  char *pchD = DEFAULT_BACKDROP_DIR;
  unsigned int chlen;
  char * homeDir;

  /*
   * Set up initial stuff
   */
  pch = *ppchBackdropDirs;
  len = strlen (pchD);
  pchEnd = pch + strlen(pch);
  
  while (!bFound && (pch != NULL) && (*pch != NULL))
    {
      if (strncmp (pch, pchD, len) == 0)
	{
	  /* found partial match, confirm complete match ...
	   * complete match if char off end of partial match
	   * is a NULL or a colon 
	   */
	  pch2 = pch + len;	
	  if ((pch2 <= pchEnd) &&
	      ((*pch2 == NULL) ||
	       (((mblen (pch2, MB_CUR_MAX) == 1) &&
		 (*pch2 == ':')))))
	    {
	      bFound = True;
	    }
	}
      else 
	{
	  /* find next path component */
	  pch = strchr (pch, (int) ':'); 
	  if ((pch != NULL) && (*pch != NULL))
	    { 
	      /* skip path separator */
	      chlen = mblen (pch, MB_CUR_MAX);
	      pch += chlen;
	    }
	}
    }
  

  /*
   * Always add the user's home directory to the beginning of the string
   */
  homeDir = (char *) XmeGetHomeDirName();  
    
  /*
   * If found add the user's home directory ($HOME/.dt/backdrops) and the 
   * admin directory /etc/dt/backdrops to the beginning of the string
   */
  
  if (bFound)  
    {
      len = strlen (homeDir) + strlen("/.dt/backdrops") + 
	    strlen (*ppchBackdropDirs) + strlen("/etc/dt/backdrops") + 3;
      tmpptr = XtMalloc (len * sizeof (char *));
      strcpy (tmpptr, homeDir);
      strcat (tmpptr, "/.dt/backdrops");
      strcat (tmpptr, ":");
      strcat (tmpptr, "/etc/dt/backdrops");
      strcat (tmpptr, ":");
      strcat (tmpptr, *ppchBackdropDirs);
      *ppchBackdropDirs = tmpptr;
    }
  else
    /*
     * If string not found, then add home directory to the beginning of 
     * string and the admin directory and system directory to the end.
     */
    {
      len = strlen (homeDir) + strlen("/.dt/backdrops") + 
	    strlen (*ppchBackdropDirs) + strlen(pchD) + 
	    strlen("/etc/dt/backdrops") + 4;
      tmpptr = XtMalloc (len * sizeof (char *));
      strcpy (tmpptr, homeDir);
      strcat (tmpptr, "/.dt/backdrops");
      strcat (tmpptr, ":");
      strcat (tmpptr, *ppchBackdropDirs); 
      strcat (tmpptr, ":");
      strcat (tmpptr, "/etc/dt/backdrops"); 
      strcat (tmpptr, ":");
      strcat (tmpptr, pchD);
      *ppchBackdropDirs = tmpptr;
    }
  
} /* END OF FUNCTION InsureDefaultBackdropDirs */
#endif /* WSM */


/*************************************<->*************************************
 *
 *  ProcessMotifWmInfo (rootWindowOfScreen)
 *
 *
 *  Description:
 *  -----------
 *  This function is used retrieve and save the information in the 
 *  _MOTIF_WM_INFO property.  If the property does not exist then
 *  the start / restart state is set to initial startup with the
 *  user specified (not standard) configuration.
 *
 *
 *  Outputs:
 *  -------
 *  wmGD.useStandardBehavior = True if set indicated in property
 *
 *  wmGD.wmRestarted = True if the window manager was restarted
 * 
 *************************************<->***********************************/

void ProcessMotifWmInfo (Window rootWindowOfScreen)
{
    MwmInfo *pMwmInfo;

    wmGD.xa_MWM_INFO = XInternAtom (DISPLAY, _XA_MWM_INFO, False);
    if ((pMwmInfo = (MotifWmInfo *)GetMwmInfo (rootWindowOfScreen)) != NULL)
    {
	wmGD.useStandardBehavior =
		(pMwmInfo->flags & MWM_INFO_STARTUP_STANDARD) ? True : False;
	wmGD.wmRestarted = True;
	XFree ((char *)pMwmInfo);
    }
    else
    {
	wmGD.useStandardBehavior = False;
	wmGD.wmRestarted = False;
    }

} /* END OF FUNCTION ProcessMotifWmInfo */



/*************************************<->*************************************
 *
 *  SetupWmWorkspaceWindows ()
 *
 *
 *  Description:
 *  -----------
 *  This function is used to setup a window that can be used in doing window
 *  management functions.  This window is not visible on the screen.
 *
 *
 *  Outputs:
 *  -------
 *  pSD->wmWorkspaceWin = window that is used to hold wm properties
 * 
 *************************************<->***********************************/

void SetupWmWorkspaceWindows (void)
{
    int scr;
    WmScreenData *pSD;
    XSetWindowAttributes sAttributes;

    for (scr = 0; scr < wmGD.numScreens; scr++)
    {
	pSD = &(wmGD.Screens[scr]);
	if (pSD->managed)
	{
	    sAttributes.override_redirect = True;
	    sAttributes.event_mask = FocusChangeMask | PropertyChangeMask;
	    pSD->wmWorkspaceWin = XCreateWindow (DISPLAY, pSD->rootWindow, 
				      -100, -100, 10, 10, 0, 0, 
				      InputOnly, CopyFromParent,
				      (CWOverrideRedirect |CWEventMask),
				      &sAttributes);

	    XMapWindow (DISPLAY, pSD->wmWorkspaceWin);

	    SetMwmInfo (pSD->rootWindow, 
			(long) ((wmGD.useStandardBehavior) ?
                        MWM_INFO_STARTUP_STANDARD : MWM_INFO_STARTUP_CUSTOM), 
			pSD->wmWorkspaceWin);
#ifdef WSM
	    XSaveContext (DISPLAY, pSD->wmWorkspaceWin, 
		    wmGD.mwmWindowContextType, (caddr_t)pSD);
#endif /* WSM */
	}
    }

} /* END OF FUNCTION SetupWmWorkspaceWindow */



/*************************************<->*************************************
 *
 *  MakeWorkspaceCursors ()
 *
 *
 *  Description:
 *  -----------
 *  This function makes the cursors that the window manager uses.
 *
 *
 *  Inputs:
 *  ------
 *  XXinput = ...
 *
 *  XXinput = ...
 *
 * 
 *  Outputs:
 *  -------
 *  wmGD = (stretchCursors ...)
 * 
 *************************************<->***********************************/

void MakeWorkspaceCursors (void)
{
    wmGD.workspaceCursor = XCreateFontCursor (DISPLAY, XC_left_ptr);

    wmGD.stretchCursors[STRETCH_NORTH_WEST] =
	XCreateFontCursor (DISPLAY, XC_top_left_corner);
    wmGD.stretchCursors[STRETCH_NORTH] =
	XCreateFontCursor (DISPLAY, XC_top_side);
    wmGD.stretchCursors[STRETCH_NORTH_EAST] =
	XCreateFontCursor (DISPLAY, XC_top_right_corner);
    wmGD.stretchCursors[STRETCH_EAST] =
	XCreateFontCursor (DISPLAY, XC_right_side);
    wmGD.stretchCursors[STRETCH_SOUTH_EAST] =
	XCreateFontCursor (DISPLAY, XC_bottom_right_corner);
    wmGD.stretchCursors[STRETCH_SOUTH] =
	XCreateFontCursor (DISPLAY, XC_bottom_side);
    wmGD.stretchCursors[STRETCH_SOUTH_WEST] =
	XCreateFontCursor (DISPLAY, XC_bottom_left_corner);
    wmGD.stretchCursors[STRETCH_WEST] =
	XCreateFontCursor (DISPLAY, XC_left_side);

    wmGD.configCursor = XCreateFontCursor (DISPLAY, XC_fleur);

    wmGD.movePlacementCursor = XCreateFontCursor (DISPLAY, XC_ul_angle);
    wmGD.sizePlacementCursor = XCreateFontCursor (DISPLAY, XC_lr_angle);


} /* END OF FUNCTION MakeWorkspaceCursors */



/*************************************<->*************************************
 *
 *  MakeWmFunctionResources (pSD)
 *
 *
 *  Description:
 *  -----------
 *  This function makes menus and other resources that are used by window
 *  manager functions.
 *
 *
 *  Inputs:
 *  ------
 *  wmGD  = (menuSpecs, keySpecs, buttonSpecs)
 *
 * 
 *  Outputs:
 *  -------
 *  wmGD (menuSpecs) = new menu panes, protocol atoms
 *
 *************************************<->***********************************/

void MakeWmFunctionResources (WmScreenData *pSD)
{
    ButtonSpec *buttonSpec;
    KeySpec    *keySpec;
    MenuSpec   *menuSpec;
    Context     menuContext;


    /*
     * Scan through the menu specifications and make wm protocol atoms.
     */


    /*
     * Scan through the button binding specifications making menus if the
     * f.menu function is invoked.
     */

    buttonSpec = pSD->buttonSpecs;
    while (buttonSpec)
    {
	if (buttonSpec->wmFunction == F_Menu)
	{
	    if (buttonSpec->context & F_CONTEXT_WINDOW)
	    {
		menuContext = F_CONTEXT_WINDOW;
	    }
	    else if (buttonSpec->context & F_CONTEXT_ICON)
	    {
		menuContext = F_CONTEXT_ICON;
	    }
	    else
	    {
		menuContext = F_CONTEXT_ROOT;
	    }

	    menuSpec = MAKE_MENU (pSD, NULL, buttonSpec->wmFuncArgs,
				 menuContext,
	                         buttonSpec->context, 
				 (MenuItem *) NULL, FALSE);

	    if (menuSpec)
	    /* 
	     * If successful, save in pSD->acceleratorMenuSpecs 
	     * Note: these accelerators have nonzero contexts.
	     */
	    {
		SaveMenuAccelerators (pSD, menuSpec);
	    }
	    else
	    {
		buttonSpec->wmFunction = F_Nop;
	    }
	}
	buttonSpec = buttonSpec->nextButtonSpec;
    }


    /*
     * Scan through the key binding specifications making menus if the
     * f.menu function is invoked.
     */

    keySpec = pSD->keySpecs;
    while (keySpec)
    {
	if (keySpec->wmFunction == F_Menu)
	{
	    if (keySpec->context & F_CONTEXT_WINDOW)
	    {
		menuContext = F_CONTEXT_WINDOW;
	    }
	    else if (keySpec->context & F_CONTEXT_ICON)
	    {
		menuContext = F_CONTEXT_ICON;
	    }
	    else
	    {
		menuContext = F_CONTEXT_ROOT;
	    }

	    menuSpec = MAKE_MENU (pSD, NULL, keySpec->wmFuncArgs, menuContext,
	                         keySpec->context, 
				 (MenuItem *) NULL, FALSE);

	    if (menuSpec)
	    /* 
	     * If successful, save in pSD->acceleratorMenuSpecs 
	     * Note: these accelerators have nonzero contexts.
	     */
	    {
		SaveMenuAccelerators (pSD, menuSpec);
	    }
	    else
	    {
		keySpec->wmFunction = F_Nop;
	    }
	}
	keySpec = keySpec->nextKeySpec;
    }


} /* END OF FUNCTION MakeWmFunctionResources */



/*************************************<->*************************************
 *
 *  MakeXorGC (pSD)
 *
 *
 *  Description:
 *  -----------
 *  Make an XOR graphic context for resizing and moving
 *
 *
 *  Inputs:
 *  ------
 *  pSD = pointer to screen data
 * 
 *  Outputs:
 *  -------
 *  Modifies global data
 *
 *  Comments:
 *  --------
 *  
 * 
 *************************************<->***********************************/

void MakeXorGC (WmScreenData *pSD)
{
    XGCValues gcv;
    XtGCMask  mask;

    mask = GCFunction | GCLineWidth | GCSubwindowMode | GCCapStyle;
    gcv.function = GXinvert;
    gcv.line_width = 0;
    gcv.cap_style = CapNotLast;
    gcv.subwindow_mode = IncludeInferiors;

    /* Fix so that the rubberbanding for resize and move will
     *  have more contrasting colors.
     */

    gcv.plane_mask = BlackPixelOfScreen( DefaultScreenOfDisplay( DISPLAY )) ^ 
                     WhitePixelOfScreen( DefaultScreenOfDisplay( DISPLAY ));
    mask = mask | GCPlaneMask;

    pSD->xorGC = XCreateGC (DISPLAY, pSD->rootWindow, mask, &gcv);


} /* END OF FUNCTION MakeXorGC */



/*************************************<->*************************************
 *
 *  CopyArgv (argc, argv)
 *
 *
 *  Description:
 *  -----------
 *  This function makes a copy of the window manager's argv for use by
 *  the f.restart function.  A copy must be kept because XtInitialize
 *  changes argv.
 *
 *
 *  Inputs:
 *  ------
 *  argc = the number of strings in argv
 *
 *  argv = window manager parameters
 *
 * 
 *  Outputs:
 *  -------
 *  Return = a copy of argv
 *
 *************************************<->***********************************/


void CopyArgv (int argc, char *argv [])
{
    int i;


    if ((wmGD.argv = (char **)XtMalloc ((argc + 1) * sizeof (char *))) == NULL)
    {
	Warning (((char *)GETMESSAGE(40, 10, "Insufficient memory for window manager data")));
	wmGD.argv = argv;
#ifdef WSM
	dpy2Argv = argv;
#endif /* WSM */
    }
    else
    {
	for (i = 0; i < argc; i++)
	{
	    wmGD.argv[i] = argv[i];
	}
	wmGD.argv[i] = NULL;
#ifdef WSM
	if ((dpy2Argv = (char **)XtMalloc((argc + 1) * sizeof(char *))) == NULL)
	{
	    Warning (((char *)GETMESSAGE(40, 11, "Insufficient memory for window manager data")));
	    dpy2Argv = argv;
	}
	else
	{
	    for (i = 0; i < argc; i++)
	    {
		dpy2Argv[i] = argv[i];
	    }
	    dpy2Argc = argc;
	    dpy2Argv[i] = NULL;
	}
#endif /* WSM */
    }
    
} /* END OF FUNCTION CopyArgv */


/*************************************<->*************************************
 *
 *  InitScreenNames ()
 *
 *
 *  Description:
 *  -----------
 *  Initializes the name space for screen names
 *
 *  Outputs:
 *  -------
 *  Modifies global data
 *    + screenNames
 *
 *  Comments:
 *  --------
 *  Initializes screenNames to contain a numeric name for each screen
 *
 *************************************<->***********************************/

void InitScreenNames (void)
{
    int num, numScreens;
    
    numScreens = ScreenCount (wmGD.display);
    
    if (!(wmGD.screenNames = 
	  (unsigned char **) XtMalloc (numScreens * sizeof(char *))))
    {
	ShowWaitState (FALSE);
	Warning (((char *)GETMESSAGE(40, 12, "Insufficient memory for screen names")));
	ExitWM (WM_ERROR_EXIT_VALUE);
    }
    
    for (num=0; num<numScreens; num++)
    {
	if (!(wmGD.screenNames[num] = 
	      (unsigned char *) XtMalloc (4*sizeof(char))))
	{
	    ShowWaitState (FALSE);
	    Warning (((char *)GETMESSAGE(40, 13, "Insufficient memory for screen names")));
	    ExitWM (WM_ERROR_EXIT_VALUE);
	}
	/* default name is left justified, 3-chars max, zero terminated */
#ifdef WSM
	sprintf((char *)wmGD.screenNames[num], UNSPECIFIED_SCREEN_NAME);
#else  /* WSM */
	sprintf((char *)wmGD.screenNames[num],"%d",num%1000);
#endif /* WSM */
    }
}
#ifndef NO_MESSAGE_CATALOG


void InitNlsStrings (void)
{
    char * tmpString;

#ifdef WSM
    /*
     * Initialize messages
     */
    wmGD.okLabel=XmStringCreateLocalized(_DtOkString);
    wmGD.cancelLabel=XmStringCreateLocalized(_DtCancelString);
    wmGD.helpLabel=XmStringCreateLocalized(_DtHelpString);
#endif /* WSM */    

    /*
     * catgets returns a pointer to an area that is over written
     * on each call to catgets.
     */

    tmpString = ((char *)GETMESSAGE(40, 14, "Icons"));
    if ((wmNLS.default_icon_box_title =
	 (char *)XtMalloc ((unsigned int) (strlen(tmpString) + 1))) == NULL)
    {
	Warning (((char *)GETMESSAGE(40, 15, "Insufficient memory for local message string")));
	wmNLS.default_icon_box_title = "Icons";
    }
    else
    {
	strcpy(wmNLS.default_icon_box_title, tmpString);
    }

#ifdef WSM
    tmpString = ((char *)GETMESSAGE(40, 20, "%s: %s on line %d of configuration file %s\n"));
    if ((pWarningStringFile =
	 (char *)XtMalloc ((unsigned int) (strlen(tmpString) + 1))) == NULL)
    {
	Warning (((char *)GETMESSAGE(40, 17, "Insufficient memory for local message string")));
	pWarningStringFile = "%s: %s on line %d of configuration file %s\n";
    }
    else
    {
	strcpy(pWarningStringFile, tmpString);
    }

    tmpString = ((char *)GETMESSAGE(40, 21, "%s: %s on line %d of specification string\n"));
    if ((pWarningStringLine =
	 (char *)XtMalloc ((unsigned int) (strlen(tmpString) + 1))) == NULL)
    {
	Warning (((char *)GETMESSAGE(40, 19, "Insufficient memory for local message string")));
	pWarningStringLine = "%s: %s on line %d of specification string\n";
    }
    else
    {
	strcpy(pWarningStringLine, tmpString);
    }


    tmpString = ((char *)GETMESSAGE(40, 22, "About Workspace Manager"));
    if ((wmNLS.defaultVersionTitle =
	 (char *)XtMalloc ((unsigned int) (strlen(tmpString) + 1))) == NULL)
    {
	Warning (((char *)GETMESSAGE(40, 15, "Insufficient memory for local message string")));
	wmNLS.defaultVersionTitle = "About Workspace Manager";
    }
    else
    {
	strcpy(wmNLS.defaultVersionTitle, tmpString);
    }

    tmpString = ((char *)GETMESSAGE(40, 23, "Workspace Manager - Help"));
    if ((wmNLS.defaultDtwmHelpTitle =
	 (char *)XtMalloc ((unsigned int) (strlen(tmpString) + 1))) == NULL)
    {
	Warning (((char *)GETMESSAGE(40, 15, "Insufficient memory for local message string")));
	wmNLS.defaultDtwmHelpTitle = "Workspace Manager - Help";
    }
    else
    {
	strcpy(wmNLS.defaultDtwmHelpTitle, tmpString);
    }

    tmpString = ((char *)GETMESSAGE(40, 24, "Workspace Manager - Help"));
    if ((wmNLS.defaultHelpTitle =
	 (char *)XtMalloc ((unsigned int) (strlen(tmpString) + 1))) == NULL)
    {
	Warning (((char *)GETMESSAGE(40, 15, "Insufficient memory for local message string")));
	wmNLS.defaultHelpTitle = "Workspace Manager - Help";
    }
    else
    {
	strcpy(wmNLS.defaultHelpTitle, tmpString);
    }
#endif /* WSM */

} /* InitNlsStrings  */
#endif



/******************************<->*************************************
 *
 *  InitWmDisplayEnv
 *
 *
 *  Description:
 *  -----------
 *  This function saves the display string for putenv in F_Exec.
 *
 *  Inputs:
 *  -------
 *
 *  Outputs:
 *  -------
 *************************************<->***********************************/

void
InitWmDisplayEnv (void)
{
    char *displayName;
    char *buffer;
    size_t buf_size;

    displayName = DisplayString (DISPLAY);
 
	buf_size = strlen(displayName)+10;
    buffer = (String)XtMalloc(buf_size);
    if(!buffer){
		wmGD.displayString = NULL;
        Warning (((char *)GETMESSAGE(40, 9, 
				     "Insufficient memory for displayString")));
	} else {
		snprintf(buffer, buf_size,"DISPLAY=%s",displayName);
		wmGD.displayString = buffer;
#ifdef WSM
		putenv(wmGD.displayString);
#endif /* WSM */
    }
    
} /* END OF FUNCTION  InitWmDisplayEnv */

/****************************   eof    ***************************/
