SmWindow.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  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. /* $TOG: SmWindow.c /main/6 1997/03/07 10:25:30 barstow $ */
  24. /* *
  25. * (c) Copyright 1993, 1994 Hewlett-Packard Company *
  26. * (c) Copyright 1993, 1994 International Business Machines Corp. *
  27. * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
  28. * (c) Copyright 1993, 1994 Novell, Inc. *
  29. */
  30. /*************************************<+>*************************************
  31. *****************************************************************************
  32. **
  33. ** File: SmWindow.c
  34. **
  35. ** Project: HP DT Session Manager (dtsession)
  36. **
  37. ** Description:
  38. ** -----------
  39. ** This file contains all routines needed to query the window tree.
  40. ** The window tree needs to be queried to find all top level windows.
  41. **
  42. **
  43. *******************************************************************
  44. ** (c) Copyright Hewlett-Packard Company, 1990. All rights are
  45. ** reserved. Copying or other reproduction of this program
  46. ** except for archival purposes is prohibited without prior
  47. ** written consent of Hewlett-Packard Company.
  48. ********************************************************************
  49. **
  50. **
  51. **
  52. *****************************************************************************
  53. *************************************<+>*************************************/
  54. #include <stdio.h>
  55. #include <X11/Intrinsic.h>
  56. #include <X11/Xutil.h>
  57. #include <X11/Xatom.h>
  58. #include <Dt/UserMsg.h>
  59. #include <Dt/WsmP.h>
  60. #include "Sm.h"
  61. #include "SmError.h"
  62. #include "SmWindow.h"
  63. #include "SmProtocol.h"
  64. #include "SmGlobals.h"
  65. /*
  66. * Variables global to this module only
  67. */
  68. static Boolean commandTimeout;
  69. /*
  70. * Local Function declarations
  71. */
  72. static WindowInfo GetTopLevelWindowInfo(
  73. Window window) ;
  74. static void WaitForCommand(
  75. Window window) ;
  76. static void WaitTimeout( XtPointer , XtIntervalId *) ;
  77. /*************************************<->*************************************
  78. *
  79. * GetTopLevelWindowInfo (window)
  80. *
  81. *
  82. * Description:
  83. * -----------
  84. * Given a child of the root - find the top level window for that child.
  85. *
  86. *
  87. * Inputs:
  88. * ------
  89. * window = the current window that is being queried about
  90. *
  91. *
  92. * Outputs:
  93. * -------
  94. * retInfo = a WindowInfo structure (a window id + state of the window) that
  95. * gives the top level window information.
  96. *
  97. * Comments:
  98. * --------
  99. *
  100. *************************************<->***********************************/
  101. static WindowInfo
  102. GetTopLevelWindowInfo(
  103. Window window )
  104. {
  105. register int i;
  106. Window parent,root,*children;
  107. WindowInfo retInfo;
  108. Atom actualType;
  109. int actualFormat;
  110. unsigned long nitems;
  111. unsigned long leftover;
  112. unsigned int nchildren;
  113. WM_STATE *wmState = NULL;
  114. XWindowAttributes windowAttr;
  115. if ((XGetWindowAttributes(smGD.display, window,&windowAttr)) == 0)
  116. {
  117. retInfo.wid = 0;
  118. retInfo.termState = 0;
  119. return(retInfo);
  120. }
  121. /*
  122. * If WM_STATE could not be interned at the beginning - the window manager
  123. * may have been slow in coming up. Try it again now.
  124. */
  125. if(XaWmState == None)
  126. {
  127. XaWmState = XInternAtom(smGD.display, _XA_WM_STATE, True);
  128. }
  129. XGetWindowProperty(smGD.display,window,XaWmState,
  130. 0L,(long)BUFSIZ,False,
  131. XaWmState,&actualType,&actualFormat,
  132. &nitems,
  133. &leftover,(unsigned char **) &wmState);
  134. if (actualType==XaWmState)
  135. {
  136. retInfo.wid = window;
  137. retInfo.termState = wmState->state;
  138. /*
  139. * This data needs to be freed up!
  140. */
  141. SM_FREE((char *) wmState);
  142. return(retInfo);
  143. }
  144. else
  145. {
  146. /*
  147. * Be sure to free the window property each time we get it
  148. * if the property exists
  149. */
  150. if(actualType != None)
  151. {
  152. SM_FREE((char *) wmState);
  153. }
  154. if(XQueryTree(smGD.display,window,&root,
  155. &parent,&children,&nchildren) != 0)
  156. {
  157. if(nchildren > 0)
  158. {
  159. i = 0;
  160. while (nchildren--)
  161. {
  162. retInfo = GetTopLevelWindowInfo(children[i++]);
  163. if(retInfo.wid != 0)
  164. {
  165. SM_FREE((char *) children);
  166. return(retInfo);
  167. }
  168. }
  169. SM_FREE((char *) children);
  170. }
  171. }
  172. retInfo.wid = 0;
  173. retInfo.termState = 0;
  174. return(retInfo);
  175. }
  176. }
  177. /*************************************<->*************************************
  178. *
  179. * WaitForCommand (window)
  180. *
  181. *
  182. * Description:
  183. * -----------
  184. * This routine waits for an update on the WM_COMMAND property of a top
  185. * level window after a WM_SAVE_YOURSELF has been placed on that window.
  186. *
  187. *
  188. * Inputs:
  189. * ------
  190. * window = window id for the
  191. *
  192. *
  193. * Outputs:
  194. * -------
  195. *
  196. * Comments:
  197. * --------
  198. *
  199. *************************************<->***********************************/
  200. static void
  201. WaitForCommand(
  202. Window window )
  203. {
  204. XtInputMask isThere;
  205. XEvent event;
  206. XPropertyEvent *pEvent=(XPropertyEvent *)&event;
  207. XtIntervalId comTimerId;
  208. Boolean commandUpdated;
  209. /*
  210. * Set a configurable timer which stops the block
  211. */
  212. commandUpdated = False;
  213. commandTimeout = False;
  214. comTimerId = XtAppAddTimeOut(smGD.appCon, smRes.saveYourselfTimeout,
  215. WaitTimeout, (XtPointer) window);
  216. while((commandUpdated == False) && (commandTimeout == False))
  217. {
  218. if((isThere = XtAppPending(smGD.appCon)) != 0)
  219. {
  220. if(isThere & XtIMXEvent)
  221. {
  222. XtAppPeekEvent(smGD.appCon, &event);
  223. if (event.type==PropertyNotify&&pEvent->window==window&&
  224. pEvent->atom==XA_WM_COMMAND)
  225. {
  226. commandUpdated = True;
  227. }
  228. }
  229. if(commandTimeout == False)
  230. {
  231. XtAppProcessEvent(smGD.appCon, XtIMXEvent | XtIMTimer);
  232. }
  233. }
  234. }
  235. XtRemoveTimeOut(comTimerId);
  236. XSelectInput(smGD.display, window,NoEventMask);
  237. return;
  238. }
  239. /*************************************<->*************************************
  240. *
  241. * SaveYourself (windowInfo)
  242. *
  243. *
  244. * Description:
  245. * -----------
  246. * Places the WM_SAVE_YOURSELF property on each top level window. It then
  247. * waits for the window to update its WM_COMMAND property.
  248. *
  249. *
  250. * Inputs:
  251. * ------
  252. * windowInfo = window id for the top level wincow and the state of that
  253. * window.
  254. *
  255. *
  256. * Outputs:
  257. * -------
  258. *
  259. * Comments:
  260. * --------
  261. *
  262. *************************************<->***********************************/
  263. int
  264. SaveYourself(
  265. WindowInfo windowInfo )
  266. {
  267. int i;
  268. Atom *protoRet;
  269. int nitems;
  270. XClientMessageEvent saveYourselfMessage;
  271. /*
  272. * Get the WM_PROTOCOLS property on the clients top-level window.
  273. */
  274. if(XGetWMProtocols(smGD.display, windowInfo.wid, &protoRet, &nitems) == 0)
  275. {
  276. /*
  277. * If the client doesn't have a WM_PROTOCOLS property,
  278. * it doesn't support any protocols.
  279. */
  280. return (-1);
  281. }
  282. /* Look for WM_SAVE_YOURSELF atom. */
  283. for (i=0;i<nitems;++i)
  284. {
  285. if (protoRet[i]==XaWmSaveYourself)
  286. break;
  287. }
  288. if (i==nitems)
  289. {
  290. SM_FREE((char *) protoRet);
  291. return(-1); /* doesn't participate in WM_SAVE_YOURSELF */
  292. }
  293. /* Construct the ClientMessage. */
  294. saveYourselfMessage.type=ClientMessage;
  295. saveYourselfMessage.window=windowInfo.wid;
  296. saveYourselfMessage.message_type=XaWmProtocols;
  297. saveYourselfMessage.format=32;
  298. saveYourselfMessage.data.l[0]=XaWmSaveYourself;
  299. saveYourselfMessage.data.l[1]=CurrentTime;
  300. /*
  301. * look for changes in WM_COMMAND property
  302. */
  303. XSelectInput(smGD.display,windowInfo.wid,PropertyChangeMask);
  304. XFlush(smGD.display);
  305. /*
  306. * Send the ClientMessage to the client. XSendEvent returns a 1 if it
  307. * is successful in converting the event to a wire event.
  308. */
  309. if (XSendEvent(smGD.display,windowInfo.wid,False,NoEventMask,
  310. (XEvent *) &saveYourselfMessage) != 1)
  311. {
  312. PrintError(DtError, GETMESSAGE(20, 1, "Client message failed. Client information will not be saved."));
  313. return(-1);
  314. }
  315. /* Wait for client to update WM_COMMAND. */
  316. WaitForCommand(windowInfo.wid);
  317. SM_FREE((char *) protoRet);
  318. return (0);
  319. }
  320. /*************************************<->*************************************
  321. *
  322. * GetTopLevelWindows (screen, toplist, toplistlength, containedListLength)
  323. *
  324. *
  325. * Description:
  326. * -----------
  327. * Querys the window tree and constructs a list of all top level windows
  328. *
  329. *
  330. * Inputs:
  331. * ------
  332. * screen = pointer to the screen we're currently querying on
  333. *
  334. *
  335. * Outputs:
  336. * -------
  337. * toplist = a pointer to the list of top level windows
  338. * toplistlength = the length of the list of top level windows
  339. * containedListLength = the length of the list of contained windows
  340. *
  341. * Comments:
  342. * --------
  343. *
  344. *************************************<->***********************************/
  345. int
  346. GetTopLevelWindows(
  347. int screen,
  348. WindowInfo **topList,
  349. unsigned int *topListLength,
  350. unsigned int *containedListLength )
  351. {
  352. Window rootWindow, parentWindow, *tmpChild;
  353. Window *childList, *embeddedList, *tmpList;
  354. WindowInfo topLevelWindowInfo;
  355. int i;
  356. unsigned long numEmbedded;
  357. /*
  358. * Get a list of children of the root window
  359. */
  360. if (XQueryTree(smGD.display, RootWindow(smGD.display, screen),&rootWindow,
  361. &parentWindow, &childList, topListLength) == 0)
  362. {
  363. PrintError(DtError, GETMESSAGE(20, 2, "Invalid root window. Can not save client information."));
  364. SM_EXIT(-1);
  365. }
  366. /*
  367. * add in the list of top level windows embedded in the front panel
  368. */
  369. if(_DtGetEmbeddedClients(smGD.display, RootWindow(smGD.display, screen),
  370. &embeddedList, &numEmbedded) != Success)
  371. {
  372. numEmbedded = 0;
  373. }
  374. if (*topListLength)
  375. *topList=(WindowInfo *) SM_MALLOC(sizeof(WindowInfo)*
  376. (*topListLength + numEmbedded));
  377. tmpChild = childList;
  378. /* scan list */
  379. for (i=0 ; i<*topListLength; ++i, tmpChild++)
  380. {
  381. topLevelWindowInfo = GetTopLevelWindowInfo(*tmpChild);
  382. if (!topLevelWindowInfo.wid)
  383. {
  384. topLevelWindowInfo.wid = (*tmpChild);
  385. /*
  386. * Assume if you can't find a state that it is "don't care"
  387. * this could be a faulty assumption CHECK IT OUT
  388. */
  389. topLevelWindowInfo.termState = 0;
  390. }
  391. (*topList)[i] = topLevelWindowInfo;
  392. }
  393. /*
  394. * Now add in the extra window id's to check
  395. */
  396. tmpList = embeddedList;
  397. for(i = *topListLength;i < (*topListLength + numEmbedded);i++)
  398. {
  399. (*topList)[i].wid = *tmpList;tmpList++;
  400. (*topList)[i].termState = NormalState;
  401. }
  402. if(numEmbedded > 0)
  403. {
  404. SM_FREE((char *) embeddedList);
  405. }
  406. if(*topListLength)
  407. {
  408. SM_FREE((char *) childList);
  409. }
  410. *containedListLength = numEmbedded;
  411. return(0);
  412. }
  413. /*************************************<->*************************************
  414. *
  415. * WaitTimeout
  416. *
  417. *
  418. * Description:
  419. * -----------
  420. * Timeout procedure the WaitForCommand routine. It stops a loop waiting
  421. * for an update of the WM_COMMAND property from a client.
  422. *
  423. *
  424. * Inputs:
  425. * ------
  426. *
  427. *
  428. * Outputs:
  429. * -------
  430. * commandTimeout = (global) flag that stops the loop
  431. *
  432. * Comments:
  433. * --------
  434. *
  435. *************************************<->***********************************/
  436. static void
  437. WaitTimeout(
  438. XtPointer client_data,
  439. XtIntervalId *id )
  440. {
  441. String tmpString, tmpError;
  442. char *winName;
  443. Status success;
  444. success = XFetchName(smGD.display, (Window) client_data, &winName);
  445. if (success && winName)
  446. {
  447. tmpString = GETMESSAGE(20, 4, "Session restoration information not updated for client %s. Invalid information may be saved.");
  448. tmpError = SM_MALLOC(strlen(winName) + strlen(tmpString) + 5);
  449. if (tmpError)
  450. {
  451. sprintf(tmpError, tmpString, winName);
  452. PrintError(DtError, tmpError);
  453. SM_FREE(tmpError);
  454. }
  455. SM_FREE(winName);
  456. }
  457. commandTimeout = True;
  458. return;
  459. } /* END OF FUNCTION WaitTimeout */