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 /* $XConsortium: WmXSMP.c /main/12 1996/05/17 12:54:14 rswiston $ */
25 * (c) Copyright 1996 Digital Equipment Corporation.
26 * (c) Copyright 1996 Hewlett-Packard Company.
27 * (c) Copyright 1996 International Business Machines Corp.
28 * (c) Copyright 1996 Sun Microsystems, Inc.
29 * (c) Copyright 1996 Novell, Inc.
30 * (c) Copyright 1996 FUJITSU LIMITED.
31 * (c) Copyright 1996 Hitachi.
37 #include <sys/param.h>
38 #include <X11/Intrinsic.h>
39 #include <X11/Shell.h>
40 #include <X11/Xatom.h>
41 #include <X11/SM/SM.h>
46 # include "WmWrkspace.h"
47 # include <Dt/Session.h>
50 typedef struct _ProxyClientInfo
54 char *wmClientMachine;
58 #define RESTORE_RESOURCE(pCD, resFlag) \
59 ((pCD)->ignoreWMSaveHints || !((pCD)->wmSaveHintFlags & (resFlag)))
60 #define SAVE_RESOURCE(pCD, resFlag) RESTORE_RESOURCE(pCD, resFlag)
62 #define MAX_RESOURCE_LEN 1024
65 static char *dtwmFileName = "dtwm.db";
67 static char *dtwmFileName = ".mwmclientdb";
68 # define EXTRA_FN_CHARS 20
71 /* Fully-qualified resource names/classes. */
72 static char *xPositionStr = "%s.position.x";
73 static char *yPositionStr = "%s.position.y";
74 static char *widthSizeStr = "%s.size.width";
75 static char *heightSizeStr = "%s.size.height";
76 static char *initialStateStr = "%s.initialState";
77 static char *wmCommandStr = "%s.wmCommand";
78 static char *wmClientMachineStr = "%s.wmClientMachine";
79 static char *screenStr = "%s.screen";
81 static char *workspacesStr = "%s.workspaces";
82 static char *iconXPosStr = "%s.iconPos.x.%s";
83 static char *iconYPosStr = "%s.iconPos.y.%s";
85 static char *iconXPosStr = "%s.iconPos.x";
86 static char *iconYPosStr = "%s.iconPos.y";
89 /* Header for private database. */
90 static char *dbHeader = "\
96 /* Format for client entries in database. */
97 static char *dbClientFormat = "\
101 static char *intArg = ": %d\n";
102 static char *strArg = ": %s\n";
103 static char *normalStateStr = "NormalState";
104 static char *iconicStateStr = "IconicState";
106 static char *XSMPClientStr = "Client";
107 static char *proxyClientStr = "ProxyClient";
110 static char *dbFileArgStr = "-session";
113 /* Flag to tell us how to treat ProxyClient info. */
114 static Boolean smClientDBCheckpointed = False;
119 /* Session mgmt callbacks. */
120 static void smSaveYourselfCallback(Widget, XtPointer, XtPointer);
121 static void smDieCallback(Widget, XtPointer, XtPointer);
123 /* Build client database file name. */
124 static void buildDBFileName(char [MAXPATHLEN], Boolean);
127 *Get clientDB name according to argv; set according to dbFileName.
129 static void getClientDBName(void);
130 static void setClientDBName(void);
131 static char **getNewRestartCmd(void);
132 static void freeNewRestartCmd(char **);
136 /* Get string of client's workspaces. */
137 static char *getClientWorkspaces(ClientData *);
140 /* List-of-clients utilities. */
141 static Boolean addClientToList(ClientData ***, int *, ClientData *);
142 static int clientWorkspaceCompare(const void *, const void *);
144 /* XSMP/Proxy functions to save/restore resources. */
145 static char *getClientResource(char *, char *);
146 static char *getXSMPResource(ClientData *, int, char *);
147 static void getClientGeometry(ClientData *, int *, int *,
148 unsigned int *, unsigned int *);
149 static Boolean getProxyClientInfo(ClientData *, ProxyClientInfo *);
150 static Bool cmpProxyClientProc(XrmDatabase *, XrmBindingList,
151 XrmQuarkList, XrmRepresentation *,
152 XrmValue *, XPointer);
153 static char *findProxyClientID(ClientData *);
154 static Boolean findXSMPClientDBMatch(ClientData *, char **);
155 static Boolean findProxyClientDBMatch(ClientData *, char **);
156 static Boolean saveXSMPClient(FILE *, ClientData *);
157 static Boolean saveProxyClient(FILE *, ClientData *, int);
158 static void dbRemoveProxyClientEntry(char *);
161 smSaveYourselfCallback(Widget w, XtPointer clientData, XtPointer callData)
163 XtCheckpointToken cpToken = (XtCheckpointToken)callData;
164 XrmDatabase newClientDB;
166 static Boolean firstTime = True;
169 * This callback will be called on connection to the Session Manager.
170 * At that time, we don't want to save any state, and we don't
171 * want to request the second phase.
179 /* Only respond to Local and Both save requests. */
180 if ((cpToken->save_type != SmSaveLocal) &&
181 (cpToken->save_type != SmSaveBoth))
184 if (cpToken->shutdown &&
185 (cpToken->cancel_shutdown ||
186 cpToken->request_cancel ||
187 !cpToken->save_success))
188 return; /* Return, maintaining current state */
190 /* If first phase, request notification when all other clients saved. */
191 if (cpToken->phase == 1)
193 cpToken->request_next_phase = True;
198 /* Second phase: all other clients saved; now I can save myself. */
199 /* Copied from WmEvent.c. */
200 for (scr = 0; scr < wmGD.numScreens; scr++)
202 if (wmGD.Screens[scr].managed)
205 * Write out current workspace, frontpanel
206 * position and iconbox position and size.
208 SaveResources(&wmGD.Screens[scr]);
214 * NEW FOR SESSION MANAGEMENT: Write private client resource database.
215 * Destroy old client database and save new one.
217 if ((newClientDB = SaveClientResourceDB())
218 != (XrmDatabase)NULL)
220 if (wmGD.clientResourceDB != (XrmDatabase)NULL)
221 XrmDestroyDatabase(wmGD.clientResourceDB);
222 wmGD.clientResourceDB = newClientDB;
223 smClientDBCheckpointed = True;
226 /* Set new session properties if wmGD.dbFileName is valid. */
227 if (wmGD.dbFileName != (char *)NULL)
229 char **newRestartCmd, **ptr;
230 char *newDiscardCmd[4];
234 newDiscardCmd[0] = "rm";
235 newDiscardCmd[1] = "-f";
236 newDiscardCmd[2] = wmGD.dbFileName;
237 newDiscardCmd[3] = (char *)NULL;
239 newRestartCmd = getNewRestartCmd();
242 XtSetArg(args[nargs], XtNrestartCommand, newRestartCmd); nargs++;
243 XtSetArg(args[nargs], XtNdiscardCommand, newDiscardCmd); nargs++;
244 XtSetValues(wmGD.topLevelW, args, nargs);
246 freeNewRestartCmd(newRestartCmd);
253 smDieCallback(Widget w, XtPointer clientData, XtPointer callData)
255 /* We assume we've saved our state by the time this is called. */
260 buildDBFileName(char fileNameBuf[MAXPATHLEN], Boolean doingSave)
264 char *savePath = (char *)NULL;
266 fileNameBuf[0] = '\0';
269 char *saveFile = (char *)NULL;
272 if (DtSessionSavePath(wmGD.topLevelW, &savePath, &saveFile))
276 if ((ptr = strrchr(savePath, '/')) != (char *)NULL)
279 if (strlen(savePath) + strlen(dtwmFileName) + 2 < MAXPATHLEN)
280 sprintf(fileNameBuf, "%s/%s", savePath, dtwmFileName);
287 if (DtSessionRestorePath(wmGD.topLevelW, &savePath, dtwmFileName))
289 if ((int)strlen(savePath) < MAXPATHLEN)
290 strcpy(fileNameBuf, savePath);
296 if (fileNameBuf[0] == '\0')
297 strcpy(fileNameBuf, dtwmFileName);
301 strcpy(fileNameBuf, (wmGD.dbFileName == (char *)NULL) ?
302 dtwmFileName : wmGD.dbFileName);
310 * See if dbFileArgStr specified on command line. Save subsequent arg;
311 * if not, see if resource set; if not, put files in user's home directory.
312 * NOTE: we allocate extra space for the filename so we can append numbers
313 * without reallocating in setClientDBName.
316 getClientDBName(void)
320 /* See if DB filename specified on command line. */
321 wmGD.dbFileName = (char *)NULL;
323 if (wmGD.argv != (char **)NULL)
325 for (argP = wmGD.argv; *argP != (char *)NULL; argP++)
327 if (strcmp(*argP, dbFileArgStr) == 0)
329 if (*(++argP) != (char *)NULL)
331 if ((wmGD.dbFileName =
332 (char *)XtMalloc((strlen(*argP) + 1 +
336 strcpy(wmGD.dbFileName, *argP);
343 /* Check resource if necessary. */
344 if (wmGD.dbFileName == (char *)NULL)
346 if (wmGD.sessionClientDB != (String)NULL)
348 if ((wmGD.dbFileName =
349 (char *)XtMalloc((strlen(wmGD.sessionClientDB) + 1 +
353 strcpy(wmGD.dbFileName, wmGD.sessionClientDB);
357 if (wmGD.dbFileName == (char *)NULL)
359 char *homeDir = XmeGetHomeDirName();
361 if ((wmGD.dbFileName =
362 (char *)XtMalloc((strlen(homeDir) + strlen(dtwmFileName) + 2 +
363 EXTRA_FN_CHARS) * sizeof(char)))
365 sprintf(wmGD.dbFileName, "%s/%s", homeDir, dtwmFileName);
370 * See comments above in getClientDBName.
373 setClientDBName(void)
377 if (wmGD.dbFileName == (char *)NULL)
380 /* Change trailing ".<number>" to ".<number+1>" */
381 if ((ptr = strrchr(wmGD.dbFileName, '.')) != (char *)NULL)
385 for (p1 = ++ptr; *p1 != '\0'; p1++)
395 numSuffix = atoi(ptr) + 1;
396 sprintf(ptr, "%d", numSuffix);
398 /* Success! We're all done here. */
403 /* Otherwise, append ".0" to filename. */
404 strcat(wmGD.dbFileName, ".0");
408 getNewRestartCmd(void)
412 int fileArgIndex = -1;
416 char **newRestartCmd;
419 XtSetArg(args[nargs], XtNrestartCommand, &restartCmd); nargs++;
420 XtGetValues(wmGD.topLevelW, args, nargs);
422 if (restartCmd == (char **)NULL)
423 return (char **)NULL;
425 for (argc = 0, argP = restartCmd; *argP != (char *)NULL; argP++, argc++)
427 if (strcmp(*argP, dbFileArgStr) == 0)
429 if (*(++argP) == (char *)NULL)
432 fileArgIndex = argc++; /* Point at dbFileArgStr, not filename */
436 if (fileArgIndex < 0)
442 if ((newRestartCmd = (char **)XtMalloc((argc + 1) * sizeof(char *)))
444 return (char **)NULL;
446 for (i = 0; i < argc; i++)
448 if (i != fileArgIndex)
450 newRestartCmd[i] = XtNewString(restartCmd[i]);
454 newRestartCmd[i++] = XtNewString(dbFileArgStr);
455 newRestartCmd[i] = XtNewString(wmGD.dbFileName);
458 newRestartCmd[i] = (char *)NULL;
460 return newRestartCmd;
464 freeNewRestartCmd(char **restartCmd)
466 while (*restartCmd != (char *)NULL)
467 XtFree(*(restartCmd++));
469 XtFree((char *)restartCmd);
477 getClientWorkspaces(ClientData *pCD)
479 WmScreenData *pSD = pCD->pSD;
480 WmWorkspaceData *pWS;
482 /* Should we use _DtWmParseMakeQuotedString() when looking at */
483 /* the name of the workspace, as is done in WmWrkspace.c? */
485 /* Easy but slow way to do this would be to use XGetAtomName(). */
486 /* To avoid XServer round trips (and to weed out invalid WS names) */
487 /* we look through workspaces attached to this screen for ID matches. */
488 char *cwsP, *tmpP, *wsNameP;
492 for (i = 0; i < pCD->numInhabited; i++)
494 if ((pWS = GetWorkspaceData(pSD, pCD->pWsList[i].wsID))
495 != (WmWorkspaceData *)NULL)
500 pLen = strlen(wsNameP) + 1; /* 1 for null termination */
501 if ((cwsP = (char *)XtMalloc(pLen * sizeof(char)))
505 strcpy(cwsP, wsNameP);
509 pLen += strlen(wsNameP) + 1; /* 1 for space */
510 if ((tmpP = (char *)XtRealloc(cwsP, pLen * sizeof(char)))
513 XtFree((char *)cwsP);
518 strcat(cwsP, wsNameP);
529 addClientToList(ClientData ***cdList, int *nClients, ClientData *pCD)
531 ClientData **newPtr = (ClientData **)
532 XtRealloc((char *)*cdList, (*nClients + 1) * sizeof(ClientData *));
534 if (newPtr == (ClientData **)NULL)
536 if (*cdList != (ClientData **)NULL)
537 XtFree((char *)*cdList);
542 newPtr[*nClients] = pCD;
549 clientWorkspaceCompare(const void *ppCD1, const void *ppCD2)
551 ClientData *pCD1 = *(ClientData **)ppCD1;
552 ClientData *pCD2 = *(ClientData **)ppCD2;
555 /* Sort first by screen. */
556 if ((screenDiff = pCD1->pSD->screen - pCD2->pSD->screen) != 0)
561 /* If same screen, sort by workspace id. */
562 /* How do we handle clients that live in more than one workspace? */
563 /* For now, pick the "current" one - if not in active workspace, */
564 /* this will simply be the first one in the client's list. */
565 return (int)(pCD1->pWsList[pCD1->currentWsc].wsID -
566 pCD2->pWsList[pCD2->currentWsc].wsID);
570 /* If no WSM, must be in same workspace if screen is same! */
577 * Assumes: wmGD.clientResourceDB is non-NULL
580 getClientResource(char *clientID, char *fmtStr)
582 char resourceBuf[MAX_RESOURCE_LEN];
584 XrmValue resourceValue;
586 sprintf(resourceBuf, fmtStr, clientID);
587 if (XrmGetResource(wmGD.clientResourceDB, resourceBuf, resourceBuf,
588 &resourceType, &resourceValue))
589 return (char *)resourceValue.addr;
595 * Assumes: pCD has non-NULL smClientID;
596 * wmGD.clientResourceDB is non-NULL
599 getXSMPResource(ClientData *pCD, int resourceFlag, char *fmtStr)
601 if (RESTORE_RESOURCE(pCD, resourceFlag))
602 return getClientResource(pCD->smClientID, fmtStr);
608 * Return True if client is XSMP, False otherwise.
611 findXSMPClientDBMatch(ClientData *pCD, char **workSpaceNamesP)
613 if (pCD->smClientID != (String)NULL)
615 if (wmGD.clientResourceDB != (XrmDatabase)NULL)
619 if ((resourcePtr = getXSMPResource(pCD, WMSAVE_X, xPositionStr))
622 pCD->clientX = atoi(resourcePtr);
623 pCD->clientFlags |= SM_X;
626 if ((resourcePtr = getXSMPResource(pCD, WMSAVE_Y, yPositionStr))
629 pCD->clientY = atoi(resourcePtr);
630 pCD->clientFlags |= SM_Y;
635 getXSMPResource(pCD, WMSAVE_ICON_X, iconXPosStr))
638 ICON_X(pCD) = atoi(resourcePtr);
639 pCD->clientFlags |= SM_ICON_X;
643 getXSMPResource(pCD, WMSAVE_ICON_Y, iconYPosStr))
646 ICON_Y(pCD) = atoi(resourcePtr);
647 pCD->clientFlags |= SM_ICON_Y;
651 if ((resourcePtr = getXSMPResource(pCD, WMSAVE_WIDTH,
655 pCD->clientWidth = atoi(resourcePtr);
656 pCD->clientFlags |= SM_WIDTH;
659 if ((resourcePtr = getXSMPResource(pCD, WMSAVE_HEIGHT,
663 pCD->clientHeight = atoi(resourcePtr);
664 pCD->clientFlags |= SM_HEIGHT;
667 if ((resourcePtr = getXSMPResource(pCD, WMSAVE_STATE,
672 (strcmp(resourcePtr, normalStateStr) == 0) ?
673 NORMAL_STATE : MINIMIZED_STATE;
674 pCD->clientFlags |= SM_CLIENT_STATE;
678 if ((workSpaceNamesP != (char **)NULL) &&
679 ((resourcePtr = getXSMPResource(pCD, WMSAVE_WORKSPACES,
683 *workSpaceNamesP = XtNewString(resourcePtr);
688 /* Always return True for XSMP clients. */
696 getProxyClientInfo(ClientData *pCD, ProxyClientInfo *proxyClientInfo)
698 XTextProperty textProperty;
701 /* WM_COMMAND is required; WM_CLIENT_MACHINE is optional. */
702 if (!XGetTextProperty(wmGD.display, pCD->client, &textProperty,
706 if ((textProperty.encoding != XA_STRING) ||
707 (textProperty.format != 8) ||
708 (textProperty.value[0] == '\0'))
710 if (textProperty.value)
711 free((char *)textProperty.value);
716 /* Convert embedded NULL characters to space characters. */
717 /* (If last char is NULL, leave it alone) */
718 for (i = 0; i < textProperty.nitems - 1; i++)
720 if (textProperty.value[i] == '\0')
721 textProperty.value[i] = ' ';
724 proxyClientInfo->screen = pCD->pSD->screen;
725 proxyClientInfo->wmCommand = (char *)textProperty.value;
727 /* Since WM_CLIENT_MACHINE is optional, don't fail if not found. */
728 if (XGetWMClientMachine(wmGD.display, pCD->client, &textProperty))
729 proxyClientInfo->wmClientMachine = (char *)textProperty.value;
730 else proxyClientInfo->wmClientMachine = (char *)NULL;
732 proxyClientInfo->clientID = (char *)NULL;
738 * IMPORTANT: This function is called by XrmEnumerateDatabase().
739 * It calls other Xrm*() functions - if dtwm is threaded, THIS
740 * WILL HANG. For now, dtwm is NOT threaded, so no problem.
743 cmpProxyClientProc(XrmDatabase *clientDB, XrmBindingList bindingList,
744 XrmQuarkList quarkList, XrmRepresentation *reps,
745 XrmValue *value, XPointer uData)
749 char *wmClientMachine;
750 char *clientID = (char *)value->addr;
751 ProxyClientInfo *proxyClientInfo = (ProxyClientInfo *)uData;
754 getClientResource(clientID, wmCommandStr)) == (char *)NULL) ||
755 (strcmp(wmCommand, proxyClientInfo->wmCommand) != 0) ||
757 getClientResource(clientID, screenStr)) == (char *)NULL) ||
758 (atoi(clientScreen) != proxyClientInfo->screen))
761 /* So far so good. If WM_CLIENT_MACHINE missing from either, */
762 /* or if it is set in both and it's the same, we've got a match! */
763 if (!proxyClientInfo->wmClientMachine ||
765 getClientResource(clientID, wmClientMachineStr)) == (char *)NULL) ||
766 (strcmp(proxyClientInfo->wmClientMachine, wmClientMachine) == 0))
768 proxyClientInfo->clientID = clientID;
776 findProxyClientID(ClientData *pCD)
778 ProxyClientInfo proxyClientInfo;
779 char *clientID = (char *)NULL;
780 static XrmName proxyName[2] = {NULLQUARK, NULLQUARK};
781 static XrmClass proxyClass[2] = {NULLQUARK, NULLQUARK};
783 if (proxyName[0] == NULLQUARK)
785 proxyName[0] = XrmStringToName(proxyClientStr);
786 proxyClass[0] = XrmStringToClass(proxyClientStr);
790 * We need to match the screen and
791 * the WM_COMMAND and WM_CLIENT_MACHINE properties.
793 if (!getProxyClientInfo(pCD, &proxyClientInfo))
796 if (XrmEnumerateDatabase(wmGD.clientResourceDB, proxyName, proxyClass,
797 XrmEnumOneLevel, cmpProxyClientProc,
798 (XPointer)&proxyClientInfo))
799 clientID = proxyClientInfo.clientID;
801 if (proxyClientInfo.wmCommand)
802 free(proxyClientInfo.wmCommand);
803 if (proxyClientInfo.wmClientMachine)
804 free(proxyClientInfo.wmClientMachine);
810 * Return True if client is *not* XSMP and is listed in the resource DB
811 * and no checkpoint done yet. Also remove entry from DB if found.
814 findProxyClientDBMatch(ClientData *pCD, char **workSpaceNamesP)
816 if ((pCD->smClientID == (String)NULL) &&
817 (wmGD.clientResourceDB != (XrmDatabase)NULL) &&
818 (!smClientDBCheckpointed))
822 if ((proxyClientID = findProxyClientID(pCD)) != (char *)NULL)
827 getClientResource(proxyClientID, xPositionStr))
830 pCD->clientX = atoi(resourcePtr);
831 pCD->clientFlags |= SM_X;
835 getClientResource(proxyClientID, yPositionStr))
838 pCD->clientY = atoi(resourcePtr);
839 pCD->clientFlags |= SM_Y;
844 getClientResource(proxyClientID, iconXPosStr))
847 ICON_X(pCD) = atoi(resourcePtr);
848 pCD->clientFlags |= SM_ICON_X;
852 getClientResource(proxyClientID, iconYPosStr))
855 ICON_Y(pCD) = atoi(resourcePtr);
856 pCD->clientFlags |= SM_ICON_Y;
861 getClientResource(proxyClientID, widthSizeStr))
864 pCD->clientWidth = atoi(resourcePtr);
865 pCD->clientFlags |= SM_WIDTH;
869 getClientResource(proxyClientID, heightSizeStr))
872 pCD->clientHeight = atoi(resourcePtr);
873 pCD->clientFlags |= SM_HEIGHT;
877 getClientResource(proxyClientID, initialStateStr))
881 (strcmp(resourcePtr, normalStateStr) == 0) ?
882 NORMAL_STATE : MINIMIZED_STATE;
883 pCD->clientFlags |= SM_CLIENT_STATE;
887 if ((workSpaceNamesP != (char **)NULL) &&
889 getClientResource(proxyClientID, workspacesStr))
892 *workSpaceNamesP = XtNewString(resourcePtr);
897 /* This is done in LoadClientIconPositions() if WSM defined. */
898 dbRemoveProxyClientEntry(proxyClientID);
909 * Translate the client geometry into what's needed on restore.
912 getClientGeometry(ClientData *pCD, int *clientX, int *clientY,
913 unsigned int *clientWd, unsigned int *clientHt)
915 *clientX = pCD->clientX;
916 *clientY = pCD->clientY;
917 *clientWd = (pCD->widthInc != 0) ?
918 (pCD->clientWidth - pCD->baseWidth) / pCD->widthInc :
920 *clientHt = (pCD->heightInc != 0) ?
921 (pCD->clientHeight - pCD->baseHeight) / pCD->heightInc :
926 * Assumes: pCD->smClientID is not NULL
929 saveXSMPClient(FILE *fp, ClientData *pCD)
931 int clientX, clientY;
932 unsigned int clientWd, clientHt;
933 char *clientID = pCD->smClientID;
935 fprintf(fp, dbClientFormat, XSMPClientStr, clientID, clientID);
937 getClientGeometry(pCD, &clientX, &clientY, &clientWd, &clientHt);
939 if (SAVE_RESOURCE(pCD, WMSAVE_X))
941 fprintf(fp, xPositionStr, clientID);
942 fprintf(fp, intArg, clientX);
945 if (SAVE_RESOURCE(pCD, WMSAVE_Y))
947 fprintf(fp, yPositionStr, clientID);
948 fprintf(fp, intArg, clientY);
951 if (!pCD->pSD->useIconBox)
954 WmScreenData *pSD = pCD->pSD;
955 WmWorkspaceData *pWS;
958 for (i = 0; i < pCD->numInhabited; i++)
960 if ((pWS = GetWorkspaceData(pSD, pCD->pWsList[i].wsID))
961 != (WmWorkspaceData *)NULL)
963 if (SAVE_RESOURCE(pCD, WMSAVE_ICON_X))
965 fprintf(fp, iconXPosStr, clientID, pWS->name);
966 fprintf(fp, intArg, pCD->pWsList[i].iconX);
969 if (SAVE_RESOURCE(pCD, WMSAVE_ICON_Y))
971 fprintf(fp, iconYPosStr, clientID, pWS->name);
972 fprintf(fp, intArg, pCD->pWsList[i].iconY);
977 if (SAVE_RESOURCE(pCD, WMSAVE_ICON_X))
979 fprintf(fp, iconXPosStr, clientID);
980 fprintf(fp, intArg, ICON_X(pCD));
983 if (SAVE_RESOURCE(pCD, WMSAVE_ICON_Y))
985 fprintf(fp, iconYPosStr, clientID);
986 fprintf(fp, intArg, ICON_Y(pCD));
991 if (SAVE_RESOURCE(pCD, WMSAVE_WIDTH))
993 fprintf(fp, widthSizeStr, clientID);
994 fprintf(fp, intArg, clientWd);
997 if (SAVE_RESOURCE(pCD, WMSAVE_HEIGHT))
999 fprintf(fp, heightSizeStr, clientID);
1000 fprintf(fp, intArg, clientHt);
1003 if (SAVE_RESOURCE(pCD, WMSAVE_STATE))
1008 clientState = pCD->clientState & ~UNSEEN_STATE;
1010 clientState = pCD->clientState;
1013 fprintf(fp, initialStateStr, clientID);
1014 fprintf(fp, strArg, (clientState == NORMAL_STATE) ?
1015 normalStateStr : iconicStateStr);
1019 if (SAVE_RESOURCE(pCD, WMSAVE_WORKSPACES))
1021 char *clientWorkspaces = getClientWorkspaces(pCD);
1023 if (clientWorkspaces != (char *)NULL)
1025 fprintf(fp, workspacesStr, clientID);
1026 fprintf(fp, strArg, clientWorkspaces);
1027 XtFree(clientWorkspaces);
1036 * Assumes: pCD->smClientID is NULL
1039 saveProxyClient(FILE *fp, ClientData *pCD, int clientIDNum)
1043 ProxyClientInfo proxyClientInfo;
1044 int clientX, clientY;
1045 unsigned int clientWd, clientHt;
1047 char *clientWorkspaces;
1050 if (!getProxyClientInfo(pCD, &proxyClientInfo))
1053 sprintf(clientID, "%d", clientIDNum);
1054 fprintf(fp, dbClientFormat, proxyClientStr, clientID, clientID);
1056 fprintf(fp, screenStr, clientID);
1057 fprintf(fp, intArg, proxyClientInfo.screen);
1059 fprintf(fp, wmCommandStr, clientID);
1060 fprintf(fp, strArg, proxyClientInfo.wmCommand);
1061 free(proxyClientInfo.wmCommand);
1063 if (proxyClientInfo.wmClientMachine != (char *)NULL)
1065 fprintf(fp, wmClientMachineStr, clientID);
1066 fprintf(fp, strArg, proxyClientInfo.wmClientMachine);
1067 free(proxyClientInfo.wmClientMachine);
1070 getClientGeometry(pCD, &clientX, &clientY, &clientWd, &clientHt);
1072 fprintf(fp, xPositionStr, clientID);
1073 fprintf(fp, intArg, clientX);
1075 fprintf(fp, yPositionStr, clientID);
1076 fprintf(fp, intArg, clientY);
1078 if (!pCD->pSD->useIconBox)
1081 WmScreenData *pSD = pCD->pSD;
1082 WmWorkspaceData *pWS;
1085 for (i = 0; i < pCD->numInhabited; i++)
1087 if ((pWS = GetWorkspaceData(pSD, pCD->pWsList[i].wsID))
1088 != (WmWorkspaceData *)NULL)
1090 fprintf(fp, iconXPosStr, clientID, pWS->name);
1091 fprintf(fp, intArg, pCD->pWsList[i].iconX);
1093 fprintf(fp, iconYPosStr, clientID, pWS->name);
1094 fprintf(fp, intArg, pCD->pWsList[i].iconY);
1098 fprintf(fp, iconXPosStr, clientID);
1099 fprintf(fp, intArg, ICON_X(pCD));
1101 fprintf(fp, iconYPosStr, clientID);
1102 fprintf(fp, intArg, ICON_Y(pCD));
1106 fprintf(fp, widthSizeStr, clientID);
1107 fprintf(fp, intArg, clientWd);
1109 fprintf(fp, heightSizeStr, clientID);
1110 fprintf(fp, intArg, clientHt);
1113 clientState = pCD->clientState & ~UNSEEN_STATE;
1115 clientState = pCD->clientState;
1118 fprintf(fp, initialStateStr, clientID);
1119 fprintf(fp, strArg, (clientState == NORMAL_STATE) ?
1120 normalStateStr : iconicStateStr);
1123 clientWorkspaces = getClientWorkspaces(pCD);
1124 if (clientWorkspaces != (char *)NULL)
1126 fprintf(fp, workspacesStr, clientID);
1127 fprintf(fp, strArg, clientWorkspaces);
1128 XtFree(clientWorkspaces);
1136 dbRemoveProxyClientEntry(char *proxyClientID)
1138 char resourceBuf[MAX_RESOURCE_LEN];
1140 /* Remove entry from DB. Since Xrm does not provide a means */
1141 /* of removing something from the DB, we blank out key info. */
1142 sprintf(resourceBuf, wmCommandStr, proxyClientID);
1143 strcat(resourceBuf, ":");
1144 XrmPutLineResource(&wmGD.clientResourceDB, resourceBuf);
1148 * Add callbacks used in session management.
1151 AddSMCallbacks(void)
1153 XtAddCallback(wmGD.topLevelW, XtNsaveCallback,
1154 smSaveYourselfCallback, (XtPointer)NULL);
1155 XtAddCallback(wmGD.topLevelW, XtNdieCallback,
1156 smDieCallback, (XtPointer)NULL);
1160 * Resign from session management, closing any connections made.
1167 XtVaSetValues(wmGD.topLevelW,
1168 XtNjoinSession, False,
1174 * Exit the WM, being polite by first resigning from session mgmt.
1177 ExitWM(int exitCode)
1184 * Read our private database of client resources.
1187 LoadClientResourceDB(void)
1189 char dbFileName[MAXPATHLEN];
1194 buildDBFileName(dbFileName, False);
1196 return XrmGetFileDatabase(dbFileName);
1200 * Write our private database of client resources.
1203 SaveClientResourceDB(void)
1206 char dbFileName[MAXPATHLEN];
1211 int clientIDNum = 0;
1212 ClientListEntry *pCL;
1214 /* Iterate through client list, saving */
1215 /* appropriate resources for each. */
1219 buildDBFileName(dbFileName, True);
1220 if ((fp = fopen(dbFileName, "w")) == (FILE *)NULL)
1221 return (XrmDatabase)NULL;
1223 XtVaGetValues(wmGD.topLevelW,
1224 XtNsessionID, &mySessionID,
1226 fprintf(fp, dbHeader, dtwmFileName, "dtwm Version XSMP1.0",
1227 (mySessionID != (String)NULL) ? mySessionID : "");
1229 for (scr = 0; scr < wmGD.numScreens; scr++)
1231 pSD = &(wmGD.Screens[scr]);
1233 for (pCL = pSD->clientList;
1234 pCL != (ClientListEntry *)NULL;
1235 pCL = pCL->nextSibling)
1237 /* Each client may be in list twice: normal & icon */
1238 if (pCL->type != NORMAL_STATE)
1243 if (pCD->smClientID != (String)NULL)
1245 saveXSMPClient(fp, pCD);
1249 if (saveProxyClient(fp, pCD, clientIDNum))
1257 /* Retrieve database from file. */
1258 return XrmGetFileDatabase(dbFileName);
1262 * As with FindDtSessionMatch(), sets properties and then returns
1263 * an allocated string of workspace names. This string must be
1264 * freed by the caller using XtFree().
1267 FindClientDBMatch(ClientData *pCD, char **workSpaceNamesP)
1269 return (findXSMPClientDBMatch(pCD, workSpaceNamesP) ||
1270 findProxyClientDBMatch(pCD, workSpaceNamesP));
1274 GetSmClientIdClientList(ClientData ***clients, int *nClients)
1279 ClientListEntry *pCL;
1282 *clients = (ClientData **)NULL;
1283 for (scr = 0; scr < wmGD.numScreens; scr++)
1285 pSD = &(wmGD.Screens[scr]);
1287 for (pCL = pSD->clientList;
1288 pCL != (ClientListEntry *)NULL;
1289 pCL = pCL->nextSibling)
1291 /* Each client may be in list twice: normal & icon */
1292 if (pCL->type != NORMAL_STATE)
1297 if (pCD->smClientID != (String)NULL)
1299 /* addClientToList() reclaims memory on failure. */
1300 if (!addClientToList(clients, nClients, pCD))
1310 SortClientListByWorkspace(ClientData **clients, int nClients)
1314 qsort((void *)clients, nClients,
1315 sizeof(ClientData *), clientWorkspaceCompare);
1320 /* This needs to be called if WSM defined; if WSM not defined, icon */
1321 /* positions are read at the same time as other resources. */
1323 LoadClientIconPositions(ClientData *pCD)
1325 char resourceBuf[MAX_RESOURCE_LEN];
1326 WmScreenData *pSD = pCD->pSD;
1327 WmWorkspaceData *pWS;
1331 if (wmGD.clientResourceDB == (XrmDatabase)NULL)
1334 if (pCD->smClientID != (String)NULL)
1336 for (i = 0; i < pCD->numInhabited; i++)
1338 if ((pWS = GetWorkspaceData(pSD, pCD->pWsList[i].wsID))
1339 != (WmWorkspaceData *)NULL)
1341 sprintf(resourceBuf, iconXPosStr, "%s", pWS->name);
1343 getXSMPResource(pCD, WMSAVE_ICON_X, resourceBuf))
1346 pCD->pWsList[i].iconX = atoi(resourcePtr);
1347 pCD->clientFlags |= SM_ICON_X;
1350 sprintf(resourceBuf, iconYPosStr, "%s", pWS->name);
1352 getXSMPResource(pCD, WMSAVE_ICON_Y, resourceBuf))
1355 pCD->pWsList[i].iconY = atoi(resourcePtr);
1356 pCD->clientFlags |= SM_ICON_Y;
1364 if (!smClientDBCheckpointed)
1366 char *proxyClientID;
1368 if ((proxyClientID = findProxyClientID(pCD)) != (char *)NULL)
1370 for (i = 0; i < pCD->numInhabited; i++)
1372 if ((pWS = GetWorkspaceData(pSD, pCD->pWsList[i].wsID))
1373 != (WmWorkspaceData *)NULL)
1375 sprintf(resourceBuf, iconXPosStr, "%s", pWS->name);
1377 getClientResource(proxyClientID, resourceBuf))
1380 pCD->pWsList[i].iconX = atoi(resourcePtr);
1381 pCD->clientFlags |= SM_ICON_X;
1384 sprintf(resourceBuf, iconYPosStr, "%s", pWS->name);
1386 getClientResource(proxyClientID, resourceBuf))
1389 pCD->pWsList[i].iconY = atoi(resourcePtr);
1390 pCD->clientFlags |= SM_ICON_Y;
1394 dbRemoveProxyClientEntry(proxyClientID);