WmXSMP.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  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)
  10. * any later version.
  11. *
  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
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /*
  24. * (c) Copyright 1996 Digital Equipment Corporation.
  25. * (c) Copyright 1996 Hewlett-Packard Company.
  26. * (c) Copyright 1996 International Business Machines Corp.
  27. * (c) Copyright 1996 Sun Microsystems, Inc.
  28. * (c) Copyright 1996 Novell, Inc.
  29. * (c) Copyright 1996 FUJITSU LIMITED.
  30. * (c) Copyright 1996 Hitachi.
  31. */
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <ctype.h>
  35. #include <sys/param.h>
  36. #include <X11/Intrinsic.h>
  37. #include <X11/Shell.h>
  38. #include <X11/Xatom.h>
  39. #include <X11/SM/SM.h>
  40. #include <Xm/XmP.h>
  41. #include "WmGlobal.h"
  42. #include "WmXSMP.h"
  43. #include "WmWrkspace.h"
  44. #include <Dt/Session.h>
  45. typedef struct _ProxyClientInfo
  46. {
  47. int screen;
  48. char *wmCommand;
  49. char *wmClientMachine;
  50. char *clientID;
  51. } ProxyClientInfo;
  52. #define RESTORE_RESOURCE(pCD, resFlag) \
  53. ((pCD)->ignoreWMSaveHints || !((pCD)->wmSaveHintFlags & (resFlag)))
  54. #define SAVE_RESOURCE(pCD, resFlag) RESTORE_RESOURCE(pCD, resFlag)
  55. #define MAX_RESOURCE_LEN 1024
  56. static char *dtwmFileName = "dtwm.db";
  57. /* Fully-qualified resource names/classes. */
  58. static char *xPositionStr = "%s.position.x";
  59. static char *yPositionStr = "%s.position.y";
  60. static char *widthSizeStr = "%s.size.width";
  61. static char *heightSizeStr = "%s.size.height";
  62. static char *initialStateStr = "%s.initialState";
  63. static char *wmCommandStr = "%s.wmCommand";
  64. static char *wmClientMachineStr = "%s.wmClientMachine";
  65. static char *screenStr = "%s.screen";
  66. static char *workspacesStr = "%s.workspaces";
  67. static char *iconXPosStr = "%s.iconPos.x.%s";
  68. static char *iconYPosStr = "%s.iconPos.y.%s";
  69. /* Header for private database. */
  70. static char *dbHeader = "\
  71. ! %s\n\
  72. !\n\
  73. .version: %s\n\
  74. .dtwmID: %s\n";
  75. /* Format for client entries in database. */
  76. static char *dbClientFormat = "\
  77. !\n\
  78. %s.%s: %s\n\
  79. !\n";
  80. static char *intArg = ": %d\n";
  81. static char *strArg = ": %s\n";
  82. static char *normalStateStr = "NormalState";
  83. static char *iconicStateStr = "IconicState";
  84. static char *XSMPClientStr = "Client";
  85. static char *proxyClientStr = "ProxyClient";
  86. /* Flag to tell us how to treat ProxyClient info. */
  87. static Boolean smClientDBCheckpointed = False;
  88. /*
  89. * Prototypes
  90. */
  91. /* Session mgmt callbacks. */
  92. static void smSaveYourselfCallback(Widget, XtPointer, XtPointer);
  93. static void smDieCallback(Widget, XtPointer, XtPointer);
  94. /* Build client database file name. */
  95. static void buildDBFileName(char [MAXPATHLEN], Boolean);
  96. /* Get string of client's workspaces. */
  97. static char *getClientWorkspaces(ClientData *);
  98. /* List-of-clients utilities. */
  99. static Boolean addClientToList(ClientData ***, int *, ClientData *);
  100. static int clientWorkspaceCompare(const void *, const void *);
  101. /* XSMP/Proxy functions to save/restore resources. */
  102. static char *getClientResource(char *, char *);
  103. static char *getXSMPResource(ClientData *, int, char *);
  104. static void getClientGeometry(ClientData *, int *, int *,
  105. unsigned int *, unsigned int *);
  106. static Boolean getProxyClientInfo(ClientData *, ProxyClientInfo *);
  107. static Bool cmpProxyClientProc(XrmDatabase *, XrmBindingList,
  108. XrmQuarkList, XrmRepresentation *,
  109. XrmValue *, XPointer);
  110. static char *findProxyClientID(ClientData *);
  111. static Boolean findXSMPClientDBMatch(ClientData *, char **);
  112. static Boolean findProxyClientDBMatch(ClientData *, char **);
  113. static Boolean saveXSMPClient(FILE *, ClientData *);
  114. static Boolean saveProxyClient(FILE *, ClientData *, int);
  115. static void dbRemoveProxyClientEntry(char *);
  116. static void
  117. smSaveYourselfCallback(Widget w, XtPointer clientData, XtPointer callData)
  118. {
  119. XtCheckpointToken cpToken = (XtCheckpointToken)callData;
  120. XrmDatabase newClientDB;
  121. int scr;
  122. static Boolean firstTime = True;
  123. /*
  124. * This callback will be called on connection to the Session Manager.
  125. * At that time, we don't want to save any state, and we don't
  126. * want to request the second phase.
  127. */
  128. if (firstTime)
  129. {
  130. firstTime = False;
  131. return;
  132. }
  133. /* Only respond to Local and Both save requests. */
  134. if ((cpToken->save_type != SmSaveLocal) &&
  135. (cpToken->save_type != SmSaveBoth))
  136. return;
  137. if (cpToken->shutdown &&
  138. (cpToken->cancel_shutdown ||
  139. cpToken->request_cancel ||
  140. !cpToken->save_success))
  141. return; /* Return, maintaining current state */
  142. /* If first phase, request notification when all other clients saved. */
  143. if (cpToken->phase == 1)
  144. {
  145. cpToken->request_next_phase = True;
  146. return;
  147. }
  148. /* Second phase: all other clients saved; now I can save myself. */
  149. /* Copied from WmEvent.c. */
  150. for (scr = 0; scr < wmGD.numScreens; scr++)
  151. {
  152. if (wmGD.Screens[scr].managed)
  153. {
  154. /*
  155. * Write out current workspace, frontpanel
  156. * position and iconbox position and size.
  157. */
  158. SaveResources(&wmGD.Screens[scr]);
  159. }
  160. }
  161. /*
  162. * NEW FOR SESSION MANAGEMENT: Write private client resource database.
  163. * Destroy old client database and save new one.
  164. */
  165. if ((newClientDB = SaveClientResourceDB())
  166. != (XrmDatabase)NULL)
  167. {
  168. if (wmGD.clientResourceDB != (XrmDatabase)NULL)
  169. XrmDestroyDatabase(wmGD.clientResourceDB);
  170. wmGD.clientResourceDB = newClientDB;
  171. smClientDBCheckpointed = True;
  172. }
  173. }
  174. static void
  175. smDieCallback(Widget w, XtPointer clientData, XtPointer callData)
  176. {
  177. /* We assume we've saved our state by the time this is called. */
  178. ExitWM(0);
  179. }
  180. static void
  181. buildDBFileName(char fileNameBuf[MAXPATHLEN], Boolean doingSave)
  182. {
  183. char *savePath = (char *)NULL;
  184. fileNameBuf[0] = '\0';
  185. if (doingSave)
  186. {
  187. char *saveFile = (char *)NULL;
  188. char *ptr;
  189. if (DtSessionSavePath(wmGD.topLevelW, &savePath, &saveFile))
  190. {
  191. XtFree(saveFile);
  192. if ((ptr = strrchr(savePath, '/')) != (char *)NULL)
  193. *ptr = '\0';
  194. if (strlen(savePath) + strlen(dtwmFileName) + 2 < MAXPATHLEN)
  195. sprintf(fileNameBuf, "%s/%s", savePath, dtwmFileName);
  196. XtFree(savePath);
  197. }
  198. }
  199. else
  200. {
  201. if (DtSessionRestorePath(wmGD.topLevelW, &savePath, dtwmFileName))
  202. {
  203. if ((int)strlen(savePath) < MAXPATHLEN)
  204. strcpy(fileNameBuf, savePath);
  205. XtFree(savePath);
  206. }
  207. }
  208. if (fileNameBuf[0] == '\0')
  209. strcpy(fileNameBuf, dtwmFileName);
  210. }
  211. static char *
  212. getClientWorkspaces(ClientData *pCD)
  213. {
  214. WmScreenData *pSD = pCD->pSD;
  215. WmWorkspaceData *pWS;
  216. /* Should we use _DtWmParseMakeQuotedString() when looking at */
  217. /* the name of the workspace, as is done in WmWrkspace.c? */
  218. /* Easy but slow way to do this would be to use XGetAtomName(). */
  219. /* To avoid XServer round trips (and to weed out invalid WS names) */
  220. /* we look through workspaces attached to this screen for ID matches. */
  221. char *cwsP = NULL, *tmpP, *wsNameP;
  222. int pLen = 0;
  223. int i;
  224. for (i = 0; i < pCD->numInhabited; i++)
  225. {
  226. if ((pWS = GetWorkspaceData(pSD, pCD->pWsList[i].wsID))
  227. != (WmWorkspaceData *)NULL)
  228. {
  229. wsNameP = pWS->name;
  230. if (pLen == 0)
  231. {
  232. pLen = strlen(wsNameP) + 1; /* 1 for null termination */
  233. if ((cwsP = (char *)XtMalloc(pLen * sizeof(char)))
  234. == (char *)NULL)
  235. return (char *)NULL;
  236. strcpy(cwsP, wsNameP);
  237. }
  238. else
  239. {
  240. pLen += strlen(wsNameP) + 1; /* 1 for space */
  241. if ((tmpP = (char *)XtRealloc(cwsP, pLen * sizeof(char)))
  242. == (char *)NULL)
  243. {
  244. XtFree((char *)cwsP);
  245. return (char *)NULL;
  246. }
  247. cwsP = tmpP;
  248. strcat(cwsP, " ");
  249. strcat(cwsP, wsNameP);
  250. }
  251. }
  252. }
  253. return cwsP;
  254. }
  255. static Boolean
  256. addClientToList(ClientData ***cdList, int *nClients, ClientData *pCD)
  257. {
  258. ClientData **newPtr = (ClientData **)
  259. XtRealloc((char *)*cdList, (*nClients + 1) * sizeof(ClientData *));
  260. if (newPtr == (ClientData **)NULL)
  261. {
  262. if (*cdList != (ClientData **)NULL)
  263. XtFree((char *)*cdList);
  264. return False;
  265. }
  266. *cdList = newPtr;
  267. newPtr[*nClients] = pCD;
  268. (*nClients)++;
  269. return True;
  270. }
  271. static int
  272. clientWorkspaceCompare(const void *ppCD1, const void *ppCD2)
  273. {
  274. ClientData *pCD1 = *(ClientData **)ppCD1;
  275. ClientData *pCD2 = *(ClientData **)ppCD2;
  276. int screenDiff;
  277. /* Sort first by screen. */
  278. if ((screenDiff = pCD1->pSD->screen - pCD2->pSD->screen) != 0)
  279. return screenDiff;
  280. /* If same screen, sort by workspace id. */
  281. /* How do we handle clients that live in more than one workspace? */
  282. /* For now, pick the "current" one - if not in active workspace, */
  283. /* this will simply be the first one in the client's list. */
  284. return (int)(pCD1->pWsList[pCD1->currentWsc].wsID -
  285. pCD2->pWsList[pCD2->currentWsc].wsID);
  286. }
  287. /*
  288. * Assumes: wmGD.clientResourceDB is non-NULL
  289. */
  290. static char *
  291. getClientResource(char *clientID, char *fmtStr)
  292. {
  293. char resourceBuf[MAX_RESOURCE_LEN];
  294. char *resourceType;
  295. XrmValue resourceValue;
  296. sprintf(resourceBuf, fmtStr, clientID);
  297. if (XrmGetResource(wmGD.clientResourceDB, resourceBuf, resourceBuf,
  298. &resourceType, &resourceValue))
  299. return (char *)resourceValue.addr;
  300. return (char *)NULL;
  301. }
  302. /*
  303. * Assumes: pCD has non-NULL smClientID;
  304. * wmGD.clientResourceDB is non-NULL
  305. */
  306. static char *
  307. getXSMPResource(ClientData *pCD, int resourceFlag, char *fmtStr)
  308. {
  309. if (RESTORE_RESOURCE(pCD, resourceFlag))
  310. return getClientResource(pCD->smClientID, fmtStr);
  311. return (char *)NULL;
  312. }
  313. /*
  314. * Return True if client is XSMP, False otherwise.
  315. */
  316. static Boolean
  317. findXSMPClientDBMatch(ClientData *pCD, char **workSpaceNamesP)
  318. {
  319. if (pCD->smClientID != (String)NULL)
  320. {
  321. if (wmGD.clientResourceDB != (XrmDatabase)NULL)
  322. {
  323. char *resourcePtr;
  324. if ((resourcePtr = getXSMPResource(pCD, WMSAVE_X, xPositionStr))
  325. != (char *)NULL)
  326. {
  327. pCD->clientX = atoi(resourcePtr);
  328. pCD->clientFlags |= SM_X;
  329. }
  330. if ((resourcePtr = getXSMPResource(pCD, WMSAVE_Y, yPositionStr))
  331. != (char *)NULL)
  332. {
  333. pCD->clientY = atoi(resourcePtr);
  334. pCD->clientFlags |= SM_Y;
  335. }
  336. if ((resourcePtr = getXSMPResource(pCD, WMSAVE_WIDTH,
  337. widthSizeStr))
  338. != (char *)NULL)
  339. {
  340. pCD->clientWidth = atoi(resourcePtr);
  341. pCD->clientFlags |= SM_WIDTH;
  342. }
  343. if ((resourcePtr = getXSMPResource(pCD, WMSAVE_HEIGHT,
  344. heightSizeStr))
  345. != (char *)NULL)
  346. {
  347. pCD->clientHeight = atoi(resourcePtr);
  348. pCD->clientFlags |= SM_HEIGHT;
  349. }
  350. if ((resourcePtr = getXSMPResource(pCD, WMSAVE_STATE,
  351. initialStateStr))
  352. != (char *)NULL)
  353. {
  354. pCD->clientState =
  355. (strcmp(resourcePtr, normalStateStr) == 0) ?
  356. NORMAL_STATE : MINIMIZED_STATE;
  357. pCD->clientFlags |= SM_CLIENT_STATE;
  358. }
  359. if ((workSpaceNamesP != (char **)NULL) &&
  360. ((resourcePtr = getXSMPResource(pCD, WMSAVE_WORKSPACES,
  361. workspacesStr))
  362. != (char *)NULL))
  363. {
  364. *workSpaceNamesP = XtNewString(resourcePtr);
  365. }
  366. }
  367. /* Always return True for XSMP clients. */
  368. return True;
  369. }
  370. return False;
  371. }
  372. static Boolean
  373. getProxyClientInfo(ClientData *pCD, ProxyClientInfo *proxyClientInfo)
  374. {
  375. XTextProperty textProperty;
  376. unsigned long i;
  377. /* WM_COMMAND is required; WM_CLIENT_MACHINE is optional. */
  378. if (!XGetTextProperty(wmGD.display, pCD->client, &textProperty,
  379. XA_WM_COMMAND))
  380. return False;
  381. if ((textProperty.encoding != XA_STRING) ||
  382. (textProperty.format != 8) ||
  383. (textProperty.value[0] == '\0'))
  384. {
  385. if (textProperty.value)
  386. free((char *)textProperty.value);
  387. return False;
  388. }
  389. /* Convert embedded NULL characters to space characters. */
  390. /* (If last char is NULL, leave it alone) */
  391. for (i = 0; i < textProperty.nitems - 1; i++)
  392. {
  393. if (textProperty.value[i] == '\0')
  394. textProperty.value[i] = ' ';
  395. }
  396. proxyClientInfo->screen = pCD->pSD->screen;
  397. proxyClientInfo->wmCommand = (char *)textProperty.value;
  398. /* Since WM_CLIENT_MACHINE is optional, don't fail if not found. */
  399. if (XGetWMClientMachine(wmGD.display, pCD->client, &textProperty))
  400. proxyClientInfo->wmClientMachine = (char *)textProperty.value;
  401. else proxyClientInfo->wmClientMachine = (char *)NULL;
  402. proxyClientInfo->clientID = (char *)NULL;
  403. return True;
  404. }
  405. /*
  406. * IMPORTANT: This function is called by XrmEnumerateDatabase().
  407. * It calls other Xrm*() functions - if dtwm is threaded, THIS
  408. * WILL HANG. For now, dtwm is NOT threaded, so no problem.
  409. */
  410. static Bool
  411. cmpProxyClientProc(XrmDatabase *clientDB, XrmBindingList bindingList,
  412. XrmQuarkList quarkList, XrmRepresentation *reps,
  413. XrmValue *value, XPointer uData)
  414. {
  415. char *clientScreen;
  416. char *wmCommand;
  417. char *wmClientMachine;
  418. char *clientID = (char *)value->addr;
  419. ProxyClientInfo *proxyClientInfo = (ProxyClientInfo *)uData;
  420. if (((wmCommand =
  421. getClientResource(clientID, wmCommandStr)) == (char *)NULL) ||
  422. (strcmp(wmCommand, proxyClientInfo->wmCommand) != 0) ||
  423. ((clientScreen =
  424. getClientResource(clientID, screenStr)) == (char *)NULL) ||
  425. (atoi(clientScreen) != proxyClientInfo->screen))
  426. return FALSE;
  427. /* So far so good. If WM_CLIENT_MACHINE missing from either, */
  428. /* or if it is set in both and it's the same, we've got a match! */
  429. if (!proxyClientInfo->wmClientMachine ||
  430. ((wmClientMachine =
  431. getClientResource(clientID, wmClientMachineStr)) == (char *)NULL) ||
  432. (strcmp(proxyClientInfo->wmClientMachine, wmClientMachine) == 0))
  433. {
  434. proxyClientInfo->clientID = clientID;
  435. return TRUE;
  436. }
  437. return FALSE;
  438. }
  439. static char *
  440. findProxyClientID(ClientData *pCD)
  441. {
  442. ProxyClientInfo proxyClientInfo;
  443. char *clientID = (char *)NULL;
  444. static XrmName proxyName[2] = {NULLQUARK, NULLQUARK};
  445. static XrmClass proxyClass[2] = {NULLQUARK, NULLQUARK};
  446. if (proxyName[0] == NULLQUARK)
  447. {
  448. proxyName[0] = XrmStringToName(proxyClientStr);
  449. proxyClass[0] = XrmStringToClass(proxyClientStr);
  450. }
  451. /*
  452. * We need to match the screen and
  453. * the WM_COMMAND and WM_CLIENT_MACHINE properties.
  454. */
  455. if (!getProxyClientInfo(pCD, &proxyClientInfo))
  456. return clientID;
  457. if (XrmEnumerateDatabase(wmGD.clientResourceDB, proxyName, proxyClass,
  458. XrmEnumOneLevel, cmpProxyClientProc,
  459. (XPointer)&proxyClientInfo))
  460. clientID = proxyClientInfo.clientID;
  461. if (proxyClientInfo.wmCommand)
  462. free(proxyClientInfo.wmCommand);
  463. if (proxyClientInfo.wmClientMachine)
  464. free(proxyClientInfo.wmClientMachine);
  465. return clientID;
  466. }
  467. /*
  468. * Return True if client is *not* XSMP and is listed in the resource DB
  469. * and no checkpoint done yet. Also remove entry from DB if found.
  470. */
  471. static Boolean
  472. findProxyClientDBMatch(ClientData *pCD, char **workSpaceNamesP)
  473. {
  474. if ((pCD->smClientID == (String)NULL) &&
  475. (wmGD.clientResourceDB != (XrmDatabase)NULL) &&
  476. (!smClientDBCheckpointed))
  477. {
  478. char *proxyClientID;
  479. if ((proxyClientID = findProxyClientID(pCD)) != (char *)NULL)
  480. {
  481. char *resourcePtr;
  482. if ((resourcePtr =
  483. getClientResource(proxyClientID, xPositionStr))
  484. != (char *)NULL)
  485. {
  486. pCD->clientX = atoi(resourcePtr);
  487. pCD->clientFlags |= SM_X;
  488. }
  489. if ((resourcePtr =
  490. getClientResource(proxyClientID, yPositionStr))
  491. != (char *)NULL)
  492. {
  493. pCD->clientY = atoi(resourcePtr);
  494. pCD->clientFlags |= SM_Y;
  495. }
  496. if ((resourcePtr =
  497. getClientResource(proxyClientID, widthSizeStr))
  498. != (char *)NULL)
  499. {
  500. pCD->clientWidth = atoi(resourcePtr);
  501. pCD->clientFlags |= SM_WIDTH;
  502. }
  503. if ((resourcePtr =
  504. getClientResource(proxyClientID, heightSizeStr))
  505. != (char *)NULL)
  506. {
  507. pCD->clientHeight = atoi(resourcePtr);
  508. pCD->clientFlags |= SM_HEIGHT;
  509. }
  510. if ((resourcePtr =
  511. getClientResource(proxyClientID, initialStateStr))
  512. != (char *)NULL)
  513. {
  514. pCD->clientState =
  515. (strcmp(resourcePtr, normalStateStr) == 0) ?
  516. NORMAL_STATE : MINIMIZED_STATE;
  517. pCD->clientFlags |= SM_CLIENT_STATE;
  518. }
  519. if ((workSpaceNamesP != (char **)NULL) &&
  520. ((resourcePtr =
  521. getClientResource(proxyClientID, workspacesStr))
  522. != (char *)NULL))
  523. {
  524. *workSpaceNamesP = XtNewString(resourcePtr);
  525. }
  526. return True;
  527. }
  528. }
  529. return False;
  530. }
  531. /*
  532. * Translate the client geometry into what's needed on restore.
  533. */
  534. static void
  535. getClientGeometry(ClientData *pCD, int *clientX, int *clientY,
  536. unsigned int *clientWd, unsigned int *clientHt)
  537. {
  538. *clientX = pCD->clientX;
  539. *clientY = pCD->clientY;
  540. *clientWd = (pCD->widthInc != 0) ?
  541. (pCD->clientWidth - pCD->baseWidth) / pCD->widthInc :
  542. pCD->clientWidth;
  543. *clientHt = (pCD->heightInc != 0) ?
  544. (pCD->clientHeight - pCD->baseHeight) / pCD->heightInc :
  545. pCD->clientHeight;
  546. }
  547. /*
  548. * Assumes: pCD->smClientID is not NULL
  549. */
  550. static Boolean
  551. saveXSMPClient(FILE *fp, ClientData *pCD)
  552. {
  553. int clientX, clientY;
  554. unsigned int clientWd, clientHt;
  555. char *clientID = pCD->smClientID;
  556. fprintf(fp, dbClientFormat, XSMPClientStr, clientID, clientID);
  557. getClientGeometry(pCD, &clientX, &clientY, &clientWd, &clientHt);
  558. if (SAVE_RESOURCE(pCD, WMSAVE_X))
  559. {
  560. fprintf(fp, xPositionStr, clientID);
  561. fprintf(fp, intArg, clientX);
  562. }
  563. if (SAVE_RESOURCE(pCD, WMSAVE_Y))
  564. {
  565. fprintf(fp, yPositionStr, clientID);
  566. fprintf(fp, intArg, clientY);
  567. }
  568. if (!pCD->pSD->useIconBox)
  569. {
  570. WmScreenData *pSD = pCD->pSD;
  571. WmWorkspaceData *pWS;
  572. int i;
  573. for (i = 0; i < pCD->numInhabited; i++)
  574. {
  575. if ((pWS = GetWorkspaceData(pSD, pCD->pWsList[i].wsID))
  576. != (WmWorkspaceData *)NULL)
  577. {
  578. if (SAVE_RESOURCE(pCD, WMSAVE_ICON_X))
  579. {
  580. fprintf(fp, iconXPosStr, clientID, pWS->name);
  581. fprintf(fp, intArg, pCD->pWsList[i].iconX);
  582. }
  583. if (SAVE_RESOURCE(pCD, WMSAVE_ICON_Y))
  584. {
  585. fprintf(fp, iconYPosStr, clientID, pWS->name);
  586. fprintf(fp, intArg, pCD->pWsList[i].iconY);
  587. }
  588. }
  589. }
  590. }
  591. if (SAVE_RESOURCE(pCD, WMSAVE_WIDTH))
  592. {
  593. fprintf(fp, widthSizeStr, clientID);
  594. fprintf(fp, intArg, clientWd);
  595. }
  596. if (SAVE_RESOURCE(pCD, WMSAVE_HEIGHT))
  597. {
  598. fprintf(fp, heightSizeStr, clientID);
  599. fprintf(fp, intArg, clientHt);
  600. }
  601. if (SAVE_RESOURCE(pCD, WMSAVE_STATE))
  602. {
  603. int clientState;
  604. clientState = pCD->clientState & ~UNSEEN_STATE;
  605. fprintf(fp, initialStateStr, clientID);
  606. fprintf(fp, strArg, (clientState == NORMAL_STATE) ?
  607. normalStateStr : iconicStateStr);
  608. }
  609. if (SAVE_RESOURCE(pCD, WMSAVE_WORKSPACES))
  610. {
  611. char *clientWorkspaces = getClientWorkspaces(pCD);
  612. if (clientWorkspaces != (char *)NULL)
  613. {
  614. fprintf(fp, workspacesStr, clientID);
  615. fprintf(fp, strArg, clientWorkspaces);
  616. XtFree(clientWorkspaces);
  617. }
  618. }
  619. return True;
  620. }
  621. /*
  622. * Assumes: pCD->smClientID is NULL
  623. */
  624. static Boolean
  625. saveProxyClient(FILE *fp, ClientData *pCD, int clientIDNum)
  626. {
  627. char clientID[50];
  628. int clientState;
  629. ProxyClientInfo proxyClientInfo;
  630. int clientX, clientY;
  631. unsigned int clientWd, clientHt;
  632. char *clientWorkspaces;
  633. if (!getProxyClientInfo(pCD, &proxyClientInfo))
  634. return False;
  635. sprintf(clientID, "%d", clientIDNum);
  636. fprintf(fp, dbClientFormat, proxyClientStr, clientID, clientID);
  637. fprintf(fp, screenStr, clientID);
  638. fprintf(fp, intArg, proxyClientInfo.screen);
  639. fprintf(fp, wmCommandStr, clientID);
  640. fprintf(fp, strArg, proxyClientInfo.wmCommand);
  641. free(proxyClientInfo.wmCommand);
  642. if (proxyClientInfo.wmClientMachine != (char *)NULL)
  643. {
  644. fprintf(fp, wmClientMachineStr, clientID);
  645. fprintf(fp, strArg, proxyClientInfo.wmClientMachine);
  646. free(proxyClientInfo.wmClientMachine);
  647. }
  648. getClientGeometry(pCD, &clientX, &clientY, &clientWd, &clientHt);
  649. fprintf(fp, xPositionStr, clientID);
  650. fprintf(fp, intArg, clientX);
  651. fprintf(fp, yPositionStr, clientID);
  652. fprintf(fp, intArg, clientY);
  653. if (!pCD->pSD->useIconBox)
  654. {
  655. WmScreenData *pSD = pCD->pSD;
  656. WmWorkspaceData *pWS;
  657. int i;
  658. for (i = 0; i < pCD->numInhabited; i++)
  659. {
  660. if ((pWS = GetWorkspaceData(pSD, pCD->pWsList[i].wsID))
  661. != (WmWorkspaceData *)NULL)
  662. {
  663. fprintf(fp, iconXPosStr, clientID, pWS->name);
  664. fprintf(fp, intArg, pCD->pWsList[i].iconX);
  665. fprintf(fp, iconYPosStr, clientID, pWS->name);
  666. fprintf(fp, intArg, pCD->pWsList[i].iconY);
  667. }
  668. }
  669. }
  670. fprintf(fp, widthSizeStr, clientID);
  671. fprintf(fp, intArg, clientWd);
  672. fprintf(fp, heightSizeStr, clientID);
  673. fprintf(fp, intArg, clientHt);
  674. clientState = pCD->clientState & ~UNSEEN_STATE;
  675. fprintf(fp, initialStateStr, clientID);
  676. fprintf(fp, strArg, (clientState == NORMAL_STATE) ?
  677. normalStateStr : iconicStateStr);
  678. clientWorkspaces = getClientWorkspaces(pCD);
  679. if (clientWorkspaces != (char *)NULL)
  680. {
  681. fprintf(fp, workspacesStr, clientID);
  682. fprintf(fp, strArg, clientWorkspaces);
  683. XtFree(clientWorkspaces);
  684. }
  685. return True;
  686. }
  687. static void
  688. dbRemoveProxyClientEntry(char *proxyClientID)
  689. {
  690. char resourceBuf[MAX_RESOURCE_LEN];
  691. /* Remove entry from DB. Since Xrm does not provide a means */
  692. /* of removing something from the DB, we blank out key info. */
  693. sprintf(resourceBuf, wmCommandStr, proxyClientID);
  694. strcat(resourceBuf, ":");
  695. XrmPutLineResource(&wmGD.clientResourceDB, resourceBuf);
  696. }
  697. /*
  698. * Add callbacks used in session management.
  699. */
  700. void
  701. AddSMCallbacks(void)
  702. {
  703. XtAddCallback(wmGD.topLevelW, XtNsaveCallback,
  704. smSaveYourselfCallback, (XtPointer)NULL);
  705. XtAddCallback(wmGD.topLevelW, XtNdieCallback,
  706. smDieCallback, (XtPointer)NULL);
  707. }
  708. /*
  709. * Resign from session management, closing any connections made.
  710. */
  711. void
  712. ResignFromSM(void)
  713. {
  714. if (wmGD.topLevelW)
  715. {
  716. XtVaSetValues(wmGD.topLevelW,
  717. XtNjoinSession, False,
  718. NULL);
  719. }
  720. }
  721. /*
  722. * Exit the WM, being polite by first resigning from session mgmt.
  723. */
  724. void
  725. ExitWM(int exitCode)
  726. {
  727. ResignFromSM();
  728. exit(exitCode);
  729. }
  730. /*
  731. * Read our private database of client resources.
  732. */
  733. XrmDatabase
  734. LoadClientResourceDB(void)
  735. {
  736. char dbFileName[MAXPATHLEN];
  737. buildDBFileName(dbFileName, False);
  738. return XrmGetFileDatabase(dbFileName);
  739. }
  740. /*
  741. * Write our private database of client resources.
  742. */
  743. XrmDatabase
  744. SaveClientResourceDB(void)
  745. {
  746. String mySessionID;
  747. char dbFileName[MAXPATHLEN];
  748. FILE *fp;
  749. int scr;
  750. WmScreenData *pSD;
  751. ClientData *pCD;
  752. int clientIDNum = 0;
  753. ClientListEntry *pCL;
  754. /* Iterate through client list, saving */
  755. /* appropriate resources for each. */
  756. buildDBFileName(dbFileName, True);
  757. if ((fp = fopen(dbFileName, "w")) == (FILE *)NULL)
  758. return (XrmDatabase)NULL;
  759. XtVaGetValues(wmGD.topLevelW,
  760. XtNsessionID, &mySessionID,
  761. NULL);
  762. fprintf(fp, dbHeader, dtwmFileName, "dtwm Version XSMP1.0",
  763. (mySessionID != (String)NULL) ? mySessionID : "");
  764. for (scr = 0; scr < wmGD.numScreens; scr++)
  765. {
  766. pSD = &(wmGD.Screens[scr]);
  767. for (pCL = pSD->clientList;
  768. pCL != (ClientListEntry *)NULL;
  769. pCL = pCL->nextSibling)
  770. {
  771. /* Each client may be in list twice: normal & icon */
  772. if (pCL->type != NORMAL_STATE)
  773. continue;
  774. pCD = pCL->pCD;
  775. if (pCD->smClientID != (String)NULL)
  776. {
  777. saveXSMPClient(fp, pCD);
  778. }
  779. else
  780. {
  781. if (saveProxyClient(fp, pCD, clientIDNum))
  782. clientIDNum++;
  783. }
  784. }
  785. }
  786. fclose(fp);
  787. /* Retrieve database from file. */
  788. return XrmGetFileDatabase(dbFileName);
  789. }
  790. /*
  791. * As with FindDtSessionMatch(), sets properties and then returns
  792. * an allocated string of workspace names. This string must be
  793. * freed by the caller using XtFree().
  794. */
  795. Boolean
  796. FindClientDBMatch(ClientData *pCD, char **workSpaceNamesP)
  797. {
  798. return (findXSMPClientDBMatch(pCD, workSpaceNamesP) ||
  799. findProxyClientDBMatch(pCD, workSpaceNamesP));
  800. }
  801. Boolean
  802. GetSmClientIdClientList(ClientData ***clients, int *nClients)
  803. {
  804. int scr;
  805. WmScreenData *pSD;
  806. ClientData *pCD;
  807. ClientListEntry *pCL;
  808. *nClients = 0;
  809. *clients = (ClientData **)NULL;
  810. for (scr = 0; scr < wmGD.numScreens; scr++)
  811. {
  812. pSD = &(wmGD.Screens[scr]);
  813. for (pCL = pSD->clientList;
  814. pCL != (ClientListEntry *)NULL;
  815. pCL = pCL->nextSibling)
  816. {
  817. /* Each client may be in list twice: normal & icon */
  818. if (pCL->type != NORMAL_STATE)
  819. continue;
  820. pCD = pCL->pCD;
  821. if (pCD->smClientID != (String)NULL)
  822. {
  823. /* addClientToList() reclaims memory on failure. */
  824. if (!addClientToList(clients, nClients, pCD))
  825. return False;
  826. }
  827. }
  828. }
  829. return True;
  830. }
  831. void
  832. SortClientListByWorkspace(ClientData **clients, int nClients)
  833. {
  834. if (nClients > 0)
  835. {
  836. qsort((void *)clients, nClients,
  837. sizeof(ClientData *), clientWorkspaceCompare);
  838. }
  839. }
  840. void
  841. LoadClientIconPositions(ClientData *pCD)
  842. {
  843. char resourceBuf[MAX_RESOURCE_LEN];
  844. WmScreenData *pSD = pCD->pSD;
  845. WmWorkspaceData *pWS;
  846. int i;
  847. char *resourcePtr;
  848. if (wmGD.clientResourceDB == (XrmDatabase)NULL)
  849. return;
  850. if (pCD->smClientID != (String)NULL)
  851. {
  852. for (i = 0; i < pCD->numInhabited; i++)
  853. {
  854. if ((pWS = GetWorkspaceData(pSD, pCD->pWsList[i].wsID))
  855. != (WmWorkspaceData *)NULL)
  856. {
  857. sprintf(resourceBuf, iconXPosStr, "%s", pWS->name);
  858. if ((resourcePtr =
  859. getXSMPResource(pCD, WMSAVE_ICON_X, resourceBuf))
  860. != (char *)NULL)
  861. {
  862. pCD->pWsList[i].iconX = atoi(resourcePtr);
  863. pCD->clientFlags |= SM_ICON_X;
  864. }
  865. sprintf(resourceBuf, iconYPosStr, "%s", pWS->name);
  866. if ((resourcePtr =
  867. getXSMPResource(pCD, WMSAVE_ICON_Y, resourceBuf))
  868. != (char *)NULL)
  869. {
  870. pCD->pWsList[i].iconY = atoi(resourcePtr);
  871. pCD->clientFlags |= SM_ICON_Y;
  872. }
  873. }
  874. }
  875. return;
  876. }
  877. /* Proxy client */
  878. if (!smClientDBCheckpointed)
  879. {
  880. char *proxyClientID;
  881. if ((proxyClientID = findProxyClientID(pCD)) != (char *)NULL)
  882. {
  883. for (i = 0; i < pCD->numInhabited; i++)
  884. {
  885. if ((pWS = GetWorkspaceData(pSD, pCD->pWsList[i].wsID))
  886. != (WmWorkspaceData *)NULL)
  887. {
  888. sprintf(resourceBuf, iconXPosStr, "%s", pWS->name);
  889. if ((resourcePtr =
  890. getClientResource(proxyClientID, resourceBuf))
  891. != (char *)NULL)
  892. {
  893. pCD->pWsList[i].iconX = atoi(resourcePtr);
  894. pCD->clientFlags |= SM_ICON_X;
  895. }
  896. sprintf(resourceBuf, iconYPosStr, "%s", pWS->name);
  897. if ((resourcePtr =
  898. getClientResource(proxyClientID, resourceBuf))
  899. != (char *)NULL)
  900. {
  901. pCD->pWsList[i].iconY = atoi(resourcePtr);
  902. pCD->clientFlags |= SM_ICON_Y;
  903. }
  904. }
  905. }
  906. dbRemoveProxyClientEntry(proxyClientID);
  907. }
  908. }
  909. }