2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $TOG: SmSave.c /main/27 1998/07/23 18:07:58 mgreess $ */
24 /*************************************<+>*************************************
25 *****************************************************************************
29 ** Project: HP DT Session Manager (dtsession)
33 ** This file contains all routines that save off the session at any point
34 ** in time. The session includes settings, resources, and clients. How
35 ** the session manager behaves during a save depends on how the user has
36 ** configured it to behave.
39 *****************************************************************************
40 *************************************<+>*************************************/
42 * (c) Copyright 1997 The Open Group
43 * (c) Copyright 1996 Digital Equipment Corporation.
44 * (c) Copyright 1990, 1993, 1994, 1996 Hewlett-Packard Company.
45 * (c) Copyright 1993, 1994, 1996 International Business Machines Corp.
46 * (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc.
47 * (c) Copyright 1993, 1994, 1996 Novell, Inc.
48 * (c) Copyright 1996 FUJITSU LIMITED.
49 * (c) Copyright 1996 Hitachi.
56 #include <sys/types.h>
58 #include <sys/param.h>
60 #include <sys/socket.h>
61 #include <netinet/in.h>
64 #include <arpa/inet.h>
68 #include <X11/Intrinsic.h>
69 #include <X11/Xutil.h>
70 #include <X11/Xatom.h>
71 #include <X11/StringDefs.h>
72 #include <X11/keysymdef.h>
74 #include <Dt/Connect.h>
75 #include <Dt/UserMsg.h>
76 #include <Dt/SessionM.h>
77 #include <Dt/MsgLog.h>
80 #include "SmResource.h"
82 #include "SmGlobals.h"
85 #include "SmProtocol.h"
86 #include "SmRestore.h"
89 #include "SmProperty.h"
92 #include "SrvFile_io.h"
100 #include <X11/Xlibint.h>
103 typedef struct _ProxyClientCache {
106 } ProxyClientCache, *ProxyClientCachePtr;
108 static ProxyClientCachePtr proxyList;
109 static int numProxyClients = 0;
110 static int numProxyAllocated = 0;
111 static int proxyCacheAllocIncrement = 10;
114 * Local Function Declarations
116 static void CacheProxyClient (
121 static void PruneSessionDirectory ();
123 static Boolean WriteClientDatabase ();
125 static void OutputXSMPClients (
128 static void OutputProxyClients (
131 static Boolean CheckRequiredProperties (
132 ClientRecPtr pClientRec);
134 static void PrintStartupInfo(
138 static int QueryServerSettings( void ) ;
139 static int SaveCustomizeSettings( void ) ;
140 static int OutputResource( void ) ;
141 static void PrintPointerControl(
142 XrmDatabase *smBase) ;
143 static void PrintSessionInfo(
144 XrmDatabase *smBase) ;
145 static void PrintScreenSaver(
146 XrmDatabase *smBase) ;
147 static int PrintFontPaths(
151 static int PrintKeyboardControl(
152 XrmDatabase *smBase);
153 static int PrintPointerMapping(
157 static void PrintWorkHintString(
160 static void PrintCmdHintString(
163 static void PrintCmdString(
166 static void PrintRemoteCmdString(
172 * Global variables that are exposed
174 SmScreenInfo screenSaverVals;
175 SmAudioInfo audioVals;
176 SmKeyboardInfo keyboardVals;
179 * Variables global to this module only
183 * used as a buffer to write resources into
184 * before they are written out
186 static int resSize = 10000;
187 static char *resSpec;
190 * Vars used to maintain state that is sent to the SaveState
193 static Boolean saveHome;
199 /*************************************<->*************************************
205 * Do all of the preliminary work that must be done before the state
206 * of a checkpoint can be saved.
210 * saveToHome: This session is to be saved to the home session or current
211 * mode = whether the session is to be reset or restarted
213 *************************************<->***********************************/
219 unsigned char *propData;
222 * Cache saveToHome and mode - they will be needed after all of
223 * the XSMP clients are saved and the Proxy clients are saved.
225 saveHome = saveToHome;
229 * First set up the save paths so we know if we have to do anything here
231 if ((SetSavePath(saveToHome, mode)) == -1)
235 * Take care of the save mode property on the root window so that the
236 * clients will know how to save this file (if they save files)
238 if(saveToHome == False)
240 propData = (unsigned char *) SM_CURRENT_DIRECTORY;
244 propData = (unsigned char *) SM_HOME_DIRECTORY;
248 * Change the save mode to give the subdirectory saved to
251 XChangeProperty(smGD.display, RootWindow(smGD.display, 0),
252 XaSmSaveMode, XA_STRING, 8, PropModeReplace,
253 propData, strlen((char *)propData));
254 XFlush(smGD.display);
257 /*************************************<->*************************************
263 * Tells the SM to notify the XSMP clients to save their state.
264 * The function CompleteSave fill be invoked after the XSMP clients
265 * have completed their save.
269 * saveToHome: This session is to be saved to the home session or current
270 * mode = whether the session is to be reset or restarted
274 * As a result of this routine files will be saved in the users .dt directory
275 * that will allow the session manager to restore the session at a later
278 * NOTE - this function is called as the result of the following
281 * 1. User initiates a Save Home Session via the Style Manager
282 * 2. The Session Manager receives a SM_XSESSION_EXIT message
283 * 3. The Session Manager receives a SM_SAVE_SESSION message
285 *************************************<->***********************************/
297 * Notify XSMP clients of the save
299 SaveYourselfReqProc (NULL, NULL, saveType, shutdown, interactStyle,
304 /*************************************<->*************************************
310 * Called after the XSMP clients have saved their state. In charge of
311 * calling all routines that save session information for XSMP client
312 * and Proxy clients as well as settings, resources, etc.
317 *************************************<->***********************************/
323 unsigned char *propData;
324 char *tmpPath, tmpVersion[20];
326 Boolean saveToHome = saveHome;
330 * If this is a Home session and the user is logging out, return
331 * now - the XSMP clients have all responded to the save and the
332 * ICCC clients don't save their state when a Home session is
335 if (smGD.sessionType == HOME_SESSION &&
336 smXSMP.saveState.shutdown == True &&
337 smSettings.startState == DtSM_HOME_STATE)
341 * Start a wait state - don't want anything to happen while
342 * ICCC clients are being saved
346 resSpec = (char *) SM_MALLOC(resSize * sizeof(char));
349 PrintErrnoError(DtError, smNLS.cantMallocErrorString);
353 if (!WriteClientDatabase ()) {
354 ShowWaitState(False);
360 * WARNING - THIS VARIABLE MUST BE SET BEFORE THE SETTING INFORMATION IS
361 * CALLED - SETTINGS MUST BE SAVED BEFORE RESOURCES BECAUSE SETTINGS
362 * GETS INFORMATION SAVED IN RESOURCES (smToSet.dClickBuf)
364 smToSet.dClickBuf[0] = 0;
367 * Do the actual output of the X settings information. Output will
368 * go to the resource database at this point and be written to the
369 * resource file with the rest of the resources (below).
371 if(smRes.querySettings == True)
373 QueryServerSettings();
377 SaveCustomizeSettings();
381 * Do the output of resource information.
385 ShowWaitState(False);
390 XDeleteProperty(smGD.display, DefaultRootWindow(smGD.display), XaSmSaveMode);
393 * Go save the default palette at this time
395 if(saveToHome == True)
396 SaveDefaultPalette(smGD.display, smGD.savePath, DtSM_HOME_STATE);
398 SaveDefaultPalette(smGD.display, smGD.savePath, mode);
400 PruneSessionDirectory ();
402 ShowWaitState(False);
408 /*************************************<->*************************************
410 * PruneSessionDirectory -
412 * Description: Removes the oldest session direcotry if the number
413 * of directories exceeds the smRes.numSessionsBackedup.
417 *************************************<->***********************************/
419 PruneSessionDirectory ()
428 char *oldDir; /* the .old dir */
433 if ((dirp = opendir (smGD.savePath)) == NULL)
436 clientDB = (char*) XtMalloc((2*MAXPATHLEN) + 1);
437 oldestDir = (char*) XtMalloc(MAXPATHLEN + 1);
438 saveDir = (char*) XtMalloc(MAXPATHLEN + 1);
439 tmpDir = (char*) XtMalloc(MAXPATHLEN + 1);
441 dirPrefix = XtMalloc (strlen (smGD.restoreSession) + 2);
442 sprintf (dirPrefix, "%s.", smGD.restoreSession);
443 if (strlen (dirPrefix) > 5) {
445 dirPrefix[5] = '\000';
448 oldDir = XtMalloc (strlen (smGD.restoreSession) +
449 strlen (SM_OLD_EXTENSION) + 2);
450 sprintf (oldDir, "%s.%s", smGD.restoreSession, SM_OLD_EXTENSION);
452 (void) time (&oldestTime);
454 while ((dp = readdir (dirp)) != NULL) {
456 * Do some sanity checks to limit the number of * stat()
457 * calls. Note that for backward compatibility with CDE
458 * 1.0 if a ".old" directory exists, keep it.
460 if ((!strcmp (dp->d_name, ".")) ||
461 (!strcmp (dp->d_name, "..")) ||
462 (!strcmp (dp->d_name, oldDir)) ||
463 (strncmp (dp->d_name, dirPrefix, strlen (dirPrefix))))
466 sprintf (tmpDir, "%s/%s", smGD.savePath, dp->d_name);
468 if (((stat (tmpDir, &buf)) == 0) && S_ISDIR (buf.st_mode)) {
469 if (buf.st_mtime < oldestTime) {
471 * Keep track of the oldest dir in case
472 * it needs to be removed
474 oldestTime = buf.st_mtime;
475 strcpy (oldestDir, tmpDir);
482 if (numDirs > smRes.numSessionsBackedup) {
484 * Need to remove the oldest directory. The general
485 * process (using "home" as an example) is:
489 * Execute the DiscardCommand props in the home directory
493 * The reason this is done is because when the
494 * DiscardCommand were saved, the directory at the time of
495 * the save contained "home". For example, a DiscardCommand
498 * rm -f /u/somebody/.dt/sessions/home/app.state
500 * yet because of the session archiving, the app.state
501 * file may actually be in a directory like:
503 * /u/somebody/.dt/sessions/home.<tempnam>
509 tmpName = (char *) XtMalloc (strlen (smGD.restoreSession) + 2);
510 sprintf (tmpName, "%s.", smGD.restoreSession);
511 if (strlen (tmpName) > 5) {
515 tmp = (char *) tempnam (smGD.savePath, tmpName);
517 sprintf (saveDir, "%s/%s", smGD.savePath, smGD.restoreSession);
519 MoveDirectory (saveDir, tmp, False);
520 MoveDirectory (oldestDir, saveDir, False);
522 sprintf (clientDB, "%s/%s/%s", smGD.savePath,
523 smGD.restoreSession, SM_CLIENT_FILE2);
525 ExecuteDiscardCommands (clientDB);
527 MoveDirectory (tmp, saveDir, True);
534 * If exiting and the current session is a Current session
535 * but smSettings.startState has been set to to a
536 * Home session (this would be true if a user started a
537 * Current session but used the Style Manager to set the session
538 * upon next login to be a Home session), then if a home
539 * directory exists, mv current to current.old
542 if (smXSMP.saveState.shutdown && smGD.sessionType == CURRENT_SESSION &&
543 smSettings.startState == DtSM_HOME_STATE) {
545 sprintf (tmpDir, "%s/%s", smGD.savePath, SM_HOME_DIRECTORY);
547 if (((stat (tmpDir, &buf)) == 0) && S_ISDIR (buf.st_mode)) {
549 sprintf (saveDir, "%s/%s", smGD.savePath, oldDir);
551 if (((stat (saveDir, &buf)) == 0) &&
552 S_ISDIR (buf.st_mode)) {
554 sprintf (clientDB, "rm -rf %s", saveDir);
555 SystemCmd (clientDB);
557 sprintf (oldestDir, "%s/%s", smGD.savePath,
558 SM_CURRENT_DIRECTORY);
560 MoveDirectory (oldestDir, saveDir, False);
574 /*************************************<->*************************************
576 * WriteClientDatabase -
578 * Description: Writes the client database (for XSMP and Proxy clients)
582 * Returns True if the database is wrtten OK; False otherwise
584 *************************************<->***********************************/
586 WriteClientDatabase ()
591 db = (char*) XtMalloc(MAXPATHLEN + 1);
592 (void) sprintf (db, "%s/%s/%s", smGD.savePath, smGD.restoreSession,
595 if ((outputDB = OpenOutputClientDB (db, smXSMP.dbVersion,
596 smXSMP.dbSessionId)) == NULL) {
599 str = strdup ((char *) GETMESSAGE (40, 18,
600 "The following database file cannot be opened for writing:\n\n %s\n\nThe session will not be saved."));
603 DtMsgLogMessage (smGD.programName, DtMsgLogError,
613 OutputProxyClients (outputDB);
615 OutputXSMPClients (outputDB);
617 CloseClientDB (outputDB, True);
623 /*************************************<->*************************************
625 * OutputProxyClients -
627 * Description: Outputs the Proxy clients
629 * Inputs: database pointer
633 *************************************<->***********************************/
639 for (i = 0; i < numProxyClients; i++)
640 PrintStartupInfo (outputDB,
642 proxyList[i].window);
646 /*************************************<->*************************************
648 * OutputXSMPClients -
650 * Description: Outputs the XSMP clients
652 * Inputs: database pointer
656 *************************************<->***********************************/
661 XSMPClientDBRec dbRec;
662 ClientRecPtr pClientRec;
664 for (pClientRec = connectedList; pClientRec != NULL;
665 pClientRec = pClientRec->next) {
667 dbRec.restartHint = pClientRec->restartHint;
668 (void) GetCardPropertyValue (pClientRec, SmRestartStyleHint,
671 if (dbRec.restartHint == SmRestartNever)
674 if (!pClientRec->active)
677 if (!CheckRequiredProperties (pClientRec))
682 dbRec.clientId = pClientRec->clientId;
683 dbRec.clientHost = pClientRec->clientHost;
685 dbRec.program = GetArrayPropertyValue (pClientRec,
687 dbRec.cwd = GetArrayPropertyValue (pClientRec,
690 dbRec.restartCommand = GetListOfArrayPropertyValue (pClientRec,
692 dbRec.cloneCommand = GetListOfArrayPropertyValue (pClientRec,
694 dbRec.discardCommand = GetListOfArrayPropertyValue (pClientRec,
696 dbRec.environment = GetListOfArrayPropertyValue (pClientRec,
699 if (!PutXSMPClientDBRec (outputDB, &dbRec)) {
703 str = strdup ((char *) GETMESSAGE (40, 19,
704 "Application '%s' cannot be saved."));
707 DtMsgLogMessage (smGD.programName,
714 if (dbRec.restartCommand)
715 XtFree ((char *) dbRec.restartCommand);
716 if (dbRec.cloneCommand)
717 XtFree ((char *) dbRec.cloneCommand);
718 if (dbRec.discardCommand)
719 XtFree ((char *) dbRec.discardCommand);
720 if (dbRec.environment)
721 XtFree ((char *) dbRec.environment);
726 /*************************************<->*************************************
728 * CheckRequiredProperties -
730 * Description: Check a client's required properties
732 * Inputs: ClientRecPtr
734 * Returns: True if the client has all of the required properties;
735 * otherwise returns False
737 *************************************<->***********************************/
739 CheckRequiredProperties (
740 ClientRecPtr pClientRec)
742 PropertyRecPtr pPropRec;
744 char * program = NULL;
746 if ((program = GetArrayPropertyValue (pClientRec, SmProgram)) == NULL){
748 str = strdup ((char *) GETMESSAGE (40, 23,
749 "The following application did not set the required\nproperty '%s':\n\n %s\n\nThis application will not be saved."));
752 DtMsgLogMessage (smGD.programName, DtMsgLogError, str,
753 SmProgram, pClientRec->clientId);
759 if ((pPropRec = GetPropertyRec (pClientRec, SmRestartCommand)) == NULL){
761 str = strdup ((char *) GETMESSAGE (40, 24,
762 "24 Application '%s' will not be saved because it did not set\nthe required property '%s'."));
765 DtMsgLogMessage (smGD.programName, DtMsgLogError,
766 str, program, SmRestartCommand);
772 if ((pPropRec = GetPropertyRec (pClientRec, SmCloneCommand)) == NULL) {
774 * This is a warning - still want to save the client
776 str = strdup ((char *) GETMESSAGE (40, 25,
777 "Application '%s' did not set the required property '%s'."));
780 DtMsgLogMessage (smGD.programName, DtMsgLogWarning, str,
781 program, SmCloneCommand);
790 /*************************************<->*************************************
792 * NotifyProxyClients -
797 * Notify Proxy clients - calls routines to find top level windows, and
798 * notifies the Proxy clients about an impending save.
806 *************************************<->***********************************/
808 NotifyProxyClients ( )
810 unsigned int topListLength, containedListLength;
811 WindowInfo * topList; /* list of top-level windows */
812 WindowInfo topLevelWindowInfo;
815 unsigned long nitems;
816 unsigned long leftover;
817 unsigned char * data = NULL;
818 Boolean containedClient;
823 * Save off the clients currently running. This will be done
824 * one screen at a time
826 for(j = 0;j < smGD.numSavedScreens;j++)
829 * Get a list of children of the root window. If there are none
830 * return with an error condition.
832 if(GetTopLevelWindows(j,&topList,&topListLength, &containedListLength))
836 * Figure out how to restart the client associate with each window.
838 for (i=0 ; i<(topListLength + containedListLength); ++i)
840 topLevelWindowInfo=topList[i];
842 if(i >= topListLength)
844 containedClient = True;
848 containedClient = False;
852 * If this window is my window - skip it I don't want to
853 * save myself because I will be started automatically
855 if (XGetWindowProperty(smGD.display, topLevelWindowInfo.wid,
857 (long)BUFSIZ,False,XA_STRING,&actualType,
858 &actualFormat,&nitems,&leftover,
861 if (actualType==XA_STRING &&
862 !strcmp((char *) data, SM_RESOURCE_NAME))
864 SM_FREE((char *)data);
869 SM_FREE((char *)data);
874 * If the client participates in the WM_SAVE_YOURSELF protocol,
875 * send the appropriate messages and wait for the proper
878 (void) SaveYourself(topLevelWindowInfo);
880 CacheProxyClient ((numClients == 0), j, topLevelWindowInfo.wid);
886 * Free space malloc'd by GetTopLevelWindowInfo
888 if(topListLength > 0)
890 SM_FREE((char *) topList);
896 /*************************************<->*************************************
902 * Add a Proxy client to the proxy client cache.
906 * firstClient - if True, this is the first client in the cache
907 * screenNum - the client's screen number
908 * window - the client's window number
913 *************************************<->***********************************/
914 static void CacheProxyClient (
922 if (numProxyClients >= numProxyAllocated) {
923 numProxyAllocated += proxyCacheAllocIncrement;
924 proxyList = (ProxyClientCachePtr) XtRealloc ((char *) proxyList,
925 numProxyAllocated * sizeof (ProxyClientCache));
928 proxyList[numProxyClients].screen = screenNum;
929 proxyList[numProxyClients].window = window;
936 /*************************************<->*************************************
942 * Output startup information for one proxy client
946 * outputDB = a pointer to the client database
947 * screen = which screen the client is running on
948 * window = the top level window of the lient
956 *************************************<->***********************************/
967 XWindowAttributes windowAttr;
970 ProxyClientDBRec dbRec;
975 #ifdef _SUN_OS /* pull out quotes from OpenWindow tools commands */
980 * Get the attributes and properties on the window
982 if ((XGetWindowAttributes(smGD.display, window, &windowAttr)) == 0)
985 if (GetStandardProperties(window, screen, &wargc, &wargv,
986 &clientMachine, &xsmpClient)==0)
990 * If the client doesn't have a WM_COMMAND property, we can't restart it
992 if (!wargv||!wargv[0])
996 * If the client is an XSMP client, don't save it as a Proxy client.
1001 #ifdef _SUN_OS /* pull out quotes from OpenWindow tools commands */
1004 /* check for foreground */
1005 if ((ptr = strstr (ptr, "fg \"")) != NULL) {
1006 if (strlen (ptr) > 3)
1008 if ((ptr = strchr (ptr, '"')) != NULL)
1012 /* check for background */
1013 if ((ptr = strstr (wargv[0], "bg \"")) != NULL) {
1014 if (strlen (ptr) > 3)
1016 if ((ptr = strchr (ptr, '"')) != NULL)
1023 * Find out if the client is running locally
1025 dbRec.clientHost = NULL;
1026 if(clientMachine != NULL)
1028 if(DtIsLocalHostP(clientMachine) == FALSE)
1030 dbRec.clientHost = clientMachine;
1035 * Must NULL-terminate the WM_COMMAND before writing it
1037 argv = (char **) XtMalloc ((wargc + 1) * sizeof (char *));
1041 for (i = 0; i < wargc; i++)
1045 dbRec.command = argv;
1046 dbRec.screenNum = screen;
1048 writeStatus = PutProxyClientDBRec (outputDB, &dbRec);
1050 XtFree ((char *) argv);
1052 if (writeStatus == False)
1055 * There should be an error written here - however
1056 * since this means that there already is a write error to
1057 * the disk - no error can be written
1059 (void) CloseClientDB (outputDB, True);
1062 * On a write error - move the old session back to
1063 * be used and exit with an error condition
1065 XFreeStringList(wargv);
1067 strcat(smGD.savePath, "/");
1068 if(smGD.sessionType == HOME_SESSION)
1070 strcat(smGD.savePath, SM_HOME_DIRECTORY);
1074 strcat(smGD.savePath, SM_CURRENT_DIRECTORY);
1077 MoveDirectory(smGD.etcPath, smGD.savePath, False);
1082 * Free up the argv property
1084 XFreeStringList(wargv);
1088 /*************************************<->*************************************
1090 * QueryServerSettings ()
1095 * Query the server for all it's current settings information, and then
1096 * write that information to the session managers settings resource file.
1100 * smGD.settingPath = (global) pointer to file where
1101 * setting info should be saved.
1108 * This routine slows down the session manager's shutdown process
1109 * considerably, and is therefore only called when the user specifies
1110 * that all settings should be queried. Otherwise, only settings set in
1111 * the customizer should be saved.
1113 *************************************<->***********************************/
1115 QueryServerSettings( void )
1119 KeySym *tmpSyms, tmpMod;
1120 XModifierKeymap *modMap;
1122 int numButton, numPaths;
1123 int buttonSize = 128;
1124 XrmDatabase smBase = NULL;
1128 buttonRet = (char *) SM_MALLOC(buttonSize * sizeof(char));
1129 if (buttonRet==NULL)
1131 PrintErrnoError(DtError, smNLS.cantMallocErrorString);
1136 * First set up all pointer control parameters
1137 * These are simple integer values that get saved
1138 * here, then read into a structure and set at restore
1141 XGetPointerControl(smGD.display, &smSettings.accelNum,
1142 &smSettings.accelDenom,
1143 &smSettings.threshold);
1144 PrintPointerControl(&smBase);
1147 * Get all the screen saver values. These are all simple integer
1148 * values that are read back into a structure and set at restore
1151 XGetScreenSaver(smGD.display, &screenSaverVals.smTimeout,
1152 &screenSaverVals.smInterval,
1153 &screenSaverVals.smPreferBlank,
1154 &screenSaverVals.smAllowExp);
1155 PrintScreenSaver(&smBase);
1158 * Write out all font path information.
1159 * Write out all the paths one by one concatenated by commas.
1161 fontPath = XGetFontPath(smGD.display, &numPaths);
1162 if(fontPath != NULL)
1164 if(PrintFontPaths(&smBase, fontPath, numPaths) != 0)
1166 XFreeFontPath(fontPath);
1173 * Write out all the keyboard control information.
1175 XGetKeyboardControl(smGD.display, &smSettings.kbdState);
1176 if(PrintKeyboardControl(&smBase) != 0)
1179 XFreeFontPath(fontPath);
1184 * Put all the button modifier information into the resource database.
1185 * Find out the number of buttons and then write out the character
1186 * string for each button.
1188 numButton = XGetPointerMapping(smGD.display, (unsigned char *)buttonRet, 128);
1191 buttonRet = (char *) SM_REALLOC(buttonRet, numButton * sizeof(char));
1192 if (buttonRet==NULL)
1195 XFreeFontPath(fontPath);
1196 PrintErrnoError(DtError, smNLS.cantMallocErrorString);
1199 numButton = XGetPointerMapping(smGD.display, (unsigned char *)buttonRet, numButton);
1201 if(PrintPointerMapping(&smBase, buttonRet,
1205 XFreeFontPath(fontPath);
1211 * Put all keyboard mapping information in the resource database
1212 * Don't bother putting this in a separate print function because
1213 * the customizer doesn't do keymap savings this way.
1215 smSettings.numKeyCode = smGD.display->max_keycode -
1216 smGD.display->min_keycode;
1217 tmpSyms = XGetKeyboardMapping(smGD.display,
1218 (KeyCode) smGD.display->min_keycode,
1219 smSettings.numKeyCode,
1220 &smSettings.keySymPerCode);
1224 XFreeFontPath(fontPath);
1226 PrintErrnoError(DtError, smNLS.cantMallocErrorString);
1230 strcpy(resSpec, SM_RESOURCE_CLASS);
1231 strcat(resSpec, "*");
1232 strcat(resSpec, SmCnumKeyCode);
1233 strcat(resSpec, ":");
1234 sprintf(tmpChar,"%d", smSettings.numKeyCode);
1235 strcat(resSpec, tmpChar);
1236 XrmPutLineResource( &smBase, resSpec);
1238 strcpy(resSpec, SM_RESOURCE_CLASS);
1239 strcat(resSpec, "*");
1240 strcat(resSpec, SmCkeySymsPerKey);
1241 strcat(resSpec, ":");
1242 sprintf(tmpChar,"%d", smSettings.keySymPerCode);
1243 strcat(resSpec, tmpChar);
1244 XrmPutLineResource( &smBase, resSpec);
1246 strcpy(resSpec, SM_RESOURCE_CLASS);
1247 strcat(resSpec, "*");
1248 strcat(resSpec, SmCkeySyms);
1249 strcat(resSpec, ":");
1250 numLoops = smSettings.numKeyCode * smSettings.keySymPerCode;
1251 sprintf(tmpChar,"%ld", tmpSyms[0]);
1252 strcat(resSpec, tmpChar);
1253 for(i = 1;i < numLoops;i++)
1255 if((strlen(resSpec) + 5) >= resSize)
1258 resSpec = (char *) SM_REALLOC(resSpec, resSize * sizeof(char));
1261 SM_FREE((char *)tmpSyms);
1263 SM_FREE((char *)fontPath);
1265 PrintErrnoError(DtError, smNLS.cantMallocErrorString);
1269 strcat(resSpec, ",");
1270 sprintf(tmpChar,"%ld", tmpSyms[i]);
1271 strcat(resSpec, tmpChar);
1273 XrmPutLineResource( &smBase, resSpec);
1277 * Write out all keyboard modifier info. This will be a pretty slow
1278 * process considering that every keycode will have to be turned into
1279 * a keysym before writing. Don't bother putting print stuff in a
1280 * separate function because it will not be handled in the customize
1283 modMap = XGetModifierMapping(smGD.display);
1286 SM_FREE((char *)tmpSyms);
1288 XFreeFontPath(fontPath);
1290 PrintErrnoError(DtError, smNLS.cantMallocErrorString);
1294 strcpy(resSpec, SM_RESOURCE_CLASS);
1295 strcat(resSpec, "*");
1296 strcat(resSpec, SmCmaxKeyPerMod);
1297 strcat(resSpec, ":");
1298 sprintf(tmpChar,"%d", modMap->max_keypermod);
1299 strcat(resSpec, tmpChar);
1300 XrmPutLineResource( &smBase, resSpec);
1302 strcpy(resSpec, SM_RESOURCE_CLASS);
1303 strcat(resSpec, "*");
1304 strcat(resSpec, SmCmodMap);
1305 strcat(resSpec, ":");
1306 numLoops = (8 * modMap->max_keypermod) - 1;
1307 for(i = 0;i <= numLoops;i++)
1309 if((strlen(resSpec) + 9) >= resSize)
1312 resSpec = (char *) SM_REALLOC(resSpec, resSize * sizeof(char));
1315 SM_FREE((char *)tmpSyms);
1316 XFreeModifiermap(modMap);
1318 XFreeFontPath(fontPath);
1320 PrintErrnoError(DtError, smNLS.cantMallocErrorString);
1324 tmpMod = XKeycodeToKeysym(smGD.display, modMap->modifiermap[i], 0);
1325 sprintf(tmpChar,"%ld", tmpMod);
1326 strcat(resSpec, tmpChar);
1329 strcat(resSpec, ",");
1332 XrmPutLineResource( &smBase, resSpec);
1336 * Print session manager settings
1338 PrintSessionInfo(&smBase);
1341 * Write settings resources out to disk
1343 XrmPutFileDatabase(smBase, smGD.settingPath);
1346 * Free all allocated resources
1349 XFreeFontPath(fontPath);
1350 SM_FREE((char *)tmpSyms);
1351 XFreeModifiermap(modMap);
1353 XrmDestroyDatabase(smBase);
1358 /*************************************<->*************************************
1360 * SaveCustomizeSettings ()
1365 * Saves those settings that have been set in the customizer during the
1366 * session to whatever values they were set to during the session.
1371 * smGD.resourcePath = (global) a pointer
1372 * to where the settings should be stored.
1381 * This routine is the default saved for saving settings. If the user
1382 * wants all settings saved, they have to set a resource saying that that
1385 *************************************<->***********************************/
1387 SaveCustomizeSettings( void )
1391 XrmDatabase smBase = NULL;
1392 char *tmpChar[20], *ptrRet = NULL, *tmpKey;
1397 if(smCust.pointerChange)
1399 newStat = _DtGetSmPointer(smGD.display, smGD.topLevelWindow,
1400 XaDtSmPointerInfo, &ptrRet);
1401 if(newStat != Success)
1403 smToSet.pointerChange = False;
1404 smToSet.pointerMapChange = False;
1408 sscanf(ptrRet, "%d %s %d %d %s",
1411 &smSettings.accelNum,
1412 &smSettings.threshold,
1413 &smToSet.dClickBuf);
1414 smSettings.accelDenom = 1;
1416 tmpKey = strtok(tmpMap, "_");
1418 while(tmpKey != NULL)
1420 smToSet.pointerMap[i] = (char) atoi(tmpKey);
1422 tmpKey = strtok(NULL, "_");
1427 * append a \n to dClickBuf because it was scanned out
1429 strcat(smToSet.dClickBuf, "\n");
1431 if (ptrRet) XFree(ptrRet);
1434 if(smToSet.pointerChange == True)
1436 PrintPointerControl(&smBase);
1439 if(smToSet.pointerMapChange == True)
1441 if(PrintPointerMapping(&smBase, smToSet.pointerMap,
1442 smToSet.numButton) != 0)
1448 if(smToSet.screenSavChange == True)
1450 PrintScreenSaver(&smBase);
1453 if(smCust.audioChange == True)
1455 newStat = _DtGetSmAudio(smGD.display, smGD.topLevelWindow,
1456 XaDtSmAudioInfo, &audioVals);
1458 if(newStat == Success)
1460 smSettings.kbdState.bell_percent = audioVals.smBellPercent;
1461 smSettings.kbdState.bell_pitch = audioVals.smBellPitch;
1462 smSettings.kbdState.bell_duration = audioVals.smBellDuration;
1466 smToSet.audioChange = False;
1470 if (smToSet.audioChange)
1472 strcpy(resSpec, SM_RESOURCE_CLASS);
1473 strcat(resSpec, "*");
1474 strcat(resSpec, SmCbellPercent);
1475 strcat(resSpec, ":");
1476 sprintf((char *)tmpChar,"%d",smSettings.kbdState.bell_percent);
1477 strcat(resSpec, (char *)tmpChar);
1478 XrmPutLineResource(&smBase, resSpec);
1480 strcpy(resSpec, SM_RESOURCE_CLASS);
1481 strcat(resSpec, "*");
1482 strcat(resSpec, SmCbellPitch);
1483 strcat(resSpec, ":");
1484 sprintf((char *)tmpChar,"%d",smSettings.kbdState.bell_pitch);
1485 strcat(resSpec, (char *)tmpChar);
1486 XrmPutLineResource(&smBase, resSpec);
1488 strcpy(resSpec, SM_RESOURCE_CLASS);
1489 strcat(resSpec, "*");
1490 strcat(resSpec, SmCbellDuration);
1491 strcat(resSpec, ":");
1492 sprintf((char *)tmpChar,"%d",smSettings.kbdState.bell_duration);
1493 strcat(resSpec, (char *)tmpChar);
1494 XrmPutLineResource(&smBase, resSpec);
1497 if(smCust.keyboardChange == True)
1499 newStat = _DtGetSmKeyboard(smGD.display, smGD.topLevelWindow,
1500 XaDtSmKeyboardInfo, &keyboardVals);
1501 if(newStat == Success)
1503 smSettings.kbdState.key_click_percent = keyboardVals.smKeyClickPercent;
1504 smSettings.kbdState.global_auto_repeat = keyboardVals.smGlobalAutoRepeat;
1508 smToSet.keyboardChange = False;
1512 if(smToSet.keyboardChange == True)
1514 strcpy(resSpec, SM_RESOURCE_CLASS);
1515 strcat(resSpec, "*");
1516 strcat(resSpec, SmCkeyClick);
1517 strcat(resSpec, ":");
1518 sprintf((char *)tmpChar,"%d", smSettings.kbdState.key_click_percent);
1519 strcat(resSpec, (char *)tmpChar);
1520 XrmPutLineResource(&smBase, resSpec);
1522 strcpy(resSpec, SM_RESOURCE_CLASS);
1523 strcat(resSpec, "*");
1524 strcat(resSpec, SmCglobalRepeats);
1525 strcat(resSpec, ":");
1526 sprintf((char *)tmpChar,"%d", smSettings.kbdState.global_auto_repeat);
1527 strcat(resSpec, (char *)tmpChar);
1528 XrmPutLineResource(&smBase, resSpec);
1533 * Write out all font path information.
1534 * Write out all the paths one by one concatenated by commas.
1537 fontPath = XGetFontPath(smGD.display, &numPaths);
1538 if(fontPath != NULL) {
1539 if(PrintFontPaths(&smBase, fontPath, numPaths) != 0) {
1540 XFreeFontPath(fontPath);
1546 * Save session manager settings
1548 PrintSessionInfo(&smBase);
1551 XFreeFontPath(fontPath);
1554 * Write settings resources out to disk
1556 XrmPutFileDatabase(smBase, smGD.settingPath);
1557 XrmDestroyDatabase(smBase);
1564 /*************************************<->*************************************
1571 * Save session resources by getting the current RESOURCE_MANAGER property
1572 * on the root window.
1576 * smGD.resourcePath = (global) file name
1577 * where property contents should be saved.
1585 * This method is not a 100% accurate representation of currently active
1586 * resources in the system. It is however, the best representation (the
1587 * values with the highest priority) without becoming overly invasive
1590 *************************************<->***********************************/
1592 OutputResource( void )
1596 unsigned long nitems, leftover;
1600 char *fontBuf = NULL, *langPtr, tmpChar[20], *sessionRes;
1603 char *preeditBuf = NULL;
1606 * Add anything to the Resource Manager property that needs to be added
1610 * Write out the LANG variable and the screen's Y resolution
1613 langPtr = getenv("LANG");
1614 if((langPtr != NULL) && (*langPtr != 0))
1616 sprintf(resSpec, "%s*%s: %s\n", SM_RESOURCE_NAME, SmNsessionLang,
1621 sprintf(resSpec, "%s*%s: \n", SM_RESOURCE_NAME, SmNsessionLang);
1624 fltYRes = ((float) DisplayHeight(smGD.display, 0) /
1625 (float) DisplayHeightMM(smGD.display, 0)) * 1000;
1630 strcpy(resSpec, SM_RESOURCE_NAME);
1634 strcat(resSpec, SM_RESOURCE_NAME);
1636 strcat(resSpec, "*");
1637 strcat(resSpec, SmNdisplayResolution);
1638 strcat(resSpec, ":");
1639 sprintf(tmpChar, "%d",intYRes);
1640 strcat(resSpec, tmpChar);
1641 strcat(resSpec, "\n");
1642 _DtAddToResource(smGD.display, resSpec);
1644 if(smCust.fontChange == True)
1646 newStat = _DtGetSmFont(smGD.display, smGD.topLevelWindow,
1647 XaDtSmFontInfo, &fontBuf);
1648 if(newStat == Success)
1651 * Create the auxillary resource file
1653 if(SetFontSavePath(langPtr) != -1)
1655 db = XrmGetStringDatabase(fontBuf);
1657 if(intYRes < MED_RES_Y_RES)
1659 sessionRes = SM_LOW_RES_EXT;
1663 if(intYRes >= HIGH_RES_Y_RES)
1665 sessionRes = SM_HIGH_RES_EXT;
1669 sessionRes = SM_MED_RES_EXT;
1673 strcat(smGD.fontPath, "/");
1674 strcat(smGD.fontPath, SM_FONT_FILE);
1676 strcat(smGD.fontPath, ".");
1677 strcat(smGD.fontPath, sessionRes);
1679 XrmPutFileDatabase(db, smGD.fontPath);
1680 XrmDestroyDatabase(db);
1684 * Now add this to the resource manager property to be saved
1686 _DtAddToResource(smGD.display, fontBuf);
1688 if (fontBuf) XFree(fontBuf);
1691 if(smCust.preeditChange == True)
1693 newStat = _DtGetSmPreedit(smGD.display, smGD.topLevelWindow,
1694 XaDtSmPreeditInfo, &preeditBuf);
1695 if(newStat == Success)
1697 _DtAddToResource(smGD.display, preeditBuf);
1699 if (preeditBuf) XFree(preeditBuf);
1702 if((smCust.dClickChange == True) && (smToSet.dClickBuf[0] != 0))
1704 _DtAddToResource(smGD.display, (char *)smToSet.dClickBuf);
1708 * Get the contents of the _DT_SM_PREFERENCES property
1710 data = _DtGetResString(smGD.display, _DT_ATR_PREFS);
1713 * Get _DT_SM_PREFERENCES database 'db'.
1715 db = XrmGetStringDatabase((char *)data);
1717 XrmPutFileDatabase(db, smGD.resourcePath);
1720 * Don't forget to free your data
1722 SM_FREE((char *)data);
1723 XrmDestroyDatabase(db);
1730 /*************************************<->*************************************
1732 * PrintPointerControl (smBase)
1737 * A convenience function that is separated out instead of being included
1738 * in both QueryServerSettings, and SaveCustomizeSettings.
1739 * Saves pointer control information to the named resource file.
1743 * smBase = pointer to newly opened resource db used to store setting info
1744 * resSpec = a buffer to hold string resource information until it is
1746 * smSettings = place where settings are stored.
1754 *************************************<->***********************************/
1756 PrintPointerControl(
1757 XrmDatabase *smBase)
1761 strcpy(resSpec, SM_RESOURCE_CLASS);
1762 strcat(resSpec, "*");
1763 strcat(resSpec, SmCaccelNum);
1764 strcat(resSpec, ":");
1765 sprintf(tmpChar, "%d", smSettings.accelNum);
1766 strcat(resSpec, tmpChar);
1767 XrmPutLineResource(smBase, resSpec);
1769 strcpy(resSpec, SM_RESOURCE_CLASS);
1770 strcat(resSpec, "*");
1771 strcat(resSpec, SmCaccelDenom);
1772 strcat(resSpec, ":");
1773 sprintf(tmpChar, "%d",smSettings.accelDenom);
1774 strcat(resSpec, tmpChar);
1775 XrmPutLineResource(smBase, resSpec);
1777 strcpy(resSpec, SM_RESOURCE_CLASS);
1778 strcat(resSpec, "*");
1779 strcat(resSpec, SmCthreshold);
1780 strcat(resSpec, ":");
1781 sprintf(tmpChar, "%d",smSettings.threshold);
1782 strcat(resSpec, tmpChar);
1783 XrmPutLineResource(smBase, resSpec);
1789 /*************************************<->*************************************
1791 * PrintSessionInfo (smBase)
1796 * A convenience function that is separated out instead of being included
1797 * in both QueryServerSettings, and SaveCustomizeSettings.
1798 * Saves session manager settings to the named resource file.
1802 * smBase = pointer to newly opened resource db used to store setting info
1803 * resSpec = a buffer to hold string resource information until it is
1805 * smSettings = place where settings are stored.
1813 *************************************<->***********************************/
1816 XrmDatabase *smBase)
1821 * Write out the settings for logout confirmation and
1822 * the correct session to return to
1824 strcpy(resSpec, SM_RESOURCE_CLASS);
1825 strcat(resSpec, "*");
1826 strcat(resSpec, SmCshutDownState);
1827 strcat(resSpec, ":");
1828 sprintf(tmpChar, "%d",smSettings.confirmMode);
1829 strcat(resSpec, tmpChar);
1830 XrmPutLineResource(smBase, resSpec);
1832 strcpy(resSpec, SM_RESOURCE_CLASS);
1833 strcat(resSpec, "*");
1834 strcat(resSpec, SmCshutDownMode);
1835 strcat(resSpec, ":");
1836 sprintf(tmpChar, "%d",smSettings.startState);
1837 strcat(resSpec, tmpChar);
1838 XrmPutLineResource(smBase, resSpec);
1844 /*************************************<->*************************************
1846 * PrintScreenSaver (smBase)
1851 * A convenience function that is separated out instead of being included
1852 * in both QueryServerSettings, and SaveCustomizeSettings.
1853 * Saves screen saver information to the named resource file.
1857 * smBase = pointer to newly opened resource db used to store setting info
1858 * resSpec = a buffer to hold string resource information until it is
1867 *************************************<->***********************************/
1870 XrmDatabase *smBase)
1872 Status newScreenStat;
1875 if(smCust.screenSavChange == True)
1877 newScreenStat = _DtGetSmScreen(smGD.display, smGD.topLevelWindow,
1878 XaDtSmScreenInfo, &screenSaverVals);
1880 * If the property has been deleted, it means that we return to
1883 if(newScreenStat != Success)
1889 strcpy(resSpec, SM_RESOURCE_CLASS);
1890 strcat(resSpec, "*");
1891 strcat(resSpec, SmCtimeout);
1892 strcat(resSpec, ":");
1893 sprintf(tmpChar, "%d", screenSaverVals.smTimeout);
1894 strcat(resSpec, tmpChar);
1895 XrmPutLineResource(smBase, resSpec);
1897 strcpy(resSpec, SM_RESOURCE_CLASS);
1898 strcat(resSpec, "*");
1899 strcat(resSpec, SmCinterval);
1900 strcat(resSpec, ":");
1901 sprintf(tmpChar, "%d", screenSaverVals.smInterval);
1902 strcat(resSpec, tmpChar);
1903 XrmPutLineResource(smBase, resSpec);
1905 strcpy(resSpec, SM_RESOURCE_CLASS);
1906 strcat(resSpec, "*");
1907 strcat(resSpec, SmCpreferBlank);
1908 strcat(resSpec, ":");
1909 sprintf(tmpChar, "%d", screenSaverVals.smPreferBlank);
1910 strcat(resSpec, tmpChar);
1911 XrmPutLineResource(smBase, resSpec);
1913 strcpy(resSpec, SM_RESOURCE_CLASS);
1914 strcat(resSpec, "*");
1915 strcat(resSpec, SmCallowExp);
1916 strcat(resSpec, ":");
1917 sprintf(tmpChar, "%d", screenSaverVals.smAllowExp);
1918 strcat(resSpec, tmpChar);
1919 XrmPutLineResource(smBase, resSpec);
1925 /*************************************<->*************************************
1927 * PrintFontPaths (smBase, fontPaths, numPaths)
1932 * A convenience function that is separated out instead of being included
1933 * in both QueryServerSettings, and SaveCustomizeSettings.
1934 * Saves pointer control information to the named resource file.
1938 * smBase = pointer to newly opened resource db used to store setting info
1939 * resSpec = a buffer to hold string resource information until it is
1941 * fontPaths = font paths to be saved
1942 * numPaths = number of font paths to be saved
1946 * resSize = made bigger if current buffer is too small to hold all font info
1951 *************************************<->***********************************/
1954 XrmDatabase *smBase,
1960 /* If no fp save req'd, just pretend we did it */
1961 if (smRes.saveFontPath == False) return 0;
1963 strcpy(resSpec, SM_RESOURCE_CLASS);
1964 strcat(resSpec, "*");
1965 strcat(resSpec, SmCfontPath);
1966 strcat(resSpec, ":");
1967 strcat(resSpec, *fontPath);
1968 for(i = 1;i < numPaths;i++)
1970 if((strlen(resSpec) + strlen(fontPath[i]) + 1) >= resSize)
1973 resSpec = (char *) SM_REALLOC(resSpec, resSize * sizeof(char));
1976 PrintErrnoError(DtError, smNLS.cantMallocErrorString);
1980 strcat(resSpec, ",");
1981 strcat(resSpec, fontPath[i]);
1983 XrmPutLineResource(smBase, resSpec);
1990 /*************************************<->*************************************
1992 * PrintKeyboardControl (smBase)
1997 * A convenience function that is separated out instead of being included
1998 * in both QueryServerSettings, and SaveCustomizeSettings.
1999 * Saves pointer control information to the named resource file.
2003 * smBase = pointer to newly opened resource db used to store setting info
2004 * resSpec = a buffer to hold string resource information until it is
2006 * resSize = size of current resource buffer
2010 * resSize = buffer is enlarged if more room is need to hold this info
2015 *************************************<->***********************************/
2017 PrintKeyboardControl(
2018 XrmDatabase *smBase)
2022 Bool firstRepeat = True;
2025 strcpy(resSpec, SM_RESOURCE_CLASS);
2026 strcat(resSpec, "*");
2027 strcat(resSpec, SmCkeyClick);
2028 strcat(resSpec, ":");
2029 sprintf(tmpChar, "%d",smSettings.kbdState.key_click_percent);
2030 strcat(resSpec, tmpChar);
2031 XrmPutLineResource(smBase, resSpec);
2033 strcpy(resSpec, SM_RESOURCE_CLASS);
2034 strcat(resSpec, "*");
2035 strcat(resSpec, SmCbellPercent);
2036 strcat(resSpec, ":");
2037 sprintf(tmpChar, "%d",smSettings.kbdState.bell_percent);
2038 strcat(resSpec, tmpChar);
2039 XrmPutLineResource(smBase, resSpec);
2041 strcpy(resSpec, SM_RESOURCE_CLASS);
2042 strcat(resSpec, "*");
2043 strcat(resSpec, SmCbellPitch);
2044 strcat(resSpec, ":");
2045 sprintf(tmpChar, "%d",smSettings.kbdState.bell_pitch);
2046 strcat(resSpec, tmpChar);
2047 XrmPutLineResource(smBase, resSpec);
2049 strcpy(resSpec, SM_RESOURCE_CLASS);
2050 strcat(resSpec, "*");
2051 strcat(resSpec, SmCbellDuration);
2052 strcat(resSpec, ":");
2053 sprintf(tmpChar, "%d",smSettings.kbdState.bell_duration);
2054 strcat(resSpec, tmpChar);
2055 XrmPutLineResource(smBase, resSpec);
2057 strcpy(resSpec, SM_RESOURCE_CLASS);
2058 strcat(resSpec, "*");
2059 strcat(resSpec, SmCledMask);
2060 strcat(resSpec, ":");
2061 sprintf(tmpChar, "%ld",smSettings.kbdState.led_mask);
2062 strcat(resSpec, tmpChar);
2063 XrmPutLineResource(smBase, resSpec);
2065 strcpy(resSpec, SM_RESOURCE_CLASS);
2066 strcat(resSpec, "*");
2067 strcat(resSpec, SmCglobalRepeats);
2068 strcat(resSpec, ":");
2069 sprintf(tmpChar, "%d",smSettings.kbdState.global_auto_repeat);
2070 strcat(resSpec, tmpChar);
2071 XrmPutLineResource(smBase, resSpec);
2073 strcpy(resSpec, SM_RESOURCE_CLASS);
2074 strcat(resSpec, "*");
2075 strcat(resSpec, SmCautoRepeats);
2076 strcat(resSpec, ":");
2079 * Now write out which keys need to be auto repeated one at a time
2081 if(smSettings.kbdState.global_auto_repeat != AutoRepeatModeOn)
2083 for(i = 0;i < 32;i++)
2086 for(j = 0;j < 8;j++)
2088 if((bitTest & smSettings.kbdState.auto_repeats[i]) != 0)
2090 if(firstRepeat == True)
2092 firstRepeat = False;
2096 strcat(resSpec, ",");
2099 if((strlen(resSpec) + 5) >= resSize)
2102 resSpec = (char *) SM_REALLOC(resSpec,
2103 resSize * sizeof(char));
2106 PrintErrnoError(DtError,
2107 smNLS.cantMallocErrorString);
2112 sprintf(tmpChar, "%d", ((8 * i) + j));
2113 strcat(resSpec, tmpChar);
2121 strcat(resSpec, "");
2123 XrmPutLineResource(smBase, resSpec);
2130 /*************************************<->*************************************
2132 * PrintPointerMapping (smBase, buttonRet, numButton)
2137 * A convenience function that is separated out instead of being included
2138 * in both QueryServerSettings, and SaveCustomizeSettings.
2139 * Saves pointer mapping information to the named resource file.
2143 * smBase = pointer to newly opened resource db used to store setting info
2144 * resSpec = a buffer to hold string resource information until it is
2146 * resSize = size of resource buffer
2147 * buttonRet = button mapping to be saved
2148 * numButton = number of buttons in button mapping
2152 * resSize = size of buffer is change if it needs to be enlarged during
2158 *************************************<->***********************************/
2160 PrintPointerMapping(
2161 XrmDatabase *smBase,
2168 strcpy(resSpec, SM_RESOURCE_CLASS);
2169 strcat(resSpec, "*");
2170 strcat(resSpec, SmCbuttonMap);
2171 strcat(resSpec, ":");
2173 numLoops = numButton - 1;
2174 for(i = 0;i <= numLoops;i++)
2176 if((strlen(resSpec) + 5) >= resSize)
2179 resSpec = (char *) SM_REALLOC(resSpec, resSize * sizeof(char));
2182 PrintErrnoError(DtError, smNLS.cantMallocErrorString);
2187 sprintf(tmpChar, "%d",buttonRet[i]);
2188 strcat(resSpec, tmpChar);
2191 strcat(resSpec, ",");
2193 XrmPutLineResource(smBase, resSpec);