WmXSMP.c 28 KB

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