1 /* $TOG: SmWindow.c /main/6 1997/03/07 10:25:30 barstow $ */
3 * (c) Copyright 1993, 1994 Hewlett-Packard Company *
4 * (c) Copyright 1993, 1994 International Business Machines Corp. *
5 * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
6 * (c) Copyright 1993, 1994 Novell, Inc. *
8 /*************************************<+>*************************************
9 *****************************************************************************
13 ** Project: HP DT Session Manager (dtsession)
17 ** This file contains all routines needed to query the window tree.
18 ** The window tree needs to be queried to find all top level windows.
21 *******************************************************************
22 ** (c) Copyright Hewlett-Packard Company, 1990. All rights are
23 ** reserved. Copying or other reproduction of this program
24 ** except for archival purposes is prohibited without prior
25 ** written consent of Hewlett-Packard Company.
26 ********************************************************************
30 *****************************************************************************
31 *************************************<+>*************************************/
34 #include <X11/Intrinsic.h>
35 #include <X11/Xutil.h>
36 #include <X11/Xatom.h>
37 #include <Dt/UserMsg.h>
41 #include "SmProtocol.h"
42 #include "SmGlobals.h"
46 * Variables global to this module only
48 static Boolean commandTimeout;
51 * Local Function declarations
54 static WindowInfo GetTopLevelWindowInfo(
56 static void WaitForCommand(
58 static void WaitTimeout( XtPointer , XtIntervalId *) ;
63 /*************************************<->*************************************
65 * GetTopLevelWindowInfo (window)
70 * Given a child of the root - find the top level window for that child.
75 * window = the current window that is being queried about
80 * retInfo = a WindowInfo structure (a window id + state of the window) that
81 * gives the top level window information.
86 *************************************<->***********************************/
88 GetTopLevelWindowInfo(
92 Window parent,root,*children;
97 unsigned long leftover;
98 unsigned int nchildren;
99 WM_STATE *wmState = NULL;
100 XWindowAttributes windowAttr;
102 if ((XGetWindowAttributes(smGD.display, window,&windowAttr)) == 0)
105 retInfo.termState = 0;
110 * If WM_STATE could not be interned at the beginning - the window manager
111 * may have been slow in coming up. Try it again now.
113 if(XaWmState == None)
115 XaWmState = XInternAtom(smGD.display, _XA_WM_STATE, True);
118 XGetWindowProperty(smGD.display,window,XaWmState,
119 0L,(long)BUFSIZ,False,
120 XaWmState,&actualType,&actualFormat,
122 &leftover,(unsigned char **) &wmState);
123 if (actualType==XaWmState)
125 retInfo.wid = window;
126 retInfo.termState = wmState->state;
129 * This data needs to be freed up!
131 SM_FREE((char *) wmState);
137 * Be sure to free the window property each time we get it
138 * if the property exists
140 if(actualType != None)
142 SM_FREE((char *) wmState);
145 if(XQueryTree(smGD.display,window,&root,
146 &parent,&children,&nchildren) != 0)
153 retInfo = GetTopLevelWindowInfo(children[i++]);
156 SM_FREE((char *) children);
160 SM_FREE((char *) children);
164 retInfo.termState = 0;
171 /*************************************<->*************************************
173 * WaitForCommand (window)
178 * This routine waits for an update on the WM_COMMAND property of a top
179 * level window after a WM_SAVE_YOURSELF has been placed on that window.
184 * window = window id for the
193 *************************************<->***********************************/
200 XPropertyEvent *pEvent=(XPropertyEvent *)&event;
201 XtIntervalId comTimerId;
202 Boolean commandUpdated;
205 * Set a configurable timer which stops the block
207 commandUpdated = False;
208 commandTimeout = False;
209 comTimerId = XtAppAddTimeOut(smGD.appCon, smRes.saveYourselfTimeout,
210 WaitTimeout, (XtPointer) window);
212 while((commandUpdated == False) && (commandTimeout == False))
214 if((isThere = XtAppPending(smGD.appCon)) != 0)
216 if(isThere & XtIMXEvent)
218 XtAppPeekEvent(smGD.appCon, &event);
219 if (event.type==PropertyNotify&&pEvent->window==window&&
220 pEvent->atom==XA_WM_COMMAND)
222 commandUpdated = True;
225 if(commandTimeout == False)
227 XtAppProcessEvent(smGD.appCon, XtIMXEvent | XtIMTimer);
232 XtRemoveTimeOut(comTimerId);
233 XSelectInput(smGD.display, window,NoEventMask);
240 /*************************************<->*************************************
242 * SaveYourself (windowInfo)
247 * Places the WM_SAVE_YOURSELF property on each top level window. It then
248 * waits for the window to update its WM_COMMAND property.
253 * windowInfo = window id for the top level wincow and the state of that
263 *************************************<->***********************************/
266 WindowInfo windowInfo )
272 XClientMessageEvent saveYourselfMessage;
275 * Get the WM_PROTOCOLS property on the clients top-level window.
277 if(XGetWMProtocols(smGD.display, windowInfo.wid, &protoRet, &nitems) == 0)
280 * If the client doesn't have a WM_PROTOCOLS property,
281 * it doesn't support any protocols.
286 /* Look for WM_SAVE_YOURSELF atom. */
287 for (i=0;i<nitems;++i)
289 if (protoRet[i]==XaWmSaveYourself)
295 SM_FREE((char *) protoRet);
296 return(-1); /* doesn't participate in WM_SAVE_YOURSELF */
299 /* Construct the ClientMessage. */
300 saveYourselfMessage.type=ClientMessage;
301 saveYourselfMessage.window=windowInfo.wid;
302 saveYourselfMessage.message_type=XaWmProtocols;
303 saveYourselfMessage.format=32;
304 saveYourselfMessage.data.l[0]=XaWmSaveYourself;
305 saveYourselfMessage.data.l[1]=CurrentTime;
308 * look for changes in WM_COMMAND property
310 XSelectInput(smGD.display,windowInfo.wid,PropertyChangeMask);
311 XFlush(smGD.display);
314 * Send the ClientMessage to the client. XSendEvent returns a 1 if it
315 * is successful in converting the event to a wire event.
317 if (XSendEvent(smGD.display,windowInfo.wid,False,NoEventMask,
318 (XEvent *) &saveYourselfMessage) != 1)
320 PrintError(DtError, GETMESSAGE(20, 1, "Client message failed. Client information will not be saved."));
324 /* Wait for client to update WM_COMMAND. */
325 WaitForCommand(windowInfo.wid);
327 SM_FREE((char *) protoRet);
334 /*************************************<->*************************************
336 * GetTopLevelWindows (screen, toplist, toplistlength, containedListLength)
341 * Querys the window tree and constructs a list of all top level windows
346 * screen = pointer to the screen we're currently querying on
351 * toplist = a pointer to the list of top level windows
352 * toplistlength = the length of the list of top level windows
353 * containedListLength = the length of the list of contained windows
358 *************************************<->***********************************/
362 WindowInfo **topList,
363 unsigned int *topListLength,
364 unsigned int *containedListLength )
366 Window rootWindow, parentWindow, *tmpChild;
367 Window *childList, *embeddedList, *tmpList;
368 WindowInfo topLevelWindowInfo;
370 unsigned long numEmbedded;
373 * Get a list of children of the root window
375 if (XQueryTree(smGD.display, RootWindow(smGD.display, screen),&rootWindow,
376 &parentWindow, &childList, topListLength) == 0)
378 PrintError(DtError, GETMESSAGE(20, 2, "Invalid root window. Can not save client information."));
383 * add in the list of top level windows embedded in the front panel
385 if(_DtGetEmbeddedClients(smGD.display, RootWindow(smGD.display, screen),
386 &embeddedList, &numEmbedded) != Success)
392 *topList=(WindowInfo *) SM_MALLOC(sizeof(WindowInfo)*
393 (*topListLength + numEmbedded));
395 tmpChild = childList;
397 for (i=0 ; i<*topListLength; ++i, tmpChild++)
399 topLevelWindowInfo = GetTopLevelWindowInfo(*tmpChild);
400 if (!topLevelWindowInfo.wid)
402 topLevelWindowInfo.wid = (*tmpChild);
404 * Assume if you can't find a state that it is "don't care"
405 * this could be a faulty assumption CHECK IT OUT
407 topLevelWindowInfo.termState = 0;
409 (*topList)[i] = topLevelWindowInfo;
413 * Now add in the extra window id's to check
415 tmpList = embeddedList;
416 for(i = *topListLength;i < (*topListLength + numEmbedded);i++)
418 (*topList)[i].wid = *tmpList;tmpList++;
419 (*topList)[i].termState = NormalState;
424 SM_FREE((char *) embeddedList);
429 SM_FREE((char *) childList);
432 *containedListLength = numEmbedded;
439 /*************************************<->*************************************
446 * Timeout procedure the WaitForCommand routine. It stops a loop waiting
447 * for an update of the WM_COMMAND property from a client.
456 * commandTimeout = (global) flag that stops the loop
461 *************************************<->***********************************/
464 XtPointer client_data,
467 String tmpString, tmpError;
471 success = XFetchName(smGD.display, (Window) client_data, &winName);
472 if (success && winName)
474 tmpString = GETMESSAGE(20, 4, "Session restoration information not updated for client %s. Invalid information may be saved.");
475 tmpError = SM_MALLOC(strlen(winName) + strlen(tmpString) + 5);
478 sprintf(tmpError, tmpString, winName);
479 PrintError(DtError, tmpError);
484 commandTimeout = True;
486 } /* END OF FUNCTION WaitTimeout */