/* * CDE - Common Desktop Environment * * Copyright (c) 1993-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 libraries and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* $TOG: SmSave.c /main/27 1998/07/23 18:07:58 mgreess $ */ /*************************************<+>************************************* ***************************************************************************** ** ** File: SmSave.c ** ** Project: HP DT Session Manager (dtsession) ** ** Description: ** ----------- ** This file contains all routines that save off the session at any point ** in time. The session includes settings, resources, and clients. How ** the session manager behaves during a save depends on how the user has ** configured it to behave. ** ** ***************************************************************************** *************************************<+>*************************************/ /* * (c) Copyright 1997 The Open Group * (c) Copyright 1996 Digital Equipment Corporation. * (c) Copyright 1990, 1993, 1994, 1996 Hewlett-Packard Company. * (c) Copyright 1993, 1994, 1996 International Business Machines Corp. * (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc. * (c) Copyright 1993, 1994, 1996 Novell, Inc. * (c) Copyright 1996 FUJITSU LIMITED. * (c) Copyright 1996 Hitachi. */ #include #include #include #include #include #include #include #include #include #ifdef _SUN_OS #include #include #endif /* _SUN_OS */ #include #include #include #include #include #include
#include
#include
#include
#include
#include "Sm.h" #include "SmSave.h" #include "SmResource.h" #include "SmError.h" #include "SmGlobals.h" #include "SmUI.h" #include "SmWindow.h" #include "SmProtocol.h" #include "SmRestore.h" #include "SmXSMP.h" #include "SmDB.h" #include "SmProperty.h" #include "SmProp.h" #include "Srv.h" #include "SrvFile_io.h" #ifdef MULTIBYTE #include #include #endif #include typedef struct _ProxyClientCache { Window window; int screen; } ProxyClientCache, *ProxyClientCachePtr; static ProxyClientCachePtr proxyList; static int numProxyClients = 0; static int numProxyAllocated = 0; static int proxyCacheAllocIncrement = 10; /* * Local Function Declarations */ static void CacheProxyClient ( Boolean firstClient, int screenNum, Window window); static void PruneSessionDirectory (); static Boolean WriteClientDatabase (); static void OutputXSMPClients ( ClientDB outputDB); static void OutputProxyClients ( ClientDB outputDB); static Boolean CheckRequiredProperties ( ClientRecPtr pClientRec); static void PrintStartupInfo( ClientDB outputDB, int screen, Window window); static int QueryServerSettings( void ) ; static int SaveCustomizeSettings( void ) ; static int OutputResource( void ) ; static void PrintPointerControl( XrmDatabase *smBase) ; static void PrintSessionInfo( XrmDatabase *smBase) ; static void PrintScreenSaver( XrmDatabase *smBase) ; static int PrintFontPaths( XrmDatabase *smBase, char **fontPath, int numPaths) ; static int PrintKeyboardControl( XrmDatabase *smBase); static int PrintPointerMapping( XrmDatabase *smBase, char *buttonRet, int numButton) ; static void PrintWorkHintString( FILE *hintFile, char *hintString) ; static void PrintCmdHintString( FILE *hintFile, char *hintString) ; static void PrintCmdString( FILE *cmdFile, char *cmdString) ; static void PrintRemoteCmdString( FILE *cmdFile, char *cmdString) ; /* * Global variables that are exposed */ SmScreenInfo screenSaverVals; SmAudioInfo audioVals; SmKeyboardInfo keyboardVals; /* * Variables global to this module only */ /* * used as a buffer to write resources into * before they are written out */ static int resSize = 10000; static char *resSpec; /* * Vars used to maintain state that is sent to the SaveState * function. */ static Boolean saveHome; int saveMode; /*************************************<->************************************* * * SetupSaveState * * Description: * ----------- * Do all of the preliminary work that must be done before the state * of a checkpoint can be saved. * * Inputs: * ------ * saveToHome: This session is to be saved to the home session or current * mode = whether the session is to be reset or restarted * *************************************<->***********************************/ void SetupSaveState( Boolean saveToHome, int mode) { unsigned char *propData; /* * Cache saveToHome and mode - they will be needed after all of * the XSMP clients are saved and the Proxy clients are saved. */ saveHome = saveToHome; saveMode = mode; /* * First set up the save paths so we know if we have to do anything here */ if ((SetSavePath(saveToHome, mode)) == -1) return; /* * Take care of the save mode property on the root window so that the * clients will know how to save this file (if they save files) */ if(saveToHome == False) { propData = (unsigned char *) SM_CURRENT_DIRECTORY; } else { propData = (unsigned char *) SM_HOME_DIRECTORY; } /* * Change the save mode to give the subdirectory saved to * */ XChangeProperty(smGD.display, RootWindow(smGD.display, 0), XaSmSaveMode, XA_STRING, 8, PropModeReplace, propData, strlen((char *)propData)); XFlush(smGD.display); } /*************************************<->************************************* * * SaveState * * Description: * ----------- * Tells the SM to notify the XSMP clients to save their state. * The function CompleteSave fill be invoked after the XSMP clients * have completed their save. * * Inputs: * ------ * saveToHome: This session is to be saved to the home session or current * mode = whether the session is to be reset or restarted * * Comments: * -------- * As a result of this routine files will be saved in the users .dt directory * that will allow the session manager to restore the session at a later * time. * * NOTE - this function is called as the result of the following * events: * * 1. User initiates a Save Home Session via the Style Manager * 2. The Session Manager receives a SM_XSESSION_EXIT message * 3. The Session Manager receives a SM_SAVE_SESSION message * *************************************<->***********************************/ void SaveState( Boolean saveToHome, int mode, int saveType, Bool shutdown, int interactStyle, Bool fast, Bool global) { /* * Notify XSMP clients of the save */ SaveYourselfReqProc (NULL, NULL, saveType, shutdown, interactStyle, fast, global); } /*************************************<->************************************* * * CompleteSave * * Description: * ----------- * Called after the XSMP clients have saved their state. In charge of * calling all routines that save session information for XSMP client * and Proxy clients as well as settings, resources, etc. * * Outputs: * ------- * *************************************<->***********************************/ int CompleteSave (void) { FILE *convertFP; unsigned char *propData; char *tmpPath, tmpVersion[20]; Boolean saveToHome = saveHome; int mode = saveMode; /* * If this is a Home session and the user is logging out, return * now - the XSMP clients have all responded to the save and the * ICCC clients don't save their state when a Home session is * exited. */ if (smGD.sessionType == HOME_SESSION && smXSMP.saveState.shutdown == True && smSettings.startState == DtSM_HOME_STATE) return (0); /* * Start a wait state - don't want anything to happen while * ICCC clients are being saved */ ShowWaitState(True); resSpec = (char *) SM_MALLOC(resSize * sizeof(char)); if (resSpec==NULL) { PrintErrnoError(DtError, smNLS.cantMallocErrorString); return(-1); } if (!WriteClientDatabase ()) { ShowWaitState(False); SM_FREE(resSpec); return (-1); } /* * WARNING - THIS VARIABLE MUST BE SET BEFORE THE SETTING INFORMATION IS * CALLED - SETTINGS MUST BE SAVED BEFORE RESOURCES BECAUSE SETTINGS * GETS INFORMATION SAVED IN RESOURCES (smToSet.dClickBuf) */ smToSet.dClickBuf[0] = 0; /* * Do the actual output of the X settings information. Output will * go to the resource database at this point and be written to the * resource file with the rest of the resources (below). */ if(smRes.querySettings == True) { QueryServerSettings(); } else { SaveCustomizeSettings(); } /* * Do the output of resource information. */ if(OutputResource()) { ShowWaitState(False); SM_FREE(resSpec); return(-1); } XDeleteProperty(smGD.display, DefaultRootWindow(smGD.display), XaSmSaveMode); /* * Go save the default palette at this time */ if(saveToHome == True) SaveDefaultPalette(smGD.display, smGD.savePath, DtSM_HOME_STATE); else SaveDefaultPalette(smGD.display, smGD.savePath, mode); PruneSessionDirectory (); ShowWaitState(False); return(0); } /*************************************<->************************************* * * PruneSessionDirectory - * * Description: Removes the oldest session direcotry if the number * of directories exceeds the smRes.numSessionsBackedup. * * Inputs: void * *************************************<->***********************************/ static void PruneSessionDirectory (void) { DIR * dirp; struct dirent * dp; int numDirs = 0; struct stat buf; time_t oldestTime; char *clientDB; char *dirPrefix; char *oldDir; /* the .old dir */ char *oldestDir; char *saveDir; char *tmpDir; if ((dirp = opendir (smGD.savePath)) == NULL) return; clientDB = (char*) XtMalloc((2*MAXPATHLEN) + 1); oldestDir = (char*) XtMalloc(MAXPATHLEN + 1); saveDir = (char*) XtMalloc(MAXPATHLEN + 1); tmpDir = (char*) XtMalloc(MAXPATHLEN + 1); dirPrefix = XtMalloc (strlen (smGD.restoreSession) + 2); sprintf (dirPrefix, "%s.", smGD.restoreSession); if (strlen (dirPrefix) > 5) { dirPrefix[4] = '.'; dirPrefix[5] = '\000'; } oldDir = XtMalloc (strlen (smGD.restoreSession) + strlen (SM_OLD_EXTENSION) + 2); sprintf (oldDir, "%s.%s", smGD.restoreSession, SM_OLD_EXTENSION); (void) time (&oldestTime); while ((dp = readdir (dirp)) != NULL) { /* * Do some sanity checks to limit the number of * stat() * calls. Note that for backward compatibility with CDE * 1.0 if a ".old" directory exists, keep it. */ if ((!strcmp (dp->d_name, ".")) || (!strcmp (dp->d_name, "..")) || (!strcmp (dp->d_name, oldDir)) || (strncmp (dp->d_name, dirPrefix, strlen (dirPrefix)))) continue; sprintf (tmpDir, "%s/%s", smGD.savePath, dp->d_name); if (((stat (tmpDir, &buf)) == 0) && S_ISDIR (buf.st_mode)) { if (buf.st_mtime < oldestTime) { /* * Keep track of the oldest dir in case * it needs to be removed */ oldestTime = buf.st_mtime; strcpy (oldestDir, tmpDir); } numDirs++; } } closedir(dirp); if (numDirs > smRes.numSessionsBackedup) { /* * Need to remove the oldest directory. The general * process (using "home" as an example) is: * * mv home home.tmp * mv oldestDir home * Execute the DiscardCommand props in the home directory * rm -rf home * mv home.tmp home * * The reason this is done is because when the * DiscardCommand were saved, the directory at the time of * the save contained "home". For example, a DiscardCommand * may look like: * * rm -f /u/somebody/.dt/sessions/home/app.state * * yet because of the session archiving, the app.state * file may actually be in a directory like: * * /u/somebody/.dt/sessions/home. */ char * tmpName; int len, tfd; len = strlen(smGD.savePath) + strlen(smGD.restoreSession) + strlen("XXXXXX") + 3; tmpName = XtCalloc (1, len); sprintf(tmpName, "%s/%s.XXXXXX", smGD.savePath, smGD.restoreSession); if ((tfd = mkstemp(tmpName)) == -1) { PrintErrnoError(DtError, smNLS.cantCreateDirsString); } else { close(tfd); unlink(tmpName); sprintf (saveDir, "%s/%s", smGD.savePath, smGD.restoreSession); MoveDirectory (saveDir, tmpName, False); MoveDirectory (oldestDir, saveDir, False); sprintf (clientDB, "%s/%s/%s", smGD.savePath, smGD.restoreSession, SM_CLIENT_FILE2); ExecuteDiscardCommands (clientDB); MoveDirectory (tmpName, saveDir, True); } XtFree (tmpName); } /* * If exiting and the current session is a Current session * but smSettings.startState has been set to to a * Home session (this would be true if a user started a * Current session but used the Style Manager to set the session * upon next login to be a Home session), then if a home * directory exists, mv current to current.old */ if (smXSMP.saveState.shutdown && smGD.sessionType == CURRENT_SESSION && smSettings.startState == DtSM_HOME_STATE) { sprintf (tmpDir, "%s/%s", smGD.savePath, SM_HOME_DIRECTORY); if (((stat (tmpDir, &buf)) == 0) && S_ISDIR (buf.st_mode)) { sprintf (saveDir, "%s/%s", smGD.savePath, oldDir); if (((stat (saveDir, &buf)) == 0) && S_ISDIR (buf.st_mode)) { sprintf (clientDB, "/bin/rm -rf %s", saveDir); SystemCmd (clientDB); sprintf (oldestDir, "%s/%s", smGD.savePath, SM_CURRENT_DIRECTORY); MoveDirectory (oldestDir, saveDir, False); } } } XtFree(clientDB); XtFree(dirPrefix); XtFree(oldDir); XtFree(oldestDir); XtFree(saveDir); XtFree(tmpDir); } /*************************************<->************************************* * * WriteClientDatabase - * * Description: Writes the client database (for XSMP and Proxy clients) * * Inputs: None * * Returns True if the database is wrtten OK; False otherwise * *************************************<->***********************************/ static Boolean WriteClientDatabase (void) { char *db; ClientDB outputDB; db = (char*) XtMalloc(MAXPATHLEN + 1); (void) sprintf (db, "%s/%s/%s", smGD.savePath, smGD.restoreSession, SM_CLIENT_FILE2); if ((outputDB = OpenOutputClientDB (db, smXSMP.dbVersion, smXSMP.dbSessionId)) == NULL) { char * str; str = strdup ((char *) GETMESSAGE (40, 18, "The following database file cannot be opened for writing:\n\n %s\n\nThe session will not be saved.")); if (str) { DtMsgLogMessage (smGD.programName, DtMsgLogError, str, db); free (str); } XtFree(db); return (False); } XtFree(db); OutputProxyClients (outputDB); OutputXSMPClients (outputDB); CloseClientDB (outputDB, True); return (True); } /*************************************<->************************************* * * OutputProxyClients - * * Description: Outputs the Proxy clients * * Inputs: database pointer * * Returns: void * *************************************<->***********************************/ static void OutputProxyClients ( ClientDB outputDB) { int i; for (i = 0; i < numProxyClients; i++) PrintStartupInfo (outputDB, proxyList[i].screen, proxyList[i].window); } /*************************************<->************************************* * * OutputXSMPClients - * * Description: Outputs the XSMP clients * * Inputs: database pointer * * Returns: void * *************************************<->***********************************/ static void OutputXSMPClients ( ClientDB outputDB) { XSMPClientDBRec dbRec; ClientRecPtr pClientRec; for (pClientRec = connectedList; pClientRec != NULL; pClientRec = pClientRec->next) { dbRec.restartHint = pClientRec->restartHint; (void) GetCardPropertyValue (pClientRec, SmRestartStyleHint, &dbRec.restartHint); if (dbRec.restartHint == SmRestartNever) continue; if (!pClientRec->active) continue; if (!CheckRequiredProperties (pClientRec)) continue; dbRec.screenNum = 0; dbRec.clientId = pClientRec->clientId; dbRec.clientHost = pClientRec->clientHost; dbRec.program = GetArrayPropertyValue (pClientRec, SmProgram); dbRec.cwd = GetArrayPropertyValue (pClientRec, SmCurrentDirectory); dbRec.restartCommand = GetListOfArrayPropertyValue (pClientRec, SmRestartCommand); dbRec.cloneCommand = GetListOfArrayPropertyValue (pClientRec, SmCloneCommand); dbRec.discardCommand = GetListOfArrayPropertyValue (pClientRec, SmDiscardCommand); dbRec.environment = GetListOfArrayPropertyValue (pClientRec, SmEnvironment); if (!PutXSMPClientDBRec (outputDB, &dbRec)) { char *str; str = strdup ((char *) GETMESSAGE (40, 19, "Application '%s' cannot be saved.")); if (str) { DtMsgLogMessage (smGD.programName, DtMsgLogError, str, dbRec.program); free (str); } } if (dbRec.restartCommand) XtFree ((char *) dbRec.restartCommand); if (dbRec.cloneCommand) XtFree ((char *) dbRec.cloneCommand); if (dbRec.discardCommand) XtFree ((char *) dbRec.discardCommand); if (dbRec.environment) XtFree ((char *) dbRec.environment); } } /*************************************<->************************************* * * CheckRequiredProperties - * * Description: Check a client's required properties * * Inputs: ClientRecPtr * * Returns: True if the client has all of the required properties; * otherwise returns False * *************************************<->***********************************/ static Boolean CheckRequiredProperties ( ClientRecPtr pClientRec) { PropertyRecPtr pPropRec; char * str; char * program = NULL; if ((program = GetArrayPropertyValue (pClientRec, SmProgram)) == NULL){ str = strdup ((char *) GETMESSAGE (40, 23, "The following application did not set the required\nproperty '%s':\n\n %s\n\nThis application will not be saved.")); if (str) { DtMsgLogMessage (smGD.programName, DtMsgLogError, str, SmProgram, pClientRec->clientId); free (str); } return (False); } if ((pPropRec = GetPropertyRec (pClientRec, SmRestartCommand)) == NULL){ str = strdup ((char *) GETMESSAGE (40, 24, "24 Application '%s' will not be saved because it did not set\nthe required property '%s'.")); if (str) { DtMsgLogMessage (smGD.programName, DtMsgLogError, str, program, SmRestartCommand); free (str); } return (False); } if ((pPropRec = GetPropertyRec (pClientRec, SmCloneCommand)) == NULL) { /* * This is a warning - still want to save the client */ str = strdup ((char *) GETMESSAGE (40, 25, "Application '%s' did not set the required property '%s'.")); if (str) { DtMsgLogMessage (smGD.programName, DtMsgLogWarning, str, program, SmCloneCommand); free (str); } } return (True); } /*************************************<->************************************* * * NotifyProxyClients - * * * Description: * ----------- * Notify Proxy clients - calls routines to find top level windows, and * notifies the Proxy clients about an impending save. * * Inputs: * ------ * * Outputs: * ------- * *************************************<->***********************************/ void NotifyProxyClients (void) { unsigned int topListLength, containedListLength; WindowInfo * topList; /* list of top-level windows */ WindowInfo topLevelWindowInfo; Atom actualType; int actualFormat; unsigned long nitems; unsigned long leftover; unsigned char * data = NULL; Boolean containedClient; int i, j; int numClients = 0; /* * Save off the clients currently running. This will be done * one screen at a time */ for(j = 0;j < smGD.numSavedScreens;j++) { /* * Get a list of children of the root window. If there are none * return with an error condition. */ if(GetTopLevelWindows(j,&topList,&topListLength, &containedListLength)) return; /* * Figure out how to restart the client associate with each window. */ for (i=0 ; i<(topListLength + containedListLength); ++i) { topLevelWindowInfo=topList[i]; if(i >= topListLength) { containedClient = True; } else { containedClient = False; } /* * If this window is my window - skip it I don't want to * save myself because I will be started automatically */ if (XGetWindowProperty(smGD.display, topLevelWindowInfo.wid, XA_WM_CLASS,0L, (long)BUFSIZ,False,XA_STRING,&actualType, &actualFormat,&nitems,&leftover, &data)==Success) { if (actualType==XA_STRING && !strcmp((char *) data, SM_RESOURCE_NAME)) { SM_FREE((char *)data); continue; } else { SM_FREE((char *)data); } } /* * If the client participates in the WM_SAVE_YOURSELF protocol, * send the appropriate messages and wait for the proper * responses. */ (void) SaveYourself(topLevelWindowInfo); CacheProxyClient ((numClients == 0), j, topLevelWindowInfo.wid); numClients++; } /* * Free space malloc'd by GetTopLevelWindowInfo */ if(topListLength > 0) { SM_FREE((char *) topList); } } } /*************************************<->************************************* * * CacheProxyClient - * * Description: * ----------- * Add a Proxy client to the proxy client cache. * * Inputs: * ------ * firstClient - if True, this is the first client in the cache * screenNum - the client's screen number * window - the client's window number * * Outputs: * ------- * *************************************<->***********************************/ static void CacheProxyClient ( Boolean firstClient, int screenNum, Window window) { if (firstClient) numProxyClients = 0; if (numProxyClients >= numProxyAllocated) { numProxyAllocated += proxyCacheAllocIncrement; proxyList = (ProxyClientCachePtr) XtRealloc ((char *) proxyList, numProxyAllocated * sizeof (ProxyClientCache)); } proxyList[numProxyClients].screen = screenNum; proxyList[numProxyClients].window = window; numProxyClients++; } /*************************************<->************************************* * * PrintStartupInfo - * * Description: * ----------- * Output startup information for one proxy client * * Inputs: * ------ * outputDB = a pointer to the client database * screen = which screen the client is running on * window = the top level window of the lient * * Outputs: * ------- * * Comments: * -------- * *************************************<->***********************************/ static void PrintStartupInfo( ClientDB outputDB, int screen, Window window) { Boolean writeStatus; int wargc; char ** wargv; char *clientMachine; XWindowAttributes windowAttr; Boolean remoteHost; Boolean xsmpClient; ProxyClientDBRec dbRec; char ** argv; int i; Status status; #ifdef _SUN_OS /* pull out quotes from OpenWindow tools commands */ char * ptr; #endif /* * Get the attributes and properties on the window */ if ((XGetWindowAttributes(smGD.display, window, &windowAttr)) == 0) return; if (GetStandardProperties(window, screen, &wargc, &wargv, &clientMachine, &xsmpClient)==0) return; /* * If the client doesn't have a WM_COMMAND property, we can't restart it */ if (!wargv||!wargv[0]) return; /* * If the client is an XSMP client, don't save it as a Proxy client. */ if (xsmpClient) return; #ifdef _SUN_OS /* pull out quotes from OpenWindow tools commands */ if (wargc == 1) { ptr = wargv[0]; /* check for foreground */ if ((ptr = strstr (ptr, "fg \"")) != NULL) { if (strlen (ptr) > 3) ptr[3] = ' '; if ((ptr = strchr (ptr, '"')) != NULL) ptr[0] = ' '; } /* check for background */ if ((ptr = strstr (wargv[0], "bg \"")) != NULL) { if (strlen (ptr) > 3) ptr[3] = ' '; if ((ptr = strchr (ptr, '"')) != NULL) ptr[0] = ' '; } } #endif /* * Find out if the client is running locally */ dbRec.clientHost = NULL; if(clientMachine != NULL) { if(DtIsLocalHostP(clientMachine) == FALSE) { dbRec.clientHost = clientMachine; } } /* * Must NULL-terminate the WM_COMMAND before writing it */ argv = (char **) XtMalloc ((wargc + 1) * sizeof (char *)); if (!argv) return; for (i = 0; i < wargc; i++) argv[i] = wargv[i]; argv[wargc] = NULL; dbRec.command = argv; dbRec.screenNum = screen; writeStatus = PutProxyClientDBRec (outputDB, &dbRec); XtFree ((char *) argv); if (writeStatus == False) { /* * There should be an error written here - however * since this means that there already is a write error to * the disk - no error can be written */ (void) CloseClientDB (outputDB, True); /* * On a write error - move the old session back to * be used and exit with an error condition */ XFreeStringList(wargv); strcat(smGD.savePath, "/"); if(smGD.sessionType == HOME_SESSION) { strcat(smGD.savePath, SM_HOME_DIRECTORY); } else { strcat(smGD.savePath, SM_CURRENT_DIRECTORY); } MoveDirectory(smGD.etcPath, smGD.savePath, False); SM_EXIT(-1); } /* * Free up the argv property */ XFreeStringList(wargv); } /*************************************<->************************************* * * QueryServerSettings () * * * Description: * ----------- * Query the server for all it's current settings information, and then * write that information to the session managers settings resource file. * * Inputs: * ------ * smGD.settingPath = (global) pointer to file where * setting info should be saved. * * Outputs: * ------- * * Comments: * -------- * This routine slows down the session manager's shutdown process * considerably, and is therefore only called when the user specifies * that all settings should be queried. Otherwise, only settings set in * the customizer should be saved. * *************************************<->***********************************/ static int QueryServerSettings( void ) { int i, numLoops; char **fontPath; KeySym *tmpSyms, tmpMod; XModifierKeymap *modMap; char *buttonRet; int numButton, numPaths; int buttonSize = 128; XrmDatabase smBase = NULL; char tmpChar[35]; buttonRet = (char *) SM_MALLOC(buttonSize * sizeof(char)); if (buttonRet==NULL) { PrintErrnoError(DtError, smNLS.cantMallocErrorString); return(-1); } /* * First set up all pointer control parameters * These are simple integer values that get saved * here, then read into a structure and set at restore * time */ XGetPointerControl(smGD.display, &smSettings.accelNum, &smSettings.accelDenom, &smSettings.threshold); PrintPointerControl(&smBase); /* * Get all the screen saver values. These are all simple integer * values that are read back into a structure and set at restore * time. */ XGetScreenSaver(smGD.display, &screenSaverVals.smTimeout, &screenSaverVals.smInterval, &screenSaverVals.smPreferBlank, &screenSaverVals.smAllowExp); PrintScreenSaver(&smBase); /* * Write out all font path information. * Write out all the paths one by one concatenated by commas. */ fontPath = XGetFontPath(smGD.display, &numPaths); if(fontPath != NULL) { if(PrintFontPaths(&smBase, fontPath, numPaths) != 0) { XFreeFontPath(fontPath); SM_FREE(buttonRet); return(-1); } } /* * Write out all the keyboard control information. */ XGetKeyboardControl(smGD.display, &smSettings.kbdState); if(PrintKeyboardControl(&smBase) != 0) { if (fontPath) XFreeFontPath(fontPath); return(-1); } /* * Put all the button modifier information into the resource database. * Find out the number of buttons and then write out the character * string for each button. */ numButton = XGetPointerMapping(smGD.display, (unsigned char *)buttonRet, 128); if(numButton > 128) { buttonRet = (char *) SM_REALLOC(buttonRet, numButton * sizeof(char)); if (buttonRet==NULL) { if (fontPath) XFreeFontPath(fontPath); PrintErrnoError(DtError, smNLS.cantMallocErrorString); return(-1); } numButton = XGetPointerMapping(smGD.display, (unsigned char *)buttonRet, numButton); } if(PrintPointerMapping(&smBase, buttonRet, numButton) != 0) { if (fontPath) XFreeFontPath(fontPath); SM_FREE(buttonRet); return(-1); } /* * Put all keyboard mapping information in the resource database * Don't bother putting this in a separate print function because * the customizer doesn't do keymap savings this way. */ smSettings.numKeyCode = smGD.display->max_keycode - smGD.display->min_keycode; tmpSyms = XGetKeyboardMapping(smGD.display, (KeyCode) smGD.display->min_keycode, smSettings.numKeyCode, &smSettings.keySymPerCode); if(tmpSyms == NULL) { if (fontPath) XFreeFontPath(fontPath); SM_FREE(buttonRet); PrintErrnoError(DtError, smNLS.cantMallocErrorString); return(-1); } strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCnumKeyCode); strcat(resSpec, ":"); sprintf(tmpChar,"%d", smSettings.numKeyCode); strcat(resSpec, tmpChar); XrmPutLineResource( &smBase, resSpec); strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCkeySymsPerKey); strcat(resSpec, ":"); sprintf(tmpChar,"%d", smSettings.keySymPerCode); strcat(resSpec, tmpChar); XrmPutLineResource( &smBase, resSpec); strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCkeySyms); strcat(resSpec, ":"); numLoops = smSettings.numKeyCode * smSettings.keySymPerCode; sprintf(tmpChar,"%ld", tmpSyms[0]); strcat(resSpec, tmpChar); for(i = 1;i < numLoops;i++) { if((strlen(resSpec) + 5) >= resSize) { resSize += 5000; resSpec = (char *) SM_REALLOC(resSpec, resSize * sizeof(char)); if (resSpec==NULL) { SM_FREE((char *)tmpSyms); if (fontPath) SM_FREE((char *)fontPath); SM_FREE(buttonRet); PrintErrnoError(DtError, smNLS.cantMallocErrorString); return(-1); } } strcat(resSpec, ","); sprintf(tmpChar,"%ld", tmpSyms[i]); strcat(resSpec, tmpChar); } XrmPutLineResource( &smBase, resSpec); /* * Write out all keyboard modifier info. This will be a pretty slow * process considering that every keycode will have to be turned into * a keysym before writing. Don't bother putting print stuff in a * separate function because it will not be handled in the customize * version. */ modMap = XGetModifierMapping(smGD.display); if(modMap == NULL) { SM_FREE((char *)tmpSyms); if (fontPath) XFreeFontPath(fontPath); SM_FREE(buttonRet); PrintErrnoError(DtError, smNLS.cantMallocErrorString); return(-1); } strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCmaxKeyPerMod); strcat(resSpec, ":"); sprintf(tmpChar,"%d", modMap->max_keypermod); strcat(resSpec, tmpChar); XrmPutLineResource( &smBase, resSpec); strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCmodMap); strcat(resSpec, ":"); numLoops = (8 * modMap->max_keypermod) - 1; for(i = 0;i <= numLoops;i++) { if((strlen(resSpec) + 9) >= resSize) { resSize += 5000; resSpec = (char *) SM_REALLOC(resSpec, resSize * sizeof(char)); if (resSpec==NULL) { SM_FREE((char *)tmpSyms); XFreeModifiermap(modMap); if (fontPath) XFreeFontPath(fontPath); SM_FREE(buttonRet); PrintErrnoError(DtError, smNLS.cantMallocErrorString); return(-1); } } tmpMod = XKeycodeToKeysym(smGD.display, modMap->modifiermap[i], 0); sprintf(tmpChar,"%ld", tmpMod); strcat(resSpec, tmpChar); if(i != numLoops) { strcat(resSpec, ","); } } XrmPutLineResource( &smBase, resSpec); /* * Print session manager settings */ PrintSessionInfo(&smBase); /* * Write settings resources out to disk */ XrmPutFileDatabase(smBase, smGD.settingPath); /* * Free all allocated resources */ if (fontPath) XFreeFontPath(fontPath); SM_FREE((char *)tmpSyms); XFreeModifiermap(modMap); SM_FREE(buttonRet); XrmDestroyDatabase(smBase); return(0); } /*************************************<->************************************* * * SaveCustomizeSettings () * * * Description: * ------------ * Saves those settings that have been set in the customizer during the * session to whatever values they were set to during the session. * * * Inputs: * ------ * smGD.resourcePath = (global) a pointer * to where the settings should be stored. * * * Outputs: * ------- * * * Comments: * -------- * This routine is the default saved for saving settings. If the user * wants all settings saved, they have to set a resource saying that that * will be the case. * *************************************<->***********************************/ static int SaveCustomizeSettings( void ) { int i,numPaths; char **fontPath; XrmDatabase smBase = NULL; char *tmpChar[20], *ptrRet = NULL, *tmpKey; Status newStat; char tmpMap[128]; if(smCust.pointerChange) { newStat = _DtGetSmPointer(smGD.display, smGD.topLevelWindow, XaDtSmPointerInfo, &ptrRet); if(newStat != Success) { smToSet.pointerChange = False; smToSet.pointerMapChange = False; } else { sscanf(ptrRet, "%d %s %d %d %s", &smToSet.numButton, &tmpMap, &smSettings.accelNum, &smSettings.threshold, &smToSet.dClickBuf); smSettings.accelDenom = 1; tmpKey = strtok(tmpMap, "_"); i = 0; while(tmpKey != NULL) { smToSet.pointerMap[i] = (char) atoi(tmpKey); i++; tmpKey = strtok(NULL, "_"); } /* * append a \n to dClickBuf because it was scanned out */ strcat(smToSet.dClickBuf, "\n"); } if (ptrRet) XFree(ptrRet); } if(smToSet.pointerChange == True) { PrintPointerControl(&smBase); } if(smToSet.pointerMapChange == True) { if(PrintPointerMapping(&smBase, smToSet.pointerMap, smToSet.numButton) != 0) { return(-1); } } if(smToSet.screenSavChange == True) { PrintScreenSaver(&smBase); } if(smCust.audioChange == True) { newStat = _DtGetSmAudio(smGD.display, smGD.topLevelWindow, XaDtSmAudioInfo, &audioVals); if(newStat == Success) { smSettings.kbdState.bell_percent = audioVals.smBellPercent; smSettings.kbdState.bell_pitch = audioVals.smBellPitch; smSettings.kbdState.bell_duration = audioVals.smBellDuration; } else { smToSet.audioChange = False; } } if (smToSet.audioChange) { strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCbellPercent); strcat(resSpec, ":"); sprintf((char *)tmpChar,"%d",smSettings.kbdState.bell_percent); strcat(resSpec, (char *)tmpChar); XrmPutLineResource(&smBase, resSpec); strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCbellPitch); strcat(resSpec, ":"); sprintf((char *)tmpChar,"%d",smSettings.kbdState.bell_pitch); strcat(resSpec, (char *)tmpChar); XrmPutLineResource(&smBase, resSpec); strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCbellDuration); strcat(resSpec, ":"); sprintf((char *)tmpChar,"%d",smSettings.kbdState.bell_duration); strcat(resSpec, (char *)tmpChar); XrmPutLineResource(&smBase, resSpec); } if(smCust.keyboardChange == True) { newStat = _DtGetSmKeyboard(smGD.display, smGD.topLevelWindow, XaDtSmKeyboardInfo, &keyboardVals); if(newStat == Success) { smSettings.kbdState.key_click_percent = keyboardVals.smKeyClickPercent; smSettings.kbdState.global_auto_repeat = keyboardVals.smGlobalAutoRepeat; } else { smToSet.keyboardChange = False; } } if(smToSet.keyboardChange == True) { strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCkeyClick); strcat(resSpec, ":"); sprintf((char *)tmpChar,"%d", smSettings.kbdState.key_click_percent); strcat(resSpec, (char *)tmpChar); XrmPutLineResource(&smBase, resSpec); strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCglobalRepeats); strcat(resSpec, ":"); sprintf((char *)tmpChar,"%d", smSettings.kbdState.global_auto_repeat); strcat(resSpec, (char *)tmpChar); XrmPutLineResource(&smBase, resSpec); } /* * Write out all font path information. * Write out all the paths one by one concatenated by commas. */ fontPath = XGetFontPath(smGD.display, &numPaths); if(fontPath != NULL) { if(PrintFontPaths(&smBase, fontPath, numPaths) != 0) { XFreeFontPath(fontPath); return(-1); } } /* * Save session manager settings */ PrintSessionInfo(&smBase); if (fontPath) XFreeFontPath(fontPath); /* * Write settings resources out to disk */ XrmPutFileDatabase(smBase, smGD.settingPath); XrmDestroyDatabase(smBase); return(0); } /*************************************<->************************************* * * OutputResource () * * * Description: * ----------- * Save session resources by getting the current RESOURCE_MANAGER property * on the root window. * * Inputs: * ------ * smGD.resourcePath = (global) file name * where property contents should be saved. * * Outputs: * ------- * * * Comments: * -------- * This method is not a 100% accurate representation of currently active * resources in the system. It is however, the best representation (the * values with the highest priority) without becoming overly invasive * and slow. * *************************************<->***********************************/ static int OutputResource( void ) { Atom actualType; int actualFormat; unsigned long nitems, leftover; char *data = NULL; XrmDatabase db; Status newStat; char *fontBuf = NULL, *langPtr, tmpChar[20], *sessionRes; float fltYRes; int intYRes; char *preeditBuf = NULL; /* * Add anything to the Resource Manager property that needs to be added */ /* * Write out the LANG variable and the screen's Y resolution */ *resSpec = 0; langPtr = getenv("LANG"); if((langPtr != NULL) && (*langPtr != 0)) { snprintf(resSpec, resSize, "%s*%s: %s\n", SM_RESOURCE_NAME, SmNsessionLang, langPtr); } else { snprintf(resSpec, resSize, "%s*%s: \n", SM_RESOURCE_NAME, SmNsessionLang); } fltYRes = ((float) DisplayHeight(smGD.display, 0) / (float) DisplayHeightMM(smGD.display, 0)) * 1000; intYRes = fltYRes; if(*resSpec == 0) { strcpy(resSpec, SM_RESOURCE_NAME); } else { strcat(resSpec, SM_RESOURCE_NAME); } strcat(resSpec, "*"); strcat(resSpec, SmNdisplayResolution); strcat(resSpec, ":"); sprintf(tmpChar, "%d",intYRes); strcat(resSpec, tmpChar); strcat(resSpec, "\n"); _DtAddToResource(smGD.display, resSpec); if(smCust.fontChange == True) { newStat = _DtGetSmFont(smGD.display, smGD.topLevelWindow, XaDtSmFontInfo, &fontBuf); if(newStat == Success) { /* * Create the auxillary resource file */ if(SetFontSavePath(langPtr) != -1) { db = XrmGetStringDatabase(fontBuf); if(intYRes < MED_RES_Y_RES) { sessionRes = SM_LOW_RES_EXT; } else { if(intYRes >= HIGH_RES_Y_RES) { sessionRes = SM_HIGH_RES_EXT; } else { sessionRes = SM_MED_RES_EXT; } } strcat(smGD.fontPath, "/"); strcat(smGD.fontPath, SM_FONT_FILE); strcat(smGD.fontPath, "."); strcat(smGD.fontPath, sessionRes); XrmPutFileDatabase(db, smGD.fontPath); XrmDestroyDatabase(db); } /* * Now add this to the resource manager property to be saved */ _DtAddToResource(smGD.display, fontBuf); } if (fontBuf) XFree(fontBuf); } if(smCust.preeditChange == True) { newStat = _DtGetSmPreedit(smGD.display, smGD.topLevelWindow, XaDtSmPreeditInfo, &preeditBuf); if(newStat == Success) { _DtAddToResource(smGD.display, preeditBuf); } if (preeditBuf) XFree(preeditBuf); } if((smCust.dClickChange == True) && (smToSet.dClickBuf[0] != 0)) { _DtAddToResource(smGD.display, (char *)smToSet.dClickBuf); } /* * Get the contents of the _DT_SM_PREFERENCES property */ data = _DtGetResString(smGD.display, _DT_ATR_PREFS); /* * Get _DT_SM_PREFERENCES database 'db'. */ db = XrmGetStringDatabase((char *)data); XrmPutFileDatabase(db, smGD.resourcePath); /* * Don't forget to free your data */ SM_FREE((char *)data); XrmDestroyDatabase(db); return(0); } /*************************************<->************************************* * * PrintPointerControl (smBase) * * * Description: * ----------- * A convenience function that is separated out instead of being included * in both QueryServerSettings, and SaveCustomizeSettings. * Saves pointer control information to the named resource file. * * Inputs: * ------ * smBase = pointer to newly opened resource db used to store setting info * resSpec = a buffer to hold string resource information until it is * printed. * smSettings = place where settings are stored. * * Outputs: * ------- * * Comments: * -------- * *************************************<->***********************************/ static void PrintPointerControl( XrmDatabase *smBase) { char tmpChar[20]; strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCaccelNum); strcat(resSpec, ":"); sprintf(tmpChar, "%d", smSettings.accelNum); strcat(resSpec, tmpChar); XrmPutLineResource(smBase, resSpec); strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCaccelDenom); strcat(resSpec, ":"); sprintf(tmpChar, "%d",smSettings.accelDenom); strcat(resSpec, tmpChar); XrmPutLineResource(smBase, resSpec); strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCthreshold); strcat(resSpec, ":"); sprintf(tmpChar, "%d",smSettings.threshold); strcat(resSpec, tmpChar); XrmPutLineResource(smBase, resSpec); return; } /*************************************<->************************************* * * PrintSessionInfo (smBase) * * * Description: * ----------- * A convenience function that is separated out instead of being included * in both QueryServerSettings, and SaveCustomizeSettings. * Saves session manager settings to the named resource file. * * Inputs: * ------ * smBase = pointer to newly opened resource db used to store setting info * resSpec = a buffer to hold string resource information until it is * printed. * smSettings = place where settings are stored. * * Outputs: * ------- * * Comments: * -------- * *************************************<->***********************************/ static void PrintSessionInfo( XrmDatabase *smBase) { char tmpChar[20]; /* * Write out the settings for logout confirmation and * the correct session to return to */ strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCshutDownState); strcat(resSpec, ":"); sprintf(tmpChar, "%d",smSettings.confirmMode); strcat(resSpec, tmpChar); XrmPutLineResource(smBase, resSpec); strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCshutDownMode); strcat(resSpec, ":"); sprintf(tmpChar, "%d",smSettings.startState); strcat(resSpec, tmpChar); XrmPutLineResource(smBase, resSpec); return; } /*************************************<->************************************* * * PrintScreenSaver (smBase) * * * Description: * ----------- * A convenience function that is separated out instead of being included * in both QueryServerSettings, and SaveCustomizeSettings. * Saves screen saver information to the named resource file. * * Inputs: * ------ * smBase = pointer to newly opened resource db used to store setting info * resSpec = a buffer to hold string resource information until it is * printed. * * Outputs: * ------- * * Comments: * -------- * *************************************<->***********************************/ static void PrintScreenSaver( XrmDatabase *smBase) { Status newScreenStat; char tmpChar[20]; if(smCust.screenSavChange == True) { newScreenStat = _DtGetSmScreen(smGD.display, smGD.topLevelWindow, XaDtSmScreenInfo, &screenSaverVals); /* * If the property has been deleted, it means that we return to * the default */ if(newScreenStat != Success) { return; } } strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCtimeout); strcat(resSpec, ":"); sprintf(tmpChar, "%d", screenSaverVals.smTimeout); strcat(resSpec, tmpChar); XrmPutLineResource(smBase, resSpec); strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCinterval); strcat(resSpec, ":"); sprintf(tmpChar, "%d", screenSaverVals.smInterval); strcat(resSpec, tmpChar); XrmPutLineResource(smBase, resSpec); strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCpreferBlank); strcat(resSpec, ":"); sprintf(tmpChar, "%d", screenSaverVals.smPreferBlank); strcat(resSpec, tmpChar); XrmPutLineResource(smBase, resSpec); strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCallowExp); strcat(resSpec, ":"); sprintf(tmpChar, "%d", screenSaverVals.smAllowExp); strcat(resSpec, tmpChar); XrmPutLineResource(smBase, resSpec); return; } /*************************************<->************************************* * * PrintFontPaths (smBase, fontPaths, numPaths) * * * Description: * ----------- * A convenience function that is separated out instead of being included * in both QueryServerSettings, and SaveCustomizeSettings. * Saves pointer control information to the named resource file. * * Inputs: * ------ * smBase = pointer to newly opened resource db used to store setting info * resSpec = a buffer to hold string resource information until it is * printed * fontPaths = font paths to be saved * numPaths = number of font paths to be saved * * Outputs: * ------- * resSize = made bigger if current buffer is too small to hold all font info * * Comments: * -------- * *************************************<->***********************************/ static int PrintFontPaths( XrmDatabase *smBase, char **fontPath, int numPaths) { int i; /* If no fp save req'd, just pretend we did it */ if (smRes.saveFontPath == False) return 0; strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCfontPath); strcat(resSpec, ":"); strcat(resSpec, *fontPath); for(i = 1;i < numPaths;i++) { if((strlen(resSpec) + strlen(fontPath[i]) + 1) >= resSize) { resSize += 5000; resSpec = (char *) SM_REALLOC(resSpec, resSize * sizeof(char)); if (resSpec==NULL) { PrintErrnoError(DtError, smNLS.cantMallocErrorString); return(-1); } } strcat(resSpec, ","); strcat(resSpec, fontPath[i]); } XrmPutLineResource(smBase, resSpec); return(0); } /*************************************<->************************************* * * PrintKeyboardControl (smBase) * * * Description: * ----------- * A convenience function that is separated out instead of being included * in both QueryServerSettings, and SaveCustomizeSettings. * Saves pointer control information to the named resource file. * * Inputs: * ------ * smBase = pointer to newly opened resource db used to store setting info * resSpec = a buffer to hold string resource information until it is * printed * resSize = size of current resource buffer * * Outputs: * ------- * resSize = buffer is enlarged if more room is need to hold this info * * Comments: * -------- * *************************************<->***********************************/ static int PrintKeyboardControl( XrmDatabase *smBase) { int i,j; char bitTest; Bool firstRepeat = True; char tmpChar[20]; strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCkeyClick); strcat(resSpec, ":"); sprintf(tmpChar, "%d",smSettings.kbdState.key_click_percent); strcat(resSpec, tmpChar); XrmPutLineResource(smBase, resSpec); strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCbellPercent); strcat(resSpec, ":"); sprintf(tmpChar, "%d",smSettings.kbdState.bell_percent); strcat(resSpec, tmpChar); XrmPutLineResource(smBase, resSpec); strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCbellPitch); strcat(resSpec, ":"); sprintf(tmpChar, "%d",smSettings.kbdState.bell_pitch); strcat(resSpec, tmpChar); XrmPutLineResource(smBase, resSpec); strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCbellDuration); strcat(resSpec, ":"); sprintf(tmpChar, "%d",smSettings.kbdState.bell_duration); strcat(resSpec, tmpChar); XrmPutLineResource(smBase, resSpec); strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCledMask); strcat(resSpec, ":"); sprintf(tmpChar, "%ld",smSettings.kbdState.led_mask); strcat(resSpec, tmpChar); XrmPutLineResource(smBase, resSpec); strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCglobalRepeats); strcat(resSpec, ":"); sprintf(tmpChar, "%d",smSettings.kbdState.global_auto_repeat); strcat(resSpec, tmpChar); XrmPutLineResource(smBase, resSpec); strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCautoRepeats); strcat(resSpec, ":"); /* * Now write out which keys need to be auto repeated one at a time */ if(smSettings.kbdState.global_auto_repeat != AutoRepeatModeOn) { for(i = 0;i < 32;i++) { bitTest = 0x01; for(j = 0;j < 8;j++) { if((bitTest & smSettings.kbdState.auto_repeats[i]) != 0) { if(firstRepeat == True) { firstRepeat = False; } else { strcat(resSpec, ","); } if((strlen(resSpec) + 5) >= resSize) { resSize += 5000; resSpec = (char *) SM_REALLOC(resSpec, resSize * sizeof(char)); if (resSpec==NULL) { PrintErrnoError(DtError, smNLS.cantMallocErrorString); return(-1); } } sprintf(tmpChar, "%d", ((8 * i) + j)); strcat(resSpec, tmpChar); } bitTest <<= 1; } } } else { strcat(resSpec, ""); } XrmPutLineResource(smBase, resSpec); return(0); } /*************************************<->************************************* * * PrintPointerMapping (smBase, buttonRet, numButton) * * * Description: * ----------- * A convenience function that is separated out instead of being included * in both QueryServerSettings, and SaveCustomizeSettings. * Saves pointer mapping information to the named resource file. * * Inputs: * ------ * smBase = pointer to newly opened resource db used to store setting info * resSpec = a buffer to hold string resource information until it is * printed * resSize = size of resource buffer * buttonRet = button mapping to be saved * numButton = number of buttons in button mapping * * Outputs: * ------- * resSize = size of buffer is change if it needs to be enlarged during * routine * * Comments: * -------- * *************************************<->***********************************/ static int PrintPointerMapping( XrmDatabase *smBase, char *buttonRet, int numButton ) { int i, numLoops; char tmpChar[20]; strcpy(resSpec, SM_RESOURCE_CLASS); strcat(resSpec, "*"); strcat(resSpec, SmCbuttonMap); strcat(resSpec, ":"); numLoops = numButton - 1; for(i = 0;i <= numLoops;i++) { if((strlen(resSpec) + 5) >= resSize) { resSize += 5000; resSpec = (char *) SM_REALLOC(resSpec, resSize * sizeof(char)); if (resSpec==NULL) { PrintErrnoError(DtError, smNLS.cantMallocErrorString); return(-1); } } sprintf(tmpChar, "%d",buttonRet[i]); strcat(resSpec, tmpChar); if(i != numLoops) { strcat(resSpec, ","); } XrmPutLineResource(smBase, resSpec); } return(0); }